/// <summary> /// Stops recording WAV audio from the underlying <see cref="IAudioStream"/> and finishes writing the WAV file. /// </summary> public void StopRecorder() { try { if (audioStream != null) { audioStream.OnBroadcast -= OnStreamBroadcast; audioStream.OnActiveChanged -= StreamActiveChanged; } if (writer != null) { if (streamWriter.BaseStream.CanWrite) { //now that audio is finished recording, write a WAV/RIFF header at the beginning of the file writer.Seek(0, SeekOrigin.Begin); AudioFunctions.WriteWavHeader(writer, audioStream.ChannelCount, audioStream.SampleRate, audioStream.BitsPerSample, byteCount); } writer.Dispose(); //this should properly close/dispose the underlying stream as well writer = null; fileStream = null; streamWriter = null; } audioStream = null; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("Error during StopRecorder: {0}", ex); throw; } }
void AudioStream_OnBroadcast(object sender, byte [] bytes) { var level = AudioFunctions.CalculateLevel(bytes); if (level > SilenceThreshold) //did we find a signal? { audioDetected = true; silenceTime = null; } else //no audio detected { //see if we've detected 'near' silence for more than <audioTimeout> if (StopRecordingOnSilence && silenceTime.HasValue) { if (DateTime.Now.Subtract(silenceTime.Value) > AudioSilenceTimeout) { Timeout("AudioRecorderService.AudioStream_OnBroadcast (): AudioSilenceTimeout exceeded, stopping recording"); return; } } else { silenceTime = DateTime.Now; } } if (StopRecordingAfterTimeout && DateTime.Now - startTime > TotalAudioTimeout) { Timeout("AudioRecorderService.AudioStream_OnBroadcast(): TotalAudioTimeout exceeded, stopping recording"); } }
/// <summary> /// Stops recording WAV audio from the underlying <see cref="IAudioStream"/> and finishes writing the WAV file. /// </summary> public void StopRecorder() { try { if (audioStream != null) { audioStream.OnBroadcast -= OnStreamBroadcast; audioStream.OnActiveChanged -= StreamActiveChanged; } using (var fileStream = new FileStream(audioFilePath, FileMode.Create, FileAccess.Write)) { using (var fileWriter = new BinaryWriter(fileStream, Encoding.UTF8)) { //now that audio is finished recording, write a WAV/RIFF header at the beginning of the file AudioFunctions.WriteWavHeader(fileWriter, audioStream.ChannelCount, audioStream.SampleRate, audioStream.BitsPerSample, byteCount); memoryAudioStream.Seek(0, SeekOrigin.Begin); memoryAudioStream.CopyTo(fileStream); } } audioStream = null; } catch (Exception ex) { Debug.WriteLine("Error during StopRecorder: {0}", ex.Message); throw; } }
unsafe void Graph_QuantumStarted(AudioGraph sender, object args) { // we'll only broadcast if we're actively monitoring audio packets if (!Active) { return; } try { // get an audio frame from the output node AudioFrame frame = outputNode.GetFrame(); if (frame.Duration?.Milliseconds == 0) // discard any empty frames { return; } using (var buffer = frame.LockBuffer(AudioBufferAccessMode.Read)) using (IMemoryBufferReference reference = buffer.CreateReference()) { // Get the buffer from the AudioFrame ((IMemoryBufferByteAccess)reference).GetBuffer(out byte *dataInBytes, out uint capacityInBytes); // convert the bytes into float float *dataInFloat = (float *)dataInBytes; if (audioBytes == null) { audioBytes = new byte [buffer.Length * broadcastSize / 2]; // buffer length * # of frames we want to accrue / 2 (because we're transforming float audio to Int 16) } for (int i = 0; i < capacityInBytes / sizeof(float); i++) { // convert the float into a double byte for 16 bit PCM var shortVal = AudioFunctions.FloatToInt16(dataInFloat [i]); byte [] chunkBytes = BitConverter.GetBytes(shortVal); audioBytes [bufferPosition++] = chunkBytes [0]; audioBytes [bufferPosition++] = chunkBytes [1]; } // we want to wait until we accrue <broadcastSize> # of frames and then broadcast them // in practice, this will take us from 20ms chunks to 100ms chunks and result in more accurate audio level calculations // we could maybe use the audiograph latency settings to achieve similar results but this seems to work well if (bufferPosition == audioBytes.Length || !Active) { // broadcast the audio data to any listeners OnBroadcast?.Invoke(this, audioBytes); audioBytes = null; bufferPosition = 0; } } } catch (Exception ex) { OnException?.Invoke(this, new Exception($"AudioStream.QueueInputCompleted() :: Error: {ex.Message}")); } }
void AudioStream_OnBroadcast(object sender, byte [] bytes) { var level = AudioFunctions.CalculateLevel(bytes); AudioLevelUpdated?.Invoke(this, level); if (level < NearZero && !audioDetected) // discard any initial 0s so we don't jump the gun on timing out { Debug.WriteLine("level == {0} && !audioDetected", level); return; } if (level > SilenceThreshold) // did we find a signal? { audioDetected = true; silenceTime = null; Debug.WriteLine("AudioStream_OnBroadcast :: {0} :: level > SilenceThreshold :: bytes: {1}; level: {2}", DateTime.Now, bytes.Length, level); } else // no audio detected { // see if we've detected 'near' silence for more than <audioTimeout> if (StopRecordingOnSilence && silenceTime.HasValue) { var currentTime = DateTime.Now; if (currentTime.Subtract(silenceTime.Value).TotalMilliseconds > AudioSilenceTimeout.TotalMilliseconds) { Timeout($"AudioStream_OnBroadcast :: {currentTime} :: AudioSilenceTimeout exceeded, stopping recording :: Near-silence detected at: {silenceTime}"); return; } } else { silenceTime = DateTime.Now; Debug.WriteLine("AudioStream_OnBroadcast :: {0} :: Near-silence detected :: bytes: {1}; level: {2}", silenceTime, bytes.Length, level); } } if (StopRecordingAfterTimeout && DateTime.Now - startTime > TotalAudioTimeout) { Timeout("AudioStream_OnBroadcast(): TotalAudioTimeout exceeded, stopping recording"); } }
async void AudioStream_OnBroadcast(object sender, byte [] bytes) { var level = AudioFunctions.CalculateLevel(bytes);//, bigEndian: true);//, bigEndian: true, signed: false); //var level = Decode(bytes).Select(Math.Abs).Average(x => x); //double level = Math.Sqrt(sum / (bytes.Length / 2)); System.Diagnostics.Debug.WriteLine("AudioStream_OnBroadcast :: calculateLevel == {0}", level); if (level > SilenceThreshold) //did we find a signal? { audioDetected = true; silenceTime = null; } else //no audio detected { //see if we've detected 'near' silence for more than <audioTimeout> if (StopRecordingOnSilence && silenceTime.HasValue) { if (DateTime.Now.Subtract(silenceTime.Value) > AudioSilenceTimeout) { System.Diagnostics.Debug.WriteLine("AudioRecorderService.AudioStream_OnBroadcast(): AudioSilenceTimeout exceeded, stopping recording"); await StopRecording(); return; } } else { silenceTime = DateTime.Now; } } if (StopRecordingAfterTimeout && DateTime.Now - startTime > TotalAudioTimeout) { System.Diagnostics.Debug.WriteLine("AudioRecorderService.AudioStream_OnBroadcast(): TotalAudioTimeout exceeded, stopping recording"); await StopRecording(); } }