BackgroundAudioPlayer "Plays" but does not call GetSampleAsync ()

I transfer music from the Internet to the background agent using my own MediaStreamSource. Under good network conditions, this works fine, but when the network connection is spotty, a strange problem arises.

When the track starts playing, everything goes up the first call to MediaStreamSource.GetSampleAsync (). Since the connection is spotty, if insufficient data is available, the source calls ReportGetSampleProgress (double) and returns without a sample message. This is consistent with the MSDN documentation and sample code.

Curiously, there are no more GetSampleAsync calls anymore! As buffering continues, the source continues to ReportGetSampleProgress until the sample is ready when it calls ReportGetSampleProgress(1.0) to indicate the full buffer.

I tried several approaches, including:

  • ReportGetSampleCompleted when buffering is complete; this is because load events occur in arbitrary threads, and this method is explicitly sensitive to both the calling thread and the call to GetSampleAsync on the stack; invalid call circumstances result in COM errors.
  • In accurate error mode, stop and start BackgroundAudioPlayer: this does not allow restarting streaming.

How can I get streaming playback again as soon as the initial failure to read the sample hangs things?

+2
source share
3 answers

Be that as it may, the solution is to break the contract suggested by the name GetSampleAsync and block this method when there is not enough buffered data. Then, the callbacks of the thread can pulsate the locked object, and the reading of the sample can be repeated. Something like this works well:

 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); } 

It would seem that blocking in the Async method may be unreasonable, but the experience of running this code on the device suggests otherwise. Per http://msdn.microsoft.com/en-us/library/system.windows.media.mediastreamsource.getsampleasync(v=vs.95).aspx , blocking may prevent other threads from reading. As a streaming music app, we only ever serve one stream at a time, so in this case it seems like we're fine.

I would like for me to know the general solution here, because it is clearly deceiving.

+1
source

ReportGetSampleCompleted When data is available, this is the right approach in this scenario.

You will need to track in your MSS whether you should immediately report any new sample data or wait for GetSampleAsync .

However, observe that crashes due to race conditions are possible between the various threads involved.

+1
source

If you do not have available data, fill the buffer with silence and report it. This will give you time to enter real data.

You want to center the data to the middle of the PCM range according to the silence data, or you will get a click on silence.

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

Luck.

+1
source

Source: https://habr.com/ru/post/971210/


All Articles