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 |