public void ApplyVoiceChannelParms(VoiceParmSet parms, bool reconfigure) { log.DebugFormat(voiceMgr, "VoiceChannel.ApplyVoiceChannelParms: voiceMgr.defaultPlaybackVolume {0}", voiceMgr.defaultPlaybackVolume); ApplyDecodecSettings(parms, reconfigure); SetPlaybackVolume(voiceMgr.defaultPlaybackVolume); ApplyJitterBufferSettings(parms, reconfigure); }
///<summary> /// Initialize a new microphone instance, creating the /// FMOD sound object, optionally opening a recording /// stream, and creating and starting a timer instance /// to copy the PCM samples. ///</summary> public void InitMicrophone(VoiceParmSet parmSet, bool reconfigure) { log.DebugFormat(voiceMgr, "MicrophoneChannel.InitMicrophone called with recording WAV({0}), Speex({1})", recordingWAV, recordingSpeex); if (channelCodec != null) return; try { log.Debug(voiceMgr, "MicrophoneChannel.InitMicrophone: Creating codec"); encoderOutputBuffer = new byte[maxBytesPerEncodedFrame]; if (voiceMgr.runningVoiceBot) { ApplyVoiceBotParms(parmSet, reconfigure); SetTimeOfNextPlayback(); } else { encoderInputBuffer = new short[maxSamplesPerFrame]; channelCodec = new SpeexCodec(); int encodecFrameSize = channelCodec.InitEncoder(maxSamplesPerFrame, samplesPerFrame, samplesPerSecond); if (encodecFrameSize != samplesPerFrame) log.ErrorFormat(voiceMgr, "MicrophoneChannel.InitMicrophone: The encoder frame size {0} != samplesPerFrame " + samplesPerFrame); ApplyMicrophoneSettings(parmSet, reconfigure); // create a sound object FMOD.RESULT result; FMOD.MODE mode = FMOD.MODE._2D | FMOD.MODE.OPENUSER | FMOD.MODE.SOFTWARE | FMOD.MODE.LOOP_NORMAL; lock(voiceMgr.usingFmod) { FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO(); exinfo.cbsize = Marshal.SizeOf(exinfo); exinfo.decodebuffersize = 0; exinfo.length = (uint)(micQueueSize * 2); exinfo.numchannels = 1; exinfo.defaultfrequency = samplesPerSecond; exinfo.format = FMOD.SOUND_FORMAT.PCM16; log.Debug(voiceMgr, "MicrophoneChannel.InitMicrophone: Creating sound"); result = voiceMgr.fmod.createSound((string)null, mode, ref exinfo, ref channelSound); } try { ERRCHECK(result); } catch (Exception e) { log.ErrorFormat(voiceMgr, "MicrophoneChannel.InitMicrophone: Error creating microphone sound: {0}; stack trace\n {1}", e.Message, e.StackTrace); } SetMicDevice(); micSamples = new short[micQueueSize]; if (recordingWAV || recordingSpeex) { log.Debug(voiceMgr, "MicrophoneChannel.InitMicrophone: Calling StartRecording"); StartRecording(channelSound, voiceMgr.LogFolderPath("RecordMic"), recordingWAV, recordingSpeex); } log.Debug(voiceMgr, "MicrophoneChannel.InitMicrophone: Calling StartFmodMicUpdates"); StartFmodMicUpdates(channelSound); log.Debug(voiceMgr, "MicrophoneChannel.InitMicrophone: Calling StartChannel"); StartChannel(false); } micHandlingTimer = new System.Timers.Timer(); micHandlingTimer.Elapsed += MicHandlingTimerTick; micHandlingTimer.Interval = 10; // ms micHandlingTimer.Enabled = true; if (usingDataFrameAggregation) { dataFrameAggregator = new DataFrameAggregator(voiceMgr, deviceNumber, this); dataFrameAggregator.Start(); } sourceReady = true; } catch (Exception e) { log.Error(voiceMgr, "MicrophoneChannel.InitMicrophone: Exception " + e.Message + ", stack trace\n" + e.StackTrace); } }
///<summary> /// The constructor creates the VoiceChannel object, /// assigning it the external voiceNumber, and finally /// activates the channel. ///</summary> public VoiceChannel(VoiceManager voiceMgr, long oid, byte voiceNumber, bool positionalSound, bool voicesRecordSpeex, VoiceParmSet parms) : base(voiceMgr, false, voicesRecordSpeex, !positionalSound) { this.oid = oid; this.positionalSound = positionalSound; this.voiceNumber = voiceNumber; this.channelCodec = new SpeexCodec(); this.decodeBuffer = new short[playbackQueueSize]; this.encodedBytes = new byte[maxBytesPerEncodedFrame]; this.queuedSamples = new CircularBuffer(playbackQueueSize); this.voiceReadCallback = new FMOD.SOUND_PCMREADCALLBACK(VoiceChannelReadPCM); this.title = "voice" + voiceNumber; this.lastSpoke = 0; ActivateChannel(); ApplyVoiceChannelParms(parms, false); }
protected void ApplyTransmissionParms(VoiceParmSet parmSet, bool reconfigure) { foreach (VoiceParm parm in parmSet.GetParmsOfKindOrDefault(VoiceParmKind.Transmission, reconfigure)) { log.DebugFormat(voiceMgr, "VoiceManager.ApplyTransmissionParms: setting voice bot parm {0} to {1}", parm.name, parm.value); switch ((TransmissionParm)(parm.ctlIndex)) { case TransmissionParm.MaxSavedFrames: maxSavedFrames = parm.ret.iValue; break; case TransmissionParm.UsePowerThreshold: usePowerThreshold = parm.ret.bValue; break; case TransmissionParm.FramePowerThreshold: framePowerThreshold = parm.ret.fValue; break; default: log.ErrorFormat(voiceMgr, "VoiceManager.ApplyTransmissionParms: Unknown voice parm '{0}', index {1}", parm.name, parm.ctlIndex); break; } } }
protected void ApplyVoiceBotParms(VoiceParmSet parmSet, bool reconfigure) { foreach (VoiceParm parm in parmSet.GetParmsOfKindOrDefault(VoiceParmKind.VoiceBot, reconfigure)) { log.DebugFormat(voiceMgr, "VoiceManager.ApplyVoiceBotParms: setting voice bot parm {0} to {1}", parm.name, parm.value); switch ((VoiceBotParm)(parm.ctlIndex)) { case VoiceBotParm.MaxWaitTilNextPlayback: maxWaitTilNextPlayback = parm.ret.iValue; break; default: log.ErrorFormat(voiceMgr, "VoiceManager.ApplyVoiceBotParms: Unknown voice parm '{0}', index {1}", parm.name, parm.ctlIndex); break; } } }
protected void ApplyPreprocessorSettings(VoiceParmSet parmSet, bool reconfigure) { List<VoiceParm> parms = parmSet.GetParmsOfKindOrDefault(VoiceParmKind.Preprocessor, reconfigure); log.DebugFormat(voiceMgr, "BasicChannel.ApplyPreprocessorSettings: There are {0} settings", parms != null ? parms.Count : 0); if (parms != null) { foreach (VoiceParm parm in parms) { log.DebugFormat(voiceMgr, "BasicChannel.ApplyPreprocessorSettings: setting {0} to {1}", parm.name, parm.value); // DENOISE, MICLEVEL, FRAME_POWER_THRESHOLD // and SET_VAD require special treatment if (parm.ctlIndex == (int)PreprocessCtlCode.SPEEX_PREPROCESS_SET_DENOISE) CheckRetCode(parm, channelCodec.SetOnePreprocessorSetting((PreprocessCtlCode)parm.ctlIndex, (parm.ret.bValue ? 1 : 2))); else if (parm.ctlIndex == (int)PreprocessCtlCode.SPEEX_PREPROCESS_SET_AGC_LEVEL) SetMicLevel(parm.ret.iValue); else if (parm.ctlIndex == (int)PreprocessCtlCode.SPEEX_PREPROCESS_SET_VAD && usePowerThreshold) // Turn off VAD if we're using the power // threshold instead of preprocess VAD CheckRetCode(parm, channelCodec.SetOnePreprocessorSetting(PreprocessCtlCode.SPEEX_PREPROCESS_SET_VAD, 0)); else { switch (parm.valueKind) { case ValueKind.Int: CheckRetCode(parm, channelCodec.SetOnePreprocessorSetting((PreprocessCtlCode)parm.ctlIndex, parm.ret.iValue)); break; case ValueKind.Float: CheckRetCode(parm, channelCodec.SetOnePreprocessorSetting((PreprocessCtlCode)parm.ctlIndex, parm.ret.fValue)); break; case ValueKind.Bool: CheckRetCode(parm, channelCodec.SetOnePreprocessorSetting((PreprocessCtlCode)parm.ctlIndex, parm.ret.bValue)); break; default: log.Error(voiceMgr, "BasicChannel.ApplyPreprocessorSettings: Unknown parm.valueKind " + parm.valueKind); break; } } } } }
protected void ApplyJitterBufferSettings(VoiceParmSet parmSet, bool reconfigure) { List<VoiceParm> parms = parmSet.GetParmsOfKindOrDefault(VoiceParmKind.JitterBuffer, reconfigure); if (parms != null) { foreach (VoiceParm parm in parms) { log.DebugFormat(voiceMgr, "BasicChannel.ApplyJitterBufferSettings: setting {0} to {1}", parm.name, parm.value); CheckRetCode(parm, channelCodec.SetOneJitterBufferSetting((JitterBufferCtlCode)parm.ctlIndex, parm.ret.iValue)); } } }
protected void ApplyEncodecSettings(VoiceParmSet parmSet, bool reconfigure) { List<VoiceParm> parms = parmSet.GetParmsOfKindOrDefault(VoiceParmKind.Encodec, reconfigure); log.DebugFormat(voiceMgr, "BasicChannel.ApplyEncodecSettings: There are {0} settings", parms != null ? parms.Count : 0); if (parms != null) { foreach (VoiceParm parm in parms) { log.DebugFormat(voiceMgr, "BasicChannel.ApplyEncodecSettings: setting {0} to {1}", parm.name, parm.value); if (parm.valueKind == ValueKind.Float) { if (parm.ctlIndex == 0) voiceMgr.silentFrameCountDeallocationThreshold = (int)(framesPerSecond * parm.ret.fValue); else log.ErrorFormat(voiceMgr, "BasicChannel.ApplyEncodecSettings: unknown float parm, ctlIndex {0}", parm.ctlIndex); } // All the rest int parms, and none of them require special treatment else if (parm.valueKind != ValueKind.Int) log.ErrorFormat(voiceMgr, "BasicChannel.ApplyEncodecSettings: codec parm '{0}' is not int-valued; instead value type is '{1}'!", parm.name, parm.valueKind); else { SpeexCtlCode code = (SpeexCtlCode)parm.ctlIndex; if (code == SpeexCtlCode.SPEEX_SET_QUALITY) { int mode = 0; channelCodec.GetOneCodecSetting(true, SpeexCtlCode.SPEEX_GET_MODE, ref mode); log.DebugFormat(voiceMgr, "BasicChannel.ApplyEncodecSettings: Before setting quality to {0}, mode is {1}", parm.ret.iValue, mode); } CheckRetCode(parm, channelCodec.SetOneCodecSetting(true, code, parm.ret.iValue)); if (code == SpeexCtlCode.SPEEX_SET_QUALITY) { int mode = 0; channelCodec.GetOneCodecSetting(true, SpeexCtlCode.SPEEX_GET_MODE, ref mode); log.DebugFormat(voiceMgr, "BasicChannel.ApplyEncodecSettings: After setting quality to {0}, mode is {1}", parm.ret.iValue, mode); } } } } }
protected void ApplyDecodecSettings(VoiceParmSet parmSet, bool reconfigure) { List<VoiceParm> parms = parmSet.GetParmsOfKindOrDefault(VoiceParmKind.Decodec, reconfigure); log.DebugFormat(voiceMgr, "BasicChannel.ApplyDecodecSettings: There are {0} settings", parms != null ? parms.Count : 0); if (parms != null) { foreach (VoiceParm parm in parms) { log.DebugFormat(voiceMgr, "BasicChannel.ApplyDecodecSettings: setting {0} to {1}", parm.name, parm.value); // They are all int parms, and none of them require special treatment if (parm.valueKind != ValueKind.Int) log.ErrorFormat(voiceMgr, "BasicChannel.ApplyDecodecSettings: codec parm '{0}' is not int-valued; instead value type is '{1}'!", parm.name, parm.valueKind); else CheckRetCode(parm, channelCodec.SetOneCodecSetting(false, (SpeexCtlCode)parm.ctlIndex, parm.ret.iValue)); } } }
public void ApplyMicrophoneSettings(VoiceParmSet parmSet, bool reconfigure) { ApplyTransmissionParms(parmSet, reconfigure); ApplyEncodecSettings(parmSet, reconfigure); ApplyPreprocessorSettings(parmSet, reconfigure); ApplyVoiceBotParms(parmSet, reconfigure); }