背景audioplayer正在播放'但不调用GetSampleAsync()
本文关键字:调用 GetSampleAsync audioplayer 播放 背景 | 更新日期: 2023-09-27 18:04:24
我在后台代理使用自定义MediaStreamSource从web流媒体音乐。在良好的网络条件下,这工作得很好,但是当网络连接不稳定时,一个奇怪的问题就出现了。
当曲目开始播放时,通过第一次调用MediaStreamSource.GetSampleAsync(),一切都顺利进行。由于连接是不稳定的,如果没有足够的数据可用,则源调用ReportGetSampleProgress(double)并返回而不报告样本。这与MSDN文档和代码示例一致。
奇怪的是根本没有对getsamplesync的进一步调用!随着缓冲的继续,源继续ReportGetSampleProgress,直到一个样本准备好,当它调用ReportGetSampleProgress(1.0)
来指示一个完整的缓冲区时。
我尝试了几种方法,包括:
- 当缓冲完成时
-
ReportGetSampleCompleted
;这是失败的,因为下载事件进入任意线程,这个方法显然对调用线程和调用GetSampleAsync是否在堆栈上都很敏感;无效调用情况导致COM错误。 - 在精确的错误条件下,停止并启动BackgroundAudioPlayer:这无法重新启动流媒体。
我怎么能让流再次开始,一旦最初的失败读取样本挂起的东西?
一旦数据可用ReportGetSampleCompleted
是正确的方法。
您必须在MSS中跟踪您是否需要立即报告任何新的样本数据或等待GetSampleAsync
被调用。
当它发生时,一个解决方案似乎是打破名称GetSampleAsync
所建议的合约,并在没有足够的数据被缓冲时阻塞该方法。然后,流回调可以对锁定的对象进行脉冲处理,并且可以重试样本读取。像这样的代码可以很好地工作:
private void OnMoreDataDownloaded(object sender, EventArgs e)
{
// We're on an arbitrary thread, so instead of reporting
// a sample here we should just pulse.
lock (buffering_lock) {
is_buffering = false;
Monitor.Pulse(buffering_lock);
}
}
protected override void GetSampleAsync()
{
while (we_need_more_data) {
lock (buffering_lock) {
is_buffering = true;
while (is_buffering) {
Monitor.Wait(buffering_lock);
}
}
// code code code
ReportGetSampleCompleted(sample);
}
在Async方法中阻塞似乎是不明智的,但是在设备上运行这段代码的经验表明情况并非如此。根据http://msdn.microsoft.com/en-us/library/system.windows.media.mediastreamsource.getsampleasync(v=vs.95).aspx,阻塞可能会阻止其他流被读取。作为一个流媒体音乐应用程序,我们每次只提供一个流媒体,所以在这种情况下,我们似乎没问题。
我希望我知道这里的一般解决方案,因为这显然是作弊。
如果没有任何可用的数据,那么用沉默填充缓冲区并报告它。这将为您获得真实数据提供时间。
你想把数据居中到你的沉默数据的PCM范围的中间,或者当你静音时你会得到一个点击。
MemoryStream stream = new MemoryStream();
byte[] silenceBuffer = BitConverter.GetBytes( (ushort)(short.MaxValue) );
for(int i=0; i < 1000; i++ )
stream.Write( silenceBuffer, 0, silenceBuffer.Length );
祝你好运