/// <inheritdoc /> public void Render(MediaBlock mediaBlock, TimeSpan clockPosition) { // We don't need to render anything while we are seeking. Simply drop the blocks. if (MediaCore.State.IsSeeking || HasFiredAudioDeviceStopped) { return; } var lockTaken = false; Monitor.TryEnter(SyncLock, SyncLockTimeout, ref lockTaken); if (lockTaken == false) { return; } try { if ((AudioDevice?.IsRunning ?? false) == false) { if (HasFiredAudioDeviceStopped) { return; } MediaElement.RaiseAudioDeviceStoppedEvent(); HasFiredAudioDeviceStopped = true; return; } if (AudioBuffer == null) { return; } // Capture Media Block Reference if (mediaBlock is AudioBlock == false) { return; } var audioBlock = (AudioBlock)mediaBlock; var audioBlocks = MediaCore.Blocks[MediaType.Audio]; while (audioBlock != null) { if (audioBlock.TryAcquireReaderLock(out var readLock) == false) { return; } using (readLock) { // Write the block if we have to, avoiding repeated blocks. if (AudioBuffer.WriteTag < audioBlock.StartTime) { AudioBuffer.Write(audioBlock.Buffer, audioBlock.SamplesBufferLength, audioBlock.StartTime, true); } // Stop adding if we have too much in there. if (AudioBuffer.CapacityPercent >= 0.5) { break; } // Retrieve the following block audioBlock = audioBlocks.ContinuousNext(audioBlock) as AudioBlock; } } } catch (Exception ex) { this.LogError(Aspects.AudioRenderer, $"{nameof(AudioRenderer)}.{nameof(Read)} has faulted.", ex); } finally { Monitor.Exit(SyncLock); } }