我使用自定义MediaStreamSource在后台代理中从网络传输音乐。在良好的网络条件下,这种方法很好,但是当网络连接不稳定时,就会出现一个奇怪的问题。
当曲目开始播放时,通过第一次调用MediaStreamSource.GetSampleAsync(),一切顺利。由于连接不稳定,如果数据不足,则源调用ReportGetSampleProgress(double)并返回而不报告样本。这符合MSDN文档和代码示例。
奇怪的是,根本没有进一步调用GetSampleAsync!当缓冲继续时,源继续ReportGetSampleProgress直到样本准备好,当它调用ReportGetSampleProgress(1.0)
以指示完整缓冲区时。
我尝试了几种方法,包括:
ReportGetSampleCompleted
;这会失败,因为下载事件会进入任意线程,并且此方法对调用线程以及对GetSampleAsync的调用是否在堆栈上显然都很敏感;无效的调用情况会导致COM错误。一旦最初读取样本失败,我怎样才能再次进行流式传输?
答案 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运气。