Пример #1
0
        //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;
                }
            }
        }
Пример #2
0
        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;
        }
Пример #3
0
        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");
        }
Пример #4
0
        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;
            }
        }
Пример #5
0
        public void Reset()
        {
            _buffer.Reset();
            _decoder.Reset();

            if (_diagnosticOutput != null)
            {
                _diagnosticOutput.Dispose();
                _diagnosticOutput = null;
            }
        }
Пример #6
0
        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;
            }
        }
Пример #7
0
        /// <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);
        }
Пример #8
0
        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();
            }
        }
Пример #9
0
        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);
            }
        }
Пример #10
0
        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();
            }
        }
Пример #12
0
 public void Dispose()
 {
     _audioWriter?.Dispose();
 }