| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "voice_engine/output_mixer.h" | 11 #include "voice_engine/output_mixer.h" |
| 12 | 12 |
| 13 #include "modules/audio_processing/include/audio_processing.h" | 13 #include "modules/audio_processing/include/audio_processing.h" |
| 14 #include "rtc_base/format_macros.h" | 14 #include "rtc_base/format_macros.h" |
| 15 #include "system_wrappers/include/file_wrapper.h" | |
| 16 #include "system_wrappers/include/trace.h" | 15 #include "system_wrappers/include/trace.h" |
| 17 #include "voice_engine/statistics.h" | 16 #include "voice_engine/statistics.h" |
| 18 #include "voice_engine/utility.h" | 17 #include "voice_engine/utility.h" |
| 19 | 18 |
| 20 namespace webrtc { | 19 namespace webrtc { |
| 21 namespace voe { | 20 namespace voe { |
| 22 | 21 |
| 23 void | 22 void |
| 24 OutputMixer::NewMixedAudio(int32_t id, | 23 OutputMixer::NewMixedAudio(int32_t id, |
| 25 const AudioFrame& generalAudioFrame, | 24 const AudioFrame& generalAudioFrame, |
| 26 const AudioFrame** uniqueAudioFrames, | 25 const AudioFrame** uniqueAudioFrames, |
| 27 uint32_t size) | 26 uint32_t size) |
| 28 { | 27 { |
| 29 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1), | 28 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1), |
| 30 "OutputMixer::NewMixedAudio(id=%d, size=%u)", id, size); | 29 "OutputMixer::NewMixedAudio(id=%d, size=%u)", id, size); |
| 31 | 30 |
| 32 _audioFrame.CopyFrom(generalAudioFrame); | 31 _audioFrame.CopyFrom(generalAudioFrame); |
| 33 _audioFrame.id_ = id; | 32 _audioFrame.id_ = id; |
| 34 } | 33 } |
| 35 | 34 |
| 36 void OutputMixer::PlayNotification(int32_t id, uint32_t durationMs) | |
| 37 { | |
| 38 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1), | |
| 39 "OutputMixer::PlayNotification(id=%d, durationMs=%d)", | |
| 40 id, durationMs); | |
| 41 // Not implement yet | |
| 42 } | |
| 43 | |
| 44 void OutputMixer::RecordNotification(int32_t id, | |
| 45 uint32_t durationMs) | |
| 46 { | |
| 47 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1), | |
| 48 "OutputMixer::RecordNotification(id=%d, durationMs=%d)", | |
| 49 id, durationMs); | |
| 50 | |
| 51 // Not implement yet | |
| 52 } | |
| 53 | |
| 54 void OutputMixer::PlayFileEnded(int32_t id) | |
| 55 { | |
| 56 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1), | |
| 57 "OutputMixer::PlayFileEnded(id=%d)", id); | |
| 58 | |
| 59 // not needed | |
| 60 } | |
| 61 | |
| 62 void OutputMixer::RecordFileEnded(int32_t id) | |
| 63 { | |
| 64 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1), | |
| 65 "OutputMixer::RecordFileEnded(id=%d)", id); | |
| 66 assert(id == _instanceId); | |
| 67 | |
| 68 rtc::CritScope cs(&_fileCritSect); | |
| 69 _outputFileRecording = false; | |
| 70 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1), | |
| 71 "OutputMixer::RecordFileEnded() =>" | |
| 72 "output file recorder module is shutdown"); | |
| 73 } | |
| 74 | |
| 75 int32_t | 35 int32_t |
| 76 OutputMixer::Create(OutputMixer*& mixer, uint32_t instanceId) | 36 OutputMixer::Create(OutputMixer*& mixer, uint32_t instanceId) |
| 77 { | 37 { |
| 78 WEBRTC_TRACE(kTraceMemory, kTraceVoice, instanceId, | 38 WEBRTC_TRACE(kTraceMemory, kTraceVoice, instanceId, |
| 79 "OutputMixer::Create(instanceId=%d)", instanceId); | 39 "OutputMixer::Create(instanceId=%d)", instanceId); |
| 80 mixer = new OutputMixer(instanceId); | 40 mixer = new OutputMixer(instanceId); |
| 81 if (mixer == NULL) | 41 if (mixer == NULL) |
| 82 { | 42 { |
| 83 WEBRTC_TRACE(kTraceMemory, kTraceVoice, instanceId, | 43 WEBRTC_TRACE(kTraceMemory, kTraceVoice, instanceId, |
| 84 "OutputMixer::Create() unable to allocate memory for" | 44 "OutputMixer::Create() unable to allocate memory for" |
| 85 "mixer"); | 45 "mixer"); |
| 86 return -1; | 46 return -1; |
| 87 } | 47 } |
| 88 return 0; | 48 return 0; |
| 89 } | 49 } |
| 90 | 50 |
| 91 OutputMixer::OutputMixer(uint32_t instanceId) : | 51 OutputMixer::OutputMixer(uint32_t instanceId) : |
| 92 _mixerModule(*AudioConferenceMixer::Create(instanceId)), | 52 _mixerModule(*AudioConferenceMixer::Create(instanceId)), |
| 93 _instanceId(instanceId), | 53 _instanceId(instanceId), |
| 94 _mixingFrequencyHz(8000), | 54 _mixingFrequencyHz(8000) |
| 95 _outputFileRecording(false) | |
| 96 { | 55 { |
| 97 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1), | 56 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1), |
| 98 "OutputMixer::OutputMixer() - ctor"); | 57 "OutputMixer::OutputMixer() - ctor"); |
| 99 | 58 |
| 100 if (_mixerModule.RegisterMixedStreamCallback(this) == -1) | 59 if (_mixerModule.RegisterMixedStreamCallback(this) == -1) |
| 101 { | 60 { |
| 102 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1), | 61 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1), |
| 103 "OutputMixer::OutputMixer() failed to register mixer" | 62 "OutputMixer::OutputMixer() failed to register mixer" |
| 104 "callbacks"); | 63 "callbacks"); |
| 105 } | 64 } |
| 106 } | 65 } |
| 107 | 66 |
| 108 void | 67 void |
| 109 OutputMixer::Destroy(OutputMixer*& mixer) | 68 OutputMixer::Destroy(OutputMixer*& mixer) |
| 110 { | 69 { |
| 111 if (mixer) | 70 if (mixer) |
| 112 { | 71 { |
| 113 delete mixer; | 72 delete mixer; |
| 114 mixer = NULL; | 73 mixer = NULL; |
| 115 } | 74 } |
| 116 } | 75 } |
| 117 | 76 |
| 118 OutputMixer::~OutputMixer() | 77 OutputMixer::~OutputMixer() |
| 119 { | 78 { |
| 120 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1), | 79 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1), |
| 121 "OutputMixer::~OutputMixer() - dtor"); | 80 "OutputMixer::~OutputMixer() - dtor"); |
| 122 { | |
| 123 rtc::CritScope cs(&_fileCritSect); | |
| 124 if (output_file_recorder_) { | |
| 125 output_file_recorder_->RegisterModuleFileCallback(NULL); | |
| 126 output_file_recorder_->StopRecording(); | |
| 127 } | |
| 128 } | |
| 129 _mixerModule.UnRegisterMixedStreamCallback(); | 81 _mixerModule.UnRegisterMixedStreamCallback(); |
| 130 delete &_mixerModule; | 82 delete &_mixerModule; |
| 131 } | 83 } |
| 132 | 84 |
| 133 int32_t | 85 int32_t |
| 134 OutputMixer::SetEngineInformation(voe::Statistics& engineStatistics) | 86 OutputMixer::SetEngineInformation(voe::Statistics& engineStatistics) |
| 135 { | 87 { |
| 136 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1), | 88 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1), |
| 137 "OutputMixer::SetEngineInformation()"); | 89 "OutputMixer::SetEngineInformation()"); |
| 138 _engineStatisticsPtr = &engineStatistics; | 90 _engineStatisticsPtr = &engineStatistics; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 150 } | 102 } |
| 151 | 103 |
| 152 int32_t | 104 int32_t |
| 153 OutputMixer::SetMixabilityStatus(MixerParticipant& participant, | 105 OutputMixer::SetMixabilityStatus(MixerParticipant& participant, |
| 154 bool mixable) | 106 bool mixable) |
| 155 { | 107 { |
| 156 return _mixerModule.SetMixabilityStatus(&participant, mixable); | 108 return _mixerModule.SetMixabilityStatus(&participant, mixable); |
| 157 } | 109 } |
| 158 | 110 |
| 159 int32_t | 111 int32_t |
| 160 OutputMixer::SetAnonymousMixabilityStatus(MixerParticipant& participant, | |
| 161 bool mixable) | |
| 162 { | |
| 163 return _mixerModule.SetAnonymousMixabilityStatus(&participant, mixable); | |
| 164 } | |
| 165 | |
| 166 int32_t | |
| 167 OutputMixer::MixActiveChannels() | 112 OutputMixer::MixActiveChannels() |
| 168 { | 113 { |
| 169 _mixerModule.Process(); | 114 _mixerModule.Process(); |
| 170 return 0; | 115 return 0; |
| 171 } | 116 } |
| 172 | 117 |
| 173 int OutputMixer::StartRecordingPlayout(const char* fileName, | |
| 174 const CodecInst* codecInst) | |
| 175 { | |
| 176 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1), | |
| 177 "OutputMixer::StartRecordingPlayout(fileName=%s)", fileName); | |
| 178 | |
| 179 if (_outputFileRecording) | |
| 180 { | |
| 181 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1), | |
| 182 "StartRecordingPlayout() is already recording"); | |
| 183 return 0; | |
| 184 } | |
| 185 | |
| 186 FileFormats format; | |
| 187 const uint32_t notificationTime(0); | |
| 188 CodecInst dummyCodec={100,"L16",16000,320,1,320000}; | |
| 189 | |
| 190 if ((codecInst != NULL) && | |
| 191 ((codecInst->channels < 1) || (codecInst->channels > 2))) | |
| 192 { | |
| 193 _engineStatisticsPtr->SetLastError( | |
| 194 VE_BAD_ARGUMENT, kTraceError, | |
| 195 "StartRecordingPlayout() invalid compression"); | |
| 196 return(-1); | |
| 197 } | |
| 198 if(codecInst == NULL) | |
| 199 { | |
| 200 format = kFileFormatPcm16kHzFile; | |
| 201 codecInst=&dummyCodec; | |
| 202 } | |
| 203 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) || | |
| 204 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) || | |
| 205 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0)) | |
| 206 { | |
| 207 format = kFileFormatWavFile; | |
| 208 } | |
| 209 else | |
| 210 { | |
| 211 format = kFileFormatCompressedFile; | |
| 212 } | |
| 213 | |
| 214 rtc::CritScope cs(&_fileCritSect); | |
| 215 | |
| 216 // Destroy the old instance | |
| 217 if (output_file_recorder_) { | |
| 218 output_file_recorder_->RegisterModuleFileCallback(NULL); | |
| 219 output_file_recorder_.reset(); | |
| 220 } | |
| 221 | |
| 222 output_file_recorder_ = FileRecorder::CreateFileRecorder( | |
| 223 _instanceId, (const FileFormats)format); | |
| 224 if (!output_file_recorder_) { | |
| 225 _engineStatisticsPtr->SetLastError( | |
| 226 VE_INVALID_ARGUMENT, kTraceError, | |
| 227 "StartRecordingPlayout() fileRecorder format isnot correct"); | |
| 228 return -1; | |
| 229 } | |
| 230 | |
| 231 if (output_file_recorder_->StartRecordingAudioFile( | |
| 232 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) { | |
| 233 _engineStatisticsPtr->SetLastError( | |
| 234 VE_BAD_FILE, kTraceError, | |
| 235 "StartRecordingAudioFile() failed to start file recording"); | |
| 236 output_file_recorder_->StopRecording(); | |
| 237 output_file_recorder_.reset(); | |
| 238 return -1; | |
| 239 } | |
| 240 output_file_recorder_->RegisterModuleFileCallback(this); | |
| 241 _outputFileRecording = true; | |
| 242 | |
| 243 return 0; | |
| 244 } | |
| 245 | |
| 246 int OutputMixer::StartRecordingPlayout(OutStream* stream, | |
| 247 const CodecInst* codecInst) | |
| 248 { | |
| 249 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1), | |
| 250 "OutputMixer::StartRecordingPlayout()"); | |
| 251 | |
| 252 if (_outputFileRecording) | |
| 253 { | |
| 254 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1), | |
| 255 "StartRecordingPlayout() is already recording"); | |
| 256 return 0; | |
| 257 } | |
| 258 | |
| 259 FileFormats format; | |
| 260 const uint32_t notificationTime(0); | |
| 261 CodecInst dummyCodec={100,"L16",16000,320,1,320000}; | |
| 262 | |
| 263 if (codecInst != NULL && codecInst->channels != 1) | |
| 264 { | |
| 265 _engineStatisticsPtr->SetLastError( | |
| 266 VE_BAD_ARGUMENT, kTraceError, | |
| 267 "StartRecordingPlayout() invalid compression"); | |
| 268 return(-1); | |
| 269 } | |
| 270 if(codecInst == NULL) | |
| 271 { | |
| 272 format = kFileFormatPcm16kHzFile; | |
| 273 codecInst=&dummyCodec; | |
| 274 } | |
| 275 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) || | |
| 276 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) || | |
| 277 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0)) | |
| 278 { | |
| 279 format = kFileFormatWavFile; | |
| 280 } | |
| 281 else | |
| 282 { | |
| 283 format = kFileFormatCompressedFile; | |
| 284 } | |
| 285 | |
| 286 rtc::CritScope cs(&_fileCritSect); | |
| 287 | |
| 288 // Destroy the old instance | |
| 289 if (output_file_recorder_) { | |
| 290 output_file_recorder_->RegisterModuleFileCallback(NULL); | |
| 291 output_file_recorder_.reset(); | |
| 292 } | |
| 293 | |
| 294 output_file_recorder_ = FileRecorder::CreateFileRecorder( | |
| 295 _instanceId, (const FileFormats)format); | |
| 296 if (!output_file_recorder_) { | |
| 297 _engineStatisticsPtr->SetLastError( | |
| 298 VE_INVALID_ARGUMENT, kTraceError, | |
| 299 "StartRecordingPlayout() fileRecorder format isnot correct"); | |
| 300 return -1; | |
| 301 } | |
| 302 | |
| 303 if (output_file_recorder_->StartRecordingAudioFile(stream, *codecInst, | |
| 304 notificationTime) != 0) { | |
| 305 _engineStatisticsPtr->SetLastError( | |
| 306 VE_BAD_FILE, kTraceError, | |
| 307 "StartRecordingAudioFile() failed to start file recording"); | |
| 308 output_file_recorder_->StopRecording(); | |
| 309 output_file_recorder_.reset(); | |
| 310 return -1; | |
| 311 } | |
| 312 | |
| 313 output_file_recorder_->RegisterModuleFileCallback(this); | |
| 314 _outputFileRecording = true; | |
| 315 | |
| 316 return 0; | |
| 317 } | |
| 318 | |
| 319 int OutputMixer::StopRecordingPlayout() | |
| 320 { | |
| 321 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1), | |
| 322 "OutputMixer::StopRecordingPlayout()"); | |
| 323 | |
| 324 if (!_outputFileRecording) | |
| 325 { | |
| 326 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1), | |
| 327 "StopRecordingPlayout() file isnot recording"); | |
| 328 return -1; | |
| 329 } | |
| 330 | |
| 331 rtc::CritScope cs(&_fileCritSect); | |
| 332 | |
| 333 if (output_file_recorder_->StopRecording() != 0) { | |
| 334 _engineStatisticsPtr->SetLastError( | |
| 335 VE_STOP_RECORDING_FAILED, kTraceError, | |
| 336 "StopRecording(), could not stop recording"); | |
| 337 return -1; | |
| 338 } | |
| 339 output_file_recorder_->RegisterModuleFileCallback(NULL); | |
| 340 output_file_recorder_.reset(); | |
| 341 _outputFileRecording = false; | |
| 342 | |
| 343 return 0; | |
| 344 } | |
| 345 | |
| 346 int OutputMixer::GetMixedAudio(int sample_rate_hz, | 118 int OutputMixer::GetMixedAudio(int sample_rate_hz, |
| 347 size_t num_channels, | 119 size_t num_channels, |
| 348 AudioFrame* frame) { | 120 AudioFrame* frame) { |
| 349 WEBRTC_TRACE( | 121 WEBRTC_TRACE( |
| 350 kTraceStream, kTraceVoice, VoEId(_instanceId,-1), | 122 kTraceStream, kTraceVoice, VoEId(_instanceId,-1), |
| 351 "OutputMixer::GetMixedAudio(sample_rate_hz=%d, num_channels=%" PRIuS ")", | 123 "OutputMixer::GetMixedAudio(sample_rate_hz=%d, num_channels=%" PRIuS ")", |
| 352 sample_rate_hz, num_channels); | 124 sample_rate_hz, num_channels); |
| 353 | 125 |
| 354 // --- Record playout if enabled | |
| 355 { | |
| 356 rtc::CritScope cs(&_fileCritSect); | |
| 357 if (_outputFileRecording && output_file_recorder_) | |
| 358 output_file_recorder_->RecordAudioToFile(_audioFrame); | |
| 359 } | |
| 360 | |
| 361 frame->num_channels_ = num_channels; | 126 frame->num_channels_ = num_channels; |
| 362 frame->sample_rate_hz_ = sample_rate_hz; | 127 frame->sample_rate_hz_ = sample_rate_hz; |
| 363 // TODO(andrew): Ideally the downmixing would occur much earlier, in | 128 // TODO(andrew): Ideally the downmixing would occur much earlier, in |
| 364 // AudioCodingModule. | 129 // AudioCodingModule. |
| 365 RemixAndResample(_audioFrame, &resampler_, frame); | 130 RemixAndResample(_audioFrame, &resampler_, frame); |
| 366 return 0; | 131 return 0; |
| 367 } | 132 } |
| 368 | 133 |
| 369 int32_t | 134 int32_t |
| 370 OutputMixer::DoOperationsOnCombinedSignal(bool feed_data_to_apm) | 135 OutputMixer::DoOperationsOnCombinedSignal(bool feed_data_to_apm) |
| (...skipping 12 matching lines...) Expand all Loading... |
| 383 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), | 148 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1), |
| 384 "AudioProcessingModule::ProcessReverseStream() => error"); | 149 "AudioProcessingModule::ProcessReverseStream() => error"); |
| 385 RTC_NOTREACHED(); | 150 RTC_NOTREACHED(); |
| 386 } | 151 } |
| 387 } | 152 } |
| 388 | 153 |
| 389 return 0; | 154 return 0; |
| 390 } | 155 } |
| 391 } // namespace voe | 156 } // namespace voe |
| 392 } // namespace webrtc | 157 } // namespace webrtc |
| OLD | NEW |