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/base/format_macros.h"
14#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
15#include "webrtc/system_wrappers/include/critical_section_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/voice_engine_impl.h"
20
21namespace webrtc {
22
23VoECodec* VoECodec::GetInterface(VoiceEngine* voiceEngine) {
24#ifndef WEBRTC_VOICE_ENGINE_CODEC_API
25  return NULL;
26#else
27  if (NULL == voiceEngine) {
28    return NULL;
29  }
30  VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
31  s->AddRef();
32  return s;
33#endif
34}
35
36#ifdef WEBRTC_VOICE_ENGINE_CODEC_API
37
38VoECodecImpl::VoECodecImpl(voe::SharedData* shared) : _shared(shared) {
39  WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
40               "VoECodecImpl() - ctor");
41}
42
43VoECodecImpl::~VoECodecImpl() {
44  WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
45               "~VoECodecImpl() - dtor");
46}
47
48int VoECodecImpl::NumOfCodecs() {
49  // Number of supported codecs in the ACM
50  uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
51  return (nSupportedCodecs);
52}
53
54int VoECodecImpl::GetCodec(int index, CodecInst& codec) {
55  if (AudioCodingModule::Codec(index, &codec) == -1) {
56    _shared->SetLastError(VE_INVALID_LISTNR, kTraceError,
57                          "GetCodec() invalid index");
58    return -1;
59  }
60  return 0;
61}
62
63int VoECodecImpl::SetSendCodec(int channel, const CodecInst& codec) {
64  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
65               "SetSendCodec(channel=%d, codec)", channel);
66  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
67               "codec: plname=%s, pacsize=%d, plfreq=%d, pltype=%d, "
68               "channels=%" PRIuS ", rate=%d",
69               codec.plname, codec.pacsize, codec.plfreq, codec.pltype,
70               codec.channels, codec.rate);
71  if (!_shared->statistics().Initialized()) {
72    _shared->SetLastError(VE_NOT_INITED, kTraceError);
73    return -1;
74  }
75  // External sanity checks performed outside the ACM
76  if ((STR_CASE_CMP(codec.plname, "L16") == 0) && (codec.pacsize >= 960)) {
77    _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
78                          "SetSendCodec() invalid L16 packet size");
79    return -1;
80  }
81  if (!STR_CASE_CMP(codec.plname, "CN") ||
82      !STR_CASE_CMP(codec.plname, "TELEPHONE-EVENT") ||
83      !STR_CASE_CMP(codec.plname, "RED")) {
84    _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
85                          "SetSendCodec() invalid codec name");
86    return -1;
87  }
88  if ((codec.channels != 1) && (codec.channels != 2)) {
89    _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
90                          "SetSendCodec() invalid number of channels");
91    return -1;
92  }
93  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
94  voe::Channel* channelPtr = ch.channel();
95  if (channelPtr == NULL) {
96    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
97                          "GetSendCodec() failed to locate channel");
98    return -1;
99  }
100  if (!AudioCodingModule::IsCodecValid(codec)) {
101    _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
102                          "SetSendCodec() invalid codec");
103    return -1;
104  }
105  if (channelPtr->SetSendCodec(codec) != 0) {
106    _shared->SetLastError(VE_CANNOT_SET_SEND_CODEC, kTraceError,
107                          "SetSendCodec() failed to set send codec");
108    return -1;
109  }
110
111  return 0;
112}
113
114int VoECodecImpl::GetSendCodec(int channel, CodecInst& codec) {
115  if (!_shared->statistics().Initialized()) {
116    _shared->SetLastError(VE_NOT_INITED, kTraceError);
117    return -1;
118  }
119  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
120  voe::Channel* channelPtr = ch.channel();
121  if (channelPtr == NULL) {
122    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
123                          "GetSendCodec() failed to locate channel");
124    return -1;
125  }
126  if (channelPtr->GetSendCodec(codec) != 0) {
127    _shared->SetLastError(VE_CANNOT_GET_SEND_CODEC, kTraceError,
128                          "GetSendCodec() failed to get send codec");
129    return -1;
130  }
131  return 0;
132}
133
134int VoECodecImpl::SetBitRate(int channel, int bitrate_bps) {
135  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
136               "SetBitRate(bitrate_bps=%d)", bitrate_bps);
137  if (!_shared->statistics().Initialized()) {
138    _shared->SetLastError(VE_NOT_INITED, kTraceError);
139    return -1;
140  }
141  _shared->channel_manager().GetChannel(channel).channel()->SetBitRate(
142      bitrate_bps);
143  return 0;
144}
145
146int VoECodecImpl::GetRecCodec(int channel, CodecInst& codec) {
147  if (!_shared->statistics().Initialized()) {
148    _shared->SetLastError(VE_NOT_INITED, kTraceError);
149    return -1;
150  }
151  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
152  voe::Channel* channelPtr = ch.channel();
153  if (channelPtr == NULL) {
154    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
155                          "GetRecCodec() failed to locate channel");
156    return -1;
157  }
158  return channelPtr->GetRecCodec(codec);
159}
160
161int VoECodecImpl::SetRecPayloadType(int channel, const CodecInst& codec) {
162  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
163               "SetRecPayloadType(channel=%d, codec)", channel);
164  WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1),
165               "codec: plname=%s, plfreq=%d, pltype=%d, channels=%" PRIuS ", "
166               "pacsize=%d, rate=%d",
167               codec.plname, codec.plfreq, codec.pltype, codec.channels,
168               codec.pacsize, codec.rate);
169  if (!_shared->statistics().Initialized()) {
170    _shared->SetLastError(VE_NOT_INITED, kTraceError);
171    return -1;
172  }
173  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
174  voe::Channel* channelPtr = ch.channel();
175  if (channelPtr == NULL) {
176    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
177                          "GetRecPayloadType() failed to locate channel");
178    return -1;
179  }
180  return channelPtr->SetRecPayloadType(codec);
181}
182
183int VoECodecImpl::GetRecPayloadType(int channel, CodecInst& codec) {
184  if (!_shared->statistics().Initialized()) {
185    _shared->SetLastError(VE_NOT_INITED, kTraceError);
186    return -1;
187  }
188  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
189  voe::Channel* channelPtr = ch.channel();
190  if (channelPtr == NULL) {
191    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
192                          "GetRecPayloadType() failed to locate channel");
193    return -1;
194  }
195  return channelPtr->GetRecPayloadType(codec);
196}
197
198int VoECodecImpl::SetSendCNPayloadType(int channel,
199                                       int type,
200                                       PayloadFrequencies frequency) {
201  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
202               "SetSendCNPayloadType(channel=%d, type=%d, frequency=%d)",
203               channel, type, frequency);
204  if (!_shared->statistics().Initialized()) {
205    _shared->SetLastError(VE_NOT_INITED, kTraceError);
206    return -1;
207  }
208  if (type < 96 || type > 127) {
209    // Only allow dynamic range: 96 to 127
210    _shared->SetLastError(VE_INVALID_PLTYPE, kTraceError,
211                          "SetSendCNPayloadType() invalid payload type");
212    return -1;
213  }
214  if ((frequency != kFreq16000Hz) && (frequency != kFreq32000Hz)) {
215    // It is not possible to modify the payload type for CN/8000.
216    // We only allow modification of the CN payload type for CN/16000
217    // and CN/32000.
218    _shared->SetLastError(VE_INVALID_PLFREQ, kTraceError,
219                          "SetSendCNPayloadType() invalid payload frequency");
220    return -1;
221  }
222  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
223  voe::Channel* channelPtr = ch.channel();
224  if (channelPtr == NULL) {
225    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
226                          "SetSendCNPayloadType() failed to locate channel");
227    return -1;
228  }
229  return channelPtr->SetSendCNPayloadType(type, frequency);
230}
231
232int VoECodecImpl::SetFECStatus(int channel, bool enable) {
233  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
234               "SetCodecFECStatus(channel=%d, enable=%d)", channel, enable);
235  if (!_shared->statistics().Initialized()) {
236    _shared->SetLastError(VE_NOT_INITED, kTraceError);
237    return -1;
238  }
239  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
240  voe::Channel* channelPtr = ch.channel();
241  if (channelPtr == NULL) {
242    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
243                          "SetCodecFECStatus() failed to locate channel");
244    return -1;
245  }
246  return channelPtr->SetCodecFECStatus(enable);
247}
248
249int VoECodecImpl::GetFECStatus(int channel, bool& enabled) {
250  if (!_shared->statistics().Initialized()) {
251    _shared->SetLastError(VE_NOT_INITED, kTraceError);
252    return -1;
253  }
254  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
255  voe::Channel* channelPtr = ch.channel();
256  if (channelPtr == NULL) {
257    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
258                          "GetFECStatus() failed to locate channel");
259    return -1;
260  }
261  enabled = channelPtr->GetCodecFECStatus();
262  return 0;
263}
264
265int VoECodecImpl::SetVADStatus(int channel,
266                               bool enable,
267                               VadModes mode,
268                               bool disableDTX) {
269  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
270               "SetVADStatus(channel=%i, enable=%i, mode=%i, disableDTX=%i)",
271               channel, enable, mode, disableDTX);
272
273  if (!_shared->statistics().Initialized()) {
274    _shared->SetLastError(VE_NOT_INITED, kTraceError);
275    return -1;
276  }
277  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
278  voe::Channel* channelPtr = ch.channel();
279  if (channelPtr == NULL) {
280    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
281                          "SetVADStatus failed to locate channel");
282    return -1;
283  }
284
285  ACMVADMode vadMode(VADNormal);
286  switch (mode) {
287    case kVadConventional:
288      vadMode = VADNormal;
289      break;
290    case kVadAggressiveLow:
291      vadMode = VADLowBitrate;
292      break;
293    case kVadAggressiveMid:
294      vadMode = VADAggr;
295      break;
296    case kVadAggressiveHigh:
297      vadMode = VADVeryAggr;
298      break;
299  }
300  return channelPtr->SetVADStatus(enable, vadMode, disableDTX);
301}
302
303int VoECodecImpl::GetVADStatus(int channel,
304                               bool& enabled,
305                               VadModes& mode,
306                               bool& disabledDTX) {
307  if (!_shared->statistics().Initialized()) {
308    _shared->SetLastError(VE_NOT_INITED, kTraceError);
309    return -1;
310  }
311  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
312  voe::Channel* channelPtr = ch.channel();
313  if (channelPtr == NULL) {
314    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
315                          "GetVADStatus failed to locate channel");
316    return -1;
317  }
318
319  ACMVADMode vadMode;
320  int ret = channelPtr->GetVADStatus(enabled, vadMode, disabledDTX);
321
322  if (ret != 0) {
323    _shared->SetLastError(VE_INVALID_OPERATION, kTraceError,
324                          "GetVADStatus failed to get VAD mode");
325    return -1;
326  }
327  switch (vadMode) {
328    case VADNormal:
329      mode = kVadConventional;
330      break;
331    case VADLowBitrate:
332      mode = kVadAggressiveLow;
333      break;
334    case VADAggr:
335      mode = kVadAggressiveMid;
336      break;
337    case VADVeryAggr:
338      mode = kVadAggressiveHigh;
339      break;
340  }
341
342  return 0;
343}
344
345int VoECodecImpl::SetOpusMaxPlaybackRate(int channel, int frequency_hz) {
346  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
347               "SetOpusMaxPlaybackRate(channel=%d, frequency_hz=%d)", channel,
348               frequency_hz);
349  if (!_shared->statistics().Initialized()) {
350    _shared->SetLastError(VE_NOT_INITED, kTraceError);
351    return -1;
352  }
353  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
354  voe::Channel* channelPtr = ch.channel();
355  if (channelPtr == NULL) {
356    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
357                          "SetOpusMaxPlaybackRate failed to locate channel");
358    return -1;
359  }
360  return channelPtr->SetOpusMaxPlaybackRate(frequency_hz);
361}
362
363int VoECodecImpl::SetOpusDtx(int channel, bool enable_dtx) {
364  WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
365               "SetOpusDtx(channel=%d, enable_dtx=%d)", channel, enable_dtx);
366  if (!_shared->statistics().Initialized()) {
367    _shared->SetLastError(VE_NOT_INITED, kTraceError);
368    return -1;
369  }
370  voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
371  voe::Channel* channelPtr = ch.channel();
372  if (channelPtr == NULL) {
373    _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
374                          "SetOpusDtx failed to locate channel");
375    return -1;
376  }
377  return channelPtr->SetOpusDtx(enable_dtx);
378}
379
380RtcEventLog* VoECodecImpl::GetEventLog() {
381  return _shared->channel_manager().GetEventLog();
382}
383
384#endif  // WEBRTC_VOICE_ENGINE_CODEC_API
385
386}  // namespace webrtc
387