sp_session_player_load() 上的 AccessViolationException
AccessViolationException on sp_session_player_load()
我正在尝试创建一个基于 Spotify 的 libspotify SDK 的流媒体应用程序。
为了在 C# 中实现这一点,我使用了 ohLibspotify 绑定和包装器。这只是一个薄的抽象层,所以它的大部分将是一个 1:1 映射到 libspotify SDK。要播放传入的 PCM 数据,我正在使用 NAudio 库。
大多数时候我可以播放第一首曲目。然后当我加载第二个时,我在尝试调用 sp_session_player_load()
时得到 AccessViolationException
。此外,这有时会在我第一次尝试播放曲目时发生,有时会在第三次发生。
这是我用来播放曲目的函数。
public void playTrack(string track, string juke)
{
new Thread(new ThreadStart(() =>
{
var playable = Link.CreateFromString(string.Format("spotify:track:{0}", track)).AsTrack();
if (playing)
{
player.Pause();
App.Logic.spotify.sp_session.PlayerUnload();
}
buffer = new BufferedWaveProvider(new WaveFormat())
{
BufferDuration = TimeSpan.FromSeconds(120),
DiscardOnBufferOverflow = false
};
var waitEvent = new AutoResetEvent(false);
while (!playable.IsLoaded())
{
waitEvent.WaitOne(30);
}
App.Logic.spotify.sp_session.PlayerLoad(playable);
App.Logic.spotify.sp_session.PlayerPlay(true);
player = new WaveOut();
player.Init(buffer);
player.Play();
playing = true;
})).Start();
}
AccessViolationException 出现在包装库中以下代码的第 6 行。
[DllImport("libspotify")]
internal static extern SpotifyError sp_session_player_load(IntPtr @session, IntPtr @track);
public void PlayerLoad(Track @track)
{
SpotifyError errorValue;
errorValue = NativeMethods.sp_session_player_load(this._handle, track._handle);
SpotifyMarshalling.CheckError(errorValue);
}
流式回调:
public override void GetAudioBufferStats(SpotifySession session, out AudioBufferStats stats)
{
stats = new AudioBufferStats()
{
samples = App.Logic.spotify.player.buffer.BufferedBytes / 2,
stutter = 0
};
}
public override int MusicDelivery(SpotifySession session, AudioFormat format, IntPtr frames, int num_frames) {
int incoming_size = num_frames * format.channels * 2;
try
{
if (incoming_size > sample_buffer.Length)
{
short rendered_frames = Convert.ToInt16(Math.Floor((sample_buffer.Length / format.channels / 2d)));
short rendered_size = Convert.ToInt16(rendered_frames * format.channels * 2);
Marshal.Copy(frames, sample_buffer, 0, rendered_size);
App.Logic.spotify.player.buffer.AddSamples(sample_buffer, 0, rendered_size);
return rendered_frames;
}
else
{
Marshal.Copy(frames, sample_buffer, 0, incoming_size);
App.Logic.spotify.player.buffer.AddSamples(sample_buffer, 0, incoming_size);
return num_frames;
}
}
catch (Exception e)
{
return 0;
}
}
正如@Weeble 在他对我的问题的评论中所说的那样。很难诊断 AccessViolationException
的可能来源。在我的例子中,它是线程化的,有多个线程同时访问 Spotify 会话对象。
如果这也可能是您的问题,您可能需要查看 this article。它讨论了 C# 和 VB.Net 中的线程同步。真的很简单。
lock(sessionLock)
{
App.Logic.spotify.sp_session.PlayerLoad(playable);
App.Logic.spotify.sp_session.PlayerPlay(true);
}
sessionLock
对象可以是Object
类型的简单实例化。尽管不建议为此使用任何 "actual" 对象。在我的例子中,我做了以下事情:
public class Player
{
private object sessionLock = new object();
// Rest of code with locks
}
这样您就可以在每次想要访问时锁定 sessionLock
对象,在本例中是 SpotifySession
对象。这样,当线程 1 正在加载歌曲时,线程 2 同时要处理事件时,线程 2 将被阻塞,直到 sessionLock
上的锁被解除。
正如@Weeble 所建议的,如果线程不是问题,您可能还需要研究其他一些事情。
- 您可能没有正确处理 spotify 的引用计数,不小心过早地减少了引用计数,或者忘记在必要的地方增加一个。
- 您可能破坏了处理本机指针的音乐回调中的内存。
- ohLibspotify 或 libspotify 中可能存在错误。如果您认为是这种情况,请前往 ohLibspotify repo or the openhome forum 报告您的问题。
我正在尝试创建一个基于 Spotify 的 libspotify SDK 的流媒体应用程序。
为了在 C# 中实现这一点,我使用了 ohLibspotify 绑定和包装器。这只是一个薄的抽象层,所以它的大部分将是一个 1:1 映射到 libspotify SDK。要播放传入的 PCM 数据,我正在使用 NAudio 库。
大多数时候我可以播放第一首曲目。然后当我加载第二个时,我在尝试调用 sp_session_player_load()
时得到 AccessViolationException
。此外,这有时会在我第一次尝试播放曲目时发生,有时会在第三次发生。
这是我用来播放曲目的函数。
public void playTrack(string track, string juke)
{
new Thread(new ThreadStart(() =>
{
var playable = Link.CreateFromString(string.Format("spotify:track:{0}", track)).AsTrack();
if (playing)
{
player.Pause();
App.Logic.spotify.sp_session.PlayerUnload();
}
buffer = new BufferedWaveProvider(new WaveFormat())
{
BufferDuration = TimeSpan.FromSeconds(120),
DiscardOnBufferOverflow = false
};
var waitEvent = new AutoResetEvent(false);
while (!playable.IsLoaded())
{
waitEvent.WaitOne(30);
}
App.Logic.spotify.sp_session.PlayerLoad(playable);
App.Logic.spotify.sp_session.PlayerPlay(true);
player = new WaveOut();
player.Init(buffer);
player.Play();
playing = true;
})).Start();
}
AccessViolationException 出现在包装库中以下代码的第 6 行。
[DllImport("libspotify")]
internal static extern SpotifyError sp_session_player_load(IntPtr @session, IntPtr @track);
public void PlayerLoad(Track @track)
{
SpotifyError errorValue;
errorValue = NativeMethods.sp_session_player_load(this._handle, track._handle);
SpotifyMarshalling.CheckError(errorValue);
}
流式回调:
public override void GetAudioBufferStats(SpotifySession session, out AudioBufferStats stats)
{
stats = new AudioBufferStats()
{
samples = App.Logic.spotify.player.buffer.BufferedBytes / 2,
stutter = 0
};
}
public override int MusicDelivery(SpotifySession session, AudioFormat format, IntPtr frames, int num_frames) {
int incoming_size = num_frames * format.channels * 2;
try
{
if (incoming_size > sample_buffer.Length)
{
short rendered_frames = Convert.ToInt16(Math.Floor((sample_buffer.Length / format.channels / 2d)));
short rendered_size = Convert.ToInt16(rendered_frames * format.channels * 2);
Marshal.Copy(frames, sample_buffer, 0, rendered_size);
App.Logic.spotify.player.buffer.AddSamples(sample_buffer, 0, rendered_size);
return rendered_frames;
}
else
{
Marshal.Copy(frames, sample_buffer, 0, incoming_size);
App.Logic.spotify.player.buffer.AddSamples(sample_buffer, 0, incoming_size);
return num_frames;
}
}
catch (Exception e)
{
return 0;
}
}
正如@Weeble 在他对我的问题的评论中所说的那样。很难诊断 AccessViolationException
的可能来源。在我的例子中,它是线程化的,有多个线程同时访问 Spotify 会话对象。
如果这也可能是您的问题,您可能需要查看 this article。它讨论了 C# 和 VB.Net 中的线程同步。真的很简单。
lock(sessionLock)
{
App.Logic.spotify.sp_session.PlayerLoad(playable);
App.Logic.spotify.sp_session.PlayerPlay(true);
}
sessionLock
对象可以是Object
类型的简单实例化。尽管不建议为此使用任何 "actual" 对象。在我的例子中,我做了以下事情:
public class Player
{
private object sessionLock = new object();
// Rest of code with locks
}
这样您就可以在每次想要访问时锁定 sessionLock
对象,在本例中是 SpotifySession
对象。这样,当线程 1 正在加载歌曲时,线程 2 同时要处理事件时,线程 2 将被阻塞,直到 sessionLock
上的锁被解除。
正如@Weeble 所建议的,如果线程不是问题,您可能还需要研究其他一些事情。
- 您可能没有正确处理 spotify 的引用计数,不小心过早地减少了引用计数,或者忘记在必要的地方增加一个。
- 您可能破坏了处理本机指针的音乐回调中的内存。
- ohLibspotify 或 libspotify 中可能存在错误。如果您认为是这种情况,请前往 ohLibspotify repo or the openhome forum 报告您的问题。