/// <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}"));
            }
        }
Beispiel #5
0
        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");
            }
        }
Beispiel #6
0
        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();
            }
        }