BackgroundAudioPlayer是'正在播放'但没有调用GetSampleAsync()

时间:2013-03-15 22:14:36

标签: c# windows-phone-8 windows-phone background-audio

我使用自定义MediaStreamSource在后台代理中从网络传输音乐。在良好的网络条件下,这种方法很好,但是当网络连接不稳定时,就会出现一个奇怪的问题。

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

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

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

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

一旦最初读取样本失败,我怎样才能再次进行流式传输?

3 个答案:

答案 0 :(得分:1)

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

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

然而,请注意所涉及的各种线程之间可能因竞争条件而导致的失败。

答案 1 :(得分:1)

实际上,解决方案似乎是打破名称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方法中阻塞可能并不明智,但在设备上运行此代码的经验则表明不然。根据{{​​3}},阻止可能会阻止其他流被读取。作为一个流媒体音乐应用,我们一次只提供一个流,所以在这种情况下,我们似乎没事。

我希望我知道这里的一般解决方案,因为这显然是在作弊。

答案 2 :(得分:1)

如果您没有任何可用数据,请填写缓冲区并报告。这将为您提供实时数据的时间。

您希望将数据置于静音数据的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 );

Gook运气。