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_codec_impl.h"
12
13#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
14#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
15#include "webrtc/system_wrappers/interface/trace.h"
16#include "webrtc/voice_engine/channel.h"
17#include "webrtc/voice_engine/include/voe_errors.h"
18#include "webrtc/voice_engine/voice_engine_impl.h"
19
20namespace webrtc
21{
22
23VoECodec* VoECodec::GetInterface(VoiceEngine* voiceEngine)
24{
25#ifndef WEBRTC_VOICE_ENGINE_CODEC_API
26    return NULL;
27#else
28    if (NULL == voiceEngine)
29    {
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_CODEC_API
39
40VoECodecImpl::VoECodecImpl(voe::SharedData* shared) : _shared(shared)
41{
42    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
43                 "VoECodecImpl() - ctor");
44}
45
46VoECodecImpl::~VoECodecImpl()
47{
48    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
49                 "~VoECodecImpl() - dtor");
50}
51
52int VoECodecImpl::NumOfCodecs()
53{
54    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
55                 "NumOfCodecs()");
56
57    // Number of supported codecs in the ACM
58    uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
59
60    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
61        VoEId(_shared->instance_id(), -1),
62        "NumOfCodecs() => %u", nSupportedCodecs);
63    return (nSupportedCodecs);
64}
65
66int VoECodecImpl::GetCodec(int index, CodecInst& codec)
67{
68    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
69                 "GetCodec(index=%d, codec=?)", index);
70    CodecInst acmCodec;
71    if (AudioCodingModule::Codec(index, &acmCodec)
72            == -1)
73    {
74        _shared->SetLastError(VE_INVALID_LISTNR, kTraceError,
75            "GetCodec() invalid index");
76        return -1;
77    }
78    ACMToExternalCodecRepresentation(codec, acmCodec);
79    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
80        VoEId(_shared->instance_id(), -1),
81        "GetCodec() => plname=%s, pacsize=%d, plfreq=%d, pltype=%d, "
82        "channels=%d, rate=%d", codec.plname, codec.pacsize,
83        codec.plfreq, codec.pltype, codec.channels, codec.rate);
84    return 0;
85}
86
87int VoECodecImpl::SetSendCodec(int channel, const CodecInst& codec)
88{
89    CodecInst copyCodec;
90    ExternalToACMCodecRepresentation(copyCodec, codec);
91
92    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
93                 "SetSendCodec(channel=%d, codec)", channel);
94    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
95                 "codec: plname=%s, pacsize=%d, plfreq=%d, pltype=%d, "
96                 "channels=%d, rate=%d", codec.plname, codec.pacsize,
97                 codec.plfreq, codec.pltype, codec.channels, codec.rate);
98    if (!_shared->statistics().Initialized())
99    {
100        _shared->SetLastError(VE_NOT_INITED, kTraceError);
101        return -1;
102    }
103    // External sanity checks performed outside the ACM
104    if ((STR_CASE_CMP(copyCodec.plname, "L16") == 0) &&
105            (copyCodec.pacsize >= 960))
106    {
107        _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
108            "SetSendCodec() invalid L16 packet size");
109        return -1;
110    }
111    if (!STR_CASE_CMP(copyCodec.plname, "CN")
112            || !STR_CASE_CMP(copyCodec.plname, "TELEPHONE-EVENT")
113            || !STR_CASE_CMP(copyCodec.plname, "RED"))
114    {
115        _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
116            "SetSendCodec() invalid codec name");
117        return -1;
118    }
119    if ((copyCodec.channels != 1) && (copyCodec.channels != 2))
120    {
121        _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
122            "SetSendCodec() invalid number of channels");
123        return -1;
124    }
125    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
126    voe::Channel* channelPtr = ch.channel();
127    if (channelPtr == NULL)
128    {
129        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
130            "GetSendCodec() failed to locate channel");
131        return -1;
132    }
133    if (!AudioCodingModule::IsCodecValid(
134            (CodecInst&) copyCodec))
135    {
136        _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
137            "SetSendCodec() invalid codec");
138        return -1;
139    }
140    if (channelPtr->SetSendCodec(copyCodec) != 0)
141    {
142        _shared->SetLastError(VE_CANNOT_SET_SEND_CODEC, kTraceError,
143            "SetSendCodec() failed to set send codec");
144        return -1;
145    }
146
147    return 0;
148}
149
150int VoECodecImpl::GetSendCodec(int channel, CodecInst& codec)
151{
152    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
153                 "GetSendCodec(channel=%d, codec=?)", channel);
154    if (!_shared->statistics().Initialized())
155    {
156        _shared->SetLastError(VE_NOT_INITED, kTraceError);
157        return -1;
158    }
159    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
160    voe::Channel* channelPtr = ch.channel();
161    if (channelPtr == NULL)
162    {
163        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
164            "GetSendCodec() failed to locate channel");
165        return -1;
166    }
167    CodecInst acmCodec;
168    if (channelPtr->GetSendCodec(acmCodec) != 0)
169    {
170        _shared->SetLastError(VE_CANNOT_GET_SEND_CODEC, kTraceError,
171            "GetSendCodec() failed to get send codec");
172        return -1;
173    }
174    ACMToExternalCodecRepresentation(codec, acmCodec);
175    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
176        VoEId(_shared->instance_id(), -1),
177        "GetSendCodec() => plname=%s, pacsize=%d, plfreq=%d, "
178        "channels=%d, rate=%d", codec.plname, codec.pacsize,
179        codec.plfreq, codec.channels, codec.rate);
180    return 0;
181}
182
183int VoECodecImpl::GetRecCodec(int channel, CodecInst& codec)
184{
185    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
186                 "GetRecCodec(channel=%d, codec=?)", channel);
187    if (!_shared->statistics().Initialized())
188    {
189        _shared->SetLastError(VE_NOT_INITED, kTraceError);
190        return -1;
191    }
192    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
193    voe::Channel* channelPtr = ch.channel();
194    if (channelPtr == NULL)
195    {
196        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
197            "GetRecCodec() failed to locate channel");
198        return -1;
199    }
200    CodecInst acmCodec;
201    if (channelPtr->GetRecCodec(acmCodec) != 0)
202    {
203        _shared->SetLastError(VE_CANNOT_GET_REC_CODEC, kTraceError,
204            "GetRecCodec() failed to get received codec");
205        return -1;
206    }
207    ACMToExternalCodecRepresentation(codec, acmCodec);
208    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
209        VoEId(_shared->instance_id(), -1),
210        "GetRecCodec() => plname=%s, pacsize=%d, plfreq=%d, "
211        "channels=%d, rate=%d", codec.plname, codec.pacsize,
212        codec.plfreq, codec.channels, codec.rate);
213    return 0;
214}
215
216int VoECodecImpl::SetRecPayloadType(int channel, const CodecInst& codec)
217{
218    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
219                 "SetRecPayloadType(channel=%d, codec)", channel);
220    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
221               "codec: plname=%s, plfreq=%d, pltype=%d, channels=%u, "
222               "pacsize=%d, rate=%d", codec.plname, codec.plfreq, codec.pltype,
223               codec.channels, codec.pacsize, codec.rate);
224    if (!_shared->statistics().Initialized())
225    {
226        _shared->SetLastError(VE_NOT_INITED, kTraceError);
227        return -1;
228    }
229    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
230    voe::Channel* channelPtr = ch.channel();
231    if (channelPtr == NULL)
232    {
233        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
234            "GetRecPayloadType() failed to locate channel");
235        return -1;
236    }
237    return channelPtr->SetRecPayloadType(codec);
238}
239
240int VoECodecImpl::GetRecPayloadType(int channel, CodecInst& codec)
241{
242    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
243                 "GetRecPayloadType(channel=%d, codec)", channel);
244    if (!_shared->statistics().Initialized())
245    {
246        _shared->SetLastError(VE_NOT_INITED, kTraceError);
247        return -1;
248    }
249    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
250    voe::Channel* channelPtr = ch.channel();
251    if (channelPtr == NULL)
252    {
253        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
254            "GetRecPayloadType() failed to locate channel");
255        return -1;
256    }
257    return channelPtr->GetRecPayloadType(codec);
258}
259
260int VoECodecImpl::SetSendCNPayloadType(int channel, int type,
261                                       PayloadFrequencies frequency)
262{
263    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
264                 "SetSendCNPayloadType(channel=%d, type=%d, frequency=%d)",
265                 channel, type, frequency);
266    if (!_shared->statistics().Initialized())
267    {
268        _shared->SetLastError(VE_NOT_INITED, kTraceError);
269        return -1;
270    }
271    if (type < 96 || type > 127)
272    {
273        // Only allow dynamic range: 96 to 127
274        _shared->SetLastError(VE_INVALID_PLTYPE, kTraceError,
275            "SetSendCNPayloadType() invalid payload type");
276        return -1;
277    }
278    if ((frequency != kFreq16000Hz) && (frequency != kFreq32000Hz))
279    {
280        // It is not possible to modify the payload type for CN/8000.
281        // We only allow modification of the CN payload type for CN/16000
282        // and CN/32000.
283        _shared->SetLastError(VE_INVALID_PLFREQ, kTraceError,
284            "SetSendCNPayloadType() invalid payload frequency");
285        return -1;
286    }
287    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
288    voe::Channel* channelPtr = ch.channel();
289    if (channelPtr == NULL)
290    {
291        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
292            "SetSendCNPayloadType() failed to locate channel");
293        return -1;
294    }
295    return channelPtr->SetSendCNPayloadType(type, frequency);
296}
297
298int VoECodecImpl::SetFECStatus(int channel, bool enable) {
299  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
300               "SetCodecFECStatus(channel=%d, enable=%d)", channel, enable);
301  if (!_shared->statistics().Initialized()) {
302    _shared->SetLastError(VE_NOT_INITED, kTraceError);
303    return -1;
304  }
305  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
306  voe::Channel* channelPtr = ch.channel();
307  if (channelPtr == NULL) {
308    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
309                          "SetCodecFECStatus() failed to locate channel");
310    return -1;
311  }
312  return channelPtr->SetCodecFECStatus(enable);
313}
314
315int VoECodecImpl::GetFECStatus(int channel, bool& enabled) {
316  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
317               "GetCodecFECStatus(channel=%d)", channel);
318  if (!_shared->statistics().Initialized()) {
319    _shared->SetLastError(VE_NOT_INITED, kTraceError);
320    return -1;
321  }
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                          "GetFECStatus() failed to locate channel");
327    return -1;
328  }
329  enabled = channelPtr->GetCodecFECStatus();
330  return 0;
331}
332
333int VoECodecImpl::SetVADStatus(int channel, bool enable, VadModes mode,
334                               bool disableDTX)
335{
336    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
337                 "SetVADStatus(channel=%i, enable=%i, mode=%i, disableDTX=%i)",
338                 channel, enable, mode, disableDTX);
339
340    if (!_shared->statistics().Initialized())
341    {
342        _shared->SetLastError(VE_NOT_INITED, kTraceError);
343        return -1;
344    }
345    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
346    voe::Channel* channelPtr = ch.channel();
347    if (channelPtr == NULL)
348    {
349        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
350            "SetVADStatus failed to locate channel");
351        return -1;
352    }
353
354    ACMVADMode vadMode(VADNormal);
355    switch (mode)
356    {
357        case kVadConventional:
358            vadMode = VADNormal;
359            break;
360        case kVadAggressiveLow:
361            vadMode = VADLowBitrate;
362            break;
363        case kVadAggressiveMid:
364            vadMode = VADAggr;
365            break;
366        case kVadAggressiveHigh:
367            vadMode = VADVeryAggr;
368            break;
369    }
370    return channelPtr->SetVADStatus(enable, vadMode, disableDTX);
371}
372
373int VoECodecImpl::GetVADStatus(int channel, bool& enabled, VadModes& mode,
374                               bool& disabledDTX)
375{
376    WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
377                 "GetVADStatus(channel=%i)", channel);
378
379    if (!_shared->statistics().Initialized())
380    {
381        _shared->SetLastError(VE_NOT_INITED, kTraceError);
382        return -1;
383    }
384    voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
385    voe::Channel* channelPtr = ch.channel();
386    if (channelPtr == NULL)
387    {
388        _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
389            "GetVADStatus failed to locate channel");
390        return -1;
391    }
392
393    ACMVADMode vadMode;
394    int ret = channelPtr->GetVADStatus(enabled, vadMode, disabledDTX);
395
396    if (ret != 0)
397    {
398        _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
399            "GetVADStatus failed to get VAD mode");
400        return -1;
401    }
402    switch (vadMode)
403    {
404        case VADNormal:
405            mode = kVadConventional;
406            break;
407        case VADLowBitrate:
408            mode = kVadAggressiveLow;
409            break;
410        case VADAggr:
411            mode = kVadAggressiveMid;
412            break;
413        case VADVeryAggr:
414            mode = kVadAggressiveHigh;
415            break;
416    }
417
418    return 0;
419}
420
421int VoECodecImpl::SetOpusMaxPlaybackRate(int channel, int frequency_hz) {
422  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
423               "SetOpusMaxPlaybackRate(channel=%d, frequency_hz=%d)", channel,
424               frequency_hz);
425  if (!_shared->statistics().Initialized()) {
426    _shared->SetLastError(VE_NOT_INITED, kTraceError);
427    return -1;
428  }
429  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
430  voe::Channel* channelPtr = ch.channel();
431  if (channelPtr == NULL) {
432    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
433                          "SetOpusMaxPlaybackRate failed to locate channel");
434    return -1;
435  }
436  return channelPtr->SetOpusMaxPlaybackRate(frequency_hz);
437}
438
439void VoECodecImpl::ACMToExternalCodecRepresentation(CodecInst& toInst,
440                                                    const CodecInst& fromInst)
441{
442    toInst = fromInst;
443    if (STR_CASE_CMP(fromInst.plname,"SILK") == 0)
444    {
445        if (fromInst.plfreq == 12000)
446        {
447            if (fromInst.pacsize == 320)
448            {
449                toInst.pacsize = 240;
450            }
451            else if (fromInst.pacsize == 640)
452            {
453                toInst.pacsize = 480;
454            }
455            else if (fromInst.pacsize == 960)
456            {
457                toInst.pacsize = 720;
458            }
459        }
460        else if (fromInst.plfreq == 24000)
461        {
462            if (fromInst.pacsize == 640)
463            {
464                toInst.pacsize = 480;
465            }
466            else if (fromInst.pacsize == 1280)
467            {
468                toInst.pacsize = 960;
469            }
470            else if (fromInst.pacsize == 1920)
471            {
472                toInst.pacsize = 1440;
473            }
474        }
475    }
476}
477
478void VoECodecImpl::ExternalToACMCodecRepresentation(CodecInst& toInst,
479                                                    const CodecInst& fromInst)
480{
481    toInst = fromInst;
482    if (STR_CASE_CMP(fromInst.plname,"SILK") == 0)
483    {
484        if (fromInst.plfreq == 12000)
485        {
486            if (fromInst.pacsize == 240)
487            {
488                toInst.pacsize = 320;
489            }
490            else if (fromInst.pacsize == 480)
491            {
492                toInst.pacsize = 640;
493            }
494            else if (fromInst.pacsize == 720)
495            {
496                toInst.pacsize = 960;
497            }
498        }
499        else if (fromInst.plfreq == 24000)
500        {
501            if (fromInst.pacsize == 480)
502            {
503                toInst.pacsize = 640;
504            }
505            else if (fromInst.pacsize == 960)
506            {
507                toInst.pacsize = 1280;
508            }
509            else if (fromInst.pacsize == 1440)
510            {
511                toInst.pacsize = 1920;
512            }
513        }
514    }
515}
516
517int VoECodecImpl::SetSecondarySendCodec(int channel, const CodecInst& codec,
518                                        int red_payload_type) {
519  CodecInst copy_codec;
520  ExternalToACMCodecRepresentation(copy_codec, codec);
521
522  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
523               "SetSecondarySendCodec(channel=%d, codec)", channel);
524  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
525               "codec: plname=%s, pacsize=%d, plfreq=%d, pltype=%d, "
526               "channels=%d, rate=%d", codec.plname, codec.pacsize,
527               codec.plfreq, codec.pltype, codec.channels, codec.rate);
528  if (!_shared->statistics().Initialized()) {
529    _shared->SetLastError(VE_NOT_INITED, kTraceError);
530    return -1;
531  }
532
533  // External sanity checks performed outside the ACM
534  if ((STR_CASE_CMP(copy_codec.plname, "L16") == 0) &&
535      (copy_codec.pacsize >= 960)) {
536    _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
537                          "SetSecondarySendCodec() invalid L16 packet size");
538    return -1;
539  }
540
541  // None of the following codecs can be registered as the secondary encoder.
542  if (!STR_CASE_CMP(copy_codec.plname, "CN") ||
543      !STR_CASE_CMP(copy_codec.plname, "TELEPHONE-EVENT") ||
544      !STR_CASE_CMP(copy_codec.plname, "RED"))  {
545    _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
546                          "SetSecondarySendCodec() invalid codec name");
547    return -1;
548  }
549
550  // Only mono and stereo are supported.
551  if ((copy_codec.channels != 1) && (copy_codec.channels != 2)) {
552    _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
553                          "SetSecondarySendCodec() invalid number of channels");
554    return -1;
555  }
556  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
557  voe::Channel* channelPtr = ch.channel();
558  if (channelPtr == NULL) {
559    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
560                          "SetSecondarySendCodec() failed to locate channel");
561    return -1;
562  }
563  if (!AudioCodingModule::IsCodecValid(copy_codec)) {
564    _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
565                          "SetSecondarySendCodec() invalid codec");
566    return -1;
567  }
568  if (channelPtr->SetSecondarySendCodec(copy_codec, red_payload_type) != 0) {
569    _shared->SetLastError(VE_CANNOT_SET_SECONDARY_SEND_CODEC, kTraceError,
570                          "SetSecondarySendCodec() failed to set secondary "
571                          "send codec");
572    return -1;
573  }
574  return 0;
575}
576
577int VoECodecImpl::GetSecondarySendCodec(int channel, CodecInst& codec) {
578  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
579               "GetSecondarySendCodec(channel=%d, codec=?)", channel);
580  if (!_shared->statistics().Initialized()) {
581    _shared->SetLastError(VE_NOT_INITED, kTraceError);
582    return -1;
583  }
584  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
585  voe::Channel* channelPtr = ch.channel();
586  if (channelPtr == NULL) {
587    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
588                          "GetSecondarySendCodec() failed to locate channel");
589    return -1;
590  }
591  CodecInst acm_codec;
592  if (channelPtr->GetSecondarySendCodec(&acm_codec) != 0) {
593    _shared->SetLastError(VE_CANNOT_GET_SECONDARY_SEND_CODEC, kTraceError,
594                          "GetSecondarySendCodec() failed to get secondary "
595                          "send codec");
596    return -1;
597  }
598  ACMToExternalCodecRepresentation(codec, acm_codec);
599  WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
600               VoEId(_shared->instance_id(), -1),
601               "GetSecondarySendCodec() => plname=%s, pacsize=%d, plfreq=%d, "
602               "channels=%d, rate=%d", codec.plname, codec.pacsize,
603               codec.plfreq, codec.channels, codec.rate);
604  return 0;
605}
606
607int VoECodecImpl::RemoveSecondarySendCodec(int channel) {
608  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
609               "RemoveSecondarySendCodec(channel=%d)", channel);
610  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
611  voe::Channel* channelPtr = ch.channel();
612  if (channelPtr == NULL) {
613    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
614                          "RemoveSecondarySendCodec() failed to locate "
615                          "channel");
616    return -1;
617  }
618  channelPtr->RemoveSecondarySendCodec();
619  return 0;
620}
621
622#endif  // WEBRTC_VOICE_ENGINE_CODEC_API
623
624}  // namespace webrtc
625