//These methods run on the main thread, they drain audio from the mic and send it across to the other thread for proper processing // // Update - Either discard mic samples (if no one is subscribed to mic data) or call DrainMicSamples // DrainMicSamples - Read as many samples as possible from the mic (using a set of pow2 sized buffers to get as // much as possible), passes samples to ConsumeMicSamples // ConsumeMicSamples - Take some number of samples from produced by DrainMicSamples and buffer them up, call SendFrame // every time some samples are added to the buffer // SendFrame - Read as many frames as possible from the buffer and send them to the other thread. Also poke the other thread // to tell it that it has work to do public void Update() { if (!_started) { _readHead = Microphone.GetPosition(_micName); _started = _readHead > 0; if (!_started) { return; } } if (_preprocessing.RequiresInput) { //Read samples from clip into mic sample buffer DrainMicSamples(); } else { //We're not interested in the audio from the mic, so skip the read head to the current mic position and drop all the audio _readHead = Microphone.GetPosition(_micName); _rawMicSamples.Reset(); _rawMicFrames.Reset(); _preprocessing.Reset(); if (_microphoneDiagnosticOutput != null) { _microphoneDiagnosticOutput.Dispose(); _microphoneDiagnosticOutput = null; } } }
public virtual void StopCapture() { Log.AssertAndThrowPossibleBug(_clip != null, "CDDAE69D-44DC-487F-9B69-4703B779400E", "Attempted to stop microphone capture, but it is already stopped"); //Stop diagnostic output if (_microphoneDiagnosticOutput != null) { _microphoneDiagnosticOutput.Dispose(); _microphoneDiagnosticOutput = null; } //Stop capture Microphone.End(_micName); _format = null; _clip = null; _readHead = 0; _started = false; _micName = null; //Clean the buffers _rawMicSamples.Reset(); _rawMicFrames.Reset(); //Stop watching for device changes AudioSettings.OnAudioConfigurationChanged -= OnAudioDeviceChanged; _audioDeviceChanged = false; }
public virtual void Dispose() { _runThread = false; _threadEvent.Set(); if (_thread.IsStarted) { _thread.Join(); } //ncrunch: no coverage start if (_diagnosticOutputRecorder != null) { _diagnosticOutputRecorder.Dispose(); _diagnosticOutputRecorder = null; } //ncrunch: no coverage end using (var subscriptions = _micSubscriptions.Lock()) while (subscriptions.Value.Count > 0) { Unsubscribe(subscriptions.Value[0]); } using (var subscriptions = _vadSubscriptions.Lock()) while (subscriptions.Value.Count > 0) { Unsubscribe(subscriptions.Value[0]); } Log.Debug("Disposed pipeline"); }
private void StopCapture() { if (!_subscribed) { throw Log.CreatePossibleBugException("Cannot unsubscribe encoder from mic: not subscribed", "8E0EAC83-BF44-4BE3-B132-BFE02AD1FADB"); } Log.Debug("Unsubscribing encoder from microphone"); _mic.Unsubscribe(this); _subscribed = false; _resetRequired = true; //Disposing the output writers is racy, because the audio thread is trying to write to them at the same time. //That's fine, because the writer have an internal SpinLock ensuring that doing this is safe if (_microphoneDiagnosticOutput != null) { _microphoneDiagnosticOutput.Dispose(); _microphoneDiagnosticOutput = null; } if (_preEncodeDiagnosticOutput != null) { _preEncodeDiagnosticOutput.Dispose(); _preEncodeDiagnosticOutput = null; } }
public void Reset() { _buffer.Reset(); _decoder.Reset(); if (_diagnosticOutput != null) { _diagnosticOutput.Dispose(); _diagnosticOutput = null; } }
public void Reset() { _buffer.Reset(); _decoder.Reset(); using (var l = _options.Lock()) l.Value = new PlaybackOptions(false, 1, ChannelPriority.Default); using (var l = _channels.Lock()) l.Value.Clear(); if (_diagnosticOutput != null) { _diagnosticOutput.Dispose(); _diagnosticOutput = null; } }
/// <summary> /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { _audioWriter.Dispose(); _videoWriter.Dispose(); var ffmpegProcess = new Process { StartInfo = { FileName = "ffmpeg.exe", Arguments = _ffmpegArgs, UseShellExecute = false, CreateNoWindow = true } }; ffmpegProcess.Start(); ffmpegProcess.WaitForExit(); File.Delete(tempAudioPath); File.Delete(tempVideoPath); }
public void OnAudioFilterRead(float[] data, int channels) { //If there is no session, clear filter and early exit var maybeSession = Session; if (!maybeSession.HasValue) { Array.Clear(data, 0, data.Length); return; } _sessionLock.EnterUpgradeableReadLock(); try { //Check if there is no session again, this time protected by a lock maybeSession = Session; if (!maybeSession.HasValue) { Array.Clear(data, 0, data.Length); return; } //Detect if the session has changed since the last call to this method, if so reset if (!maybeSession.Value.Context.Equals(_lastPlayedSessionContext)) { _lastPlayedSessionContext = maybeSession.Value.Context; ApplyReset(); } //Calculate the difference between where we should be and where we are (in samples) var session = maybeSession.Value; _desync.Update(IdealPlaybackPosition, PlaybackPosition); //If necessary skip samples to bring us back in sync int deltaDesync, deltaSamples; var complete = Skip(session, _desync.DesyncMilliseconds, out deltaSamples, out deltaDesync); Interlocked.Add(ref _totalSamplesRead, deltaSamples); _desync.Skip(deltaDesync); //If the session wasn't completed by the skip, keep playing if (!complete) { int samples; float arv; complete = Filter(session, data, channels, _temp, _diagnosticOutput, out arv, out samples, MultiplyBySource); _arv = arv; Interlocked.Add(ref _totalSamplesRead, samples); } //Clean up now that this session is complete if (complete) { Log.Debug("Finished playback of speech session. id={0}", session.Context.Id); //Clear the session _sessionLock.EnterWriteLock(); try { Session = null; } finally { _sessionLock.ExitWriteLock(); } //Reset the state ApplyReset(); //Discard the diagnostic recorder if necessary if (_diagnosticOutput != null) { _diagnosticOutput.Dispose(); _diagnosticOutput = null; } } } finally { _sessionLock.ExitUpgradeableReadLock(); } }
private void Record() { try { _stopWrite.Reset(); if (!String.IsNullOrEmpty(Micobject.recorder.trigger)) { string[] tid = Micobject.recorder.trigger.Split(','); switch (tid[0]) { case "1": VolumeLevel vl = MainForm.InstanceReference.GetVolumeLevel(Convert.ToInt32(tid[1])); if (vl != null && !vl.Recording) vl.RecordSwitch(true); break; case "2": CameraWindow c = MainForm.InstanceReference.GetCameraWindow(Convert.ToInt32(tid[1])); if (c != null && !c.Recording) c.RecordSwitch(true); break; } } var cw = CameraControl; // if (cw != null) { if (cw.AbortedAudio) { MainForm.LogErrorToFile(Micobject.name + ": paired recording aborted as the camera is already recording"); ForcedRecording = false; return; } } try { if (cw != null) { cw.ForcedRecording = ForcedRecording; cw.StartSaving(); _stopWrite.WaitOne(); } else { #region mp3writer DateTime date = DateTime.Now; string filename = String.Format("{0}-{1}-{2}_{3}-{4}-{5}", date.Year, Helper.ZeroPad(date.Month), Helper.ZeroPad(date.Day), Helper.ZeroPad(date.Hour), Helper.ZeroPad(date.Minute), Helper.ZeroPad(date.Second)); AudioFileName = Micobject.id + "_" + filename; string folder = Dir.Entry + "audio\\" + Micobject.directory + "\\"; if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); filename = folder + AudioFileName; _writer = new AudioFileWriter(); try { Program.FFMPEGMutex.WaitOne(); _writer.Open(filename + ".mp3", AudioCodec.MP3, AudioSource.RecordingFormat.BitsPerSample*AudioSource.RecordingFormat.SampleRate* AudioSource.RecordingFormat.Channels, AudioSource.RecordingFormat.SampleRate, AudioSource.RecordingFormat.Channels); } finally { try { Program.FFMPEGMutex.ReleaseMutex(); } catch (ObjectDisposedException) { //can happen on shutdown } } double maxlevel = 0; bool first = true; DateTime recordingStart = Helper.Now; try { while (!_stopWrite.WaitOne(5)) { Helper.FrameAction fa; while (Buffer.TryDequeue(out fa)) { if (first) { recordingStart = fa.TimeStamp; first = false; } if (fa.FrameType == Enums.FrameType.Audio) { unsafe { fixed (byte* p = fa.Content) { _writer.WriteAudio(p, fa.DataLength); } } float d = Levels.Max(); _soundData.Append(String.Format(CultureInfo.InvariantCulture, "{0:0.000}", d)); _soundData.Append(","); if (d > maxlevel) maxlevel = d; } fa.Nullify(); } } FilesFile ff = _filelist.FirstOrDefault(p => p.Filename.EndsWith(AudioFileName + ".mp3")); bool newfile = false; if (ff == null) { ff = new FilesFile(); newfile = true; } string[] fnpath = (filename + ".mp3").Split('\\'); string fn = fnpath[fnpath.Length - 1]; var fi = new FileInfo(filename + ".mp3"); var dSeconds = Convert.ToInt32((Helper.Now - recordingStart).TotalSeconds); ff.CreatedDateTicks = DateTime.Now.Ticks; ff.Filename = fnpath[fnpath.Length - 1]; ff.MaxAlarm = maxlevel; ff.SizeBytes = fi.Length; ff.DurationSeconds = dSeconds; ff.IsTimelapse = false; ff.IsMergeFile = false; ff.AlertData = Helper.GetMotionDataPoints(_soundData); _soundData.Clear(); ff.TriggerLevel = Micobject.detector.minsensitivity; ff.TriggerLevelMax = Micobject.detector.maxsensitivity; if (newfile) { lock (_lockobject) { _filelist.Insert(0, ff); } MainForm.MasterFileAdd(new FilePreview(fn, dSeconds, Micobject.name, DateTime.Now.Ticks, 1, Micobject.id, ff.MaxAlarm, false, false)); MainForm.NeedsMediaRefresh = Helper.Now; } } catch (Exception ex) { if (ErrorHandler != null) ErrorHandler(ex.Message); } if (_writer != null && _writer.IsOpen) { try { Program.FFMPEGMutex.WaitOne(); _writer.Dispose(); } catch (Exception ex) { if (ErrorHandler != null) ErrorHandler(ex.Message); } finally { try { Program.FFMPEGMutex.ReleaseMutex(); } catch (ObjectDisposedException) { //can happen on shutdown } } } _writer = null; #endregion } UpdateFloorplans(false); } catch (Exception ex) { if (ErrorHandler != null) ErrorHandler(ex.Message); } if (!String.IsNullOrEmpty(Micobject.recorder.trigger)) { string[] tid = Micobject.recorder.trigger.Split(','); switch (tid[0]) { case "1": VolumeLevel vl = MainForm.InstanceReference.GetVolumeLevel(Convert.ToInt32(tid[1])); if (vl != null) vl.RecordSwitch(false); break; case "2": CameraWindow c = MainForm.InstanceReference.GetCameraWindow(Convert.ToInt32(tid[1])); if (c != null) c.RecordSwitch(false); break; } } if (cw == null) { Micobject.newrecordingcount++; if (Notification != null) Notification(this, new NotificationType("NewRecording", Micobject.name, "")); } } catch (Exception ex) { MainForm.LogExceptionToFile(ex); } }
private void Record() { _stopWrite = false; DateTime recordingStart = DateTime.MinValue; if (!String.IsNullOrEmpty(Micobject.recorder.trigger) && TopLevelControl != null) { string[] tid = Micobject.recorder.trigger.Split(','); switch (tid[0]) { case "1": VolumeLevel vl = ((MainForm)TopLevelControl).GetVolumeLevel(Convert.ToInt32(tid[1])); if (vl != null) vl.RecordSwitch(true); break; case "2": CameraWindow cw = ((MainForm)TopLevelControl).GetCameraWindow(Convert.ToInt32(tid[1])); if (cw != null) cw.RecordSwitch(true); break; } } try { WriterBuffer = new QueueWithEvents<AudioAction>(); WriterBuffer.Changed += WriterBufferChanged; _pairedRecording = false; if (CameraControl!=null && CameraControl.Camobject.settings.active) { _pairedRecording = true; CameraControl.StartSaving(); CameraControl.ForcedRecording = ForcedRecording; while (!_stopWrite) { _newRecordingFrame.WaitOne(200); } } else { #region mp3writer DateTime date = DateTime.Now; string filename = String.Format("{0}-{1}-{2}_{3}-{4}-{5}", date.Year, Helper.ZeroPad(date.Month), Helper.ZeroPad(date.Day), Helper.ZeroPad(date.Hour), Helper.ZeroPad(date.Minute), Helper.ZeroPad(date.Second)); AudioFileName = Micobject.id + "_" + filename; filename = MainForm.Conf.MediaDirectory + "audio\\" + Micobject.directory + "\\"; filename += AudioFileName; Program.WriterMutex.WaitOne(); try { _writer = new AudioFileWriter(); _writer.Open(filename + ".mp3", AudioCodec.MP3, AudioSource.RecordingFormat.BitsPerSample * AudioSource.RecordingFormat.SampleRate * AudioSource.RecordingFormat.Channels, AudioSource.RecordingFormat.SampleRate, AudioSource.RecordingFormat.Channels); } catch (Exception ex) { Log.Error("",ex);//MainForm.LogExceptionToFile(ex); } finally { Program.WriterMutex.ReleaseMutex(); } double maxlevel = 0; foreach (AudioAction aa in AudioBuffer.OrderBy(p=>p.TimeStamp)) { if (recordingStart == DateTime.MinValue) { recordingStart = aa.TimeStamp; } unsafe { fixed (byte* p = aa.Decoded) { _writer.WriteAudio(p, aa.Decoded.Length); } } _soundData.Append(String.Format(CultureInfo.InvariantCulture, "{0:0.000}", aa.SoundLevel)); _soundData.Append(","); if (aa.SoundLevel > maxlevel) maxlevel = aa.SoundLevel; } AudioBuffer.Clear(); if (recordingStart == DateTime.MinValue) recordingStart = DateTime.Now; try { while (!_stopWrite) { while (WriterBuffer.Count > 0) { AudioAction b; lock (_obj) { b = WriterBuffer.Dequeue(); } unsafe { fixed (byte* p = b.Decoded) { _writer.WriteAudio(p, b.Decoded.Length); } } float d = Levels.Max(); _soundData.Append(String.Format(CultureInfo.InvariantCulture, "{0:0.000}", d)); _soundData.Append(","); if (d > maxlevel) maxlevel = d; } _newRecordingFrame.WaitOne(200); } FilesFile ff = FileList.FirstOrDefault(p => p.Filename.EndsWith(AudioFileName + ".mp3")); bool newfile = false; if (ff == null) { ff = new FilesFile(); newfile = true; } string[] fnpath = (filename + ".mp3").Split('\\'); string fn = fnpath[fnpath.Length - 1]; var fi = new FileInfo(filename + ".mp3"); var dSeconds = Convert.ToInt32((DateTime.Now - recordingStart).TotalSeconds); ff.CreatedDateTicks = DateTime.Now.Ticks; ff.Filename = fnpath[fnpath.Length - 1]; ff.MaxAlarm = maxlevel; ff.SizeBytes = fi.Length; ff.DurationSeconds = dSeconds; ff.IsTimelapse = false; ff.AlertData = Helper.GetMotionDataPoints(_soundData); _soundData.Clear(); ff.TriggerLevel = Micobject.detector.sensitivity; if (newfile) { FileList.Insert(0, ff); if (MainForm.MasterFileList.Count(p => p.Filename.EndsWith(fn)) == 0) { MainForm.MasterFileList.Add(new FilePreview(fn, dSeconds, Micobject.name, DateTime.Now.Ticks, 1,Micobject.id, ff.MaxAlarm)); } } } catch (Exception ex) { Log.Error("",ex);//MainForm.LogExceptionToFile(ex); } Program.WriterMutex.WaitOne(); try { _writer.Close(); _writer.Dispose(); } catch (Exception ex) { Log.Error("",ex);//MainForm.LogExceptionToFile(ex); } finally { Program.WriterMutex.ReleaseMutex(); } _writer = null; #endregion } _stopWrite = false; WriterBuffer = null; _recordingTime = 0; UpdateFloorplans(false); } catch (Exception ex) { Log.Error("",ex);//MainForm.LogExceptionToFile(ex); } if (!String.IsNullOrEmpty(Micobject.recorder.trigger) && TopLevelControl != null) { string[] tid = Micobject.recorder.trigger.Split(','); switch (tid[0]) { case "1": VolumeLevel vl = ((MainForm)TopLevelControl).GetVolumeLevel(Convert.ToInt32(tid[1])); if (vl != null) vl.RecordSwitch(false); break; case "2": CameraWindow cw = ((MainForm)TopLevelControl).GetCameraWindow(Convert.ToInt32(tid[1])); if (cw != null) cw.RecordSwitch(false); break; } } if (!_pairedRecording) { Micobject.newrecordingcount++; if (Notification != null) Notification(this, new NotificationType("NewRecording", Micobject.name, "")); } }
public void OnAudioFilterRead([NotNull] float[] data, int channels) { //If there is no session, clear filter and early exit var maybeSession = Session; if (!maybeSession.HasValue) { Array.Clear(data, 0, data.Length); return; } _sessionLock.EnterUpgradeableReadLock(); try { //Check if there is no session again, this time protected by a lock maybeSession = Session; if (!maybeSession.HasValue) { Array.Clear(data, 0, data.Length); return; } //Detect if the session has changed since the last call to this method, if so reset var session = maybeSession.Value; if (!session.Context.Equals(_lastPlayedSessionContext)) { _lastPlayedSessionContext = maybeSession.Value.Context; ApplyReset(); } // Read data from pipeline float arv; var complete = Filter(session, data, channels, _temp, _diagnosticOutput, out arv); _arv = arv; //Clean up now that this session is complete if (complete) { Log.Debug("Finished playback of speech session. id={0}. player={1}", session.Context.Id, session.Context.PlayerName); //Clear the session _sessionLock.EnterWriteLock(); try { Session = null; } finally { _sessionLock.ExitWriteLock(); } //Reset the state ApplyReset(); //Discard the diagnostic recorder if necessary if (_diagnosticOutput != null) { _diagnosticOutput.Dispose(); _diagnosticOutput = null; } } } finally { _sessionLock.ExitUpgradeableReadLock(); } }
public void Dispose() { _audioWriter?.Dispose(); }