/// <summary> /// Erstellt einen neuen Dienst. /// </summary> /// <param name="configuration">Die zu verwendende Konfiguration.</param> /// <param name="factory">Kann Gerätebeschreibungen erzeugen.</param> public RecordingService( RecordingServiceConfiguration configuration, IRecordingDeviceFactory factory ) { // Remember Devices = new RecordingDevices( configuration.DeviceNames, configuration.Comparer, factory ); Configuration = configuration; Name = configuration.Name; }
/// <summary> /// Used to initiate sending the PeakLevelChanged notifications. /// Currently this typically happens when the Recorder instance is created, /// which is usually when the talking book tool asks for the AudioDevicesJson. /// This is not very intuitive, but it's the most easily detectable event /// that indicates that the talking book tool is actually active. /// </summary> public void BeginMonitoring() { if (!RecordingDevices.Contains(RecordingDevice)) { RecordingDevice = RecordingDevices.FirstOrDefault(); } if (RecordingDevice != null) { Recorder.BeginMonitoring(); } }
/// <summary> /// Returns a json string like {"devices":["microphone", "Logitech Headset"], "productName":"Logitech Headset", "genericName":"Headset"}, /// except that in practice currrently the generic and product names are the same and not as helpful as the above. /// Devices is a list of product names (of available recording devices), the productName and genericName refer to the /// current selection (or will be null, if no current device). /// </summary> public void HandleAudioDevices(ApiRequest request) { try { var sb = new StringBuilder("{\"devices\":["); sb.Append(string.Join(",", RecordingDevices.Select(d => "\"" + d.ProductName + "\""))); sb.Append("],\"productName\":"); if (CurrentRecording.RecordingDevice != null) { sb.Append("\"" + CurrentRecording.RecordingDevice.ProductName + "\""); } else { sb.Append("null"); } sb.Append(",\"genericName\":"); if (CurrentRecording.RecordingDevice != null) { sb.Append("\"" + CurrentRecording.RecordingDevice.GenericName + "\""); } else { sb.Append("null"); } sb.Append("}"); request.ReplyWithJson(sb.ToString()); } catch (Exception e) { Logger.WriteError("AudioRecording could not find devices: ", e); // BL-7272 shows an exception occurred somewhere, and it may have been here. // If so, we just assume no input devices could be found. request.ReplyWithJson("{\"devices\":[],\"productName\":null,\"genericName\":null}"); } }
public void HandleStartRecording(ApiRequest request) { // Precondition: HandleStartRecording shouldn't run until the previous HandleEndRecord() is completely done with PathToRecordableAudioForCurrentSegment // Unfortunately this is not as easy to ensure on the code side due to HandleStartRecord() not being able to be moved off the UI thread, and deadlock potential // I found it too difficult to actually violate this precondition from the user side. // Therefore, I just assume this to be true. if (Recording) { request.Failed("Already recording"); return; } string segmentId = request.RequiredParam("id"); PathToRecordableAudioForCurrentSegment = GetPathToRecordableAudioForSegment(segmentId); // Careful! Overwrites the previous value of the member variable. PathToTemporaryWav = Path.GetTempFileName(); if (Recorder.RecordingState == RecordingState.RequestedStop) { request.Failed(LocalizationManager.GetString("EditTab.Toolbox.TalkingBook.BadState", "Bloom recording is in an unusual state, possibly caused by unplugging a microphone. You will need to restart.", "This is very low priority for translation.")); } // If someone unplugged the microphone we were planning to use switch to another. // This also triggers selecting the first one initially. if (!RecordingDevices.Contains(RecordingDevice)) { RecordingDevice = RecordingDevices.FirstOrDefault(); } if (RecordingDevice == null) { ReportNoMicrophone(); request.Failed("No Microphone"); return; } if (Recording) { request.Failed("Already Recording"); return; } if (!PrepareBackupFile(PathToRecordableAudioForCurrentSegment, ref _backupPathForRecordableAudio, request)) { return; } // There are two possible scenarios when starting to record. // 1. We have a recordable file and corresponding publishable file. // In that case, we need to make sure to restore the publishable file if we restore the recordable one so they stay in sync. // 2. We have an publishable file with no corresponding recordable file. // In that case, we need to restore it if there is any problem creating a new recordable file. if (!PrepareBackupFile(GetPathToPublishableAudioForSegment(segmentId), ref _backupPathForPublishableAudio, request)) { return; } _startRecording = DateTime.Now; _startRecordingTimer.Start(); request.ReplyWithText("starting record soon"); }