背景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:这无法重新启动流媒体。

我怎么能让流再次开始,一旦最初的失败读取样本挂起的东西?

背景audioplayer正在播放'但不调用GetSampleAsync()

一旦数据可用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 );

祝你好运