aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/audio_coding/main/acm2/acm_codec_database.cc
blob: f7842ce5b174dcb279c2dac07d98063eff2050b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

/*
 * This file generates databases with information about all supported audio
 * codecs.
 */

// TODO(tlegrand): Change constant input pointers in all functions to constant
// references, where appropriate.
#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"

#include <assert.h>

#include "webrtc/base/checks.h"
#include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
#include "webrtc/system_wrappers/include/trace.h"

namespace webrtc {

namespace acm2 {

namespace {

// Checks if the bitrate is valid for the codec.
bool IsRateValid(int codec_id, int rate) {
  return ACMCodecDB::database_[codec_id].rate == rate;
}

// Checks if the bitrate is valid for iSAC.
bool IsISACRateValid(int rate) {
  return (rate == -1) || ((rate <= 56000) && (rate >= 10000));
}

// Checks if the bitrate is valid for iLBC.
bool IsILBCRateValid(int rate, int frame_size_samples) {
  if (((frame_size_samples == 240) || (frame_size_samples == 480)) &&
      (rate == 13300)) {
    return true;
  } else if (((frame_size_samples == 160) || (frame_size_samples == 320)) &&
      (rate == 15200)) {
    return true;
  } else {
    return false;
  }
}

// Checks if the bitrate is valid for Opus.
bool IsOpusRateValid(int rate) {
  return (rate >= 6000) && (rate <= 510000);
}

}  // namespace

// Not yet used payload-types.
// 83,  82,  81, 80, 79,  78,  77,  76,  75,  74,  73,  72,  71,  70,  69, 68,
// 67, 66, 65

const CodecInst ACMCodecDB::database_[] = {
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
  {103, "ISAC", 16000, kIsacPacSize480, 1, kIsacWbDefaultRate},
# if (defined(WEBRTC_CODEC_ISAC))
  {104, "ISAC", 32000, kIsacPacSize960, 1, kIsacSwbDefaultRate},
# endif
#endif
  // Mono
  {107, "L16", 8000, 80, 1, 128000},
  {108, "L16", 16000, 160, 1, 256000},
  {109, "L16", 32000, 320, 1, 512000},
  // Stereo
  {111, "L16", 8000, 80, 2, 128000},
  {112, "L16", 16000, 160, 2, 256000},
  {113, "L16", 32000, 320, 2, 512000},
  // G.711, PCM mu-law and A-law.
  // Mono
  {0, "PCMU", 8000, 160, 1, 64000},
  {8, "PCMA", 8000, 160, 1, 64000},
  // Stereo
  {110, "PCMU", 8000, 160, 2, 64000},
  {118, "PCMA", 8000, 160, 2, 64000},
#ifdef WEBRTC_CODEC_ILBC
  {102, "ILBC", 8000, 240, 1, 13300},
#endif
#ifdef WEBRTC_CODEC_G722
  // Mono
  {9, "G722", 16000, 320, 1, 64000},
  // Stereo
  {119, "G722", 16000, 320, 2, 64000},
#endif
#ifdef WEBRTC_CODEC_OPUS
  // Opus internally supports 48, 24, 16, 12, 8 kHz.
  // Mono and stereo.
  {120, "opus", 48000, 960, 2, 64000},
#endif
  // Comfort noise for four different sampling frequencies.
  {13, "CN", 8000, 240, 1, 0},
  {98, "CN", 16000, 480, 1, 0},
  {99, "CN", 32000, 960, 1, 0},
#ifdef ENABLE_48000_HZ
  {100, "CN", 48000, 1440, 1, 0},
#endif
  {106, "telephone-event", 8000, 240, 1, 0},
#ifdef WEBRTC_CODEC_RED
  {127, "red", 8000, 0, 1, 0},
#endif
  // To prevent compile errors due to trailing commas.
  {-1, "Null", -1, -1, -1, -1}
};

// Create database with all codec settings at compile time.
// Each entry needs the following parameters in the given order:
// Number of allowed packet sizes, a vector with the allowed packet sizes,
// Basic block samples, max number of channels that are supported.
const ACMCodecDB::CodecSettings ACMCodecDB::codec_settings_[] = {
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
    {2, {kIsacPacSize480, kIsacPacSize960}, 0, 1},
# if (defined(WEBRTC_CODEC_ISAC))
    {1, {kIsacPacSize960}, 0, 1},
# endif
#endif
    // Mono
    {4, {80, 160, 240, 320}, 0, 2},
    {4, {160, 320, 480, 640}, 0, 2},
    {2, {320, 640}, 0, 2},
    // Stereo
    {4, {80, 160, 240, 320}, 0, 2},
    {4, {160, 320, 480, 640}, 0, 2},
    {2, {320, 640}, 0, 2},
    // G.711, PCM mu-law and A-law.
    // Mono
    {6, {80, 160, 240, 320, 400, 480}, 0, 2},
    {6, {80, 160, 240, 320, 400, 480}, 0, 2},
    // Stereo
    {6, {80, 160, 240, 320, 400, 480}, 0, 2},
    {6, {80, 160, 240, 320, 400, 480}, 0, 2},
#ifdef WEBRTC_CODEC_ILBC
    {4, {160, 240, 320, 480}, 0, 1},
#endif
#ifdef WEBRTC_CODEC_G722
    // Mono
    {6, {160, 320, 480, 640, 800, 960}, 0, 2},
    // Stereo
    {6, {160, 320, 480, 640, 800, 960}, 0, 2},
#endif
#ifdef WEBRTC_CODEC_OPUS
    // Opus supports frames shorter than 10ms,
    // but it doesn't help us to use them.
    // Mono and stereo.
    {4, {480, 960, 1920, 2880}, 0, 2},
#endif
    // Comfort noise for three different sampling frequencies.
    {1, {240}, 240, 1},
    {1, {480}, 480, 1},
    {1, {960}, 960, 1},
#ifdef ENABLE_48000_HZ
    {1, {1440}, 1440, 1},
#endif
    {1, {240}, 240, 1},
#ifdef WEBRTC_CODEC_RED
    {1, {0}, 0, 1},
#endif
    // To prevent compile errors due to trailing commas.
    {-1, {-1}, -1, -1}
};

// Create a database of all NetEQ decoders at compile time.
const NetEqDecoder ACMCodecDB::neteq_decoders_[] = {
#if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX))
    NetEqDecoder::kDecoderISAC,
# if (defined(WEBRTC_CODEC_ISAC))
    NetEqDecoder::kDecoderISACswb,
# endif
#endif
    // Mono
    NetEqDecoder::kDecoderPCM16B, NetEqDecoder::kDecoderPCM16Bwb,
    NetEqDecoder::kDecoderPCM16Bswb32kHz,
    // Stereo
    NetEqDecoder::kDecoderPCM16B_2ch, NetEqDecoder::kDecoderPCM16Bwb_2ch,
    NetEqDecoder::kDecoderPCM16Bswb32kHz_2ch,
    // G.711, PCM mu-las and A-law.
    // Mono
    NetEqDecoder::kDecoderPCMu, NetEqDecoder::kDecoderPCMa,
    // Stereo
    NetEqDecoder::kDecoderPCMu_2ch, NetEqDecoder::kDecoderPCMa_2ch,
#ifdef WEBRTC_CODEC_ILBC
    NetEqDecoder::kDecoderILBC,
#endif
#ifdef WEBRTC_CODEC_G722
    // Mono
    NetEqDecoder::kDecoderG722,
    // Stereo
    NetEqDecoder::kDecoderG722_2ch,
#endif
#ifdef WEBRTC_CODEC_OPUS
    // Mono and stereo.
    NetEqDecoder::kDecoderOpus,
#endif
    // Comfort noise for three different sampling frequencies.
    NetEqDecoder::kDecoderCNGnb, NetEqDecoder::kDecoderCNGwb,
    NetEqDecoder::kDecoderCNGswb32kHz,
#ifdef ENABLE_48000_HZ
    NetEqDecoder::kDecoderCNGswb48kHz,
#endif
    NetEqDecoder::kDecoderAVT,
#ifdef WEBRTC_CODEC_RED
    NetEqDecoder::kDecoderRED,
#endif
};

// Get codec information from database.
// TODO(tlegrand): replace memcpy with a pointer to the data base memory.
int ACMCodecDB::Codec(int codec_id, CodecInst* codec_inst) {
  // Error check to see that codec_id is not out of bounds.
  if (static_cast<size_t>(codec_id) >= RentACodec::NumberOfCodecs()) {
    return -1;
  }

  // Copy database information for the codec to the output.
  memcpy(codec_inst, &database_[codec_id], sizeof(CodecInst));

  return 0;
}

// Enumerator for error codes when asking for codec database id.
enum {
  kInvalidCodec = -10,
  kInvalidPayloadtype = -30,
  kInvalidPacketSize = -40,
  kInvalidRate = -50
};

// Gets the codec id number from the database. If there is some mismatch in
// the codec settings, the function will return an error code.
// NOTE! The first mismatch found will generate the return value.
int ACMCodecDB::CodecNumber(const CodecInst& codec_inst) {
  // Look for a matching codec in the database.
  int codec_id = CodecId(codec_inst);

  // Checks if we found a matching codec.
  if (codec_id == -1) {
    return kInvalidCodec;
  }

  // Checks the validity of payload type
  if (!ValidPayloadType(codec_inst.pltype)) {
    return kInvalidPayloadtype;
  }

  // Comfort Noise is special case, packet-size & rate is not checked.
  if (STR_CASE_CMP(database_[codec_id].plname, "CN") == 0) {
    return codec_id;
  }

  // RED is special case, packet-size & rate is not checked.
  if (STR_CASE_CMP(database_[codec_id].plname, "red") == 0) {
    return codec_id;
  }

  // Checks the validity of packet size.
  if (codec_settings_[codec_id].num_packet_sizes > 0) {
    bool packet_size_ok = false;
    int i;
    int packet_size_samples;
    for (i = 0; i < codec_settings_[codec_id].num_packet_sizes; i++) {
      packet_size_samples =
          codec_settings_[codec_id].packet_sizes_samples[i];
      if (codec_inst.pacsize == packet_size_samples) {
        packet_size_ok = true;
        break;
      }
    }

    if (!packet_size_ok) {
      return kInvalidPacketSize;
    }
  }

  if (codec_inst.pacsize < 1) {
    return kInvalidPacketSize;
  }

  // Check the validity of rate. Codecs with multiple rates have their own
  // function for this.
  if (STR_CASE_CMP("isac", codec_inst.plname) == 0) {
    return IsISACRateValid(codec_inst.rate) ? codec_id : kInvalidRate;
  } else if (STR_CASE_CMP("ilbc", codec_inst.plname) == 0) {
    return IsILBCRateValid(codec_inst.rate, codec_inst.pacsize)
        ? codec_id : kInvalidRate;
  } else if (STR_CASE_CMP("opus", codec_inst.plname) == 0) {
    return IsOpusRateValid(codec_inst.rate)
        ? codec_id : kInvalidRate;
  }

  return IsRateValid(codec_id, codec_inst.rate) ?
      codec_id : kInvalidRate;
}

// Looks for a matching payload name, frequency, and channels in the
// codec list. Need to check all three since some codecs have several codec
// entries with different frequencies and/or channels.
// Does not check other codec settings, such as payload type and packet size.
// Returns the id of the codec, or -1 if no match is found.
int ACMCodecDB::CodecId(const CodecInst& codec_inst) {
  return (CodecId(codec_inst.plname, codec_inst.plfreq,
                  codec_inst.channels));
}

int ACMCodecDB::CodecId(const char* payload_name, int frequency, int channels) {
  for (const CodecInst& ci : RentACodec::Database()) {
    bool name_match = false;
    bool frequency_match = false;
    bool channels_match = false;

    // Payload name, sampling frequency and number of channels need to match.
    // NOTE! If |frequency| is -1, the frequency is not applicable, and is
    // always treated as true, like for RED.
    name_match = (STR_CASE_CMP(ci.plname, payload_name) == 0);
    frequency_match = (frequency == ci.plfreq) || (frequency == -1);
    // The number of channels must match for all codecs but Opus.
    if (STR_CASE_CMP(payload_name, "opus") != 0) {
      channels_match = (channels == ci.channels);
    } else {
      // For opus we just check that number of channels is valid.
      channels_match = (channels == 1 || channels == 2);
    }

    if (name_match && frequency_match && channels_match) {
      // We have found a matching codec in the list.
      return &ci - RentACodec::Database().data();
    }
  }

  // We didn't find a matching codec.
  return -1;
}
// Gets codec id number from database for the receiver.
int ACMCodecDB::ReceiverCodecNumber(const CodecInst& codec_inst) {
  // Look for a matching codec in the database.
  return CodecId(codec_inst);
}

// Returns the codec sampling frequency for codec with id = "codec_id" in
// database.
int ACMCodecDB::CodecFreq(int codec_id) {
  const size_t i = static_cast<size_t>(codec_id);
  const auto db = RentACodec::Database();
  return i < db.size() ? db[i].plfreq : -1;
}

// Checks if the payload type is in the valid range.
bool ACMCodecDB::ValidPayloadType(int payload_type) {
  return (payload_type >= 0) && (payload_type <= 127);
}

}  // namespace acm2

}  // namespace webrtc