/// <summary> /// Thread to record the ARCore session. /// </summary> /// <returns>An event of WaitForSeconds or null.</returns> private IEnumerator Record() { Extensions.Session.enabled = false; // It can take up to 10s until AR Foundation unlocked session native pointer. // Before that, the session handle returns IntPtr.Zero and fails StartRecording(). RecordingResult result = RecordingResult.SessionNotReady; _recordingConfig.Mp4DatasetFilepath = _filenameToSave; yield return(new WaitWhile(() => { result = _recordingManager.StartRecording(_recordingConfig); return result == RecordingResult.SessionNotReady; })); if (result != RecordingResult.OK) { Extensions.Session.enabled = true; _status = RecorderStatus.Stopped; yield break; } ResetScenes(); yield return(null); Extensions.Session.enabled = true; _status = RecorderStatus.Recording; _timeWhenRecorderStarts = Time.time; RecordingTimerText.gameObject.SetActive(true); }
/// <summary> /// Thread to playback an ARCore session. /// </summary> /// <param name="datasetPath">Location of the dataset.</param> /// <returns>An event of WaitForSeconds or null.</returns> private IEnumerator PlaybackDataset(string datasetPath) { // Deal with cases: // - Idle -> PreparePlayback => Playback. // - Playback -> PrepareIdle => Idle. Extensions.Session.enabled = false; // It can take up to 10s until AR Foundation unlocked session native pointer. // Before that, the session handle returns IntPtr.Zero and fails SetPlaybackDataset(). PlaybackResult result = PlaybackResult.SessionNotReady; yield return(new WaitWhile(() => { result = _playbackManager.SetPlaybackDataset(datasetPath); return result == PlaybackResult.SessionNotReady; })); if (result != PlaybackResult.OK) { yield break; } yield return(null); Extensions.Session.enabled = true; if (datasetPath == null) { _status = RecorderStatus.Stopped; } else { _status = RecorderStatus.Playingback; } }
private async Task InitAsync() { try { // initialize media capture MediaCaptureInitializationSettings settings = new MediaCaptureInitializationSettings { StreamingCaptureMode = StreamingCaptureMode.Audio }; _Capture = new MediaCapture(); await _Capture.InitializeAsync(settings); // this only happens if you try to record for more than 3 hours // these event handlers are safe - Service is a singleton and will only ever have 1 instance for the life of the app _Capture.RecordLimitationExceeded += async(MediaCapture sender) => { await _Capture.StopRecordAsync(); }; _Capture.Failed += (MediaCapture sender, MediaCaptureFailedEventArgs errorEventArgs) => { RecorderReady = true; // TODO: handle record failure RecorderStatus?.Invoke(this, new EventArgs()); }; RecorderReady = true; RecorderStatus?.Invoke(this, new EventArgs()); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(string.Format("*** AudioService.InitRecordAsync - Exception: {0}", ex)); } }
/// <summary> /// 开始 /// </summary> /// <param name="frameEventHandler">每帧回调(默认不需要填)</param> public virtual void Start(NewFrameEventHandler frameEventHandler = null) { //继续播放 if (this.RecorderStatus == RecorderStatus.Pause) { this.VideoStreamer.Start(); this.wavRecorder.Start(); return; } this.RecorderStatus = RecorderStatus.Start; //设置所有显示器 foreach (Screen screen in Screen.AllScreens) { this.ScreenArea = Rectangle.Union(this.ScreenArea, screen.Bounds); } //打开录制器 this.VideoWriter.Open(this.AviFilePath, this.ScreenWidth, this.ScreenHight, this.FrameRate, this.VideoCodec, this.BitRate); this.VideoStreamer = new ScreenCaptureStream(this.ScreenArea); this.VideoStreamer.NewFrame += VideoStreamer_NewFrame; if (frameEventHandler != null) { this.VideoStreamer.NewFrame += frameEventHandler; } this.VideoStreamer.Start(); //是否需要录制声音 if (wavRecorder != null) { wavRecorder.Start(); } }
/// <summary> /// 暂停 /// </summary> public void Pause() { this.VideoStreamer.Stop(); this.RecorderStatus = RecorderStatus.Pause; //是否需要暂停录制声音 if (wavRecorder != null) { wavRecorder.Pause(); } }
/// <summary> /// 开始 /// </summary> public void Start() { //继续播放 if (this.RecorderStatus == RecorderStatus.Pause) { this.mRecBuffer.Start(true); return; } this.RecorderStatus = RecorderStatus.Start; InitCaptureDevice(); mWavFormat = CreateWaveFormat(); SetFileName(WavFilePath); RecStart(); }
/// <summary> /// 开始 /// </summary> /// <param name="frameEventHandler">每帧回调(默认不需要填)</param> public virtual void Start(NewFrameEventHandler frameEventHandler = null) { //继续播放 if (this.RecorderStatus == RecorderStatus.Pause) { this.VideoStreamer.Start(); if (wavRecorder != null) { this.wavRecorder.Start(); } this.RecorderStatus = RecorderStatus.Start; return; } this.RecorderStatus = RecorderStatus.Start; try { //获取摄像头列表 var devs = new FilterInfoCollection(FilterCategory.VideoInputDevice); if (devs.Count != 0) { Camera = new VideoCaptureDevice(devs[0].MonikerString); //配置录像参数(宽,高,帧率,比特率等参数)VideoCapabilities这个属性会返回摄像头支持哪些配置,从这里面选一个赋值接即可,我选了第1个 Camera.VideoResolution = Camera.VideoCapabilities[0]; //设置回调,aforge会不断从这个回调推出图像数据 Camera.NewFrame += Camera_NewFrame; //打开摄像头 Camera.Start(); } else { MessageBox.Show("摄像头不存在!"); return; } } catch { MessageBox.Show("摄像头不存在!"); return; } //是否需要录制声音 if (wavRecorder != null) { wavRecorder.Start(); } }
/// <summary> /// 结束 /// </summary> public virtual void End() { this.RecorderStatus = RecorderStatus.End; VideoStreamer.Stop(); VideoWriter.Close(); //是否需要录制声音 if (wavRecorder != null) { wavRecorder.End(); //获取和保存音频流到文件(桌面录制) AviManager aviManager = new AviManager(AviFilePath, true); aviManager.AddAudioStream(wavRecorder.WavFilePath, 0); aviManager.Close(); //删除临时音频文件 try { File.Delete(wavRecorder.WavFilePath); } catch { } } }
private void ChangeLabelRecorder(RecorderStatus newStatus) { var status = string.Empty; recordState = newStatus; switch (recordState) { case RecorderStatus.Stopping: status = "Saving"; this.buttonRecord.Image = Resources.play_disable; this.buttonStop.Image = Resources.stop_disable; break; case RecorderStatus.Recording: status = "Recording"; this.buttonRecord.Image = Resources.pause; break; case RecorderStatus.Paused: status = "Paused"; this.buttonRecord.Image = Resources.play_button; this.buttonStop.Image = Resources.stop; break; case RecorderStatus.Ready: this.buttonRecord.Image = Resources.play_button; this.buttonStop.Image = Resources.stop_disable; status = "Ready"; break; case RecorderStatus.Nothing: break; default: break; } labelStatus.Text = status; }
/// <summary> /// Starts to record the RGBD sequence if the current status is Stopped. /// Stops the recording otherwise. /// </summary> public void OnRecordButtonTapped() { if (_status == RecorderStatus.Stopped) { _status = RecorderStatus.ReadyToRecord; IEnumerator recordThread = Record(); RecordButton.gameObject.SetActive(false); PlaybackButton.gameObject.SetActive(false); StopRecordingButton.gameObject.SetActive(true); StartCoroutine(recordThread); } else if (_status == RecorderStatus.Recording) { _status = RecorderStatus.Exporting; RecordButton.gameObject.SetActive(true); PlaybackButton.gameObject.SetActive(true); StopRecordingButton.gameObject.SetActive(false); RecordingTimerText.gameObject.SetActive(false); _recordingManager.StopRecording(); _status = RecorderStatus.Stopped; ResetScenes(); } }
/// <summary> /// Starts to playback the latest RGBD sequence. /// Stops the recording otherwise. /// </summary> public void OnPlaybackButtonTapped() { if (_status == RecorderStatus.Stopped) { _status = RecorderStatus.ReadyToPlayback; PlaybackButton.gameObject.SetActive(false); StopPlayingbackButton.gameObject.SetActive(true); RecordButton.gameObject.SetActive(false); CarouselUIToggle.CarouselVisible(false); Carousel3D.gameObject.SetActive(false); IEnumerator playbackThread = PlaybackDataset(_filenameToSave); StartCoroutine(playbackThread); } else if (_status == RecorderStatus.Playingback) { CarouselUIToggle.CarouselVisible(true); Carousel3D.gameObject.SetActive(true); RecordButton.gameObject.SetActive(true); PlaybackButton.gameObject.SetActive(true); StopPlayingbackButton.gameObject.SetActive(false); IEnumerator stopPlaybackThread = PlaybackDataset(null); StartCoroutine(stopPlaybackThread); } }
// ReSharper restore PublicConstructorInAbstractClass // ReSharper disable PublicConstructorInAbstractClass public RecorderBase(uint loggingInterval) { SyncRoot = new object(); this.loggingInterval = loggingInterval; status = RecorderStatus.None; encoding = Encoding.GetEncoding(Encoding.Default.CodePage); InitializeconstraintDataLookUp(); // ReSharper disable DoNotCallOverridableMethodsInConstructor InitializeComponent(); // ReSharper restore DoNotCallOverridableMethodsInConstructor }
private void Rec_OnStatusChanged(object sender, RecordingStatusEventArgs e) { Console.WriteLine("Rec_OnStatusChanged"); RecorderStatus status = e.Status; }
private void Rec_OnStatusChanged(object sender, RecordingStatusEventArgs e) { RecorderStatus status = e.Status; Debug.WriteLine(status.ToString()); }
public void StopButtonRecordingHandler(int scriptIndex, PowerPointSlide currentSlide, bool buffered) { // enable the control of play button playButton.Enabled = true; // change rec button status, rec button text, update status label // and stop timer _recButtonStatus = RecorderStatus.Idle; recButton.Image = Properties.Resources.Record; statusLabel.Text = TextCollection.RecorderReadyStatusLabel; ResetTimer(); // get current playback, can be null if there's no matched audio var currentPlayback = GetPlaybackFromList(scriptIndex, currentSlide.ID); try { // stop recording in the first play to reduce redundant recording NStopRecordAudio(); // adjust the stop time difference between timer-stop and recording-stop _recordTotalLength += NGetRecordLengthMillis(); timerLabel.Text = AudioHelper.ConvertMillisToTime(_recordTotalLength); // recorder resources clean up NCleanup(); // ask if the user wants to do the replacement var result = DialogResult.Yes; // prompt to the user only when escaping the slide show while recording if (_inShowControlBox != null && _inShowControlBox.GetCurrentStatus() == InShowControl.ButtonStatus.Estop) { if (currentPlayback == null) { result = MessageBox.Show(TextCollection.RecorderSaveRecordMsg, TextCollection.RecorderSaveRecordMsgBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question); } else { result = MessageBox.Show( string.Format(TextCollection.RecorderReplaceRecordMsgFormat, currentPlayback.Name), TextCollection.RecorderReplaceRecordMsgBoxTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Question); } } if (result == DialogResult.No) { // user does not want to save the file, delete all the temp files DeleteTempAudioFiles(); } else { // user confirms the recording, save the file and replace the record string saveName; string displayName; Audio newRec; var relativeSlideId = GetRelativeSlideIndex(currentSlide.ID); // map the script index with record index // here a simple iteration will find: // 1. the replacement position if a record exists; // 2. an insertion position if a record needs to be added // specially, index == -1 means the record needs to be appended var recordIndex = -1; if (scriptIndex == -1) { if (recDisplay.SelectedItems.Count > 0) { recordIndex = recDisplay.SelectedIndices[0]; } } else { for (int i = 0; i < _audioList[relativeSlideId].Count; i++) { var audio = _audioList[relativeSlideId][i]; if (audio.MatchScriptID >= scriptIndex) { recordIndex = i; break; } } } // if current playback != null -> there's a corresponding record for the // script, we can do the replacement; if (currentPlayback != null) { saveName = currentPlayback.SaveName.Replace(".wav", " rec.wav"); displayName = currentPlayback.Name; var matchId = currentPlayback.MatchScriptID; if (scriptIndex == -1) { matchId = -1; } newRec = AudioHelper.DumpAudio(displayName, saveName, _recordTotalLength, matchId); // note down the old record and replace the record list _undoAudioBuffer = _audioList[relativeSlideId][recordIndex]; _audioList[relativeSlideId][recordIndex] = newRec; // update the item in display // check status of in show control box to: // 1. reduce unnecessary update (won't see the display lists while slide show) // 2. current slide == null during slide show, use in show box status to guard // null ptr exception. if (_inShowControlBox == null || _inShowControlBox.GetCurrentStatus() != InShowControl.ButtonStatus.Rec && relativeSlideId == GetRelativeSlideIndex(PowerPointCurrentPresentationInfo.CurrentSlide.ID)) { UpdateRecordList(recordIndex, displayName, newRec.Length); } } else // if current playback == null -> there's NO corresponding record for the // script, we need to construct the new record and insert it to a proper // position { var saveNameSuffix = " " + scriptIndex + " rec.wav"; saveName = _tempFullPath + String.Format(SaveNameFormat, relativeSlideId) + saveNameSuffix; // the display name -> which script it corresponds to displayName = String.Format(SpeechShapeFormat, scriptIndex); newRec = AudioHelper.DumpAudio(displayName, saveName, _recordTotalLength, scriptIndex); // insert the new audio if (recordIndex == -1) { _audioList[relativeSlideId].Add(newRec); // update record index, will be used in highlighting recordIndex = _audioList[relativeSlideId].Count - 1; } else { _audioList[relativeSlideId].Insert(recordIndex, newRec); } // update the whole record display list if not in slide show mode if (_inShowControlBox == null || _inShowControlBox.GetCurrentStatus() != InShowControl.ButtonStatus.Rec && relativeSlideId == GetRelativeSlideIndex(PowerPointCurrentPresentationInfo.CurrentSlide.ID)) { UpdateRecordList(relativeSlideId); // highlight the latest added record recDisplay.Items[recordIndex].Selected = true; } } // save current sound -> rename the temp file to the correct save name NMergeAudios(_tempFullPath, "temp", saveName); // update the script list if not in slide show mode if (scriptIndex != -1 && (_inShowControlBox == null || _inShowControlBox.GetCurrentStatus() != InShowControl.ButtonStatus.Rec && relativeSlideId == GetRelativeSlideIndex(PowerPointCurrentPresentationInfo.CurrentSlide.ID))) { UpdateScriptList(scriptIndex, null, ScriptStatus.Recorded); } // check if we need to buffer the audio or embed the audio if (!buffered) { newRec.EmbedOnSlide(currentSlide, scriptIndex); if (!Globals.ThisAddIn.Ribbon.RemoveAudioEnabled) { Globals.ThisAddIn.Ribbon.RemoveAudioEnabled = true; Globals.ThisAddIn.Ribbon.RefreshRibbonControl("RemoveAudioButton"); } } else { while (AudioBuffer.Count < currentSlide.Index) { AudioBuffer.Add(new List<Tuple<Audio, int>>()); } AudioBuffer[currentSlide.Index - 1].Add(new Tuple<Audio, int>(newRec, scriptIndex)); } } } catch (Exception e) { ErrorDialogWrapper.ShowDialog("Record cannot be saved\n", "Error when saving the file", e); throw; } finally // do the following UI re-setup { // enable control of both lists recDisplay.Enabled = true; scriptDisplay.Enabled = true; // disable stop button stopButton.Enabled = false; } }
protected virtual bool Initialize() { lock (SyncRoot) { while ((status & RecorderStatus.Initializing) != RecorderStatus.None) Monitor.Wait(SyncRoot); if ((status & RecorderStatus.Initialized) != RecorderStatus.None) return true; status |= RecorderStatus.Initializing; Monitor.PulseAll(SyncRoot); } try { if ((InitializeInstance() & NextInstruction.Do) == NextInstruction.Do && (ValidateGlobalParameters() & NextInstruction.Do) == NextInstruction.Do) { PrepareEncoding(ref encoding); lock (SyncRoot) { status = RecorderStatus.Initialized; Monitor.PulseAll(SyncRoot); return true; } } } finally { lock (SyncRoot) { if ((status & RecorderStatus.Initializing) == RecorderStatus.Initializing) { status ^= (status & RecorderStatus.Initializing); Monitor.PulseAll(SyncRoot); } } } return false; }
private void RecButtonRecordingHandler() { // make sure stop button is enabled stopButton.Enabled = true; // change the status to pause and change the button text to resume _recButtonStatus = RecorderStatus.Pause; statusLabel.Text = TextCollection.RecorderPauseStatusLabel; recButton.Image = Properties.Resources.Record; // stop the sound, increase clip counter, add current clip length to // total record length and stop the timer NStopRecordAudio(); _recordClipCnt++; _recordTotalLength += NGetRecordLengthMillis(); _timer.Dispose(); // since the timer is counting in seconds, we need to know how many // millis to wait before next integral second. // retrieve current length int currentLen = NGetRecordLengthMillis(); _resumeWaitingTime = _timerCnt * 1000 - currentLen; if (_resumeWaitingTime < 0) { _resumeWaitingTime = 0; } NCleanup(); }
private void PlayButtonPlayingHandler() { // make sure stop button is enabled stopButton.Enabled = true; // change the status to pause and change the text to resume _playButtonStatus = RecorderStatus.Pause; statusLabel.Text = TextCollection.RecorderPauseStatusLabel; playButton.Image = Properties.Resources.Play; // pause the sound, timer and trackbar Native.mciSendString("pause sound", null, 0, IntPtr.Zero); _timer.Dispose(); _stopwatch.Stop(); _trackbarThread.Interrupt(); // since the timer is counting in seconds, we need to know how many // millis to wait before next integral second. // retrieve current length int currentLen = AudioHelper.GetAudioCurrentPosition(); _resumeWaitingTime = _timerCnt * 1000 - currentLen; if (_resumeWaitingTime < 0) { _resumeWaitingTime = 0; } }
private void PlayButtonIdleHandler() { // close unfinished session ResetSession(); ResetRecorder(); // get play back length var playback = GetPlaybackFromList(); if (playback == null) { MessageBox.Show(TextCollection.RecorderNoRecordToPlayError); } else { // UI settings statusLabel.Text = TextCollection.RecorderPlayingStatusLabel; statusLabel.Visible = true; // enable stop button stopButton.Enabled = true; // disable control of both lists recDisplay.Enabled = false; scriptDisplay.Enabled = false; // change the button status _playButtonStatus = RecorderStatus.Playing; playButton.Image = Properties.Resources.Pause; _playbackLenMillis = playback.LengthMillis; // start the timer and track bar _timerCnt = 0; _timer = new System.Threading.Timer(TimerEvent, null, 0, 1000); _trackbarThread = new Thread(TrackbarEvent); _trackbarThread.Start(); // start play back AudioHelper.OpenAudio(playback.SaveName); Native.mciSendString("play sound notify", null, 0, Handle); } }
/// <summary> /// 结束 /// </summary> public void End() { this.RecorderStatus = RecorderStatus.End; RecStop(); }
/// <summary> /// 暂停 /// </summary> public void Pause() { this.RecorderStatus = RecorderStatus.Pause; mRecBuffer.Stop(); }
/// <summary> /// 暂停 /// </summary> public void Pause() { this.VideoStreamer.Stop(); this.RecorderStatus = RecorderStatus.Pause; }
private void Rec_OnStatusChanged(object sender, RecordingStatusEventArgs e) { RecorderStatus status = e.Status; }
private void StopButtonPlayingHandler() { // change play button status, update play button text, update // status label and reset all sessions Native.mciSendString("stop sound", null, 0, IntPtr.Zero); // UI settings ResetSession(); _playButtonStatus = RecorderStatus.Idle; playButton.Image = Properties.Resources.Play; statusLabel.Text = TextCollection.RecorderReadyStatusLabel; // enable both lists recDisplay.Enabled = true; scriptDisplay.Enabled = true; // disable stop button stopButton.Enabled = false; }
private void PlayButtonPauseHandler() { // make sure stop button is enabled stopButton.Enabled = true; // change the status to playing and change the button text to // pause _playButtonStatus = RecorderStatus.Playing; statusLabel.Text = TextCollection.RecorderPlayingStatusLabel; playButton.Image = Properties.Resources.Pause; // resume recording, restart the timer and continue the track bar Native.mciSendString("resume sound", null, 0, IntPtr.Zero); _timer = new System.Threading.Timer(TimerEvent, null, _resumeWaitingTime, 1000); _trackbarThread = new Thread(TrackbarEvent); _trackbarThread.Start(); }
private void Rec_OnStatusChanged(object sender, RecordingStatusEventArgs e) { RecorderStatus status = e.Status; UpdateLogFile("Recorder status has changed. New status: " + e.Status.ToString()); }
private void RecButtonPauseHandler() { // make sure stop button is enabled stopButton.Enabled = true; // change the status to recording and change the button text to // pause _recButtonStatus = RecorderStatus.Recording; statusLabel.Text = TextCollection.RecorderRecordingStatusLabel; recButton.Image = Properties.Resources.Pause; // start a new recording, name it after clip counter and restart the timer var tempSaveName = String.Format(_tempWaveFileNameFormat, _recordClipCnt); NStartRecordAudio(tempSaveName, 11025, 16, 1, true); _timer = new System.Threading.Timer(TimerEvent, null, _resumeWaitingTime, 1000); }
public void Play() { Status = RecorderStatus.Playing; }
private void ResetRecorder() { soundTrackBar.Value = 0; timerLabel.Text = TextCollection.RecorderInitialTimer; statusLabel.Text = TextCollection.RecorderReadyStatusLabel; recButton.Image = Properties.Resources.Record; playButton.Image = Properties.Resources.Play; _recButtonStatus = RecorderStatus.Idle; _playButtonStatus = RecorderStatus.Idle; }
public void Stop() { Status = RecorderStatus.Stopped; }
public void RecButtonIdleHandler() { // close unfinished session ResetSession(); // check input device, abort if no input device connected if (!NInputDeviceExists()) { MessageBox.Show(TextCollection.RecorderNoInputDeviceMsg, TextCollection.RecorderNoInputDeviceMsgBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // UI settings ResetRecorder(); statusLabel.Text = TextCollection.RecorderRecordingStatusLabel; statusLabel.Visible = true; recButton.Image = Properties.Resources.Pause; // disable control of playing playButton.Enabled = false; // enable stop button stopButton.Enabled = true; // disable control of both lists recDisplay.Enabled = false; scriptDisplay.Enabled = false; // clear the undo buffer _undoAudioBuffer = null; // track the on going script index if not in slide show mode if (_inShowControlBox == null || _inShowControlBox.GetCurrentStatus() == InShowControl.ButtonStatus.Idle) { // if there's a corresponding script if (scriptDisplay.SelectedIndices.Count > 0) { _replaceScriptIndex = scriptDisplay.SelectedIndices[0]; } else { _replaceScriptIndex = -1; } _replaceScriptSlide = PowerPointCurrentPresentationInfo.CurrentSlide; } // change the status to recording status _recButtonStatus = RecorderStatus.Recording; // new record, clip counter and total length should be reset _recordClipCnt = 0; _recordTotalLength = 0; // construct new save name var tempSaveName = String.Format(_tempWaveFileNameFormat, _recordClipCnt); // start recording NStartRecordAudio(tempSaveName, 11025, 16, 1, true); // start the timer _timerCnt = 0; _timer = new System.Threading.Timer(TimerEvent, null, 0, 1000); }
public void Record() { Status = RecorderStatus.Recording; }
protected override void WndProc(ref Message m) { if (m.Msg == AudioHelper.MM_MCINOTIFY) { switch (m.WParam.ToInt32()) { case AudioHelper.MCI_NOTIFY_SUCCESS: // UI settings statusLabel.Text = TextCollection.RecorderReadyStatusLabel; playButton.Image = Properties.Resources.Play; _playButtonStatus = RecorderStatus.Idle; // disable stop button stopButton.Enabled = false; // enable both lists recDisplay.Enabled = true; scriptDisplay.Enabled = true; // dispose timer and track bar timer while setting the // track bar to full ResetSession(); soundTrackBar.Value = soundTrackBar.Maximum; break; case AudioHelper.MCI_NOTIFY_ABORTED: ResetTrackbar(0); break; default: MessageBox.Show(TextCollection.RecorderWndMessageError); break; } } base.WndProc(ref m); }
public void Pause() { Status = RecorderStatus.Paused; }