2

我正在使用自定义 MediaStreamSource 在后台代理中从网络流式传输音乐。在良好的网络条件下,这可以正常工作,但当网络连接不稳定时,就会出现一个奇怪的问题。

当曲目开始播放时,通过第一次调用 MediaStreamSource.GetSampleAsync() 一切顺利。因为连接不稳定,如果没有足够的数据可用,源调用 ReportGetSampleProgress(double) 并返回而不报告样本。这符合 MSDN 文档和代码示例。

奇怪的是根本没有对 GetSampleAsync 的进一步调用!随着缓冲的继续,源继续 ReportGetSampleProgress 直到样本准备好,此时它调用ReportGetSampleProgress(1.0)以指示缓冲区已满。

我尝试了几种方法,包括:

  • ReportGetSampleCompleted缓冲完成时;这失败了,因为下载事件来自任意线程,并且此方法显然对调用线程以及对 GetSampleAsync 的调用是否在堆栈上都很敏感;无效的调用情况会导致 COM 错误。
  • 在精确的错误情况下,停止并启动 BackgroundAudioPlayer:这将无法重新启动流式传输。

一旦最初无法读取示例挂起,我如何才能重新开始流式传输?

4

3 回答 3

1

ReportGetSampleCompleted在这种情况下,一旦数据可用是正确的方法。

您必须在 MSS 中跟踪您是否需要立即报告任何新的样本数据或等待GetSampleAsync被调用。

但是请注意,在涉及的各个线程之间可能会由于竞争条件而导致失败。

于 2013-03-15T22:37:24.027 回答
1

碰巧,一个解决方案似乎是打破 name 建议的合同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,阻塞可能会阻止其他流被读取。作为一个流媒体音乐应用程序,我们一次只提供一个流,所以在这种情况下,我们似乎没问题。

不过,我希望我知道一个通​​用的解决方案,因为这显然是作弊。

于 2013-03-17T05:12:56.343 回答
1

If you don't have any data available then fill a buffer with silence and report that. This will give you time for real data to come in.

You want to center the data to the middle of a PCM range on your silence data or you'll get a click when going silent.

MemoryStream stream = new MemoryStream();

byte[] silenceBuffer = BitConverter.GetBytes( (ushort)(short.MaxValue) );
for(int i=0; i < 1000; i++ )
    stream.Write( silenceBuffer, 0, silenceBuffer.Length );

Gook luck.

于 2013-05-30T13:36:27.273 回答