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/media_file.h"
14 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
15 #include "webrtc/system_wrappers/include/file_wrapper.h"
16 #include "webrtc/system_wrappers/include/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 #ifndef WEBRTC_VOICE_ENGINE_FILE_API
27 return NULL;
28 #else
29 if (NULL == voiceEngine) {
30 return NULL;
31 }
32 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
33 s->AddRef();
34 return s;
35 #endif
36 }
37
38 #ifdef WEBRTC_VOICE_ENGINE_FILE_API
39
VoEFileImpl(voe::SharedData * shared)40 VoEFileImpl::VoEFileImpl(voe::SharedData* shared) : _shared(shared) {
41 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
42 "VoEFileImpl::VoEFileImpl() - ctor");
43 }
44
~VoEFileImpl()45 VoEFileImpl::~VoEFileImpl() {
46 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
47 "VoEFileImpl::~VoEFileImpl() - dtor");
48 }
49
StartPlayingFileLocally(int channel,const char fileNameUTF8[1024],bool loop,FileFormats format,float volumeScaling,int startPointMs,int stopPointMs)50 int VoEFileImpl::StartPlayingFileLocally(int channel,
51 const char fileNameUTF8[1024],
52 bool loop,
53 FileFormats format,
54 float volumeScaling,
55 int startPointMs,
56 int stopPointMs) {
57 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
58 "StartPlayingFileLocally(channel=%d, fileNameUTF8[]=%s, "
59 "loop=%d, format=%d, volumeScaling=%5.3f, startPointMs=%d,"
60 " stopPointMs=%d)",
61 channel, fileNameUTF8, loop, format, volumeScaling, startPointMs,
62 stopPointMs);
63 static_assert(1024 == FileWrapper::kMaxFileNameSize, "");
64 if (!_shared->statistics().Initialized()) {
65 _shared->SetLastError(VE_NOT_INITED, kTraceError);
66 return -1;
67 }
68 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
69 voe::Channel* channelPtr = ch.channel();
70 if (channelPtr == NULL) {
71 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
72 "StartPlayingFileLocally() failed to locate channel");
73 return -1;
74 }
75
76 return channelPtr->StartPlayingFileLocally(fileNameUTF8, loop, format,
77 startPointMs, volumeScaling,
78 stopPointMs, NULL);
79 }
80
StartPlayingFileLocally(int channel,InStream * stream,FileFormats format,float volumeScaling,int startPointMs,int stopPointMs)81 int VoEFileImpl::StartPlayingFileLocally(int channel,
82 InStream* stream,
83 FileFormats format,
84 float volumeScaling,
85 int startPointMs,
86 int stopPointMs) {
87 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
88 "StartPlayingFileLocally(channel=%d, stream, format=%d, "
89 "volumeScaling=%5.3f, startPointMs=%d, stopPointMs=%d)",
90 channel, format, volumeScaling, startPointMs, stopPointMs);
91
92 if (!_shared->statistics().Initialized()) {
93 _shared->SetLastError(VE_NOT_INITED, kTraceError);
94 return -1;
95 }
96
97 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
98 voe::Channel* channelPtr = ch.channel();
99 if (channelPtr == NULL) {
100 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
101 "StartPlayingFileLocally() failed to locate channel");
102 return -1;
103 }
104
105 return channelPtr->StartPlayingFileLocally(stream, format, startPointMs,
106 volumeScaling, stopPointMs, NULL);
107 }
108
StopPlayingFileLocally(int channel)109 int VoEFileImpl::StopPlayingFileLocally(int channel) {
110 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
111 "StopPlayingFileLocally()");
112 if (!_shared->statistics().Initialized()) {
113 _shared->SetLastError(VE_NOT_INITED, kTraceError);
114 return -1;
115 }
116 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
117 voe::Channel* channelPtr = ch.channel();
118 if (channelPtr == NULL) {
119 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
120 "StopPlayingFileLocally() failed to locate channel");
121 return -1;
122 }
123 return channelPtr->StopPlayingFileLocally();
124 }
125
IsPlayingFileLocally(int channel)126 int VoEFileImpl::IsPlayingFileLocally(int channel) {
127 if (!_shared->statistics().Initialized()) {
128 _shared->SetLastError(VE_NOT_INITED, kTraceError);
129 return -1;
130 }
131 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
132 voe::Channel* channelPtr = ch.channel();
133 if (channelPtr == NULL) {
134 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
135 "StopPlayingFileLocally() failed to locate channel");
136 return -1;
137 }
138 return channelPtr->IsPlayingFileLocally();
139 }
140
StartPlayingFileAsMicrophone(int channel,const char fileNameUTF8[1024],bool loop,bool mixWithMicrophone,FileFormats format,float volumeScaling)141 int VoEFileImpl::StartPlayingFileAsMicrophone(int channel,
142 const char fileNameUTF8[1024],
143 bool loop,
144 bool mixWithMicrophone,
145 FileFormats format,
146 float volumeScaling) {
147 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
148 "StartPlayingFileAsMicrophone(channel=%d, fileNameUTF8=%s, "
149 "loop=%d, mixWithMicrophone=%d, format=%d, "
150 "volumeScaling=%5.3f)",
151 channel, fileNameUTF8, loop, mixWithMicrophone, format,
152 volumeScaling);
153 static_assert(1024 == FileWrapper::kMaxFileNameSize, "");
154 if (!_shared->statistics().Initialized()) {
155 _shared->SetLastError(VE_NOT_INITED, kTraceError);
156 return -1;
157 }
158
159 const uint32_t startPointMs(0);
160 const uint32_t stopPointMs(0);
161
162 if (channel == -1) {
163 int res = _shared->transmit_mixer()->StartPlayingFileAsMicrophone(
164 fileNameUTF8, loop, format, startPointMs, volumeScaling, stopPointMs,
165 NULL);
166 if (res) {
167 WEBRTC_TRACE(
168 kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
169 "StartPlayingFileAsMicrophone() failed to start playing file");
170 return (-1);
171 } else {
172 _shared->transmit_mixer()->SetMixWithMicStatus(mixWithMicrophone);
173 return (0);
174 }
175 } else {
176 // Add file after demultiplexing <=> affects one channel only
177 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
178 voe::Channel* channelPtr = ch.channel();
179 if (channelPtr == NULL) {
180 _shared->SetLastError(
181 VE_CHANNEL_NOT_VALID, kTraceError,
182 "StartPlayingFileAsMicrophone() failed to locate channel");
183 return -1;
184 }
185
186 int res = channelPtr->StartPlayingFileAsMicrophone(
187 fileNameUTF8, loop, format, startPointMs, volumeScaling, stopPointMs,
188 NULL);
189 if (res) {
190 WEBRTC_TRACE(
191 kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
192 "StartPlayingFileAsMicrophone() failed to start playing file");
193 return -1;
194 } else {
195 channelPtr->SetMixWithMicStatus(mixWithMicrophone);
196 return 0;
197 }
198 }
199 }
200
StartPlayingFileAsMicrophone(int channel,InStream * stream,bool mixWithMicrophone,FileFormats format,float volumeScaling)201 int VoEFileImpl::StartPlayingFileAsMicrophone(int channel,
202 InStream* stream,
203 bool mixWithMicrophone,
204 FileFormats format,
205 float volumeScaling) {
206 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
207 "StartPlayingFileAsMicrophone(channel=%d, stream,"
208 " mixWithMicrophone=%d, format=%d, volumeScaling=%5.3f)",
209 channel, mixWithMicrophone, format, volumeScaling);
210
211 if (!_shared->statistics().Initialized()) {
212 _shared->SetLastError(VE_NOT_INITED, kTraceError);
213 return -1;
214 }
215
216 const uint32_t startPointMs(0);
217 const uint32_t stopPointMs(0);
218
219 if (channel == -1) {
220 int res = _shared->transmit_mixer()->StartPlayingFileAsMicrophone(
221 stream, format, startPointMs, volumeScaling, stopPointMs, NULL);
222 if (res) {
223 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
224 "StartPlayingFileAsMicrophone() failed to start "
225 "playing stream");
226 return (-1);
227 } else {
228 _shared->transmit_mixer()->SetMixWithMicStatus(mixWithMicrophone);
229 return (0);
230 }
231 } else {
232 // Add file after demultiplexing <=> affects one channel only
233 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
234 voe::Channel* channelPtr = ch.channel();
235 if (channelPtr == NULL) {
236 _shared->SetLastError(
237 VE_CHANNEL_NOT_VALID, kTraceError,
238 "StartPlayingFileAsMicrophone() failed to locate channel");
239 return -1;
240 }
241
242 int res = channelPtr->StartPlayingFileAsMicrophone(
243 stream, format, startPointMs, volumeScaling, stopPointMs, NULL);
244 if (res) {
245 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
246 "StartPlayingFileAsMicrophone() failed to start "
247 "playing stream");
248 return -1;
249 } else {
250 channelPtr->SetMixWithMicStatus(mixWithMicrophone);
251 return 0;
252 }
253 }
254 }
255
StopPlayingFileAsMicrophone(int channel)256 int VoEFileImpl::StopPlayingFileAsMicrophone(int channel) {
257 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
258 "StopPlayingFileAsMicrophone(channel=%d)", channel);
259 if (!_shared->statistics().Initialized()) {
260 _shared->SetLastError(VE_NOT_INITED, kTraceError);
261 return -1;
262 }
263 if (channel == -1) {
264 // Stop adding file before demultiplexing <=> affects all channels
265 return _shared->transmit_mixer()->StopPlayingFileAsMicrophone();
266 } else {
267 // Stop adding file after demultiplexing <=> affects one channel only
268 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
269 voe::Channel* channelPtr = ch.channel();
270 if (channelPtr == NULL) {
271 _shared->SetLastError(
272 VE_CHANNEL_NOT_VALID, kTraceError,
273 "StopPlayingFileAsMicrophone() failed to locate channel");
274 return -1;
275 }
276 return channelPtr->StopPlayingFileAsMicrophone();
277 }
278 }
279
IsPlayingFileAsMicrophone(int channel)280 int VoEFileImpl::IsPlayingFileAsMicrophone(int channel) {
281 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
282 "IsPlayingFileAsMicrophone(channel=%d)", channel);
283 if (!_shared->statistics().Initialized()) {
284 _shared->SetLastError(VE_NOT_INITED, kTraceError);
285 return -1;
286 }
287 if (channel == -1) {
288 return _shared->transmit_mixer()->IsPlayingFileAsMicrophone();
289 } else {
290 // Stop adding file after demultiplexing <=> affects one channel only
291 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
292 voe::Channel* channelPtr = ch.channel();
293 if (channelPtr == NULL) {
294 _shared->SetLastError(
295 VE_CHANNEL_NOT_VALID, kTraceError,
296 "IsPlayingFileAsMicrophone() failed to locate channel");
297 return -1;
298 }
299 return channelPtr->IsPlayingFileAsMicrophone();
300 }
301 }
302
StartRecordingPlayout(int channel,const char * fileNameUTF8,CodecInst * compression,int maxSizeBytes)303 int VoEFileImpl::StartRecordingPlayout(int channel,
304 const char* fileNameUTF8,
305 CodecInst* compression,
306 int maxSizeBytes) {
307 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
308 "StartRecordingPlayout(channel=%d, fileNameUTF8=%s, "
309 "compression, maxSizeBytes=%d)",
310 channel, fileNameUTF8, maxSizeBytes);
311 static_assert(1024 == FileWrapper::kMaxFileNameSize, "");
312
313 if (!_shared->statistics().Initialized()) {
314 _shared->SetLastError(VE_NOT_INITED, kTraceError);
315 return -1;
316 }
317 if (channel == -1) {
318 return _shared->output_mixer()->StartRecordingPlayout(fileNameUTF8,
319 compression);
320 } else {
321 // Add file after demultiplexing <=> affects one channel only
322 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
323 voe::Channel* channelPtr = ch.channel();
324 if (channelPtr == NULL) {
325 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
326 "StartRecordingPlayout() failed to locate channel");
327 return -1;
328 }
329 return channelPtr->StartRecordingPlayout(fileNameUTF8, compression);
330 }
331 }
332
StartRecordingPlayout(int channel,OutStream * stream,CodecInst * compression)333 int VoEFileImpl::StartRecordingPlayout(int channel,
334 OutStream* stream,
335 CodecInst* compression) {
336 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
337 "StartRecordingPlayout(channel=%d, stream, compression)",
338 channel);
339 if (!_shared->statistics().Initialized()) {
340 _shared->SetLastError(VE_NOT_INITED, kTraceError);
341 return -1;
342 }
343 if (channel == -1) {
344 return _shared->output_mixer()->StartRecordingPlayout(stream, compression);
345 } else {
346 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
347 voe::Channel* channelPtr = ch.channel();
348 if (channelPtr == NULL) {
349 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
350 "StartRecordingPlayout() failed to locate channel");
351 return -1;
352 }
353 return channelPtr->StartRecordingPlayout(stream, compression);
354 }
355 }
356
StopRecordingPlayout(int channel)357 int VoEFileImpl::StopRecordingPlayout(int channel) {
358 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
359 "StopRecordingPlayout(channel=%d)", channel);
360 if (!_shared->statistics().Initialized()) {
361 _shared->SetLastError(VE_NOT_INITED, kTraceError);
362 return -1;
363 }
364 if (channel == -1) {
365 return _shared->output_mixer()->StopRecordingPlayout();
366 } else {
367 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
368 voe::Channel* channelPtr = ch.channel();
369 if (channelPtr == NULL) {
370 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
371 "StopRecordingPlayout() failed to locate channel");
372 return -1;
373 }
374 return channelPtr->StopRecordingPlayout();
375 }
376 }
377
StartRecordingMicrophone(const char * fileNameUTF8,CodecInst * compression,int maxSizeBytes)378 int VoEFileImpl::StartRecordingMicrophone(const char* fileNameUTF8,
379 CodecInst* compression,
380 int maxSizeBytes) {
381 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
382 "StartRecordingMicrophone(fileNameUTF8=%s, compression, "
383 "maxSizeBytes=%d)",
384 fileNameUTF8, maxSizeBytes);
385 static_assert(1024 == FileWrapper::kMaxFileNameSize, "");
386
387 if (!_shared->statistics().Initialized()) {
388 _shared->SetLastError(VE_NOT_INITED, kTraceError);
389 return -1;
390 }
391 if (_shared->transmit_mixer()->StartRecordingMicrophone(fileNameUTF8,
392 compression)) {
393 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
394 "StartRecordingMicrophone() failed to start recording");
395 return -1;
396 }
397 if (!_shared->audio_device()->Recording()) {
398 if (_shared->audio_device()->InitRecording() != 0) {
399 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
400 "StartRecordingMicrophone() failed to initialize recording");
401 return -1;
402 }
403 if (_shared->audio_device()->StartRecording() != 0) {
404 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
405 "StartRecordingMicrophone() failed to start recording");
406 return -1;
407 }
408 }
409 return 0;
410 }
411
StartRecordingMicrophone(OutStream * stream,CodecInst * compression)412 int VoEFileImpl::StartRecordingMicrophone(OutStream* stream,
413 CodecInst* compression) {
414 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
415 "StartRecordingMicrophone(stream, compression)");
416
417 if (!_shared->statistics().Initialized()) {
418 _shared->SetLastError(VE_NOT_INITED, kTraceError);
419 return -1;
420 }
421 if (_shared->transmit_mixer()->StartRecordingMicrophone(stream,
422 compression) == -1) {
423 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
424 "StartRecordingMicrophone() failed to start recording");
425 return -1;
426 }
427 if (!_shared->audio_device()->Recording()) {
428 if (_shared->audio_device()->InitRecording() != 0) {
429 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
430 "StartRecordingMicrophone() failed to initialize recording");
431 return -1;
432 }
433 if (_shared->audio_device()->StartRecording() != 0) {
434 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
435 "StartRecordingMicrophone() failed to start recording");
436 return -1;
437 }
438 }
439 return 0;
440 }
441
StopRecordingMicrophone()442 int VoEFileImpl::StopRecordingMicrophone() {
443 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
444 "StopRecordingMicrophone()");
445 if (!_shared->statistics().Initialized()) {
446 _shared->SetLastError(VE_NOT_INITED, kTraceError);
447 return -1;
448 }
449
450 int err = 0;
451
452 // TODO(xians): consider removing Start/StopRecording() in
453 // Start/StopRecordingMicrophone() if no channel is recording.
454 if (_shared->NumOfSendingChannels() == 0 &&
455 _shared->audio_device()->Recording()) {
456 // Stop audio-device recording if no channel is recording
457 if (_shared->audio_device()->StopRecording() != 0) {
458 _shared->SetLastError(
459 VE_CANNOT_STOP_RECORDING, kTraceError,
460 "StopRecordingMicrophone() failed to stop recording");
461 err = -1;
462 }
463 }
464
465 if (_shared->transmit_mixer()->StopRecordingMicrophone() != 0) {
466 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_shared->instance_id(), -1),
467 "StopRecordingMicrophone() failed to stop recording to mixer");
468 err = -1;
469 }
470
471 return err;
472 }
473
474 #endif // #ifdef WEBRTC_VOICE_ENGINE_FILE_API
475
476 } // namespace webrtc
477