As it happens, a solution appears to be to break the contract suggested by the name GetSampleAsync
, and block in that method when not enough data has been buffered. The stream callbacks can then pulse the locked object, and the sample read can be retried. 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 an Async method might not be wise, but the experience of running this code on a device suggests otherwise. Per http://msdn.microsoft.com/en-us/library/system.windows.media.mediastreamsource.getsampleasync(v=vs.95).aspx, blocking could prevent other streams from being read. As a streaming music app, we only ever serve one stream at a time, so in this case it seems that we're OK.
I wish I knew a general solution here, though, because this clearly is cheating.