1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/voice_engine/voe_file_impl.h"
12
13 #include "webrtc/modules/media_file/interface/media_file.h"
14 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
15 #include "webrtc/system_wrappers/interface/file_wrapper.h"
16 #include "webrtc/system_wrappers/interface/trace.h"
17 #include "webrtc/voice_engine/channel.h"
18 #include "webrtc/voice_engine/include/voe_errors.h"
19 #include "webrtc/voice_engine/output_mixer.h"
20 #include "webrtc/voice_engine/transmit_mixer.h"
21 #include "webrtc/voice_engine/voice_engine_impl.h"
22
23 namespace webrtc {
24
GetInterface(VoiceEngine * voiceEngine)25 VoEFile* VoEFile::GetInterface(VoiceEngine* voiceEngine)
26 {
27 #ifndef WEBRTC_VOICE_ENGINE_FILE_API
28 return NULL;
29 #else
30 if (NULL == voiceEngine)
31 {
32 return NULL;
33 }
34 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
35 s->AddRef();
36 return s;
37 #endif
38 }
39
40 #ifdef WEBRTC_VOICE_ENGINE_FILE_API
41
VoEFileImpl(voe::SharedData * shared)42 VoEFileImpl::VoEFileImpl(voe::SharedData* shared) : _shared(shared)
43 {
44 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
45 "VoEFileImpl::VoEFileImpl() - ctor");
46 }
47
~VoEFileImpl()48 VoEFileImpl::~VoEFileImpl()
49 {
50 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
51 "VoEFileImpl::~VoEFileImpl() - dtor");
52 }
53
StartPlayingFileLocally(int channel,const char fileNameUTF8[1024],bool loop,FileFormats format,float volumeScaling,int startPointMs,int stopPointMs)54 int VoEFileImpl::StartPlayingFileLocally(
55 int channel,
56 const char fileNameUTF8[1024],
57 bool loop, FileFormats format,
58 float volumeScaling,
59 int startPointMs,
60 int stopPointMs)
61 {
62 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
63 "StartPlayingFileLocally(channel=%d, fileNameUTF8[]=%s, "
64 "loop=%d, format=%d, volumeScaling=%5.3f, startPointMs=%d,"
65 " stopPointMs=%d)",
66 channel, fileNameUTF8, loop, format, volumeScaling,
67 startPointMs, stopPointMs);
68 assert(1024 == FileWrapper::kMaxFileNameSize);
69 if (!_shared->statistics().Initialized())
70 {
71 _shared->SetLastError(VE_NOT_INITED, kTraceError);
72 return -1;
73 }
74 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
75 voe::Channel* channelPtr = ch.channel();
76 if (channelPtr == NULL)
77 {
78 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
79 "StartPlayingFileLocally() failed to locate channel");
80 return -1;
81 }
82
83 return channelPtr->StartPlayingFileLocally(fileNameUTF8,
84 loop,
85 format,
86 startPointMs,
87 volumeScaling,
88 stopPointMs,
89 NULL);
90 }
91
StartPlayingFileLocally(int channel,InStream * stream,FileFormats format,float volumeScaling,int startPointMs,int stopPointMs)92 int VoEFileImpl::StartPlayingFileLocally(int channel,
93 InStream* stream,
94 FileFormats format,
95 float volumeScaling,
96 int startPointMs,
97 int stopPointMs)
98 {
99 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
100 "StartPlayingFileLocally(channel=%d, stream, format=%d, "
101 "volumeScaling=%5.3f, startPointMs=%d, stopPointMs=%d)",
102 channel, format, volumeScaling, startPointMs, stopPointMs);
103
104 if (!_shared->statistics().Initialized())
105 {
106 _shared->SetLastError(VE_NOT_INITED, kTraceError);
107 return -1;
108 }
109
110 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
111 voe::Channel* channelPtr = ch.channel();
112 if (channelPtr == NULL)
113 {
114 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
115 "StartPlayingFileLocally() failed to locate channel");
116 return -1;
117 }
118
119 return channelPtr->StartPlayingFileLocally(stream,
120 format,
121 startPointMs,
122 volumeScaling,
123 stopPointMs,
124 NULL);
125 }
126
StopPlayingFileLocally(int channel)127 int VoEFileImpl::StopPlayingFileLocally(int channel)
128 {
129 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
130 "StopPlayingFileLocally()");
131 if (!_shared->statistics().Initialized())
132 {
133 _shared->SetLastError(VE_NOT_INITED, kTraceError);
134 return -1;
135 }
136 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
137 voe::Channel* channelPtr = ch.channel();
138 if (channelPtr == NULL)
139 {
140 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
141 "StopPlayingFileLocally() failed to locate channel");
142 return -1;
143 }
144 return channelPtr->StopPlayingFileLocally();
145 }
146
IsPlayingFileLocally(int channel)147 int VoEFileImpl::IsPlayingFileLocally(int channel)
148 {
149 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
150 "IsPlayingFileLocally(channel=%d)", channel);
151 if (!_shared->statistics().Initialized())
152 {
153 _shared->SetLastError(VE_NOT_INITED, kTraceError);
154 return -1;
155 }
156 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
157 voe::Channel* channelPtr = ch.channel();
158 if (channelPtr == NULL)
159 {
160 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
161 "StopPlayingFileLocally() failed to locate channel");
162 return -1;
163 }
164 return channelPtr->IsPlayingFileLocally();
165 }
166
StartPlayingFileAsMicrophone(int channel,const char fileNameUTF8[1024],bool loop,bool mixWithMicrophone,FileFormats format,float volumeScaling)167 int VoEFileImpl::StartPlayingFileAsMicrophone(int channel,
168 const char fileNameUTF8[1024],
169 bool loop,
170 bool mixWithMicrophone,
171 FileFormats format,
172 float volumeScaling)
173 {
174 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
175 "StartPlayingFileAsMicrophone(channel=%d, fileNameUTF8=%s, "
176 "loop=%d, mixWithMicrophone=%d, format=%d, "
177 "volumeScaling=%5.3f)",
178 channel, fileNameUTF8, loop, mixWithMicrophone, format,
179 volumeScaling);
180 assert(1024 == FileWrapper::kMaxFileNameSize);
181 if (!_shared->statistics().Initialized())
182 {
183 _shared->SetLastError(VE_NOT_INITED, kTraceError);
184 return -1;
185 }
186
187 const uint32_t startPointMs(0);
188 const uint32_t stopPointMs(0);
189
190 if (channel == -1)
191 {
192 int res = _shared->transmit_mixer()->StartPlayingFileAsMicrophone(
193 fileNameUTF8,
194 loop,
195 format,
196 startPointMs,
197 volumeScaling,
198 stopPointMs,
199 NULL);
200 if (res)
201 {
202 WEBRTC_TRACE(kTraceError, kTraceVoice,
203 VoEId(_shared->instance_id(), -1),
204 "StartPlayingFileAsMicrophone() failed to start playing file");
205 return(-1);
206 }
207 else
208 {
209 _shared->transmit_mixer()->SetMixWithMicStatus(mixWithMicrophone);
210 return(0);
211 }
212 }
213 else
214 {
215 // Add file after demultiplexing <=> affects one channel only
216 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
217 voe::Channel* channelPtr = ch.channel();
218 if (channelPtr == NULL)
219 {
220 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
221 "StartPlayingFileAsMicrophone() failed to locate channel");
222 return -1;
223 }
224
225 int res = channelPtr->StartPlayingFileAsMicrophone(fileNameUTF8,
226 loop,
227 format,
228 startPointMs,
229 volumeScaling,
230 stopPointMs,
231 NULL);
232 if (res)
233 {
234 WEBRTC_TRACE(kTraceError, kTraceVoice,
235 VoEId(_shared->instance_id(), -1),
236 "StartPlayingFileAsMicrophone() failed to start playing file");
237 return -1;
238 }
239 else
240 {
241 channelPtr->SetMixWithMicStatus(mixWithMicrophone);
242 return 0;
243 }
244 }
245 }
246
StartPlayingFileAsMicrophone(int channel,InStream * stream,bool mixWithMicrophone,FileFormats format,float volumeScaling)247 int VoEFileImpl::StartPlayingFileAsMicrophone(int channel,
248 InStream* stream,
249 bool mixWithMicrophone,
250 FileFormats format,
251 float volumeScaling)
252 {
253 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
254 "StartPlayingFileAsMicrophone(channel=%d, stream,"
255 " mixWithMicrophone=%d, format=%d, volumeScaling=%5.3f)",
256 channel, mixWithMicrophone, format, volumeScaling);
257
258 if (!_shared->statistics().Initialized())
259 {
260 _shared->SetLastError(VE_NOT_INITED, kTraceError);
261 return -1;
262 }
263
264 const uint32_t startPointMs(0);
265 const uint32_t stopPointMs(0);
266
267 if (channel == -1)
268 {
269 int res = _shared->transmit_mixer()->StartPlayingFileAsMicrophone(
270 stream,
271 format,
272 startPointMs,
273 volumeScaling,
274 stopPointMs,
275 NULL);
276 if (res)
277 {
278 WEBRTC_TRACE(kTraceError, kTraceVoice,
279 VoEId(_shared->instance_id(), -1),
280 "StartPlayingFileAsMicrophone() failed to start "
281 "playing stream");
282 return(-1);
283 }
284 else
285 {
286 _shared->transmit_mixer()->SetMixWithMicStatus(mixWithMicrophone);
287 return(0);
288 }
289 }
290 else
291 {
292 // Add file after demultiplexing <=> affects one channel only
293 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
294 voe::Channel* channelPtr = ch.channel();
295 if (channelPtr == NULL)
296 {
297 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
298 "StartPlayingFileAsMicrophone() failed to locate channel");
299 return -1;
300 }
301
302 int res = channelPtr->StartPlayingFileAsMicrophone(
303 stream, format, startPointMs, volumeScaling, stopPointMs, NULL);
304 if (res)
305 {
306 WEBRTC_TRACE(kTraceError, kTraceVoice,
307 VoEId(_shared->instance_id(), -1),
308 "StartPlayingFileAsMicrophone() failed to start "
309 "playing stream");
310 return -1;
311 }
312 else
313 {
314 channelPtr->SetMixWithMicStatus(mixWithMicrophone);
315 return 0;
316 }
317 }
318 }
319
StopPlayingFileAsMicrophone(int channel)320 int VoEFileImpl::StopPlayingFileAsMicrophone(int channel)
321 {
322 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
323 "StopPlayingFileAsMicrophone(channel=%d)", channel);
324 if (!_shared->statistics().Initialized())
325 {
326 _shared->SetLastError(VE_NOT_INITED, kTraceError);
327 return -1;
328 }
329 if (channel == -1)
330 {
331 // Stop adding file before demultiplexing <=> affects all channels
332 return _shared->transmit_mixer()->StopPlayingFileAsMicrophone();
333 }
334 else
335 {
336 // Stop adding file after demultiplexing <=> affects one channel only
337 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
338 voe::Channel* channelPtr = ch.channel();
339 if (channelPtr == NULL)
340 {
341 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
342 "StopPlayingFileAsMicrophone() failed to locate channel");
343 return -1;
344 }
345 return channelPtr->StopPlayingFileAsMicrophone();
346 }
347 }
348
IsPlayingFileAsMicrophone(int channel)349 int VoEFileImpl::IsPlayingFileAsMicrophone(int channel)
350 {
351 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
352 "IsPlayingFileAsMicrophone(channel=%d)", channel);
353 if (!_shared->statistics().Initialized())
354 {
355 _shared->SetLastError(VE_NOT_INITED, kTraceError);
356 return -1;
357 }
358 if (channel == -1)
359 {
360 return _shared->transmit_mixer()->IsPlayingFileAsMicrophone();
361 }
362 else
363 {
364 // Stop adding file after demultiplexing <=> affects one channel only
365 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
366 voe::Channel* channelPtr = ch.channel();
367 if (channelPtr == NULL)
368 {
369 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
370 "IsPlayingFileAsMicrophone() failed to locate channel");
371 return -1;
372 }
373 return channelPtr->IsPlayingFileAsMicrophone();
374 }
375 }
376
StartRecordingPlayout(int channel,const char * fileNameUTF8,CodecInst * compression,int maxSizeBytes)377 int VoEFileImpl::StartRecordingPlayout(
378 int channel, const char* fileNameUTF8, CodecInst* compression,
379 int maxSizeBytes)
380 {
381 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
382 "StartRecordingPlayout(channel=%d, fileNameUTF8=%s, "
383 "compression, maxSizeBytes=%d)",
384 channel, fileNameUTF8, maxSizeBytes);
385 assert(1024 == FileWrapper::kMaxFileNameSize);
386
387 if (!_shared->statistics().Initialized())
388 {
389 _shared->SetLastError(VE_NOT_INITED, kTraceError);
390 return -1;
391 }
392 if (channel == -1)
393 {
394 return _shared->output_mixer()->StartRecordingPlayout
395 (fileNameUTF8, compression);
396 }
397 else
398 {
399 // Add file after demultiplexing <=> affects one channel only
400 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
401 voe::Channel* channelPtr = ch.channel();
402 if (channelPtr == NULL)
403 {
404 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
405 "StartRecordingPlayout() failed to locate channel");
406 return -1;
407 }
408 return channelPtr->StartRecordingPlayout(fileNameUTF8, compression);
409 }
410 }
411
StartRecordingPlayout(int channel,OutStream * stream,CodecInst * compression)412 int VoEFileImpl::StartRecordingPlayout(
413 int channel, OutStream* stream, CodecInst* compression)
414 {
415 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
416 "StartRecordingPlayout(channel=%d, stream, compression)",
417 channel);
418 if (!_shared->statistics().Initialized())
419 {
420 _shared->SetLastError(VE_NOT_INITED, kTraceError);
421 return -1;
422 }
423 if (channel == -1)
424 {
425 return _shared->output_mixer()->
426 StartRecordingPlayout(stream, compression);
427 }
428 else
429 {
430 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
431 voe::Channel* channelPtr = ch.channel();
432 if (channelPtr == NULL)
433 {
434 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
435 "StartRecordingPlayout() failed to locate channel");
436 return -1;
437 }
438 return channelPtr->StartRecordingPlayout(stream, compression);
439 }
440 }
441
StopRecordingPlayout(int channel)442 int VoEFileImpl::StopRecordingPlayout(int channel)
443 {
444 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
445 "StopRecordingPlayout(channel=%d)", channel);
446 if (!_shared->statistics().Initialized())
447 {
448 _shared->SetLastError(VE_NOT_INITED, kTraceError);
449 return -1;
450 }
451 if (channel == -1)
452 {
453 return _shared->output_mixer()->StopRecordingPlayout();
454 }
455 else
456 {
457 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
458 voe::Channel* channelPtr = ch.channel();
459 if (channelPtr == NULL)
460 {
461 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
462 "StopRecordingPlayout() failed to locate channel");
463 return -1;
464 }
465 return channelPtr->StopRecordingPlayout();
466 }
467 }
468
StartRecordingMicrophone(const char * fileNameUTF8,CodecInst * compression,int maxSizeBytes)469 int VoEFileImpl::StartRecordingMicrophone(
470 const char* fileNameUTF8, CodecInst* compression, int maxSizeBytes)
471 {
472 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
473 "StartRecordingMicrophone(fileNameUTF8=%s, compression, "
474 "maxSizeBytes=%d)", fileNameUTF8, maxSizeBytes);
475 assert(1024 == FileWrapper::kMaxFileNameSize);
476
477 if (!_shared->statistics().Initialized())
478 {
479 _shared->SetLastError(VE_NOT_INITED, kTraceError);
480 return -1;
481 }
482 if (_shared->transmit_mixer()->StartRecordingMicrophone(fileNameUTF8,
483 compression))
484 {
485 WEBRTC_TRACE(kTraceError, kTraceVoice,
486 VoEId(_shared->instance_id(), -1),
487 "StartRecordingMicrophone() failed to start recording");
488 return -1;
489 }
490 if (_shared->audio_device()->Recording())
491 {
492 return 0;
493 }
494 if (!_shared->ext_recording())
495 {
496 if (_shared->audio_device()->InitRecording() != 0)
497 {
498 WEBRTC_TRACE(kTraceError, kTraceVoice,
499 VoEId(_shared->instance_id(), -1),
500 "StartRecordingMicrophone() failed to initialize recording");
501 return -1;
502 }
503 if (_shared->audio_device()->StartRecording() != 0)
504 {
505 WEBRTC_TRACE(kTraceError, kTraceVoice,
506 VoEId(_shared->instance_id(), -1),
507 "StartRecordingMicrophone() failed to start recording");
508 return -1;
509 }
510 }
511 return 0;
512 }
513
StartRecordingMicrophone(OutStream * stream,CodecInst * compression)514 int VoEFileImpl::StartRecordingMicrophone(
515 OutStream* stream, CodecInst* compression)
516 {
517 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
518 "StartRecordingMicrophone(stream, compression)");
519
520 if (!_shared->statistics().Initialized())
521 {
522 _shared->SetLastError(VE_NOT_INITED, kTraceError);
523 return -1;
524 }
525 if (_shared->transmit_mixer()->StartRecordingMicrophone(stream,
526 compression) == -1)
527 {
528 WEBRTC_TRACE(kTraceError, kTraceVoice,
529 VoEId(_shared->instance_id(), -1),
530 "StartRecordingMicrophone() failed to start recording");
531 return -1;
532 }
533 if (_shared->audio_device()->Recording())
534 {
535 return 0;
536 }
537 if (!_shared->ext_recording())
538 {
539 if (_shared->audio_device()->InitRecording() != 0)
540 {
541 WEBRTC_TRACE(kTraceError, kTraceVoice,
542 VoEId(_shared->instance_id(), -1),
543 "StartRecordingMicrophone() failed to initialize recording");
544 return -1;
545 }
546 if (_shared->audio_device()->StartRecording() != 0)
547 {
548 WEBRTC_TRACE(kTraceError, kTraceVoice,
549 VoEId(_shared->instance_id(), -1),
550 "StartRecordingMicrophone() failed to start recording");
551 return -1;
552 }
553 }
554 return 0;
555 }
556
StopRecordingMicrophone()557 int VoEFileImpl::StopRecordingMicrophone()
558 {
559 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
560 "StopRecordingMicrophone()");
561 if (!_shared->statistics().Initialized())
562 {
563 _shared->SetLastError(VE_NOT_INITED, kTraceError);
564 return -1;
565 }
566
567 int err = 0;
568
569 // TODO(xians): consider removing Start/StopRecording() in
570 // Start/StopRecordingMicrophone() if no channel is recording.
571 if (_shared->NumOfSendingChannels() == 0 &&
572 _shared->audio_device()->Recording())
573 {
574 // Stop audio-device recording if no channel is recording
575 if (_shared->audio_device()->StopRecording() != 0)
576 {
577 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
578 "StopRecordingMicrophone() failed to stop recording");
579 err = -1;
580 }
581 }
582
583 if (_shared->transmit_mixer()->StopRecordingMicrophone() != 0)
584 {
585 WEBRTC_TRACE(kTraceError, kTraceVoice,
586 VoEId(_shared->instance_id(), -1),
587 "StopRecordingMicrophone() failed to stop recording to mixer");
588 err = -1;
589 }
590
591 return err;
592 }
593
594 #endif // #ifdef WEBRTC_VOICE_ENGINE_FILE_API
595
596 } // namespace webrtc
597