Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "CSFLog.h"
6 : #include "nspr.h"
7 :
8 : #ifdef HAVE_NETINET_IN_H
9 : #include <netinet/in.h>
10 : #elif defined XP_WIN
11 : #include <winsock2.h>
12 : #endif
13 :
14 : #include "AudioConduit.h"
15 : #include "nsCOMPtr.h"
16 : #include "mozilla/Services.h"
17 : #include "nsServiceManagerUtils.h"
18 : #include "nsIPrefService.h"
19 : #include "nsIPrefBranch.h"
20 : #include "nsThreadUtils.h"
21 : #include "Latency.h"
22 : #include "mozilla/Telemetry.h"
23 :
24 : #include "webrtc/modules/audio_processing/include/audio_processing.h"
25 : #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
26 : #include "webrtc/voice_engine/include/voe_errors.h"
27 : #include "webrtc/voice_engine/voice_engine_impl.h"
28 : #include "webrtc/system_wrappers/include/clock.h"
29 :
30 : #ifdef MOZ_WIDGET_ANDROID
31 : #include "AndroidJNIWrapper.h"
32 : #endif
33 :
34 : namespace mozilla {
35 :
36 : static const char* logTag ="WebrtcAudioSessionConduit";
37 :
38 : // 32 bytes is what WebRTC CodecInst expects
39 : const unsigned int WebrtcAudioConduit::CODEC_PLNAME_SIZE = 32;
40 :
41 : /**
42 : * Factory Method for AudioConduit
43 : */
44 0 : RefPtr<AudioSessionConduit> AudioSessionConduit::Create()
45 : {
46 0 : CSFLogDebug(logTag, "%s ", __FUNCTION__);
47 0 : NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
48 :
49 0 : WebrtcAudioConduit* obj = new WebrtcAudioConduit();
50 0 : if(obj->Init() != kMediaConduitNoError)
51 : {
52 0 : CSFLogError(logTag, "%s AudioConduit Init Failed ", __FUNCTION__);
53 0 : delete obj;
54 0 : return nullptr;
55 : }
56 0 : CSFLogDebug(logTag, "%s Successfully created AudioConduit ", __FUNCTION__);
57 0 : return obj;
58 : }
59 :
60 : /**
61 : * Destruction defines for our super-classes
62 : */
63 0 : WebrtcAudioConduit::~WebrtcAudioConduit()
64 : {
65 0 : NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
66 :
67 0 : CSFLogDebug(logTag, "%s ", __FUNCTION__);
68 0 : for(auto & codec : mRecvCodecList)
69 : {
70 0 : delete codec;
71 : }
72 :
73 : // The first one of a pair to be deleted shuts down media for both
74 0 : if(mPtrVoEXmedia)
75 : {
76 0 : mPtrVoEXmedia->SetExternalRecordingStatus(false);
77 0 : mPtrVoEXmedia->SetExternalPlayoutStatus(false);
78 : }
79 :
80 : //Deal with the transport
81 0 : if(mPtrVoENetwork)
82 : {
83 0 : mPtrVoENetwork->DeRegisterExternalTransport(mChannel);
84 : }
85 :
86 0 : if(mPtrVoEBase)
87 : {
88 0 : mPtrVoEBase->StopPlayout(mChannel);
89 0 : mPtrVoEBase->StopSend(mChannel);
90 0 : mPtrVoEBase->StopReceive(mChannel);
91 0 : mChannelProxy = nullptr;
92 0 : mPtrVoEBase->DeleteChannel(mChannel);
93 : // We don't Terminate() the VoEBase here, because the Call (owned by
94 : // PeerConnectionMedia) actually owns the (shared) VoEBase/VoiceEngine
95 : // here
96 : }
97 :
98 : // We shouldn't delete the VoiceEngine until all these are released!
99 : // And we can't use a Scoped ptr, since the order is arbitrary
100 0 : mPtrVoENetwork = nullptr;
101 0 : mPtrVoEBase = nullptr;
102 0 : mPtrVoECodec = nullptr;
103 0 : mPtrVoEXmedia = nullptr;
104 0 : mPtrVoEProcessing = nullptr;
105 0 : mPtrVoEVideoSync = nullptr;
106 0 : mPtrVoERTP_RTCP = nullptr;
107 0 : mPtrRTP = nullptr;
108 :
109 0 : if (mVoiceEngine)
110 : {
111 0 : webrtc::VoiceEngine::Delete(mVoiceEngine);
112 : }
113 0 : }
114 :
115 0 : bool WebrtcAudioConduit::SetLocalSSRCs(const std::vector<unsigned int> & aSSRCs)
116 : {
117 : // This should hold true until the WebRTC.org VoE refactor
118 0 : MOZ_ASSERT(aSSRCs.size() == 1,"WebrtcAudioConduit::SetLocalSSRCs accepts exactly 1 ssrc.");
119 :
120 0 : std::vector<unsigned int> oldSsrcs = GetLocalSSRCs();
121 0 : if (oldSsrcs.empty()) {
122 0 : MOZ_ASSERT(false, "GetLocalSSRC failed");
123 : return false;
124 : }
125 :
126 0 : if (oldSsrcs == aSSRCs) {
127 0 : return true;
128 : }
129 :
130 0 : bool wasTransmitting = mEngineTransmitting;
131 0 : if (StopTransmitting() != kMediaConduitNoError) {
132 0 : return false;
133 : }
134 :
135 0 : if (mPtrRTP->SetLocalSSRC(mChannel, aSSRCs[0])) {
136 0 : return false;
137 : }
138 :
139 0 : if (wasTransmitting) {
140 0 : if (StartTransmitting() != kMediaConduitNoError) {
141 0 : return false;
142 : }
143 : }
144 0 : return true;
145 : }
146 :
147 0 : std::vector<unsigned int> WebrtcAudioConduit::GetLocalSSRCs() const {
148 : unsigned int ssrc;
149 0 : if (!mPtrRTP->GetLocalSSRC(mChannel, ssrc)) {
150 0 : return std::vector<unsigned int>(1,ssrc);
151 : }
152 0 : return std::vector<unsigned int>();
153 : }
154 :
155 0 : bool WebrtcAudioConduit::GetRemoteSSRC(unsigned int* ssrc) {
156 0 : return !mPtrRTP->GetRemoteSSRC(mChannel, *ssrc);
157 : }
158 :
159 0 : bool WebrtcAudioConduit::SetLocalCNAME(const char* cname)
160 : {
161 : char temp[256];
162 0 : strncpy(temp, cname, sizeof(temp) - 1);
163 0 : temp[sizeof(temp) - 1] = 0;
164 0 : return !mPtrRTP->SetRTCP_CNAME(mChannel, temp);
165 : }
166 :
167 0 : bool WebrtcAudioConduit::GetSendPacketTypeStats(
168 : webrtc::RtcpPacketTypeCounter* aPacketCounts)
169 : {
170 0 : if (!mEngineTransmitting) {
171 0 : return false;
172 : }
173 0 : return !mPtrVoERTP_RTCP->GetRTCPPacketTypeCounters(mChannel, *aPacketCounts);
174 : }
175 :
176 0 : bool WebrtcAudioConduit::GetRecvPacketTypeStats(
177 : webrtc::RtcpPacketTypeCounter* aPacketCounts)
178 : {
179 0 : if (!mEngineReceiving) {
180 0 : return false;
181 : }
182 0 : return !mPtrRTP->GetRTCPPacketTypeCounters(mChannel, *aPacketCounts);
183 : }
184 :
185 0 : bool WebrtcAudioConduit::GetAVStats(int32_t* jitterBufferDelayMs,
186 : int32_t* playoutBufferDelayMs,
187 : int32_t* avSyncOffsetMs) {
188 0 : return !mPtrVoEVideoSync->GetDelayEstimate(mChannel,
189 : jitterBufferDelayMs,
190 : playoutBufferDelayMs,
191 0 : avSyncOffsetMs);
192 : }
193 :
194 0 : bool WebrtcAudioConduit::GetRTPStats(unsigned int* jitterMs,
195 : unsigned int* cumulativeLost) {
196 0 : unsigned int maxJitterMs = 0;
197 : unsigned int discardedPackets;
198 0 : *jitterMs = 0;
199 0 : *cumulativeLost = 0;
200 0 : return !mPtrRTP->GetRTPStatistics(mChannel, *jitterMs, maxJitterMs,
201 0 : discardedPackets, *cumulativeLost);
202 : }
203 :
204 : DOMHighResTimeStamp
205 0 : NTPtoDOMHighResTimeStamp(uint32_t ntpHigh, uint32_t ntpLow) {
206 0 : return (uint32_t(ntpHigh - webrtc::kNtpJan1970) +
207 0 : double(ntpLow) / webrtc::kMagicNtpFractionalUnit) * 1000;
208 : }
209 :
210 0 : bool WebrtcAudioConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
211 : uint32_t* jitterMs,
212 : uint32_t* packetsReceived,
213 : uint64_t* bytesReceived,
214 : uint32_t* cumulativeLost,
215 : int32_t* rttMs) {
216 :
217 : // We get called on STS thread... the proxy thread-checks to MainThread
218 : // I removed the check, since GetRTCPStatistics ends up going down to
219 : // methods (rtp_receiver_->SSRC() and rtp_receive_statistics_->GetStatistician()
220 : // and GetStatistics that internally lock, so we're ok here without a thread-check.
221 0 : webrtc::CallStatistics call_stats = mChannelProxy->GetRTCPStatistics();
222 0 : *bytesReceived = call_stats.bytesReceived;
223 0 : *packetsReceived = call_stats.packetsReceived;
224 0 : *cumulativeLost = call_stats.cumulativeLost;
225 0 : *rttMs = call_stats.rttMs;
226 :
227 : unsigned int averageJitterMs;
228 : unsigned int maxJitterMs;
229 : unsigned int discardedPackets;
230 : unsigned int cumulative;
231 0 : mChannelProxy->GetRTPStatistics(averageJitterMs, maxJitterMs, discardedPackets, cumulative);
232 0 : *jitterMs = averageJitterMs;
233 :
234 : // XXX Note: timestamp is not correct per the spec... should be time the
235 : // rtcp was received (remote) or sent (local)
236 0 : *timestamp = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
237 0 : return true;
238 : }
239 :
240 0 : bool WebrtcAudioConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
241 : unsigned int* packetsSent,
242 : uint64_t* bytesSent) {
243 : webrtc::RTCPSenderInfo senderInfo;
244 : webrtc::RtpRtcp * rtpRtcpModule;
245 : webrtc::RtpReceiver * rtp_receiver;
246 : bool result =
247 0 : !mPtrVoEVideoSync->GetRtpRtcp(mChannel,&rtpRtcpModule,&rtp_receiver) &&
248 0 : !rtpRtcpModule->RemoteRTCPStat(&senderInfo);
249 0 : if (result){
250 0 : *timestamp = NTPtoDOMHighResTimeStamp(senderInfo.NTPseconds,
251 : senderInfo.NTPfraction);
252 0 : *packetsSent = senderInfo.sendPacketCount;
253 0 : *bytesSent = senderInfo.sendOctetCount;
254 : }
255 0 : return result;
256 : }
257 :
258 0 : bool WebrtcAudioConduit::SetDtmfPayloadType(unsigned char type, int freq) {
259 0 : CSFLogInfo(logTag, "%s : setting dtmf payload %d", __FUNCTION__, (int)type);
260 :
261 0 : int result = mChannelProxy->SetSendTelephoneEventPayloadType(type, freq);
262 0 : if (result == -1) {
263 0 : CSFLogError(logTag, "%s Failed call to SetSendTelephoneEventPayloadType(%u, %d)",
264 0 : __FUNCTION__, type, freq);
265 : }
266 0 : return result != -1;
267 : }
268 :
269 0 : bool WebrtcAudioConduit::InsertDTMFTone(int channel, int eventCode,
270 : bool outOfBand, int lengthMs,
271 : int attenuationDb) {
272 0 : NS_ASSERTION(!NS_IsMainThread(), "Do not call on main thread");
273 :
274 0 : if (!mVoiceEngine || !mDtmfEnabled) {
275 0 : return false;
276 : }
277 :
278 0 : int result = 0;
279 0 : if (outOfBand){
280 0 : result = mChannelProxy->SendTelephoneEventOutband(eventCode, lengthMs);
281 : }
282 0 : return result != -1;
283 : }
284 :
285 : /*
286 : * WebRTCAudioConduit Implementation
287 : */
288 0 : MediaConduitErrorCode WebrtcAudioConduit::Init()
289 : {
290 0 : CSFLogDebug(logTag, "%s this=%p", __FUNCTION__, this);
291 :
292 : #ifdef MOZ_WIDGET_ANDROID
293 : jobject context = jsjni_GetGlobalContextRef();
294 : // get the JVM
295 : JavaVM *jvm = jsjni_GetVM();
296 :
297 : if (webrtc::VoiceEngine::SetAndroidObjects(jvm, (void*)context) != 0) {
298 : CSFLogError(logTag, "%s Unable to set Android objects", __FUNCTION__);
299 : return kMediaConduitSessionNotInited;
300 : }
301 : #endif
302 :
303 : // Per WebRTC APIs below function calls return nullptr on failure
304 0 : if(!(mVoiceEngine = webrtc::VoiceEngine::Create()))
305 : {
306 0 : CSFLogError(logTag, "%s Unable to create voice engine", __FUNCTION__);
307 0 : return kMediaConduitSessionNotInited;
308 : }
309 :
310 0 : if(!(mPtrVoEBase = VoEBase::GetInterface(mVoiceEngine)))
311 : {
312 0 : CSFLogError(logTag, "%s Unable to initialize VoEBase", __FUNCTION__);
313 0 : return kMediaConduitSessionNotInited;
314 : }
315 :
316 : // init the engine with our audio device layer
317 0 : if(mPtrVoEBase->Init() == -1)
318 : {
319 0 : CSFLogError(logTag, "%s VoiceEngine Base Not Initialized", __FUNCTION__);
320 0 : return kMediaConduitSessionNotInited;
321 : }
322 :
323 0 : if(!(mPtrVoENetwork = VoENetwork::GetInterface(mVoiceEngine)))
324 : {
325 0 : CSFLogError(logTag, "%s Unable to initialize VoENetwork", __FUNCTION__);
326 0 : return kMediaConduitSessionNotInited;
327 : }
328 :
329 0 : if(!(mPtrVoECodec = VoECodec::GetInterface(mVoiceEngine)))
330 : {
331 0 : CSFLogError(logTag, "%s Unable to initialize VoEBCodec", __FUNCTION__);
332 0 : return kMediaConduitSessionNotInited;
333 : }
334 :
335 0 : if(!(mPtrVoEProcessing = VoEAudioProcessing::GetInterface(mVoiceEngine)))
336 : {
337 0 : CSFLogError(logTag, "%s Unable to initialize VoEProcessing", __FUNCTION__);
338 0 : return kMediaConduitSessionNotInited;
339 : }
340 0 : if(!(mPtrVoEXmedia = VoEExternalMedia::GetInterface(mVoiceEngine)))
341 : {
342 0 : CSFLogError(logTag, "%s Unable to initialize VoEExternalMedia", __FUNCTION__);
343 0 : return kMediaConduitSessionNotInited;
344 : }
345 0 : if(!(mPtrVoERTP_RTCP = VoERTP_RTCP::GetInterface(mVoiceEngine)))
346 : {
347 0 : CSFLogError(logTag, "%s Unable to initialize VoERTP_RTCP", __FUNCTION__);
348 0 : return kMediaConduitSessionNotInited;
349 : }
350 :
351 0 : if(!(mPtrVoEVideoSync = VoEVideoSync::GetInterface(mVoiceEngine)))
352 : {
353 0 : CSFLogError(logTag, "%s Unable to initialize VoEVideoSync", __FUNCTION__);
354 0 : return kMediaConduitSessionNotInited;
355 : }
356 0 : if (!(mPtrRTP = webrtc::VoERTP_RTCP::GetInterface(mVoiceEngine)))
357 : {
358 : CSFLogError(logTag, "%s Unable to get audio RTP/RTCP interface ",
359 0 : __FUNCTION__);
360 0 : return kMediaConduitSessionNotInited;
361 : }
362 :
363 0 : if( (mChannel = mPtrVoEBase->CreateChannel()) == -1)
364 : {
365 0 : CSFLogError(logTag, "%s VoiceEngine Channel creation failed",__FUNCTION__);
366 0 : return kMediaConduitChannelError;
367 : }
368 : // Needed to access TelephoneEvent APIs in 57 if we're not using Call/audio_send_stream/etc
369 0 : webrtc::VoiceEngineImpl* s = static_cast<webrtc::VoiceEngineImpl*>(mVoiceEngine);
370 0 : mChannelProxy = s->GetChannelProxy(mChannel);
371 0 : MOZ_ASSERT(mChannelProxy);
372 :
373 0 : CSFLogDebug(logTag, "%s Channel Created %d ",__FUNCTION__, mChannel);
374 :
375 0 : if(mPtrVoENetwork->RegisterExternalTransport(mChannel, *this) == -1)
376 : {
377 0 : CSFLogError(logTag, "%s VoiceEngine, External Transport Failed",__FUNCTION__);
378 0 : return kMediaConduitTransportRegistrationFail;
379 : }
380 :
381 0 : if(mPtrVoEXmedia->SetExternalRecordingStatus(true) == -1)
382 : {
383 0 : CSFLogError(logTag, "%s SetExternalRecordingStatus Failed %d",__FUNCTION__,
384 0 : mPtrVoEBase->LastError());
385 0 : return kMediaConduitExternalPlayoutError;
386 : }
387 :
388 0 : if(mPtrVoEXmedia->SetExternalPlayoutStatus(true) == -1)
389 : {
390 0 : CSFLogError(logTag, "%s SetExternalPlayoutStatus Failed %d ",__FUNCTION__,
391 0 : mPtrVoEBase->LastError());
392 0 : return kMediaConduitExternalRecordingError;
393 : }
394 :
395 0 : CSFLogDebug(logTag , "%s AudioSessionConduit Initialization Done (%p)",__FUNCTION__, this);
396 0 : return kMediaConduitNoError;
397 : }
398 :
399 : // AudioSessionConduit Implementation
400 : MediaConduitErrorCode
401 0 : WebrtcAudioConduit::SetTransmitterTransport(RefPtr<TransportInterface> aTransport)
402 : {
403 0 : CSFLogDebug(logTag, "%s ", __FUNCTION__);
404 :
405 0 : ReentrantMonitorAutoEnter enter(mTransportMonitor);
406 : // set the transport
407 0 : mTransmitterTransport = aTransport;
408 0 : return kMediaConduitNoError;
409 : }
410 :
411 : MediaConduitErrorCode
412 0 : WebrtcAudioConduit::SetReceiverTransport(RefPtr<TransportInterface> aTransport)
413 : {
414 0 : CSFLogDebug(logTag, "%s ", __FUNCTION__);
415 :
416 0 : ReentrantMonitorAutoEnter enter(mTransportMonitor);
417 : // set the transport
418 0 : mReceiverTransport = aTransport;
419 0 : return kMediaConduitNoError;
420 : }
421 :
422 : MediaConduitErrorCode
423 0 : WebrtcAudioConduit::ConfigureSendMediaCodec(const AudioCodecConfig* codecConfig)
424 : {
425 0 : CSFLogDebug(logTag, "%s ", __FUNCTION__);
426 0 : MediaConduitErrorCode condError = kMediaConduitNoError;
427 0 : int error = 0;//webrtc engine errors
428 : webrtc::CodecInst cinst;
429 :
430 : {
431 : //validate codec param
432 0 : if((condError = ValidateCodecConfig(codecConfig, true)) != kMediaConduitNoError)
433 : {
434 0 : return condError;
435 : }
436 : }
437 :
438 0 : condError = StopTransmitting();
439 0 : if (condError != kMediaConduitNoError) {
440 0 : return condError;
441 : }
442 :
443 0 : if(!CodecConfigToWebRTCCodec(codecConfig,cinst))
444 : {
445 0 : CSFLogError(logTag,"%s CodecConfig to WebRTC Codec Failed ",__FUNCTION__);
446 0 : return kMediaConduitMalformedArgument;
447 : }
448 :
449 0 : if(mPtrVoECodec->SetSendCodec(mChannel, cinst) == -1)
450 : {
451 0 : error = mPtrVoEBase->LastError();
452 : CSFLogError(logTag, "%s SetSendCodec - Invalid Codec %d ",__FUNCTION__,
453 0 : error);
454 :
455 0 : if(error == VE_CANNOT_SET_SEND_CODEC || error == VE_CODEC_ERROR)
456 : {
457 0 : CSFLogError(logTag, "%s Invalid Send Codec", __FUNCTION__);
458 0 : return kMediaConduitInvalidSendCodec;
459 : }
460 0 : CSFLogError(logTag, "%s SetSendCodec Failed %d ", __FUNCTION__,
461 0 : mPtrVoEBase->LastError());
462 0 : return kMediaConduitUnknownError;
463 : }
464 :
465 : // This must be called after SetSendCodec
466 0 : if (mPtrVoECodec->SetFECStatus(mChannel, codecConfig->mFECEnabled) == -1) {
467 0 : CSFLogError(logTag, "%s SetFECStatus Failed %d ", __FUNCTION__,
468 0 : mPtrVoEBase->LastError());
469 0 : return kMediaConduitFECStatusError;
470 : }
471 :
472 0 : mDtmfEnabled = codecConfig->mDtmfEnabled;
473 :
474 0 : if (codecConfig->mName == "opus" && codecConfig->mMaxPlaybackRate) {
475 0 : if (mPtrVoECodec->SetOpusMaxPlaybackRate(
476 : mChannel,
477 0 : codecConfig->mMaxPlaybackRate) == -1) {
478 0 : CSFLogError(logTag, "%s SetOpusMaxPlaybackRate Failed %d ", __FUNCTION__,
479 0 : mPtrVoEBase->LastError());
480 0 : return kMediaConduitUnknownError;
481 : }
482 : }
483 :
484 : // TEMPORARY - see bug 694814 comment 2
485 : nsresult rv;
486 0 : nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
487 0 : if (NS_SUCCEEDED(rv)) {
488 0 : nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
489 :
490 0 : if (branch) {
491 0 : branch->GetIntPref("media.peerconnection.capture_delay", &mCaptureDelay);
492 : }
493 : }
494 :
495 0 : condError = StartTransmitting();
496 0 : if (condError != kMediaConduitNoError) {
497 0 : return condError;
498 : }
499 :
500 : {
501 0 : MutexAutoLock lock(mCodecMutex);
502 :
503 : //Copy the applied config for future reference.
504 0 : mCurSendCodecConfig = new AudioCodecConfig(codecConfig->mType,
505 : codecConfig->mName,
506 0 : codecConfig->mFreq,
507 0 : codecConfig->mPacSize,
508 0 : codecConfig->mChannels,
509 0 : codecConfig->mRate,
510 0 : codecConfig->mFECEnabled);
511 : }
512 0 : return kMediaConduitNoError;
513 : }
514 :
515 : MediaConduitErrorCode
516 0 : WebrtcAudioConduit::ConfigureRecvMediaCodecs(
517 : const std::vector<AudioCodecConfig*>& codecConfigList)
518 : {
519 0 : CSFLogDebug(logTag, "%s ", __FUNCTION__);
520 0 : MediaConduitErrorCode condError = kMediaConduitNoError;
521 0 : int error = 0; //webrtc engine errors
522 0 : bool success = false;
523 :
524 : // Are we receiving already? If so, stop receiving and playout
525 : // since we can't apply new recv codec when the engine is playing.
526 0 : condError = StopReceiving();
527 0 : if (condError != kMediaConduitNoError) {
528 0 : return condError;
529 : }
530 :
531 0 : if(codecConfigList.empty())
532 : {
533 0 : CSFLogError(logTag, "%s Zero number of codecs to configure", __FUNCTION__);
534 0 : return kMediaConduitMalformedArgument;
535 : }
536 :
537 : // Try Applying the codecs in the list.
538 : // We succeed if at least one codec was applied and reception was
539 : // started successfully.
540 0 : for(auto codec : codecConfigList)
541 : {
542 : //if the codec param is invalid or diplicate, return error
543 0 : if((condError = ValidateCodecConfig(codec,false)) != kMediaConduitNoError)
544 : {
545 0 : return condError;
546 : }
547 :
548 : webrtc::CodecInst cinst;
549 0 : if(!CodecConfigToWebRTCCodec(codec,cinst))
550 : {
551 0 : CSFLogError(logTag,"%s CodecConfig to WebRTC Codec Failed ",__FUNCTION__);
552 0 : continue;
553 : }
554 :
555 0 : if(mPtrVoECodec->SetRecPayloadType(mChannel,cinst) == -1)
556 : {
557 0 : error = mPtrVoEBase->LastError();
558 0 : CSFLogError(logTag, "%s SetRecvCodec Failed %d ",__FUNCTION__, error);
559 0 : continue;
560 : }
561 0 : CSFLogDebug(logTag, "%s Successfully Set RecvCodec %s", __FUNCTION__,
562 0 : codec->mName.c_str());
563 :
564 : //copy this to local database
565 0 : if(!CopyCodecToDB(codec)) {
566 0 : CSFLogError(logTag,"%s Unable to updated Codec Database", __FUNCTION__);
567 0 : return kMediaConduitUnknownError;
568 : }
569 0 : success = true;
570 :
571 : } //end for
572 :
573 0 : if(!success)
574 : {
575 0 : CSFLogError(logTag, "%s Setting Receive Codec Failed ", __FUNCTION__);
576 0 : return kMediaConduitInvalidReceiveCodec;
577 : }
578 :
579 : //If we are here, atleast one codec should have been set
580 0 : condError = StartReceiving();
581 0 : if (condError != kMediaConduitNoError) {
582 0 : return condError;
583 : }
584 :
585 0 : DumpCodecDB();
586 0 : return kMediaConduitNoError;
587 : }
588 : MediaConduitErrorCode
589 0 : WebrtcAudioConduit::EnableAudioLevelExtension(bool enabled, uint8_t id)
590 : {
591 0 : CSFLogDebug(logTag, "%s %d %d ", __FUNCTION__, enabled, id);
592 :
593 0 : if (mPtrVoERTP_RTCP->SetSendAudioLevelIndicationStatus(mChannel, enabled, id) == -1)
594 : {
595 0 : CSFLogError(logTag, "%s SetSendAudioLevelIndicationStatus Failed", __FUNCTION__);
596 0 : return kMediaConduitUnknownError;
597 : }
598 :
599 0 : return kMediaConduitNoError;
600 : }
601 :
602 : MediaConduitErrorCode
603 0 : WebrtcAudioConduit::SendAudioFrame(const int16_t audio_data[],
604 : int32_t lengthSamples,
605 : int32_t samplingFreqHz,
606 : int32_t capture_delay)
607 : {
608 0 : CSFLogDebug(logTag, "%s ", __FUNCTION__);
609 : // Following checks need to be performed
610 : // 1. Non null audio buffer pointer,
611 : // 2. invalid sampling frequency - less than 0 or unsupported ones
612 : // 3. Appropriate Sample Length for 10 ms audio-frame. This represents
613 : // block size the VoiceEngine feeds into encoder for passed in audio-frame
614 : // Ex: for 16000 sampling rate , valid block-length is 160
615 : // Similarly for 32000 sampling rate, valid block length is 320
616 : // We do the check by the verify modular operator below to be zero
617 :
618 0 : if(!audio_data || (lengthSamples <= 0) ||
619 0 : (IsSamplingFreqSupported(samplingFreqHz) == false) ||
620 0 : ((lengthSamples % (samplingFreqHz / 100) != 0)) )
621 : {
622 0 : CSFLogError(logTag, "%s Invalid Parameters ",__FUNCTION__);
623 0 : MOZ_ASSERT(PR_FALSE);
624 : return kMediaConduitMalformedArgument;
625 : }
626 :
627 : //validate capture time
628 0 : if(capture_delay < 0 )
629 : {
630 0 : CSFLogError(logTag,"%s Invalid Capture Delay ", __FUNCTION__);
631 0 : MOZ_ASSERT(PR_FALSE);
632 : return kMediaConduitMalformedArgument;
633 : }
634 :
635 : // if transmission is not started .. conduit cannot insert frames
636 0 : if(!mEngineTransmitting)
637 : {
638 0 : CSFLogError(logTag, "%s Engine not transmitting ", __FUNCTION__);
639 0 : return kMediaConduitSessionNotInited;
640 : }
641 :
642 0 : if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
643 0 : struct Processing insert = { TimeStamp::Now(), 0 };
644 0 : mProcessing.AppendElement(insert);
645 : }
646 :
647 0 : capture_delay = mCaptureDelay;
648 : //Insert the samples
649 0 : if(mPtrVoEXmedia->ExternalRecordingInsertData(audio_data,
650 : lengthSamples,
651 : samplingFreqHz,
652 0 : capture_delay) == -1)
653 : {
654 0 : int error = mPtrVoEBase->LastError();
655 0 : CSFLogError(logTag, "%s Inserting audio data Failed %d", __FUNCTION__, error);
656 0 : if(error == VE_RUNTIME_REC_ERROR)
657 : {
658 0 : return kMediaConduitRecordingError;
659 : }
660 0 : return kMediaConduitUnknownError;
661 : }
662 : // we should be good here
663 0 : return kMediaConduitNoError;
664 : }
665 :
666 : MediaConduitErrorCode
667 0 : WebrtcAudioConduit::GetAudioFrame(int16_t speechData[],
668 : int32_t samplingFreqHz,
669 : int32_t capture_delay,
670 : int& lengthSamples)
671 : {
672 :
673 0 : CSFLogDebug(logTag, "%s ", __FUNCTION__);
674 0 : unsigned int numSamples = 0;
675 :
676 : //validate params
677 0 : if(!speechData )
678 : {
679 0 : CSFLogError(logTag,"%s Null Audio Buffer Pointer", __FUNCTION__);
680 0 : MOZ_ASSERT(PR_FALSE);
681 : return kMediaConduitMalformedArgument;
682 : }
683 :
684 : // Validate sample length
685 0 : if((numSamples = GetNum10msSamplesForFrequency(samplingFreqHz)) == 0 )
686 : {
687 0 : CSFLogError(logTag,"%s Invalid Sampling Frequency ", __FUNCTION__);
688 0 : MOZ_ASSERT(PR_FALSE);
689 : return kMediaConduitMalformedArgument;
690 : }
691 :
692 : //validate capture time
693 0 : if(capture_delay < 0 )
694 : {
695 0 : CSFLogError(logTag,"%s Invalid Capture Delay ", __FUNCTION__);
696 0 : MOZ_ASSERT(PR_FALSE);
697 : return kMediaConduitMalformedArgument;
698 : }
699 :
700 : //Conduit should have reception enabled before we ask for decoded
701 : // samples
702 0 : if(!mEngineReceiving)
703 : {
704 0 : CSFLogError(logTag, "%s Engine not Receiving ", __FUNCTION__);
705 0 : return kMediaConduitSessionNotInited;
706 : }
707 :
708 :
709 0 : lengthSamples = 0; //output paramter
710 :
711 0 : if(mPtrVoEXmedia->ExternalPlayoutGetData( speechData,
712 : samplingFreqHz,
713 : capture_delay,
714 0 : lengthSamples) == -1)
715 : {
716 0 : int error = mPtrVoEBase->LastError();
717 0 : CSFLogError(logTag, "%s Getting audio data Failed %d", __FUNCTION__, error);
718 0 : if(error == VE_RUNTIME_PLAY_ERROR)
719 : {
720 0 : return kMediaConduitPlayoutError;
721 : }
722 0 : return kMediaConduitUnknownError;
723 : }
724 :
725 : // Not #ifdef DEBUG or on a log module so we can use it for about:webrtc/etc
726 0 : mSamples += lengthSamples;
727 0 : if (mSamples >= mLastSyncLog + samplingFreqHz) {
728 : int jitter_buffer_delay_ms;
729 : int playout_buffer_delay_ms;
730 : int avsync_offset_ms;
731 0 : if (GetAVStats(&jitter_buffer_delay_ms,
732 : &playout_buffer_delay_ms,
733 0 : &avsync_offset_ms)) {
734 0 : if (avsync_offset_ms < 0) {
735 0 : Telemetry::Accumulate(Telemetry::WEBRTC_AVSYNC_WHEN_VIDEO_LAGS_AUDIO_MS,
736 0 : -avsync_offset_ms);
737 : } else {
738 0 : Telemetry::Accumulate(Telemetry::WEBRTC_AVSYNC_WHEN_AUDIO_LAGS_VIDEO_MS,
739 0 : avsync_offset_ms);
740 : }
741 : CSFLogError(logTag,
742 : "A/V sync: sync delta: %dms, audio jitter delay %dms, playout delay %dms",
743 0 : avsync_offset_ms, jitter_buffer_delay_ms, playout_buffer_delay_ms);
744 : } else {
745 0 : CSFLogError(logTag, "A/V sync: GetAVStats failed");
746 : }
747 0 : mLastSyncLog = mSamples;
748 : }
749 :
750 0 : if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
751 0 : if (mProcessing.Length() > 0) {
752 : unsigned int now;
753 0 : mPtrVoEVideoSync->GetPlayoutTimestamp(mChannel, now);
754 0 : if (static_cast<uint32_t>(now) != mLastTimestamp) {
755 0 : mLastTimestamp = static_cast<uint32_t>(now);
756 : // Find the block that includes this timestamp in the network input
757 0 : while (mProcessing.Length() > 0) {
758 : // FIX! assumes 20ms @ 48000Hz
759 : // FIX handle wrap-around
760 0 : if (mProcessing[0].mRTPTimeStamp + 20*(48000/1000) >= now) {
761 0 : TimeDuration t = TimeStamp::Now() - mProcessing[0].mTimeStamp;
762 : // Wrap-around?
763 0 : int64_t delta = t.ToMilliseconds() + (now - mProcessing[0].mRTPTimeStamp)/(48000/1000);
764 0 : LogTime(AsyncLatencyLogger::AudioRecvRTP, ((uint64_t) this), delta);
765 0 : break;
766 : }
767 0 : mProcessing.RemoveElementAt(0);
768 : }
769 : }
770 : }
771 : }
772 0 : CSFLogDebug(logTag,"%s GetAudioFrame:Got samples: length %d ",__FUNCTION__,
773 0 : lengthSamples);
774 0 : return kMediaConduitNoError;
775 : }
776 :
777 : // Transport Layer Callbacks
778 : MediaConduitErrorCode
779 0 : WebrtcAudioConduit::ReceivedRTPPacket(const void *data, int len, uint32_t ssrc)
780 : {
781 0 : CSFLogDebug(logTag, "%s : channel %d", __FUNCTION__, mChannel);
782 :
783 0 : if(mEngineReceiving)
784 : {
785 0 : if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
786 : // timestamp is at 32 bits in ([1])
787 : struct Processing insert = { TimeStamp::Now(),
788 0 : ntohl(static_cast<const uint32_t *>(data)[1]) };
789 0 : mProcessing.AppendElement(insert);
790 : }
791 :
792 : // XXX we need to get passed the time the packet was received
793 0 : if(mPtrVoENetwork->ReceivedRTPPacket(mChannel, data, len) == -1)
794 : {
795 0 : int error = mPtrVoEBase->LastError();
796 0 : CSFLogError(logTag, "%s RTP Processing Error %d", __FUNCTION__, error);
797 0 : if(error == VE_RTP_RTCP_MODULE_ERROR)
798 : {
799 0 : return kMediaConduitRTPRTCPModuleError;
800 : }
801 0 : return kMediaConduitUnknownError;
802 : }
803 : } else {
804 0 : CSFLogError(logTag, "Error: %s when not receiving", __FUNCTION__);
805 0 : return kMediaConduitSessionNotInited;
806 : }
807 :
808 0 : return kMediaConduitNoError;
809 : }
810 :
811 : MediaConduitErrorCode
812 0 : WebrtcAudioConduit::ReceivedRTCPPacket(const void *data, int len)
813 : {
814 0 : CSFLogDebug(logTag, "%s : channel %d",__FUNCTION__, mChannel);
815 :
816 0 : if(mPtrVoENetwork->ReceivedRTCPPacket(mChannel, data, len) == -1)
817 : {
818 0 : int error = mPtrVoEBase->LastError();
819 0 : CSFLogError(logTag, "%s RTCP Processing Error %d", __FUNCTION__, error);
820 0 : if(error == VE_RTP_RTCP_MODULE_ERROR)
821 : {
822 0 : return kMediaConduitRTPRTCPModuleError;
823 : }
824 0 : return kMediaConduitUnknownError;
825 : }
826 0 : return kMediaConduitNoError;
827 : }
828 :
829 : MediaConduitErrorCode
830 0 : WebrtcAudioConduit::StopTransmitting()
831 : {
832 0 : if(mEngineTransmitting)
833 : {
834 0 : CSFLogDebug(logTag, "%s Engine Already Sending. Attemping to Stop ", __FUNCTION__);
835 0 : if(mPtrVoEBase->StopSend(mChannel) == -1)
836 : {
837 0 : CSFLogError(logTag, "%s StopSend() Failed %d ", __FUNCTION__,
838 0 : mPtrVoEBase->LastError());
839 0 : return kMediaConduitUnknownError;
840 : }
841 0 : mEngineTransmitting = false;
842 : }
843 :
844 0 : return kMediaConduitNoError;
845 : }
846 :
847 : MediaConduitErrorCode
848 0 : WebrtcAudioConduit::StartTransmitting()
849 : {
850 0 : if (!mEngineTransmitting) {
851 : //Let's Send Transport State-machine on the Engine
852 0 : if(mPtrVoEBase->StartSend(mChannel) == -1)
853 : {
854 0 : int error = mPtrVoEBase->LastError();
855 0 : CSFLogError(logTag, "%s StartSend failed %d", __FUNCTION__, error);
856 0 : return kMediaConduitUnknownError;
857 : }
858 0 : mEngineTransmitting = true;
859 : }
860 :
861 0 : return kMediaConduitNoError;
862 : }
863 :
864 : MediaConduitErrorCode
865 0 : WebrtcAudioConduit::StopReceiving()
866 : {
867 0 : if(mEngineReceiving)
868 : {
869 0 : CSFLogDebug(logTag, "%s Engine Already Receiving. Attemping to Stop ", __FUNCTION__);
870 : // AudioEngine doesn't fail fatally on stopping reception. Ref:voe_errors.h.
871 : // hence we need not be strict in failing here on errors
872 0 : mPtrVoEBase->StopReceive(mChannel);
873 0 : CSFLogDebug(logTag, "%s Attemping to Stop playout ", __FUNCTION__);
874 0 : if(mPtrVoEBase->StopPlayout(mChannel) == -1)
875 : {
876 0 : if( mPtrVoEBase->LastError() == VE_CANNOT_STOP_PLAYOUT)
877 : {
878 0 : CSFLogDebug(logTag, "%s Stop-Playout Failed %d", __FUNCTION__, mPtrVoEBase->LastError());
879 0 : return kMediaConduitPlayoutError;
880 : }
881 : }
882 0 : mEngineReceiving = false;
883 : }
884 :
885 0 : return kMediaConduitNoError;
886 : }
887 :
888 : MediaConduitErrorCode
889 0 : WebrtcAudioConduit::StartReceiving()
890 : {
891 0 : if (!mEngineReceiving) {
892 0 : if(mPtrVoEBase->StartReceive(mChannel) == -1)
893 : {
894 0 : int error = mPtrVoEBase->LastError();
895 0 : CSFLogError(logTag , "%s StartReceive Failed %d ",__FUNCTION__, error);
896 0 : if(error == VE_RECV_SOCKET_ERROR)
897 : {
898 0 : return kMediaConduitSocketError;
899 : }
900 0 : return kMediaConduitUnknownError;
901 : }
902 :
903 0 : if(mPtrVoEBase->StartPlayout(mChannel) == -1)
904 : {
905 0 : CSFLogError(logTag, "%s Starting playout Failed", __FUNCTION__);
906 0 : return kMediaConduitPlayoutError;
907 : }
908 0 : mEngineReceiving = true;
909 : }
910 :
911 0 : return kMediaConduitNoError;
912 : }
913 :
914 : //WebRTC::RTP Callback Implementation
915 : // Called on AudioGUM or MSG thread
916 : bool
917 0 : WebrtcAudioConduit::SendRtp(const uint8_t* data,
918 : size_t len,
919 : const webrtc::PacketOptions& options)
920 : {
921 0 : CSFLogDebug(logTag, "%s: len %lu", __FUNCTION__, (unsigned long)len);
922 :
923 0 : if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
924 0 : if (mProcessing.Length() > 0) {
925 0 : TimeStamp started = mProcessing[0].mTimeStamp;
926 0 : mProcessing.RemoveElementAt(0);
927 0 : mProcessing.RemoveElementAt(0); // 20ms packetization! Could automate this by watching sizes
928 0 : TimeDuration t = TimeStamp::Now() - started;
929 0 : int64_t delta = t.ToMilliseconds();
930 0 : LogTime(AsyncLatencyLogger::AudioSendRTP, ((uint64_t) this), delta);
931 : }
932 : }
933 0 : ReentrantMonitorAutoEnter enter(mTransportMonitor);
934 : // XXX(pkerr) - the PacketOptions are being ignored. This parameter was added along
935 : // with the Call API update in the webrtc.org codebase.
936 : // The only field in it is the packet_id, which is used when the header
937 : // extension for TransportSequenceNumber is being used, which we don't.
938 : (void)options;
939 0 : if(mTransmitterTransport &&
940 0 : (mTransmitterTransport->SendRtpPacket(data, len) == NS_OK))
941 : {
942 0 : CSFLogDebug(logTag, "%s Sent RTP Packet ", __FUNCTION__);
943 0 : return true;
944 : }
945 0 : CSFLogError(logTag, "%s RTP Packet Send Failed ", __FUNCTION__);
946 0 : return false;
947 : }
948 :
949 : // Called on WebRTC Process thread and perhaps others
950 : bool
951 0 : WebrtcAudioConduit::SendRtcp(const uint8_t* data, size_t len)
952 : {
953 0 : CSFLogDebug(logTag, "%s : len %lu, first rtcp = %u ",
954 : __FUNCTION__,
955 : (unsigned long) len,
956 0 : static_cast<unsigned>(data[1]));
957 :
958 : // We come here if we have only one pipeline/conduit setup,
959 : // such as for unidirectional streams.
960 : // We also end up here if we are receiving
961 0 : ReentrantMonitorAutoEnter enter(mTransportMonitor);
962 0 : if(mReceiverTransport &&
963 0 : mReceiverTransport->SendRtcpPacket(data, len) == NS_OK)
964 : {
965 : // Might be a sender report, might be a receiver report, we don't know.
966 0 : CSFLogDebug(logTag, "%s Sent RTCP Packet ", __FUNCTION__);
967 0 : return true;
968 : }
969 0 : if (mTransmitterTransport &&
970 0 : (mTransmitterTransport->SendRtcpPacket(data, len) == NS_OK)) {
971 0 : CSFLogDebug(logTag, "%s Sent RTCP Packet (sender report) ", __FUNCTION__);
972 0 : return true;
973 : }
974 0 : CSFLogError(logTag, "%s RTCP Packet Send Failed ", __FUNCTION__);
975 0 : return false;
976 : }
977 :
978 : /**
979 : * Converts between CodecConfig to WebRTC Codec Structure.
980 : */
981 :
982 : bool
983 0 : WebrtcAudioConduit::CodecConfigToWebRTCCodec(const AudioCodecConfig* codecInfo,
984 : webrtc::CodecInst& cinst)
985 : {
986 0 : const unsigned int plNameLength = codecInfo->mName.length();
987 0 : memset(&cinst, 0, sizeof(webrtc::CodecInst));
988 0 : if(sizeof(cinst.plname) < plNameLength+1)
989 : {
990 : CSFLogError(logTag, "%s Payload name buffer capacity mismatch ",
991 0 : __FUNCTION__);
992 0 : return false;
993 : }
994 0 : memcpy(cinst.plname, codecInfo->mName.c_str(), plNameLength);
995 0 : cinst.plname[plNameLength]='\0';
996 0 : cinst.pltype = codecInfo->mType;
997 0 : cinst.rate = codecInfo->mRate;
998 0 : cinst.pacsize = codecInfo->mPacSize;
999 0 : cinst.plfreq = codecInfo->mFreq;
1000 0 : if (codecInfo->mName == "G722") {
1001 : // Compensate for G.722 spec error in RFC 1890
1002 0 : cinst.plfreq = 16000;
1003 : }
1004 0 : cinst.channels = codecInfo->mChannels;
1005 0 : return true;
1006 : }
1007 :
1008 : /**
1009 : * Supported Sampling Frequencies.
1010 : */
1011 : bool
1012 0 : WebrtcAudioConduit::IsSamplingFreqSupported(int freq) const
1013 : {
1014 0 : return GetNum10msSamplesForFrequency(freq) != 0;
1015 : }
1016 :
1017 : /* Return block-length of 10 ms audio frame in number of samples */
1018 : unsigned int
1019 0 : WebrtcAudioConduit::GetNum10msSamplesForFrequency(int samplingFreqHz) const
1020 : {
1021 0 : switch (samplingFreqHz)
1022 : {
1023 0 : case 16000: return 160; //160 samples
1024 0 : case 32000: return 320; //320 samples
1025 0 : case 44100: return 441; //441 samples
1026 0 : case 48000: return 480; //480 samples
1027 0 : default: return 0; // invalid or unsupported
1028 : }
1029 : }
1030 :
1031 : //Copy the codec passed into Conduit's database
1032 : bool
1033 0 : WebrtcAudioConduit::CopyCodecToDB(const AudioCodecConfig* codecInfo)
1034 : {
1035 :
1036 0 : AudioCodecConfig* cdcConfig = new AudioCodecConfig(codecInfo->mType,
1037 : codecInfo->mName,
1038 0 : codecInfo->mFreq,
1039 0 : codecInfo->mPacSize,
1040 0 : codecInfo->mChannels,
1041 0 : codecInfo->mRate,
1042 0 : codecInfo->mFECEnabled);
1043 0 : mRecvCodecList.push_back(cdcConfig);
1044 0 : return true;
1045 : }
1046 :
1047 : /**
1048 : * Checks if 2 codec structs are same
1049 : */
1050 : bool
1051 0 : WebrtcAudioConduit::CheckCodecsForMatch(const AudioCodecConfig* curCodecConfig,
1052 : const AudioCodecConfig* codecInfo) const
1053 : {
1054 0 : if(!curCodecConfig)
1055 : {
1056 0 : return false;
1057 : }
1058 :
1059 0 : if(curCodecConfig->mType == codecInfo->mType &&
1060 0 : (curCodecConfig->mName.compare(codecInfo->mName) == 0) &&
1061 0 : curCodecConfig->mFreq == codecInfo->mFreq &&
1062 0 : curCodecConfig->mPacSize == codecInfo->mPacSize &&
1063 0 : curCodecConfig->mChannels == codecInfo->mChannels &&
1064 0 : curCodecConfig->mRate == codecInfo->mRate)
1065 : {
1066 0 : return true;
1067 : }
1068 :
1069 0 : return false;
1070 : }
1071 :
1072 : /**
1073 : * Checks if the codec is already in Conduit's database
1074 : */
1075 : bool
1076 0 : WebrtcAudioConduit::CheckCodecForMatch(const AudioCodecConfig* codecInfo) const
1077 : {
1078 : //the db should have atleast one codec
1079 0 : for(auto codec : mRecvCodecList)
1080 : {
1081 0 : if(CheckCodecsForMatch(codec,codecInfo))
1082 : {
1083 : //match
1084 0 : return true;
1085 : }
1086 : }
1087 : //no match or empty local db
1088 0 : return false;
1089 : }
1090 :
1091 :
1092 : /**
1093 : * Perform validation on the codecConfig to be applied.
1094 : * Verifies if the codec is already applied.
1095 : */
1096 : MediaConduitErrorCode
1097 0 : WebrtcAudioConduit::ValidateCodecConfig(const AudioCodecConfig* codecInfo,
1098 : bool send)
1099 : {
1100 0 : bool codecAppliedAlready = false;
1101 :
1102 0 : if(!codecInfo)
1103 : {
1104 0 : CSFLogError(logTag, "%s Null CodecConfig ", __FUNCTION__);
1105 0 : return kMediaConduitMalformedArgument;
1106 : }
1107 :
1108 0 : if((codecInfo->mName.empty()) ||
1109 0 : (codecInfo->mName.length() >= CODEC_PLNAME_SIZE))
1110 : {
1111 0 : CSFLogError(logTag, "%s Invalid Payload Name Length ", __FUNCTION__);
1112 0 : return kMediaConduitMalformedArgument;
1113 : }
1114 :
1115 : //Only mono or stereo channels supported
1116 0 : if( (codecInfo->mChannels != 1) && (codecInfo->mChannels != 2))
1117 : {
1118 0 : CSFLogError(logTag, "%s Channel Unsupported ", __FUNCTION__);
1119 0 : return kMediaConduitMalformedArgument;
1120 : }
1121 :
1122 : //check if we have the same codec already applied
1123 0 : if(send)
1124 : {
1125 0 : MutexAutoLock lock(mCodecMutex);
1126 :
1127 0 : codecAppliedAlready = CheckCodecsForMatch(mCurSendCodecConfig,codecInfo);
1128 : } else {
1129 0 : codecAppliedAlready = CheckCodecForMatch(codecInfo);
1130 : }
1131 :
1132 0 : if(codecAppliedAlready)
1133 : {
1134 0 : CSFLogDebug(logTag, "%s Codec %s Already Applied ", __FUNCTION__, codecInfo->mName.c_str());
1135 : }
1136 0 : return kMediaConduitNoError;
1137 : }
1138 :
1139 : void
1140 0 : WebrtcAudioConduit::DumpCodecDB() const
1141 : {
1142 0 : for(auto& codec : mRecvCodecList)
1143 : {
1144 0 : CSFLogDebug(logTag,"Payload Name: %s", codec->mName.c_str());
1145 0 : CSFLogDebug(logTag,"Payload Type: %d", codec->mType);
1146 0 : CSFLogDebug(logTag,"Payload Frequency: %d", codec->mFreq);
1147 0 : CSFLogDebug(logTag,"Payload PacketSize: %d", codec->mPacSize);
1148 0 : CSFLogDebug(logTag,"Payload Channels: %d", codec->mChannels);
1149 0 : CSFLogDebug(logTag,"Payload Sampling Rate: %d", codec->mRate);
1150 : }
1151 0 : }
1152 : }// end namespace
|