private async void ReadSource() { Exception possibleError = null; bool tryAgain = true; while (tryAgain) { tryAgain = false; currentAttemptStopwatch = null; currentAttemptLastReceivedData = TimeSpan.Zero; currentAttemptReceivedBytes = 0; Stream sourceStream; try { var response = await getResponse(this.availableBytes); this.response.TrySetResult(response); if (this.availableBytes == 0) { #if WEBCLIENT size = response.ContentLength != -1 ? response.ContentLength : (long?)null; #else var ce = response.Content.Headers.ContentEncoding; if (ce == null || !ce.Any()) { size = response.Content.Headers.ContentLength; } #endif } if (availableBytes != 0) { #if WEBCLIENT var cr = response.Headers["Content-Range"]; // HACK: trust the server to return the expected range if (string.IsNullOrEmpty(cr)) #else if (response.Content == null || response.Content.Headers.ContentRange == null || response.Content.Headers.ContentRange.From.GetValueOrDefault(-1) != availableBytes) #endif { response.Dispose(); throw new NotSupportedException("The web server did not return the expected range of data."); } } if (data == null) { response.Dispose(); return; } #if WEBCLIENT sourceStream = await TaskEx.Run(() => response.GetResponseStream()); #else sourceStream = await response.Content.ReadAsStreamAsync(); #endif } catch (Exception ex) { if (possibleError == null) { possibleError = ex; } break; } this.source = sourceStream; var timedOut = false; using (sourceStream) using (var w = new Watchdog(Configuration_AudioReadTimeout, () => { timedOut = true; var s = sourceStream; if (s != null) { s.Dispose(); } })) { while (true) { if (data == null) { return; } byte[] slot; if (currentSlotFreeSpace == 0) { slot = new byte[SlotSize]; MaybeCleanupOldSlots(); currentSlotFreeSpace = SlotSize; data.Add(slot); } else { slot = data[data.Count - 1]; } int waitAndRetry = 0; try { var readBytes = source.Read(slot, SlotSize - currentSlotFreeSpace, Math.Min(currentSlotFreeSpace, ReadGranularity)); w.Pulse(); if (currentAttemptStopwatch == null) { currentAttemptStopwatch = Stopwatch.StartNew(); } currentAttemptLastReceivedData = currentAttemptStopwatch.Elapsed; if (readBytes == 0) { completed = true; CloseSource(); if (size.HasValue) { EnsureCorrectNumberOfBytes(availableBytes, size.Value); } size = availableBytes; OnNewDataAvailable(); currentAttemptStopwatch.Stop(); return; } else { possibleError = null; currentAttemptReceivedBytes += readBytes; var modified = availableBytes + readBytes; Interlocked.Exchange(ref availableBytes, modified); currentSlotFreeSpace -= readBytes; OnNewDataAvailable(); if (availableBytes >= Configuration_PrefetchLength && (consumers == 0 || availableBytes > maxRequestedByte + Configuration_NonRequestedDataLimit)) { await TaskEx.Delay(1000 *readBytes / (consumers == 0 ? Configuration_AfterPrefetchIdleSpeed : Configuration_IdleMaxSpeed)); } } } catch (Exception ex) { if (data == null) { return; } if (timedOut) { ex = new TimeoutException(); } if (possibleError == null) { possibleError = ex; } if (currentAttemptStopwatch != null) { currentAttemptStopwatch.Stop(); } if (currentAttemptReceivedBytes >= 1 * 1024 * 1024 && !(ex is InvalidDataException)) { waitAndRetry = 2; } else { waitAndRetry = 1; } } if (waitAndRetry != 0) { if (waitAndRetry == 2) { await TaskEx.Delay(ZeroSpeedAfterSilenceMilliseconds); OnNewDataAvailable(); await TaskEx.Delay(10000 - ZeroSpeedAfterSilenceMilliseconds); tryAgain = true; } break; } } } } if (possibleError != null) { error = possibleError; OnNewDataAvailable(); CloseSource(); } }
private async void ReadSource() { Exception possibleError = null; bool tryAgain = true; while (tryAgain) { tryAgain = false; currentAttemptStopwatch = null; currentAttemptLastReceivedData = TimeSpan.Zero; currentAttemptReceivedBytes = 0; Stream sourceStream; try { var response = await getResponse(this.availableBytes); if (this.availableBytes == 0) { #if WEBCLIENT size = response.ContentLength != -1 ? response.ContentLength : (long?)null; #else var ce = response.Content.Headers.ContentEncoding; if (ce == null || !ce.Any()) size = response.Content.Headers.ContentLength; #endif } if (availableBytes != 0) { #if WEBCLIENT var cr = response.Headers["Content-Range"]; // HACK: trust the server to return the expected range if (string.IsNullOrEmpty(cr)) #else if (response.Content == null || response.Content.Headers.ContentRange == null || response.Content.Headers.ContentRange.From.GetValueOrDefault(-1) != availableBytes) #endif { response.Dispose(); throw new NotSupportedException("The web server did not return the expected range of data."); } } if (data == null) { response.Dispose(); return; } #if WEBCLIENT sourceStream = await TaskEx.Run(() => response.GetResponseStream()); #else sourceStream = await response.Content.ReadAsStreamAsync(); #endif } catch (Exception ex) { if (possibleError == null) possibleError = ex; break; } this.source = sourceStream; var timedOut = false; using (sourceStream) using (var w = new Watchdog(Configuration_AudioReadTimeout, () => { timedOut = true; var s = sourceStream; if (s != null) s.Dispose(); })) { while (true) { if (data == null) return; byte[] slot; if (currentSlotFreeSpace == 0) { slot = new byte[SlotSize]; MaybeCleanupOldSlots(); currentSlotFreeSpace = SlotSize; data.Add(slot); } else { slot = data[data.Count - 1]; } int waitAndRetry = 0; try { var readBytes = source.Read(slot, SlotSize - currentSlotFreeSpace, Math.Min(currentSlotFreeSpace, ReadGranularity)); w.Pulse(); if (currentAttemptStopwatch == null) { currentAttemptStopwatch = Stopwatch.StartNew(); } currentAttemptLastReceivedData = currentAttemptStopwatch.Elapsed; if (readBytes == 0) { completed = true; CloseSource(); if (size.HasValue) EnsureCorrectNumberOfBytes(availableBytes, size.Value); size = availableBytes; OnNewDataAvailable(); currentAttemptStopwatch.Stop(); return; } else { possibleError = null; currentAttemptReceivedBytes += readBytes; var modified = availableBytes + readBytes; Interlocked.Exchange(ref availableBytes, modified); currentSlotFreeSpace -= readBytes; OnNewDataAvailable(); if (availableBytes >= Configuration_PrefetchLength && (consumers == 0 || availableBytes > maxRequestedByte + Configuration_NonRequestedDataLimit)) { await TaskEx.Delay(1000 * readBytes / (consumers == 0 ? Configuration_AfterPrefetchIdleSpeed : Configuration_IdleMaxSpeed)); } } } catch (Exception ex) { if (data == null) return; if (timedOut) ex = new TimeoutException(); if (possibleError == null) possibleError = ex; if (currentAttemptStopwatch != null) currentAttemptStopwatch.Stop(); if (currentAttemptReceivedBytes >= 1 * 1024 * 1024 && !(ex is InvalidDataException)) waitAndRetry = 2; else waitAndRetry = 1; } if (waitAndRetry != 0) { if (waitAndRetry == 2) { await TaskEx.Delay(ZeroSpeedAfterSilenceMilliseconds); OnNewDataAvailable(); await TaskEx.Delay(10000 - ZeroSpeedAfterSilenceMilliseconds); tryAgain = true; } break; } } } } if (possibleError != null) { error = possibleError; OnNewDataAvailable(); CloseSource(); } }