blob: 0b5bed1623753545b2087a6c61f595ea52fcf7f4 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32#ifdef HAVE_WEBRTC_VOICE
33
34#include "talk/media/webrtc/webrtcvoiceengine.h"
35
36#include <algorithm>
37#include <cstdio>
38#include <string>
39#include <vector>
40
Thiago Farinaef883092015-04-06 10:36:41 +000041#include "talk/media/base/audioframe.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000042#include "talk/media/base/audiorenderer.h"
43#include "talk/media/base/constants.h"
44#include "talk/media/base/streamparams.h"
solenberg7e4e01a2015-12-02 08:05:01 -080045#include "talk/media/webrtc/webrtcmediaengine.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000046#include "talk/media/webrtc/webrtcvoe.h"
tfarina5237aaf2015-11-10 23:44:30 -080047#include "webrtc/base/arraysize.h"
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000048#include "webrtc/base/base64.h"
49#include "webrtc/base/byteorder.h"
50#include "webrtc/base/common.h"
51#include "webrtc/base/helpers.h"
52#include "webrtc/base/logging.h"
53#include "webrtc/base/stringencode.h"
54#include "webrtc/base/stringutils.h"
ivoc112a3d82015-10-16 02:22:18 -070055#include "webrtc/call/rtc_event_log.h"
mallinath@webrtc.orga27be8e2013-09-27 23:04:10 +000056#include "webrtc/common.h"
solenberg26c8c912015-11-27 04:00:25 -080057#include "webrtc/modules/audio_coding/acm2/rent_a_codec.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058#include "webrtc/modules/audio_processing/include/audio_processing.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010059#include "webrtc/system_wrappers/include/field_trial.h"
solenbergbd138382015-11-20 16:08:07 -080060#include "webrtc/system_wrappers/include/trace.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062namespace cricket {
solenbergd97ec302015-10-07 01:40:33 -070063namespace {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064
solenbergbd138382015-11-20 16:08:07 -080065const int kDefaultTraceFilter = webrtc::kTraceNone | webrtc::kTraceTerseInfo |
66 webrtc::kTraceWarning | webrtc::kTraceError |
67 webrtc::kTraceCritical;
68const int kElevatedTraceFilter = kDefaultTraceFilter | webrtc::kTraceStateInfo |
69 webrtc::kTraceInfo;
70
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071// On Windows Vista and newer, Microsoft introduced the concept of "Default
72// Communications Device". This means that there are two types of default
73// devices (old Wave Audio style default and Default Communications Device).
74//
75// On Windows systems which only support Wave Audio style default, uses either
76// -1 or 0 to select the default device.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077#ifdef WIN32
solenbergd97ec302015-10-07 01:40:33 -070078const int kDefaultAudioDeviceId = -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079#else
solenbergd97ec302015-10-07 01:40:33 -070080const int kDefaultAudioDeviceId = 0;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081#endif
82
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083// Parameter used for NACK.
84// This value is equivalent to 5 seconds of audio data at 20 ms per packet.
solenbergd97ec302015-10-07 01:40:33 -070085const int kNackMaxPackets = 250;
minyue@webrtc.org2dc6f312014-10-31 05:33:10 +000086
87// Codec parameters for Opus.
henrike@webrtc.org1e09a712013-07-26 19:17:59 +000088// draft-spittka-payload-rtp-opus-03
minyue@webrtc.org2dc6f312014-10-31 05:33:10 +000089
90// Recommended bitrates:
91// 8-12 kb/s for NB speech,
92// 16-20 kb/s for WB speech,
93// 28-40 kb/s for FB speech,
94// 48-64 kb/s for FB mono music, and
95// 64-128 kb/s for FB stereo music.
96// The current implementation applies the following values to mono signals,
97// and multiplies them by 2 for stereo.
solenbergd97ec302015-10-07 01:40:33 -070098const int kOpusBitrateNb = 12000;
99const int kOpusBitrateWb = 20000;
100const int kOpusBitrateFb = 32000;
minyue@webrtc.org2dc6f312014-10-31 05:33:10 +0000101
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000102// Opus bitrate should be in the range between 6000 and 510000.
solenbergd97ec302015-10-07 01:40:33 -0700103const int kOpusMinBitrate = 6000;
104const int kOpusMaxBitrate = 510000;
buildbot@webrtc.org5d639b32014-09-10 07:57:12 +0000105
wu@webrtc.orgde305012013-10-31 15:40:38 +0000106// Default audio dscp value.
107// See http://tools.ietf.org/html/rfc2474 for details.
108// See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00
solenbergd97ec302015-10-07 01:40:33 -0700109const rtc::DiffServCodePoint kAudioDscpValue = rtc::DSCP_EF;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000110
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000111// Ensure we open the file in a writeable path on ChromeOS and Android. This
112// workaround can be removed when it's possible to specify a filename for audio
113// option based AEC dumps.
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000114//
115// TODO(grunell): Use a string in the options instead of hardcoding it here
116// and let the embedder choose the filename (crbug.com/264223).
117//
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000118// NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified
119// below.
120#if defined(CHROMEOS)
solenbergd97ec302015-10-07 01:40:33 -0700121const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump";
sergeyu@chromium.orga59696b2013-09-13 23:48:58 +0000122#elif defined(ANDROID)
solenbergd97ec302015-10-07 01:40:33 -0700123const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump";
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000124#else
solenbergd97ec302015-10-07 01:40:33 -0700125const char kAecDumpByAudioOptionFilename[] = "audio.aecdump";
henrike@webrtc.org1e09a712013-07-26 19:17:59 +0000126#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000127
Fredrik Solenbergb5727682015-12-04 15:22:19 +0100128// Constants from voice_engine_defines.h.
129const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1)
130const int kMaxTelephoneEventCode = 255;
131const int kMinTelephoneEventDuration = 100;
132const int kMaxTelephoneEventDuration = 60000; // Actual limit is 2^16
133
solenberg0b675462015-10-09 01:37:09 -0700134bool ValidateStreamParams(const StreamParams& sp) {
135 if (sp.ssrcs.empty()) {
136 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString();
137 return false;
138 }
139 if (sp.ssrcs.size() > 1) {
140 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString();
141 return false;
142 }
143 return true;
144}
145
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000146// Dumps an AudioCodec in RFC 2327-ish format.
solenbergd97ec302015-10-07 01:40:33 -0700147std::string ToString(const AudioCodec& codec) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000148 std::stringstream ss;
149 ss << codec.name << "/" << codec.clockrate << "/" << codec.channels
150 << " (" << codec.id << ")";
151 return ss.str();
152}
Minyue Li7100dcd2015-03-27 05:05:59 +0100153
solenbergd97ec302015-10-07 01:40:33 -0700154std::string ToString(const webrtc::CodecInst& codec) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000155 std::stringstream ss;
156 ss << codec.plname << "/" << codec.plfreq << "/" << codec.channels
157 << " (" << codec.pltype << ")";
158 return ss.str();
159}
160
solenbergd97ec302015-10-07 01:40:33 -0700161bool IsCodec(const AudioCodec& codec, const char* ref_name) {
Minyue Li7100dcd2015-03-27 05:05:59 +0100162 return (_stricmp(codec.name.c_str(), ref_name) == 0);
163}
164
solenbergd97ec302015-10-07 01:40:33 -0700165bool IsCodec(const webrtc::CodecInst& codec, const char* ref_name) {
Minyue Li7100dcd2015-03-27 05:05:59 +0100166 return (_stricmp(codec.plname, ref_name) == 0);
167}
168
solenbergd97ec302015-10-07 01:40:33 -0700169bool FindCodec(const std::vector<AudioCodec>& codecs,
solenberg26c8c912015-11-27 04:00:25 -0800170 const AudioCodec& codec,
171 AudioCodec* found_codec) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +0200172 for (const AudioCodec& c : codecs) {
173 if (c.Matches(codec)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000174 if (found_codec != NULL) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +0200175 *found_codec = c;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176 }
177 return true;
178 }
179 }
180 return false;
181}
wu@webrtc.org1d1ffc92013-10-16 18:12:02 +0000182
solenberg0b675462015-10-09 01:37:09 -0700183bool VerifyUniquePayloadTypes(const std::vector<AudioCodec>& codecs) {
184 if (codecs.empty()) {
185 return true;
186 }
187 std::vector<int> payload_types;
188 for (const AudioCodec& codec : codecs) {
189 payload_types.push_back(codec.id);
190 }
191 std::sort(payload_types.begin(), payload_types.end());
192 auto it = std::unique(payload_types.begin(), payload_types.end());
193 return it == payload_types.end();
194}
195
solenbergd97ec302015-10-07 01:40:33 -0700196bool IsNackEnabled(const AudioCodec& codec) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197 return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack,
198 kParamValueEmpty));
199}
200
Minyue Li7100dcd2015-03-27 05:05:59 +0100201// Return true if codec.params[feature] == "1", false otherwise.
solenberg26c8c912015-11-27 04:00:25 -0800202bool IsCodecFeatureEnabled(const AudioCodec& codec, const char* feature) {
Minyue Li7100dcd2015-03-27 05:05:59 +0100203 int value;
204 return codec.GetParam(feature, &value) && value == 1;
205}
206
207// Use params[kCodecParamMaxAverageBitrate] if it is defined, use codec.bitrate
208// otherwise. If the value (either from params or codec.bitrate) <=0, use the
209// default configuration. If the value is beyond feasible bit rate of Opus,
210// clamp it. Returns the Opus bit rate for operation.
solenbergd97ec302015-10-07 01:40:33 -0700211int GetOpusBitrate(const AudioCodec& codec, int max_playback_rate) {
Minyue Li7100dcd2015-03-27 05:05:59 +0100212 int bitrate = 0;
213 bool use_param = true;
214 if (!codec.GetParam(kCodecParamMaxAverageBitrate, &bitrate)) {
215 bitrate = codec.bitrate;
216 use_param = false;
217 }
218 if (bitrate <= 0) {
219 if (max_playback_rate <= 8000) {
220 bitrate = kOpusBitrateNb;
221 } else if (max_playback_rate <= 16000) {
222 bitrate = kOpusBitrateWb;
223 } else {
224 bitrate = kOpusBitrateFb;
225 }
226
227 if (IsCodecFeatureEnabled(codec, kCodecParamStereo)) {
228 bitrate *= 2;
229 }
230 } else if (bitrate < kOpusMinBitrate || bitrate > kOpusMaxBitrate) {
231 bitrate = (bitrate < kOpusMinBitrate) ? kOpusMinBitrate : kOpusMaxBitrate;
232 std::string rate_source =
233 use_param ? "Codec parameter \"maxaveragebitrate\"" :
234 "Supplied Opus bitrate";
235 LOG(LS_WARNING) << rate_source
236 << " is invalid and is replaced by: "
237 << bitrate;
238 }
239 return bitrate;
240}
241
242// Returns kOpusDefaultPlaybackRate if params[kCodecParamMaxPlaybackRate] is not
243// defined. Returns the value of params[kCodecParamMaxPlaybackRate] otherwise.
solenbergd97ec302015-10-07 01:40:33 -0700244int GetOpusMaxPlaybackRate(const AudioCodec& codec) {
Minyue Li7100dcd2015-03-27 05:05:59 +0100245 int value;
246 if (codec.GetParam(kCodecParamMaxPlaybackRate, &value)) {
247 return value;
248 }
249 return kOpusDefaultMaxPlaybackRate;
250}
251
solenbergd97ec302015-10-07 01:40:33 -0700252void GetOpusConfig(const AudioCodec& codec, webrtc::CodecInst* voe_codec,
Minyue Li7100dcd2015-03-27 05:05:59 +0100253 bool* enable_codec_fec, int* max_playback_rate,
254 bool* enable_codec_dtx) {
255 *enable_codec_fec = IsCodecFeatureEnabled(codec, kCodecParamUseInbandFec);
256 *enable_codec_dtx = IsCodecFeatureEnabled(codec, kCodecParamUseDtx);
257 *max_playback_rate = GetOpusMaxPlaybackRate(codec);
258
259 // If OPUS, change what we send according to the "stereo" codec
260 // parameter, and not the "channels" parameter. We set
261 // voe_codec.channels to 2 if "stereo=1" and 1 otherwise. If
262 // the bitrate is not specified, i.e. is <= zero, we set it to the
263 // appropriate default value for mono or stereo Opus.
264
265 voe_codec->channels = IsCodecFeatureEnabled(codec, kCodecParamStereo) ? 2 : 1;
266 voe_codec->rate = GetOpusBitrate(codec, *max_playback_rate);
267}
268
solenberg566ef242015-11-06 15:34:49 -0800269webrtc::AudioState::Config MakeAudioStateConfig(VoEWrapper* voe_wrapper) {
270 webrtc::AudioState::Config config;
271 config.voice_engine = voe_wrapper->engine();
272 return config;
273}
274
solenberg26c8c912015-11-27 04:00:25 -0800275class WebRtcVoiceCodecs final {
276 public:
277 // TODO(solenberg): Do this filtering once off-line, add a simple AudioCodec
278 // list and add a test which verifies VoE supports the listed codecs.
279 static std::vector<AudioCodec> SupportedCodecs() {
280 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
281 std::vector<AudioCodec> result;
282 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) {
283 // Change the sample rate of G722 to 8000 to match SDP.
284 MaybeFixupG722(&voe_codec, 8000);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000285 // Skip uncompressed formats.
Minyue Li7100dcd2015-03-27 05:05:59 +0100286 if (IsCodec(voe_codec, kL16CodecName)) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000287 continue;
288 }
289
290 const CodecPref* pref = NULL;
tfarina5237aaf2015-11-10 23:44:30 -0800291 for (size_t j = 0; j < arraysize(kCodecPrefs); ++j) {
Minyue Li7100dcd2015-03-27 05:05:59 +0100292 if (IsCodec(voe_codec, kCodecPrefs[j].name) &&
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000293 kCodecPrefs[j].clockrate == voe_codec.plfreq &&
294 kCodecPrefs[j].channels == voe_codec.channels) {
295 pref = &kCodecPrefs[j];
296 break;
297 }
298 }
299
300 if (pref) {
301 // Use the payload type that we've configured in our pref table;
302 // use the offset in our pref table to determine the sort order.
tfarina5237aaf2015-11-10 23:44:30 -0800303 AudioCodec codec(
304 pref->payload_type, voe_codec.plname, voe_codec.plfreq,
305 voe_codec.rate, voe_codec.channels,
306 static_cast<int>(arraysize(kCodecPrefs)) - (pref - kCodecPrefs));
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000307 LOG(LS_INFO) << ToString(codec);
Minyue Li7100dcd2015-03-27 05:05:59 +0100308 if (IsCodec(codec, kIsacCodecName)) {
minyue@webrtc.org26236952014-10-29 02:27:08 +0000309 // Indicate auto-bitrate in signaling.
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000310 codec.bitrate = 0;
311 }
Minyue Li7100dcd2015-03-27 05:05:59 +0100312 if (IsCodec(codec, kOpusCodecName)) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000313 // Only add fmtp parameters that differ from the spec.
314 if (kPreferredMinPTime != kOpusDefaultMinPTime) {
315 codec.params[kCodecParamMinPTime] =
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000316 rtc::ToString(kPreferredMinPTime);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000317 }
318 if (kPreferredMaxPTime != kOpusDefaultMaxPTime) {
319 codec.params[kCodecParamMaxPTime] =
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000320 rtc::ToString(kPreferredMaxPTime);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000321 }
pkasting@chromium.orgd3245462015-02-23 21:28:22 +0000322 codec.SetParam(kCodecParamUseInbandFec, 1);
minyue@webrtc.org4ef22d12014-11-17 09:26:39 +0000323
324 // TODO(hellner): Add ptime, sprop-stereo, and stereo
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000325 // when they can be set to values other than the default.
326 }
solenberg26c8c912015-11-27 04:00:25 -0800327 result.push_back(codec);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000328 } else {
329 LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec);
330 }
331 }
solenberg26c8c912015-11-27 04:00:25 -0800332 // Make sure they are in local preference order.
333 std::sort(result.begin(), result.end(), &AudioCodec::Preferable);
334 return result;
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000335 }
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000336
solenberg26c8c912015-11-27 04:00:25 -0800337 static bool ToCodecInst(const AudioCodec& in,
338 webrtc::CodecInst* out) {
339 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) {
340 // Change the sample rate of G722 to 8000 to match SDP.
341 MaybeFixupG722(&voe_codec, 8000);
342 AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq,
343 voe_codec.rate, voe_codec.channels, 0);
344 bool multi_rate = IsCodecMultiRate(voe_codec);
345 // Allow arbitrary rates for ISAC to be specified.
346 if (multi_rate) {
347 // Set codec.bitrate to 0 so the check for codec.Matches() passes.
348 codec.bitrate = 0;
349 }
350 if (codec.Matches(in)) {
351 if (out) {
352 // Fixup the payload type.
353 voe_codec.pltype = in.id;
354
355 // Set bitrate if specified.
356 if (multi_rate && in.bitrate != 0) {
357 voe_codec.rate = in.bitrate;
358 }
359
360 // Reset G722 sample rate to 16000 to match WebRTC.
361 MaybeFixupG722(&voe_codec, 16000);
362
363 // Apply codec-specific settings.
364 if (IsCodec(codec, kIsacCodecName)) {
365 // If ISAC and an explicit bitrate is not specified,
366 // enable auto bitrate adjustment.
367 voe_codec.rate = (in.bitrate > 0) ? in.bitrate : -1;
368 }
369 *out = voe_codec;
370 }
371 return true;
372 }
373 }
henrik.lundin@webrtc.org8038d422014-11-11 08:38:24 +0000374 return false;
henrik.lundin@webrtc.orgf85dbce2014-11-07 12:25:00 +0000375 }
solenberg26c8c912015-11-27 04:00:25 -0800376
377 static bool IsCodecMultiRate(const webrtc::CodecInst& codec) {
378 for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) {
379 if (IsCodec(codec, kCodecPrefs[i].name) &&
380 kCodecPrefs[i].clockrate == codec.plfreq) {
381 return kCodecPrefs[i].is_multi_rate;
382 }
383 }
384 return false;
385 }
386
387 // If the AudioCodec param kCodecParamPTime is set, then we will set it to
388 // codec pacsize if it's valid, or we will pick the next smallest value we
389 // support.
390 // TODO(Brave): Query supported packet sizes from ACM when the API is ready.
391 static bool SetPTimeAsPacketSize(webrtc::CodecInst* codec, int ptime_ms) {
392 for (const CodecPref& codec_pref : kCodecPrefs) {
393 if ((IsCodec(*codec, codec_pref.name) &&
394 codec_pref.clockrate == codec->plfreq) ||
395 IsCodec(*codec, kG722CodecName)) {
396 int packet_size_ms = SelectPacketSize(codec_pref, ptime_ms);
397 if (packet_size_ms) {
398 // Convert unit from milli-seconds to samples.
399 codec->pacsize = (codec->plfreq / 1000) * packet_size_ms;
400 return true;
401 }
402 }
403 }
404 return false;
405 }
406
407 private:
408 static const int kMaxNumPacketSize = 6;
409 struct CodecPref {
410 const char* name;
411 int clockrate;
412 int channels;
413 int payload_type;
414 bool is_multi_rate;
415 int packet_sizes_ms[kMaxNumPacketSize];
416 };
417 // Note: keep the supported packet sizes in ascending order.
418 static const CodecPref kCodecPrefs[12];
419
420 static int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) {
421 int selected_packet_size_ms = codec_pref.packet_sizes_ms[0];
422 for (int packet_size_ms : codec_pref.packet_sizes_ms) {
423 if (packet_size_ms && packet_size_ms <= ptime_ms) {
424 selected_packet_size_ms = packet_size_ms;
425 }
426 }
427 return selected_packet_size_ms;
428 }
429
430 // Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC
431 // which says that G722 should be advertised as 8 kHz although it is a 16 kHz
432 // codec.
433 static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) {
434 if (IsCodec(*voe_codec, kG722CodecName)) {
435 // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine
436 // has changed, and this special case is no longer needed.
437 RTC_DCHECK(voe_codec->plfreq != new_plfreq);
438 voe_codec->plfreq = new_plfreq;
439 }
440 }
441};
442
443const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[12] = {
444 { kOpusCodecName, 48000, 2, 111, true, { 10, 20, 40, 60 } },
445 { kIsacCodecName, 16000, 1, 103, true, { 30, 60 } },
446 { kIsacCodecName, 32000, 1, 104, true, { 30 } },
447 // G722 should be advertised as 8000 Hz because of the RFC "bug".
448 { kG722CodecName, 8000, 1, 9, false, { 10, 20, 30, 40, 50, 60 } },
449 { kIlbcCodecName, 8000, 1, 102, false, { 20, 30, 40, 60 } },
450 { kPcmuCodecName, 8000, 1, 0, false, { 10, 20, 30, 40, 50, 60 } },
451 { kPcmaCodecName, 8000, 1, 8, false, { 10, 20, 30, 40, 50, 60 } },
452 { kCnCodecName, 32000, 1, 106, false, { } },
453 { kCnCodecName, 16000, 1, 105, false, { } },
454 { kCnCodecName, 8000, 1, 13, false, { } },
455 { kRedCodecName, 8000, 1, 127, false, { } },
456 { kDtmfCodecName, 8000, 1, 126, false, { } },
457};
458} // namespace {
459
460bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in,
461 webrtc::CodecInst* out) {
462 return WebRtcVoiceCodecs::ToCodecInst(in, out);
463}
464
465WebRtcVoiceEngine::WebRtcVoiceEngine()
466 : voe_wrapper_(new VoEWrapper()),
467 audio_state_(webrtc::AudioState::Create(MakeAudioStateConfig(voe()))) {
468 Construct();
469}
470
471WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper)
472 : voe_wrapper_(voe_wrapper) {
473 Construct();
474}
475
476void WebRtcVoiceEngine::Construct() {
477 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
478 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine";
479
480 signal_thread_checker_.DetachFromThread();
481 std::memset(&default_agc_config_, 0, sizeof(default_agc_config_));
solenberg246b8172015-12-08 09:50:23 -0800482 voe_config_.Set<webrtc::VoicePacing>(new webrtc::VoicePacing(true));
solenberg26c8c912015-11-27 04:00:25 -0800483
484 webrtc::Trace::set_level_filter(kDefaultTraceFilter);
485 webrtc::Trace::SetTraceCallback(this);
486
487 // Load our audio codec list.
488 codecs_ = WebRtcVoiceCodecs::SupportedCodecs();
henrik.lundin@webrtc.orgf85dbce2014-11-07 12:25:00 +0000489}
490
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000491WebRtcVoiceEngine::~WebRtcVoiceEngine() {
solenberg566ef242015-11-06 15:34:49 -0800492 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000493 LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000494 if (adm_) {
495 voe_wrapper_.reset();
496 adm_->Release();
497 adm_ = NULL;
498 }
solenbergbd138382015-11-20 16:08:07 -0800499 webrtc::Trace::SetTraceCallback(nullptr);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000500}
501
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000502bool WebRtcVoiceEngine::Init(rtc::Thread* worker_thread) {
solenberg566ef242015-11-06 15:34:49 -0800503 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrikg91d6ede2015-09-17 00:24:34 -0700504 RTC_DCHECK(worker_thread == rtc::Thread::Current());
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000505 LOG(LS_INFO) << "WebRtcVoiceEngine::Init";
506 bool res = InitInternal();
507 if (res) {
508 LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!";
509 } else {
510 LOG(LS_ERROR) << "WebRtcVoiceEngine::Init failed";
511 Terminate();
512 }
513 return res;
514}
515
516bool WebRtcVoiceEngine::InitInternal() {
solenberg566ef242015-11-06 15:34:49 -0800517 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000518 // Temporarily turn logging level up for the Init call
solenbergbd138382015-11-20 16:08:07 -0800519 webrtc::Trace::set_level_filter(kElevatedTraceFilter);
solenberg2515af22015-12-02 06:19:36 -0800520 LOG(LS_INFO) << webrtc::VoiceEngine::GetVersionString();
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000521 if (voe_wrapper_->base()->Init(adm_) == -1) {
522 LOG_RTCERR0_EX(Init, voe_wrapper_->error());
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000523 return false;
524 }
solenbergbd138382015-11-20 16:08:07 -0800525 webrtc::Trace::set_level_filter(kDefaultTraceFilter);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000526
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000527 // Save the default AGC configuration settings. This must happen before
solenberg246b8172015-12-08 09:50:23 -0800528 // calling ApplyOptions or the default will be overwritten.
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000529 if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) {
530 LOG_RTCERR0(GetAgcConfig);
531 return false;
532 }
533
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000534 // Print our codec list again for the call diagnostic log
535 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +0200536 for (const AudioCodec& codec : codecs_) {
537 LOG(LS_INFO) << ToString(codec);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000538 }
539
solenberg246b8172015-12-08 09:50:23 -0800540 SetDefaultDevices();
541
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000542 initialized_ = true;
543 return true;
544}
545
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000546void WebRtcVoiceEngine::Terminate() {
solenberg566ef242015-11-06 15:34:49 -0800547 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000548 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate";
549 initialized_ = false;
550
551 StopAecDump();
552
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000553 voe_wrapper_->base()->Terminate();
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000554}
555
solenberg566ef242015-11-06 15:34:49 -0800556rtc::scoped_refptr<webrtc::AudioState>
557 WebRtcVoiceEngine::GetAudioState() const {
558 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
559 return audio_state_;
560}
561
Fredrik Solenberg709ed672015-09-15 12:26:33 +0200562VoiceMediaChannel* WebRtcVoiceEngine::CreateChannel(webrtc::Call* call,
Jelena Marusicc28a8962015-05-29 15:05:44 +0200563 const AudioOptions& options) {
solenberg566ef242015-11-06 15:34:49 -0800564 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -0700565 return new WebRtcVoiceMediaChannel(this, options, call);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000566}
567
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000568bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
solenberg566ef242015-11-06 15:34:49 -0800569 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrikac14f5ff2015-09-23 14:08:33 +0200570 LOG(LS_INFO) << "ApplyOptions: " << options_in.ToString();
solenberg246b8172015-12-08 09:50:23 -0800571
572 // Default engine options.
573 AudioOptions options;
574 options.echo_cancellation = rtc::Optional<bool>(true);
575 options.auto_gain_control = rtc::Optional<bool>(true);
576 options.noise_suppression = rtc::Optional<bool>(true);
577 options.highpass_filter = rtc::Optional<bool>(true);
578 options.stereo_swapping = rtc::Optional<bool>(false);
579 options.audio_jitter_buffer_max_packets = rtc::Optional<int>(50);
580 options.audio_jitter_buffer_fast_accelerate = rtc::Optional<bool>(false);
581 options.typing_detection = rtc::Optional<bool>(true);
582 options.adjust_agc_delta = rtc::Optional<int>(0);
583 options.experimental_agc = rtc::Optional<bool>(false);
584 options.extended_filter_aec = rtc::Optional<bool>(false);
585 options.delay_agnostic_aec = rtc::Optional<bool>(false);
586 options.experimental_ns = rtc::Optional<bool>(false);
587 options.aec_dump = rtc::Optional<bool>(false);
588
589 // Apply any given options on top.
590 options.SetAll(options_in);
591
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000592 // kEcConference is AEC with high suppression.
593 webrtc::EcModes ec_mode = webrtc::kEcConference;
594 webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone;
595 webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog;
596 webrtc::NsModes ns_mode = webrtc::kNsHighSuppression;
kwiberg102c6a62015-10-30 02:47:38 -0700597 if (options.aecm_generate_comfort_noise) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000598 LOG(LS_VERBOSE) << "Comfort noise explicitly set to "
kwiberg102c6a62015-10-30 02:47:38 -0700599 << *options.aecm_generate_comfort_noise
600 << " (default is false).";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000601 }
602
603#if defined(IOS)
604 // On iOS, VPIO provides built-in EC and AGC.
Karl Wibergbe579832015-11-10 22:34:18 +0100605 options.echo_cancellation = rtc::Optional<bool>(false);
606 options.auto_gain_control = rtc::Optional<bool>(false);
henrika86d907c2015-09-07 16:09:50 +0200607 LOG(LS_INFO) << "Always disable AEC and AGC on iOS. Use built-in instead.";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000608#elif defined(ANDROID)
609 ec_mode = webrtc::kEcAecm;
610#endif
611
612#if defined(IOS) || defined(ANDROID)
613 // Set the AGC mode for iOS as well despite disabling it above, to avoid
614 // unsupported configuration errors from webrtc.
615 agc_mode = webrtc::kAgcFixedDigital;
Karl Wibergbe579832015-11-10 22:34:18 +0100616 options.typing_detection = rtc::Optional<bool>(false);
617 options.experimental_agc = rtc::Optional<bool>(false);
618 options.extended_filter_aec = rtc::Optional<bool>(false);
619 options.experimental_ns = rtc::Optional<bool>(false);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000620#endif
621
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100622 // Delay Agnostic AEC automatically turns on EC if not set except on iOS
623 // where the feature is not supported.
624 bool use_delay_agnostic_aec = false;
625#if !defined(IOS)
kwiberg102c6a62015-10-30 02:47:38 -0700626 if (options.delay_agnostic_aec) {
627 use_delay_agnostic_aec = *options.delay_agnostic_aec;
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100628 if (use_delay_agnostic_aec) {
Karl Wibergbe579832015-11-10 22:34:18 +0100629 options.echo_cancellation = rtc::Optional<bool>(true);
630 options.extended_filter_aec = rtc::Optional<bool>(true);
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100631 ec_mode = webrtc::kEcConference;
632 }
633 }
634#endif
635
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000636 webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing();
637
kwiberg102c6a62015-10-30 02:47:38 -0700638 if (options.echo_cancellation) {
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000639 // Check if platform supports built-in EC. Currently only supported on
640 // Android and in combination with Java based audio layer.
641 // TODO(henrika): investigate possibility to support built-in EC also
642 // in combination with Open SL ES audio.
643 const bool built_in_aec = voe_wrapper_->hw()->BuiltInAECIsAvailable();
Bjorn Volcker73f72102015-06-03 14:50:15 +0200644 if (built_in_aec) {
Bjorn Volckerccfc9392015-05-07 07:43:17 +0200645 // Built-in EC exists on this device and use_delay_agnostic_aec is not
646 // overriding it. Enable/Disable it according to the echo_cancellation
647 // audio option.
Bjorn Volcker73f72102015-06-03 14:50:15 +0200648 const bool enable_built_in_aec =
kwiberg102c6a62015-10-30 02:47:38 -0700649 *options.echo_cancellation && !use_delay_agnostic_aec;
Bjorn Volcker73f72102015-06-03 14:50:15 +0200650 if (voe_wrapper_->hw()->EnableBuiltInAEC(enable_built_in_aec) == 0 &&
651 enable_built_in_aec) {
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100652 // Disable internal software EC if built-in EC is enabled,
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000653 // i.e., replace the software EC with the built-in EC.
Karl Wibergbe579832015-11-10 22:34:18 +0100654 options.echo_cancellation = rtc::Optional<bool>(false);
henrika@webrtc.orga954c072014-12-09 16:22:09 +0000655 LOG(LS_INFO) << "Disabling EC since built-in EC will be used instead";
656 }
657 }
kwiberg102c6a62015-10-30 02:47:38 -0700658 if (voep->SetEcStatus(*options.echo_cancellation, ec_mode) == -1) {
659 LOG_RTCERR2(SetEcStatus, *options.echo_cancellation, ec_mode);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000660 return false;
661 } else {
kwiberg102c6a62015-10-30 02:47:38 -0700662 LOG(LS_INFO) << "Echo control set to " << *options.echo_cancellation
henrika86d907c2015-09-07 16:09:50 +0200663 << " with mode " << ec_mode;
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000664 }
665#if !defined(ANDROID)
666 // TODO(ajm): Remove the error return on Android from webrtc.
kwiberg102c6a62015-10-30 02:47:38 -0700667 if (voep->SetEcMetricsStatus(*options.echo_cancellation) == -1) {
668 LOG_RTCERR1(SetEcMetricsStatus, *options.echo_cancellation);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000669 return false;
670 }
671#endif
672 if (ec_mode == webrtc::kEcAecm) {
kwiberg102c6a62015-10-30 02:47:38 -0700673 bool cn = options.aecm_generate_comfort_noise.value_or(false);
674 if (voep->SetAecmMode(aecm_mode, cn) != 0) {
675 LOG_RTCERR2(SetAecmMode, aecm_mode, cn);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000676 return false;
677 }
678 }
679 }
680
kwiberg102c6a62015-10-30 02:47:38 -0700681 if (options.auto_gain_control) {
henrikac14f5ff2015-09-23 14:08:33 +0200682 const bool built_in_agc = voe_wrapper_->hw()->BuiltInAGCIsAvailable();
683 if (built_in_agc) {
kwiberg102c6a62015-10-30 02:47:38 -0700684 if (voe_wrapper_->hw()->EnableBuiltInAGC(*options.auto_gain_control) ==
685 0 &&
686 *options.auto_gain_control) {
henrikac14f5ff2015-09-23 14:08:33 +0200687 // Disable internal software AGC if built-in AGC is enabled,
688 // i.e., replace the software AGC with the built-in AGC.
Karl Wibergbe579832015-11-10 22:34:18 +0100689 options.auto_gain_control = rtc::Optional<bool>(false);
henrikac14f5ff2015-09-23 14:08:33 +0200690 LOG(LS_INFO) << "Disabling AGC since built-in AGC will be used instead";
691 }
692 }
kwiberg102c6a62015-10-30 02:47:38 -0700693 if (voep->SetAgcStatus(*options.auto_gain_control, agc_mode) == -1) {
694 LOG_RTCERR2(SetAgcStatus, *options.auto_gain_control, agc_mode);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000695 return false;
696 } else {
kwiberg102c6a62015-10-30 02:47:38 -0700697 LOG(LS_INFO) << "Auto gain set to " << *options.auto_gain_control
698 << " with mode " << agc_mode;
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000699 }
700 }
701
kwiberg102c6a62015-10-30 02:47:38 -0700702 if (options.tx_agc_target_dbov || options.tx_agc_digital_compression_gain ||
703 options.tx_agc_limiter) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000704 // Override default_agc_config_. Generally, an unset option means "leave
705 // the VoE bits alone" in this function, so we want whatever is set to be
706 // stored as the new "default". If we didn't, then setting e.g.
707 // tx_agc_target_dbov would reset digital compression gain and limiter
708 // settings.
709 // Also, if we don't update default_agc_config_, then adjust_agc_delta
710 // would be an offset from the original values, and not whatever was set
711 // explicitly.
kwiberg102c6a62015-10-30 02:47:38 -0700712 default_agc_config_.targetLeveldBOv = options.tx_agc_target_dbov.value_or(
713 default_agc_config_.targetLeveldBOv);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000714 default_agc_config_.digitalCompressionGaindB =
kwiberg102c6a62015-10-30 02:47:38 -0700715 options.tx_agc_digital_compression_gain.value_or(
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000716 default_agc_config_.digitalCompressionGaindB);
717 default_agc_config_.limiterEnable =
kwiberg102c6a62015-10-30 02:47:38 -0700718 options.tx_agc_limiter.value_or(default_agc_config_.limiterEnable);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000719 if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) {
720 LOG_RTCERR3(SetAgcConfig,
721 default_agc_config_.targetLeveldBOv,
722 default_agc_config_.digitalCompressionGaindB,
723 default_agc_config_.limiterEnable);
724 return false;
725 }
726 }
727
kwiberg102c6a62015-10-30 02:47:38 -0700728 if (options.noise_suppression) {
henrikac14f5ff2015-09-23 14:08:33 +0200729 const bool built_in_ns = voe_wrapper_->hw()->BuiltInNSIsAvailable();
730 if (built_in_ns) {
kwiberg102c6a62015-10-30 02:47:38 -0700731 if (voe_wrapper_->hw()->EnableBuiltInNS(*options.noise_suppression) ==
732 0 &&
733 *options.noise_suppression) {
henrikac14f5ff2015-09-23 14:08:33 +0200734 // Disable internal software NS if built-in NS is enabled,
735 // i.e., replace the software NS with the built-in NS.
Karl Wibergbe579832015-11-10 22:34:18 +0100736 options.noise_suppression = rtc::Optional<bool>(false);
henrikac14f5ff2015-09-23 14:08:33 +0200737 LOG(LS_INFO) << "Disabling NS since built-in NS will be used instead";
738 }
739 }
kwiberg102c6a62015-10-30 02:47:38 -0700740 if (voep->SetNsStatus(*options.noise_suppression, ns_mode) == -1) {
741 LOG_RTCERR2(SetNsStatus, *options.noise_suppression, ns_mode);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000742 return false;
743 } else {
kwiberg102c6a62015-10-30 02:47:38 -0700744 LOG(LS_INFO) << "Noise suppression set to " << *options.noise_suppression
henrikac14f5ff2015-09-23 14:08:33 +0200745 << " with mode " << ns_mode;
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000746 }
747 }
748
kwiberg102c6a62015-10-30 02:47:38 -0700749 if (options.highpass_filter) {
750 LOG(LS_INFO) << "High pass filter enabled? " << *options.highpass_filter;
751 if (voep->EnableHighPassFilter(*options.highpass_filter) == -1) {
752 LOG_RTCERR1(SetHighpassFilterStatus, *options.highpass_filter);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000753 return false;
754 }
755 }
756
kwiberg102c6a62015-10-30 02:47:38 -0700757 if (options.stereo_swapping) {
758 LOG(LS_INFO) << "Stereo swapping enabled? " << *options.stereo_swapping;
759 voep->EnableStereoChannelSwapping(*options.stereo_swapping);
760 if (voep->IsStereoChannelSwappingEnabled() != *options.stereo_swapping) {
761 LOG_RTCERR1(EnableStereoChannelSwapping, *options.stereo_swapping);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000762 return false;
763 }
764 }
765
kwiberg102c6a62015-10-30 02:47:38 -0700766 if (options.audio_jitter_buffer_max_packets) {
767 LOG(LS_INFO) << "NetEq capacity is "
768 << *options.audio_jitter_buffer_max_packets;
Henrik Lundin64dad832015-05-11 12:44:23 +0200769 voe_config_.Set<webrtc::NetEqCapacityConfig>(
kwiberg102c6a62015-10-30 02:47:38 -0700770 new webrtc::NetEqCapacityConfig(
771 *options.audio_jitter_buffer_max_packets));
Henrik Lundin64dad832015-05-11 12:44:23 +0200772 }
773
kwiberg102c6a62015-10-30 02:47:38 -0700774 if (options.audio_jitter_buffer_fast_accelerate) {
775 LOG(LS_INFO) << "NetEq fast mode? "
776 << *options.audio_jitter_buffer_fast_accelerate;
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200777 voe_config_.Set<webrtc::NetEqFastAccelerate>(
kwiberg102c6a62015-10-30 02:47:38 -0700778 new webrtc::NetEqFastAccelerate(
779 *options.audio_jitter_buffer_fast_accelerate));
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200780 }
781
kwiberg102c6a62015-10-30 02:47:38 -0700782 if (options.typing_detection) {
783 LOG(LS_INFO) << "Typing detection is enabled? "
784 << *options.typing_detection;
785 if (voep->SetTypingDetectionStatus(*options.typing_detection) == -1) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000786 // In case of error, log the info and continue
kwiberg102c6a62015-10-30 02:47:38 -0700787 LOG_RTCERR1(SetTypingDetectionStatus, *options.typing_detection);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000788 }
789 }
790
kwiberg102c6a62015-10-30 02:47:38 -0700791 if (options.adjust_agc_delta) {
792 LOG(LS_INFO) << "Adjust agc delta is " << *options.adjust_agc_delta;
793 if (!AdjustAgcLevel(*options.adjust_agc_delta)) {
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000794 return false;
795 }
796 }
797
kwiberg102c6a62015-10-30 02:47:38 -0700798 if (options.aec_dump) {
799 LOG(LS_INFO) << "Aec dump is enabled? " << *options.aec_dump;
800 if (*options.aec_dump)
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000801 StartAecDump(kAecDumpByAudioOptionFilename);
802 else
803 StopAecDump();
804 }
805
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000806 webrtc::Config config;
807
kwiberg102c6a62015-10-30 02:47:38 -0700808 if (options.delay_agnostic_aec)
809 delay_agnostic_aec_ = options.delay_agnostic_aec;
810 if (delay_agnostic_aec_) {
811 LOG(LS_INFO) << "Delay agnostic aec is enabled? " << *delay_agnostic_aec_;
henrik.lundin0f133b92015-07-02 00:17:55 -0700812 config.Set<webrtc::DelayAgnostic>(
kwiberg102c6a62015-10-30 02:47:38 -0700813 new webrtc::DelayAgnostic(*delay_agnostic_aec_));
Bjorn Volckerbf395c12015-03-25 22:45:56 +0100814 }
815
kwiberg102c6a62015-10-30 02:47:38 -0700816 if (options.extended_filter_aec) {
817 extended_filter_aec_ = options.extended_filter_aec;
818 }
819 if (extended_filter_aec_) {
820 LOG(LS_INFO) << "Extended filter aec is enabled? " << *extended_filter_aec_;
Henrik Lundin441f6342015-06-09 16:03:13 +0200821 config.Set<webrtc::ExtendedFilter>(
kwiberg102c6a62015-10-30 02:47:38 -0700822 new webrtc::ExtendedFilter(*extended_filter_aec_));
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000823 }
824
kwiberg102c6a62015-10-30 02:47:38 -0700825 if (options.experimental_ns) {
826 experimental_ns_ = options.experimental_ns;
827 }
828 if (experimental_ns_) {
829 LOG(LS_INFO) << "Experimental ns is enabled? " << *experimental_ns_;
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000830 config.Set<webrtc::ExperimentalNs>(
kwiberg102c6a62015-10-30 02:47:38 -0700831 new webrtc::ExperimentalNs(*experimental_ns_));
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000832 }
buildbot@webrtc.org1f8a2372014-08-28 10:52:44 +0000833
834 // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
835 // returns NULL on audio_processing().
836 webrtc::AudioProcessing* audioproc = voe_wrapper_->base()->audio_processing();
837 if (audioproc) {
838 audioproc->SetExtraOptions(config);
839 }
840
kwiberg102c6a62015-10-30 02:47:38 -0700841 if (options.recording_sample_rate) {
842 LOG(LS_INFO) << "Recording sample rate is "
843 << *options.recording_sample_rate;
844 if (voe_wrapper_->hw()->SetRecordingSampleRate(
845 *options.recording_sample_rate)) {
846 LOG_RTCERR1(SetRecordingSampleRate, *options.recording_sample_rate);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000847 }
848 }
849
kwiberg102c6a62015-10-30 02:47:38 -0700850 if (options.playout_sample_rate) {
851 LOG(LS_INFO) << "Playout sample rate is " << *options.playout_sample_rate;
852 if (voe_wrapper_->hw()->SetPlayoutSampleRate(
853 *options.playout_sample_rate)) {
854 LOG_RTCERR1(SetPlayoutSampleRate, *options.playout_sample_rate);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000855 }
856 }
857
858 return true;
859}
860
solenberg246b8172015-12-08 09:50:23 -0800861void WebRtcVoiceEngine::SetDefaultDevices() {
solenberg566ef242015-11-06 15:34:49 -0800862 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000863#if !defined(IOS)
solenberg246b8172015-12-08 09:50:23 -0800864 int in_id = kDefaultAudioDeviceId;
865 int out_id = kDefaultAudioDeviceId;
866 LOG(LS_INFO) << "Setting microphone to (id=" << in_id
867 << ") and speaker to (id=" << out_id << ")";
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000868
solenbergc1a1b352015-09-22 13:31:20 -0700869 bool ret = true;
solenberg246b8172015-12-08 09:50:23 -0800870 if (voe_wrapper_->hw()->SetRecordingDevice(in_id) == -1) {
871 LOG_RTCERR1(SetRecordingDevice, in_id);
buildbot@webrtc.org13d67762014-05-02 17:33:29 +0000872 ret = false;
873 }
solenberg246b8172015-12-08 09:50:23 -0800874 webrtc::AudioProcessing* ap = voe()->base()->audio_processing();
875 if (ap) {
876 ap->Initialize();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 }
878
solenberg246b8172015-12-08 09:50:23 -0800879 if (voe_wrapper_->hw()->SetPlayoutDevice(out_id) == -1) {
880 LOG_RTCERR1(SetPlayoutDevice, out_id);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000881 ret = false;
882 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000884 if (ret) {
solenberg246b8172015-12-08 09:50:23 -0800885 LOG(LS_INFO) << "Set microphone to (id=" << in_id
886 << ") and speaker to (id=" << out_id << ")";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 }
wu@webrtc.orgcecfd182013-10-30 05:18:12 +0000888#endif // !IOS
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000889}
890
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891bool WebRtcVoiceEngine::GetOutputVolume(int* level) {
solenberg566ef242015-11-06 15:34:49 -0800892 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893 unsigned int ulevel;
894 if (voe_wrapper_->volume()->GetSpeakerVolume(ulevel) == -1) {
895 LOG_RTCERR1(GetSpeakerVolume, level);
896 return false;
897 }
898 *level = ulevel;
899 return true;
900}
901
902bool WebRtcVoiceEngine::SetOutputVolume(int level) {
solenberg566ef242015-11-06 15:34:49 -0800903 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrikg91d6ede2015-09-17 00:24:34 -0700904 RTC_DCHECK(level >= 0 && level <= 255);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905 if (voe_wrapper_->volume()->SetSpeakerVolume(level) == -1) {
906 LOG_RTCERR1(SetSpeakerVolume, level);
907 return false;
908 }
909 return true;
910}
911
912int WebRtcVoiceEngine::GetInputLevel() {
solenberg566ef242015-11-06 15:34:49 -0800913 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914 unsigned int ulevel;
915 return (voe_wrapper_->volume()->GetSpeechInputLevel(ulevel) != -1) ?
916 static_cast<int>(ulevel) : -1;
917}
918
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000919const std::vector<AudioCodec>& WebRtcVoiceEngine::codecs() {
solenberg566ef242015-11-06 15:34:49 -0800920 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000921 return codecs_;
922}
923
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100924RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const {
solenberg566ef242015-11-06 15:34:49 -0800925 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread());
Stefan Holmer9d69c3f2015-12-07 10:45:43 +0100926 RtpCapabilities capabilities;
927 capabilities.header_extensions.push_back(RtpHeaderExtension(
928 kRtpAudioLevelHeaderExtension, kRtpAudioLevelHeaderExtensionDefaultId));
929 capabilities.header_extensions.push_back(
930 RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
931 kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
932 if (webrtc::field_trial::FindFullName("WebRTC-SendSideBwe") == "Enabled") {
933 capabilities.header_extensions.push_back(RtpHeaderExtension(
934 kRtpTransportSequenceNumberHeaderExtension,
935 kRtpTransportSequenceNumberHeaderExtensionDefaultId));
936 }
937 return capabilities;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000938}
939
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940int WebRtcVoiceEngine::GetLastEngineError() {
solenberg566ef242015-11-06 15:34:49 -0800941 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000942 return voe_wrapper_->error();
943}
944
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000945void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace,
946 int length) {
solenberg566ef242015-11-06 15:34:49 -0800947 // Note: This callback can happen on any thread!
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000948 rtc::LoggingSeverity sev = rtc::LS_VERBOSE;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000949 if (level == webrtc::kTraceError || level == webrtc::kTraceCritical)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000950 sev = rtc::LS_ERROR;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000951 else if (level == webrtc::kTraceWarning)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000952 sev = rtc::LS_WARNING;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000953 else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000954 sev = rtc::LS_INFO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000955 else if (level == webrtc::kTraceTerseInfo)
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000956 sev = rtc::LS_INFO;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000957
958 // Skip past boilerplate prefix text
959 if (length < 72) {
960 std::string msg(trace, length);
961 LOG(LS_ERROR) << "Malformed webrtc log message: ";
962 LOG_V(sev) << msg;
963 } else {
964 std::string msg(trace + 71, length - 72);
Peter Boströmd5c75b12015-09-23 13:24:32 +0200965 LOG_V(sev) << "webrtc: " << msg;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000966 }
967}
968
solenberg63b34542015-09-29 06:06:31 -0700969void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel* channel) {
solenberg566ef242015-11-06 15:34:49 -0800970 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
971 RTC_DCHECK(channel);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000972 channels_.push_back(channel);
973}
974
solenberg63b34542015-09-29 06:06:31 -0700975void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel* channel) {
solenberg566ef242015-11-06 15:34:49 -0800976 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg63b34542015-09-29 06:06:31 -0700977 auto it = std::find(channels_.begin(), channels_.end(), channel);
solenberg566ef242015-11-06 15:34:49 -0800978 RTC_DCHECK(it != channels_.end());
979 channels_.erase(it);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000980}
981
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000982// Adjusts the default AGC target level by the specified delta.
983// NB: If we start messing with other config fields, we'll want
984// to save the current webrtc::AgcConfig as well.
985bool WebRtcVoiceEngine::AdjustAgcLevel(int delta) {
solenberg566ef242015-11-06 15:34:49 -0800986 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987 webrtc::AgcConfig config = default_agc_config_;
988 config.targetLeveldBOv -= delta;
989
990 LOG(LS_INFO) << "Adjusting AGC level from default -"
991 << default_agc_config_.targetLeveldBOv << "dB to -"
992 << config.targetLeveldBOv << "dB";
993
994 if (voe_wrapper_->processing()->SetAgcConfig(config) == -1) {
995 LOG_RTCERR1(SetAgcConfig, config.targetLeveldBOv);
996 return false;
997 }
998 return true;
999}
1000
Fredrik Solenbergccb49e72015-05-19 11:37:56 +02001001bool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm) {
solenberg566ef242015-11-06 15:34:49 -08001002 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 if (initialized_) {
1004 LOG(LS_WARNING) << "SetAudioDeviceModule can not be called after Init.";
1005 return false;
1006 }
1007 if (adm_) {
1008 adm_->Release();
1009 adm_ = NULL;
1010 }
1011 if (adm) {
1012 adm_ = adm;
1013 adm_->AddRef();
1014 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001015 return true;
1016}
1017
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001018bool WebRtcVoiceEngine::StartAecDump(rtc::PlatformFile file) {
solenberg566ef242015-11-06 15:34:49 -08001019 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001020 FILE* aec_dump_file_stream = rtc::FdopenPlatformFileForWriting(file);
wu@webrtc.orga8910d22014-01-23 22:12:45 +00001021 if (!aec_dump_file_stream) {
1022 LOG(LS_ERROR) << "Could not open AEC dump file stream.";
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001023 if (!rtc::ClosePlatformFile(file))
wu@webrtc.orga8910d22014-01-23 22:12:45 +00001024 LOG(LS_WARNING) << "Could not close file.";
1025 return false;
1026 }
wu@webrtc.orga9890802013-12-13 00:21:03 +00001027 StopAecDump();
wu@webrtc.orga8910d22014-01-23 22:12:45 +00001028 if (voe_wrapper_->processing()->StartDebugRecording(aec_dump_file_stream) !=
wu@webrtc.orga9890802013-12-13 00:21:03 +00001029 webrtc::AudioProcessing::kNoError) {
wu@webrtc.orga8910d22014-01-23 22:12:45 +00001030 LOG_RTCERR0(StartDebugRecording);
1031 fclose(aec_dump_file_stream);
wu@webrtc.orga9890802013-12-13 00:21:03 +00001032 return false;
1033 }
1034 is_dumping_aec_ = true;
1035 return true;
wu@webrtc.orga9890802013-12-13 00:21:03 +00001036}
1037
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001038void WebRtcVoiceEngine::StartAecDump(const std::string& filename) {
solenberg566ef242015-11-06 15:34:49 -08001039 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040 if (!is_dumping_aec_) {
1041 // Start dumping AEC when we are not dumping.
1042 if (voe_wrapper_->processing()->StartDebugRecording(
1043 filename.c_str()) != webrtc::AudioProcessing::kNoError) {
wu@webrtc.orga9890802013-12-13 00:21:03 +00001044 LOG_RTCERR1(StartDebugRecording, filename.c_str());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 } else {
1046 is_dumping_aec_ = true;
1047 }
1048 }
1049}
1050
1051void WebRtcVoiceEngine::StopAecDump() {
solenberg566ef242015-11-06 15:34:49 -08001052 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001053 if (is_dumping_aec_) {
1054 // Stop dumping AEC when we are dumping.
1055 if (voe_wrapper_->processing()->StopDebugRecording() !=
1056 webrtc::AudioProcessing::kNoError) {
1057 LOG_RTCERR0(StopDebugRecording);
1058 }
1059 is_dumping_aec_ = false;
1060 }
1061}
1062
ivoc112a3d82015-10-16 02:22:18 -07001063bool WebRtcVoiceEngine::StartRtcEventLog(rtc::PlatformFile file) {
solenberg566ef242015-11-06 15:34:49 -08001064 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
ivoc112a3d82015-10-16 02:22:18 -07001065 return voe_wrapper_->codec()->GetEventLog()->StartLogging(file);
1066}
1067
1068void WebRtcVoiceEngine::StopRtcEventLog() {
solenberg566ef242015-11-06 15:34:49 -08001069 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
ivoc112a3d82015-10-16 02:22:18 -07001070 voe_wrapper_->codec()->GetEventLog()->StopLogging();
1071}
1072
solenberg0a617e22015-10-20 15:49:38 -07001073int WebRtcVoiceEngine::CreateVoEChannel() {
solenberg566ef242015-11-06 15:34:49 -08001074 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -07001075 return voe_wrapper_->base()->CreateChannel(voe_config_);
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +00001076}
1077
solenbergc96df772015-10-21 13:01:53 -07001078class WebRtcVoiceMediaChannel::WebRtcAudioSendStream
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001079 : public AudioRenderer::Sink {
1080 public:
solenbergc96df772015-10-21 13:01:53 -07001081 WebRtcAudioSendStream(int ch, webrtc::AudioTransport* voe_audio_transport,
solenberg3a941542015-11-16 07:34:50 -08001082 uint32_t ssrc, const std::string& c_name,
1083 const std::vector<webrtc::RtpExtension>& extensions,
1084 webrtc::Call* call)
solenberg7add0582015-11-20 09:59:34 -08001085 : voe_audio_transport_(voe_audio_transport),
solenberg3a941542015-11-16 07:34:50 -08001086 call_(call),
1087 config_(nullptr) {
solenberg85a04962015-10-27 03:35:21 -07001088 RTC_DCHECK_GE(ch, 0);
1089 // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore:
1090 // RTC_DCHECK(voe_audio_transport);
solenbergc96df772015-10-21 13:01:53 -07001091 RTC_DCHECK(call);
solenberg85a04962015-10-27 03:35:21 -07001092 audio_capture_thread_checker_.DetachFromThread();
solenberg3a941542015-11-16 07:34:50 -08001093 config_.rtp.ssrc = ssrc;
1094 config_.rtp.c_name = c_name;
1095 config_.voe_channel_id = ch;
1096 RecreateAudioSendStream(extensions);
solenbergc96df772015-10-21 13:01:53 -07001097 }
solenberg3a941542015-11-16 07:34:50 -08001098
solenbergc96df772015-10-21 13:01:53 -07001099 ~WebRtcAudioSendStream() override {
solenberg566ef242015-11-06 15:34:49 -08001100 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergc96df772015-10-21 13:01:53 -07001101 Stop();
1102 call_->DestroyAudioSendStream(stream_);
1103 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001104
solenberg3a941542015-11-16 07:34:50 -08001105 void RecreateAudioSendStream(
1106 const std::vector<webrtc::RtpExtension>& extensions) {
1107 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1108 if (stream_) {
1109 call_->DestroyAudioSendStream(stream_);
1110 stream_ = nullptr;
1111 }
1112 config_.rtp.extensions = extensions;
1113 RTC_DCHECK(!stream_);
1114 stream_ = call_->CreateAudioSendStream(config_);
1115 RTC_CHECK(stream_);
1116 }
1117
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001118 bool SendTelephoneEvent(int payload_type, uint8_t event,
1119 uint32_t duration_ms) {
1120 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1121 RTC_DCHECK(stream_);
1122 return stream_->SendTelephoneEvent(payload_type, event, duration_ms);
1123 }
1124
solenberg3a941542015-11-16 07:34:50 -08001125 webrtc::AudioSendStream::Stats GetStats() const {
1126 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1127 RTC_DCHECK(stream_);
1128 return stream_->GetStats();
1129 }
1130
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001131 // Starts the rendering by setting a sink to the renderer to get data
1132 // callback.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001133 // This method is called on the libjingle worker thread.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001134 // TODO(xians): Make sure Start() is called only once.
1135 void Start(AudioRenderer* renderer) {
solenberg566ef242015-11-06 15:34:49 -08001136 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergc96df772015-10-21 13:01:53 -07001137 RTC_DCHECK(renderer);
1138 if (renderer_) {
henrikg91d6ede2015-09-17 00:24:34 -07001139 RTC_DCHECK(renderer_ == renderer);
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001140 return;
1141 }
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001142 renderer->SetSink(this);
1143 renderer_ = renderer;
1144 }
1145
solenbergc96df772015-10-21 13:01:53 -07001146 // Stops rendering by setting the sink of the renderer to nullptr. No data
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001147 // callback will be received after this method.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001148 // This method is called on the libjingle worker thread.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001149 void Stop() {
solenberg566ef242015-11-06 15:34:49 -08001150 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergc96df772015-10-21 13:01:53 -07001151 if (renderer_) {
1152 renderer_->SetSink(nullptr);
1153 renderer_ = nullptr;
solenberg98c68862015-10-09 03:27:14 -07001154 }
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001155 }
1156
1157 // AudioRenderer::Sink implementation.
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001158 // This method is called on the audio thread.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +00001159 void OnData(const void* audio_data,
1160 int bits_per_sample,
1161 int sample_rate,
1162 int number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -07001163 size_t number_of_frames) override {
solenberg566ef242015-11-06 15:34:49 -08001164 RTC_DCHECK(!worker_thread_checker_.CalledOnValidThread());
solenberg85a04962015-10-27 03:35:21 -07001165 RTC_DCHECK(audio_capture_thread_checker_.CalledOnValidThread());
solenbergc96df772015-10-21 13:01:53 -07001166 RTC_DCHECK(voe_audio_transport_);
solenberg7add0582015-11-20 09:59:34 -08001167 voe_audio_transport_->OnData(config_.voe_channel_id,
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001168 audio_data,
1169 bits_per_sample,
1170 sample_rate,
1171 number_of_channels,
1172 number_of_frames);
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001173 }
1174
1175 // Callback from the |renderer_| when it is going away. In case Start() has
1176 // never been called, this callback won't be triggered.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +00001177 void OnClose() override {
solenberg566ef242015-11-06 15:34:49 -08001178 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergc96df772015-10-21 13:01:53 -07001179 // Set |renderer_| to nullptr to make sure no more callback will get into
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001180 // the renderer.
solenbergc96df772015-10-21 13:01:53 -07001181 renderer_ = nullptr;
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001182 }
1183
1184 // Accessor to the VoE channel ID.
solenberg85a04962015-10-27 03:35:21 -07001185 int channel() const {
solenberg566ef242015-11-06 15:34:49 -08001186 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7add0582015-11-20 09:59:34 -08001187 return config_.voe_channel_id;
solenberg85a04962015-10-27 03:35:21 -07001188 }
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001189
1190 private:
solenberg566ef242015-11-06 15:34:49 -08001191 rtc::ThreadChecker worker_thread_checker_;
solenberg85a04962015-10-27 03:35:21 -07001192 rtc::ThreadChecker audio_capture_thread_checker_;
solenbergc96df772015-10-21 13:01:53 -07001193 webrtc::AudioTransport* const voe_audio_transport_ = nullptr;
1194 webrtc::Call* call_ = nullptr;
solenberg3a941542015-11-16 07:34:50 -08001195 webrtc::AudioSendStream::Config config_;
1196 // The stream is owned by WebRtcAudioSendStream and may be reallocated if
1197 // configuration changes.
solenbergc96df772015-10-21 13:01:53 -07001198 webrtc::AudioSendStream* stream_ = nullptr;
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001199
1200 // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler.
1201 // PeerConnection will make sure invalidating the pointer before the object
1202 // goes away.
solenbergc96df772015-10-21 13:01:53 -07001203 AudioRenderer* renderer_ = nullptr;
henrike@webrtc.orga7b98182014-02-21 15:51:43 +00001204
solenbergc96df772015-10-21 13:01:53 -07001205 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream);
1206};
1207
1208class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream {
1209 public:
solenberg7add0582015-11-20 09:59:34 -08001210 WebRtcAudioReceiveStream(int ch, uint32_t remote_ssrc, uint32_t local_ssrc,
1211 bool use_combined_bwe, const std::string& sync_group,
1212 const std::vector<webrtc::RtpExtension>& extensions,
1213 webrtc::Call* call)
1214 : call_(call),
1215 config_() {
1216 RTC_DCHECK_GE(ch, 0);
1217 RTC_DCHECK(call);
1218 config_.rtp.remote_ssrc = remote_ssrc;
1219 config_.rtp.local_ssrc = local_ssrc;
1220 config_.voe_channel_id = ch;
1221 config_.sync_group = sync_group;
1222 RecreateAudioReceiveStream(use_combined_bwe, extensions);
1223 }
solenbergc96df772015-10-21 13:01:53 -07001224
solenberg7add0582015-11-20 09:59:34 -08001225 ~WebRtcAudioReceiveStream() {
1226 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1227 call_->DestroyAudioReceiveStream(stream_);
1228 }
1229
1230 void RecreateAudioReceiveStream(
1231 const std::vector<webrtc::RtpExtension>& extensions) {
1232 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1233 RecreateAudioReceiveStream(config_.combined_audio_video_bwe, extensions);
1234 }
1235 void RecreateAudioReceiveStream(bool use_combined_bwe) {
1236 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1237 RecreateAudioReceiveStream(use_combined_bwe, config_.rtp.extensions);
1238 }
1239
1240 webrtc::AudioReceiveStream::Stats GetStats() const {
1241 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1242 RTC_DCHECK(stream_);
1243 return stream_->GetStats();
1244 }
1245
1246 int channel() const {
1247 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1248 return config_.voe_channel_id;
1249 }
solenbergc96df772015-10-21 13:01:53 -07001250
1251 private:
solenberg7add0582015-11-20 09:59:34 -08001252 void RecreateAudioReceiveStream(bool use_combined_bwe,
1253 const std::vector<webrtc::RtpExtension>& extensions) {
1254 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
1255 if (stream_) {
1256 call_->DestroyAudioReceiveStream(stream_);
1257 stream_ = nullptr;
1258 }
1259 config_.rtp.extensions = extensions;
1260 config_.combined_audio_video_bwe = use_combined_bwe;
1261 RTC_DCHECK(!stream_);
1262 stream_ = call_->CreateAudioReceiveStream(config_);
1263 RTC_CHECK(stream_);
1264 }
1265
1266 rtc::ThreadChecker worker_thread_checker_;
1267 webrtc::Call* call_ = nullptr;
1268 webrtc::AudioReceiveStream::Config config_;
1269 // The stream is owned by WebRtcAudioReceiveStream and may be reallocated if
1270 // configuration changes.
1271 webrtc::AudioReceiveStream* stream_ = nullptr;
solenbergc96df772015-10-21 13:01:53 -07001272
1273 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioReceiveStream);
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001274};
1275
Fredrik Solenberg709ed672015-09-15 12:26:33 +02001276WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine* engine,
Fredrik Solenbergb071a192015-09-17 16:42:56 +02001277 const AudioOptions& options,
Fredrik Solenberg709ed672015-09-15 12:26:33 +02001278 webrtc::Call* call)
solenberg566ef242015-11-06 15:34:49 -08001279 : engine_(engine), call_(call) {
solenberg0a617e22015-10-20 15:49:38 -07001280 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel";
solenberg566ef242015-11-06 15:34:49 -08001281 RTC_DCHECK(call);
solenberg0a617e22015-10-20 15:49:38 -07001282 engine->RegisterChannel(this);
Fredrik Solenbergb071a192015-09-17 16:42:56 +02001283 SetOptions(options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001284}
1285
1286WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
solenberg566ef242015-11-06 15:34:49 -08001287 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -07001288 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel";
solenberg7add0582015-11-20 09:59:34 -08001289 // TODO(solenberg): Should be able to delete the streams directly, without
1290 // going through RemoveNnStream(), once stream objects handle
1291 // all (de)configuration.
solenbergc96df772015-10-21 13:01:53 -07001292 while (!send_streams_.empty()) {
1293 RemoveSendStream(send_streams_.begin()->first);
solenbergd97ec302015-10-07 01:40:33 -07001294 }
solenberg7add0582015-11-20 09:59:34 -08001295 while (!recv_streams_.empty()) {
1296 RemoveRecvStream(recv_streams_.begin()->first);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297 }
solenberg0a617e22015-10-20 15:49:38 -07001298 engine()->UnregisterChannel(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001299}
1300
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001301bool WebRtcVoiceMediaChannel::SetSendParameters(
1302 const AudioSendParameters& params) {
solenberg566ef242015-11-06 15:34:49 -08001303 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7e4e01a2015-12-02 08:05:01 -08001304 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetSendParameters: "
1305 << params.ToString();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001306 // TODO(pthatcher): Refactor this to be more clean now that we have
1307 // all the information at once.
solenberg3a941542015-11-16 07:34:50 -08001308
1309 if (!SetSendCodecs(params.codecs)) {
1310 return false;
1311 }
1312
solenberg7e4e01a2015-12-02 08:05:01 -08001313 if (!ValidateRtpExtensions(params.extensions)) {
1314 return false;
1315 }
1316 std::vector<webrtc::RtpExtension> filtered_extensions =
1317 FilterRtpExtensions(params.extensions,
1318 webrtc::RtpExtension::IsSupportedForAudio, true);
1319 if (send_rtp_extensions_ != filtered_extensions) {
1320 send_rtp_extensions_.swap(filtered_extensions);
solenberg3a941542015-11-16 07:34:50 -08001321 for (auto& it : send_streams_) {
1322 it.second->RecreateAudioSendStream(send_rtp_extensions_);
1323 }
1324 }
1325
1326 if (!SetMaxSendBandwidth(params.max_bandwidth_bps)) {
1327 return false;
1328 }
1329 return SetOptions(params.options);
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001330}
1331
1332bool WebRtcVoiceMediaChannel::SetRecvParameters(
1333 const AudioRecvParameters& params) {
solenberg566ef242015-11-06 15:34:49 -08001334 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7e4e01a2015-12-02 08:05:01 -08001335 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetRecvParameters: "
1336 << params.ToString();
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001337 // TODO(pthatcher): Refactor this to be more clean now that we have
1338 // all the information at once.
solenberg7add0582015-11-20 09:59:34 -08001339
1340 if (!SetRecvCodecs(params.codecs)) {
1341 return false;
1342 }
1343
solenberg7e4e01a2015-12-02 08:05:01 -08001344 if (!ValidateRtpExtensions(params.extensions)) {
1345 return false;
1346 }
1347 std::vector<webrtc::RtpExtension> filtered_extensions =
1348 FilterRtpExtensions(params.extensions,
1349 webrtc::RtpExtension::IsSupportedForAudio, false);
1350 if (recv_rtp_extensions_ != filtered_extensions) {
1351 recv_rtp_extensions_.swap(filtered_extensions);
solenberg7add0582015-11-20 09:59:34 -08001352 for (auto& it : recv_streams_) {
1353 it.second->RecreateAudioReceiveStream(recv_rtp_extensions_);
1354 }
1355 }
1356
1357 return true;
Peter Thatcherc2ee2c82015-08-07 16:05:34 -07001358}
1359
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001360bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
solenberg566ef242015-11-06 15:34:49 -08001361 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001362 LOG(LS_INFO) << "Setting voice channel options: "
1363 << options.ToString();
1364
wu@webrtc.orgde305012013-10-31 15:40:38 +00001365 // Check if DSCP value is changed from previous.
1366 bool dscp_option_changed = (options_.dscp != options.dscp);
1367
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001368 // We retain all of the existing options, and apply the given ones
1369 // on top. This means there is no way to "clear" options such that
1370 // they go back to the engine default.
1371 options_.SetAll(options);
solenberg246b8172015-12-08 09:50:23 -08001372 if (!engine()->ApplyOptions(options_)) {
1373 LOG(LS_WARNING) <<
1374 "Failed to apply engine options during channel SetOptions.";
1375 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001376 }
1377
wu@webrtc.orgde305012013-10-31 15:40:38 +00001378 if (dscp_option_changed) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001379 rtc::DiffServCodePoint dscp = rtc::DSCP_DEFAULT;
solenberg246b8172015-12-08 09:50:23 -08001380 if (options_.dscp.value_or(false)) {
wu@webrtc.orgde305012013-10-31 15:40:38 +00001381 dscp = kAudioDscpValue;
solenberg246b8172015-12-08 09:50:23 -08001382 }
wu@webrtc.orgde305012013-10-31 15:40:38 +00001383 if (MediaChannel::SetDscp(dscp) != 0) {
1384 LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel";
1385 }
1386 }
solenberg8fb30c32015-10-13 03:06:58 -07001387
solenbergc96df772015-10-21 13:01:53 -07001388 // TODO(solenberg): Don't recreate unless options changed.
solenberg7add0582015-11-20 09:59:34 -08001389 for (auto& it : recv_streams_) {
1390 it.second->RecreateAudioReceiveStream(
1391 options_.combined_audio_video_bwe.value_or(false));
1392 }
solenberg8fb30c32015-10-13 03:06:58 -07001393
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001394 LOG(LS_INFO) << "Set voice channel options. Current options: "
1395 << options_.ToString();
1396 return true;
1397}
1398
1399bool WebRtcVoiceMediaChannel::SetRecvCodecs(
1400 const std::vector<AudioCodec>& codecs) {
solenberg566ef242015-11-06 15:34:49 -08001401 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg8fb30c32015-10-13 03:06:58 -07001402
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001403 // Set the payload types to be used for incoming media.
solenberg0b675462015-10-09 01:37:09 -07001404 LOG(LS_INFO) << "Setting receive voice codecs.";
solenberg0b675462015-10-09 01:37:09 -07001405
1406 if (!VerifyUniquePayloadTypes(codecs)) {
1407 LOG(LS_ERROR) << "Codec payload types overlap.";
1408 return false;
1409 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001410
1411 std::vector<AudioCodec> new_codecs;
1412 // Find all new codecs. We allow adding new codecs but don't allow changing
1413 // the payload type of codecs that is already configured since we might
1414 // already be receiving packets with that payload type.
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001415 for (const AudioCodec& codec : codecs) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001416 AudioCodec old_codec;
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001417 if (FindCodec(recv_codecs_, codec, &old_codec)) {
1418 if (old_codec.id != codec.id) {
1419 LOG(LS_ERROR) << codec.name << " payload type changed.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001420 return false;
1421 }
1422 } else {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001423 new_codecs.push_back(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001424 }
1425 }
1426 if (new_codecs.empty()) {
1427 // There are no new codecs to configure. Already configured codecs are
1428 // never removed.
1429 return true;
1430 }
1431
1432 if (playout_) {
1433 // Receive codecs can not be changed while playing. So we temporarily
1434 // pause playout.
1435 PausePlayout();
1436 }
1437
solenberg26c8c912015-11-27 04:00:25 -08001438 bool result = true;
1439 for (const AudioCodec& codec : new_codecs) {
1440 webrtc::CodecInst voe_codec;
1441 if (WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) {
1442 LOG(LS_INFO) << ToString(codec);
1443 voe_codec.pltype = codec.id;
1444 for (const auto& ch : recv_streams_) {
1445 if (engine()->voe()->codec()->SetRecPayloadType(
1446 ch.second->channel(), voe_codec) == -1) {
1447 LOG_RTCERR2(SetRecPayloadType, ch.second->channel(),
1448 ToString(voe_codec));
1449 result = false;
1450 }
1451 }
1452 } else {
1453 LOG(LS_WARNING) << "Unknown codec " << ToString(codec);
1454 result = false;
1455 break;
1456 }
1457 }
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001458 if (result) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001459 recv_codecs_ = codecs;
1460 }
1461
1462 if (desired_playout_ && !playout_) {
1463 ResumePlayout();
1464 }
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001465 return result;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001466}
1467
1468bool WebRtcVoiceMediaChannel::SetSendCodecs(
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001469 int channel, const std::vector<AudioCodec>& codecs) {
buildbot@webrtc.orgae740dd2014-06-17 10:56:41 +00001470 // Disable VAD, FEC, and RED unless we know the other side wants them.
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001471 engine()->voe()->codec()->SetVADStatus(channel, false);
1472 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
buildbot@webrtc.orgae740dd2014-06-17 10:56:41 +00001473 engine()->voe()->rtp()->SetREDStatus(channel, false);
1474 engine()->voe()->codec()->SetFECStatus(channel, false);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001475
1476 // Scan through the list to figure out the codec to use for sending, along
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001477 // with the proper configuration for VAD.
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001478 bool found_send_codec = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001479 webrtc::CodecInst send_codec;
1480 memset(&send_codec, 0, sizeof(send_codec));
1481
wu@webrtc.org05e7b442014-04-01 17:44:24 +00001482 bool nack_enabled = nack_enabled_;
buildbot@webrtc.org3ffa1f92014-07-02 19:51:26 +00001483 bool enable_codec_fec = false;
Minyue Li7100dcd2015-03-27 05:05:59 +01001484 bool enable_opus_dtx = false;
minyue@webrtc.org26236952014-10-29 02:27:08 +00001485 int opus_max_playback_rate = 0;
buildbot@webrtc.org5d639b32014-09-10 07:57:12 +00001486
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001487 // Set send codec (the first non-telephone-event/CN codec)
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001488 for (const AudioCodec& codec : codecs) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001489 // Ignore codecs we don't know about. The negotiation step should prevent
1490 // this, but double-check to be sure.
1491 webrtc::CodecInst voe_codec;
solenberg26c8c912015-11-27 04:00:25 -08001492 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001493 LOG(LS_WARNING) << "Unknown codec " << ToString(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001494 continue;
1495 }
1496
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001497 if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) {
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001498 // Skip telephone-event/CN codec, which will be handled later.
1499 continue;
1500 }
1501
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001502 // We'll use the first codec in the list to actually send audio data.
1503 // Be sure to use the payload type requested by the remote side.
buildbot@webrtc.orgae740dd2014-06-17 10:56:41 +00001504 // "red", for RED audio, is a special case where the actual codec to be
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001505 // used is specified in params.
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001506 if (IsCodec(codec, kRedCodecName)) {
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001507 // Parse out the RED parameters. If we fail, just ignore RED;
1508 // we don't support all possible params/usage scenarios.
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001509 if (!GetRedSendCodec(codec, codecs, &send_codec)) {
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001510 continue;
1511 }
1512
1513 // Enable redundant encoding of the specified codec. Treat any
1514 // failure as a fatal internal error.
buildbot@webrtc.orgae740dd2014-06-17 10:56:41 +00001515 LOG(LS_INFO) << "Enabling RED on channel " << channel;
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001516 if (engine()->voe()->rtp()->SetREDStatus(channel, true, codec.id) == -1) {
1517 LOG_RTCERR3(SetREDStatus, channel, true, codec.id);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001518 return false;
1519 }
1520 } else {
1521 send_codec = voe_codec;
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001522 nack_enabled = IsNackEnabled(codec);
Minyue Li7100dcd2015-03-27 05:05:59 +01001523 // For Opus as the send codec, we are to determine inband FEC, maximum
1524 // playback rate, and opus internal dtx.
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001525 if (IsCodec(codec, kOpusCodecName)) {
1526 GetOpusConfig(codec, &send_codec, &enable_codec_fec,
Minyue Li7100dcd2015-03-27 05:05:59 +01001527 &opus_max_playback_rate, &enable_opus_dtx);
buildbot@webrtc.org5d639b32014-09-10 07:57:12 +00001528 }
Brave Yao5225dd82015-03-26 07:39:19 +08001529
1530 // Set packet size if the AudioCodec param kCodecParamPTime is set.
1531 int ptime_ms = 0;
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001532 if (codec.GetParam(kCodecParamPTime, &ptime_ms)) {
solenberg26c8c912015-11-27 04:00:25 -08001533 if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize(&send_codec, ptime_ms)) {
Brave Yao5225dd82015-03-26 07:39:19 +08001534 LOG(LS_WARNING) << "Failed to set packet size for codec "
1535 << send_codec.plname;
1536 return false;
1537 }
1538 }
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001539 }
1540 found_send_codec = true;
1541 break;
1542 }
1543
wu@webrtc.org05e7b442014-04-01 17:44:24 +00001544 if (nack_enabled_ != nack_enabled) {
1545 SetNack(channel, nack_enabled);
1546 nack_enabled_ = nack_enabled;
1547 }
1548
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001549 if (!found_send_codec) {
1550 LOG(LS_WARNING) << "Received empty list of codecs.";
1551 return false;
1552 }
1553
1554 // Set the codec immediately, since SetVADStatus() depends on whether
1555 // the current codec is mono or stereo.
1556 if (!SetSendCodec(channel, send_codec))
1557 return false;
1558
buildbot@webrtc.org3ffa1f92014-07-02 19:51:26 +00001559 // FEC should be enabled after SetSendCodec.
1560 if (enable_codec_fec) {
1561 LOG(LS_INFO) << "Attempt to enable codec internal FEC on channel "
1562 << channel;
buildbot@webrtc.org3ffa1f92014-07-02 19:51:26 +00001563 if (engine()->voe()->codec()->SetFECStatus(channel, true) == -1) {
1564 // Enable codec internal FEC. Treat any failure as fatal internal error.
1565 LOG_RTCERR2(SetFECStatus, channel, true);
1566 return false;
1567 }
buildbot@webrtc.org3ffa1f92014-07-02 19:51:26 +00001568 }
1569
Minyue Li7100dcd2015-03-27 05:05:59 +01001570 if (IsCodec(send_codec, kOpusCodecName)) {
1571 // DTX and maxplaybackrate should be set after SetSendCodec. Because current
1572 // send codec has to be Opus.
1573
1574 // Set Opus internal DTX.
1575 LOG(LS_INFO) << "Attempt to "
solenbergbd138382015-11-20 16:08:07 -08001576 << (enable_opus_dtx ? "enable" : "disable")
Minyue Li7100dcd2015-03-27 05:05:59 +01001577 << " Opus DTX on channel "
buildbot@webrtc.org5d639b32014-09-10 07:57:12 +00001578 << channel;
Minyue Li7100dcd2015-03-27 05:05:59 +01001579 if (engine()->voe()->codec()->SetOpusDtx(channel, enable_opus_dtx)) {
1580 LOG_RTCERR2(SetOpusDtx, channel, enable_opus_dtx);
1581 return false;
1582 }
1583
1584 // If opus_max_playback_rate <= 0, the default maximum playback rate
1585 // (48 kHz) will be used.
1586 if (opus_max_playback_rate > 0) {
1587 LOG(LS_INFO) << "Attempt to set maximum playback rate to "
1588 << opus_max_playback_rate
1589 << " Hz on channel "
1590 << channel;
1591 if (engine()->voe()->codec()->SetOpusMaxPlaybackRate(
1592 channel, opus_max_playback_rate) == -1) {
1593 LOG_RTCERR2(SetOpusMaxPlaybackRate, channel, opus_max_playback_rate);
1594 return false;
1595 }
buildbot@webrtc.org5d639b32014-09-10 07:57:12 +00001596 }
buildbot@webrtc.org5d639b32014-09-10 07:57:12 +00001597 }
1598
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001599 // Always update the |send_codec_| to the currently set send codec.
1600 send_codec_.reset(new webrtc::CodecInst(send_codec));
1601
minyue@webrtc.org26236952014-10-29 02:27:08 +00001602 if (send_bitrate_setting_) {
1603 SetSendBitrateInternal(send_bitrate_bps_);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001604 }
1605
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001606 // Loop through the codecs list again to config the CN codec.
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001607 for (const AudioCodec& codec : codecs) {
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001608 // Ignore codecs we don't know about. The negotiation step should prevent
1609 // this, but double-check to be sure.
1610 webrtc::CodecInst voe_codec;
solenberg26c8c912015-11-27 04:00:25 -08001611 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001612 LOG(LS_WARNING) << "Unknown codec " << ToString(codec);
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001613 continue;
1614 }
1615
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001616 if (IsCodec(codec, kCnCodecName)) {
henrike@webrtc.org704bf9e2014-02-27 17:52:04 +00001617 // Turn voice activity detection/comfort noise on if supported.
1618 // Set the wideband CN payload type appropriately.
1619 // (narrowband always uses the static payload type 13).
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001620 webrtc::PayloadFrequencies cn_freq;
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001621 switch (codec.clockrate) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001622 case 8000:
1623 cn_freq = webrtc::kFreq8000Hz;
1624 break;
1625 case 16000:
1626 cn_freq = webrtc::kFreq16000Hz;
1627 break;
1628 case 32000:
1629 cn_freq = webrtc::kFreq32000Hz;
1630 break;
1631 default:
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001632 LOG(LS_WARNING) << "CN frequency " << codec.clockrate
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001633 << " not supported.";
1634 continue;
1635 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001636 // Set the CN payloadtype and the VAD status.
1637 // The CN payload type for 8000 Hz clockrate is fixed at 13.
1638 if (cn_freq != webrtc::kFreq8000Hz) {
1639 if (engine()->voe()->codec()->SetSendCNPayloadType(
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001640 channel, codec.id, cn_freq) == -1) {
1641 LOG_RTCERR3(SetSendCNPayloadType, channel, codec.id, cn_freq);
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001642 // TODO(ajm): This failure condition will be removed from VoE.
1643 // Restore the return here when we update to a new enough webrtc.
1644 //
1645 // Not returning false because the SetSendCNPayloadType will fail if
1646 // the channel is already sending.
1647 // This can happen if the remote description is applied twice, for
1648 // example in the case of ROAP on top of JSEP, where both side will
1649 // send the offer.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001650 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001651 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001652 // Only turn on VAD if we have a CN payload type that matches the
1653 // clockrate for the codec we are going to use.
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001654 if (codec.clockrate == send_codec.plfreq && send_codec.channels != 2) {
Minyue Li7100dcd2015-03-27 05:05:59 +01001655 // TODO(minyue): If CN frequency == 48000 Hz is allowed, consider the
1656 // interaction between VAD and Opus FEC.
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001657 LOG(LS_INFO) << "Enabling VAD";
1658 if (engine()->voe()->codec()->SetVADStatus(channel, true) == -1) {
1659 LOG_RTCERR2(SetVADStatus, channel, true);
1660 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001661 }
1662 }
1663 }
wu@webrtc.org1d1ffc92013-10-16 18:12:02 +00001664 }
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001665 return true;
1666}
1667
1668bool WebRtcVoiceMediaChannel::SetSendCodecs(
1669 const std::vector<AudioCodec>& codecs) {
solenberg566ef242015-11-06 15:34:49 -08001670 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001671 // TODO(solenberg): Validate input - that payload types don't overlap, are
1672 // within range, filter out codecs we don't support,
1673 // redundant codecs etc.
solenbergd97ec302015-10-07 01:40:33 -07001674
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001675 // Find the DTMF telephone event "codec" payload type.
1676 dtmf_payload_type_ = rtc::Optional<int>();
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001677 for (const AudioCodec& codec : codecs) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001678 if (IsCodec(codec, kDtmfCodecName)) {
Fredrik Solenbergb5727682015-12-04 15:22:19 +01001679 dtmf_payload_type_ = rtc::Optional<int>(codec.id);
1680 break;
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001681 }
1682 }
1683
1684 // Cache the codecs in order to configure the channel created later.
1685 send_codecs_ = codecs;
solenbergc96df772015-10-21 13:01:53 -07001686 for (const auto& ch : send_streams_) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001687 if (!SetSendCodecs(ch.second->channel(), codecs)) {
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001688 return false;
1689 }
1690 }
1691
wu@webrtc.org05e7b442014-04-01 17:44:24 +00001692 // Set nack status on receive channels and update |nack_enabled_|.
solenberg7add0582015-11-20 09:59:34 -08001693 for (const auto& ch : recv_streams_) {
solenberg0a617e22015-10-20 15:49:38 -07001694 SetNack(ch.second->channel(), nack_enabled_);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001695 }
solenberg0a617e22015-10-20 15:49:38 -07001696
1697 return true;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001698}
1699
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001700void WebRtcVoiceMediaChannel::SetNack(int channel, bool nack_enabled) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001701 if (nack_enabled) {
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001702 LOG(LS_INFO) << "Enabling NACK for channel " << channel;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001703 engine()->voe()->rtp()->SetNACKStatus(channel, true, kNackMaxPackets);
1704 } else {
wu@webrtc.orgcadf9042013-08-30 21:24:16 +00001705 LOG(LS_INFO) << "Disabling NACK for channel " << channel;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001706 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
1707 }
1708}
1709
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001710bool WebRtcVoiceMediaChannel::SetSendCodec(
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001711 int channel, const webrtc::CodecInst& send_codec) {
1712 LOG(LS_INFO) << "Send channel " << channel << " selected voice codec "
1713 << ToString(send_codec) << ", bitrate=" << send_codec.rate;
1714
wu@webrtc.org05e7b442014-04-01 17:44:24 +00001715 webrtc::CodecInst current_codec;
1716 if (engine()->voe()->codec()->GetSendCodec(channel, current_codec) == 0 &&
1717 (send_codec == current_codec)) {
1718 // Codec is already configured, we can return without setting it again.
1719 return true;
1720 }
1721
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001722 if (engine()->voe()->codec()->SetSendCodec(channel, send_codec) == -1) {
1723 LOG_RTCERR2(SetSendCodec, channel, ToString(send_codec));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001724 return false;
1725 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001726 return true;
1727}
1728
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001729bool WebRtcVoiceMediaChannel::SetPlayout(bool playout) {
1730 desired_playout_ = playout;
1731 return ChangePlayout(desired_playout_);
1732}
1733
1734bool WebRtcVoiceMediaChannel::PausePlayout() {
1735 return ChangePlayout(false);
1736}
1737
1738bool WebRtcVoiceMediaChannel::ResumePlayout() {
1739 return ChangePlayout(desired_playout_);
1740}
1741
1742bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
solenberg566ef242015-11-06 15:34:49 -08001743 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001744 if (playout_ == playout) {
1745 return true;
1746 }
1747
solenberg7add0582015-11-20 09:59:34 -08001748 for (const auto& ch : recv_streams_) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001749 if (!SetPlayout(ch.second->channel(), playout)) {
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001750 LOG(LS_ERROR) << "SetPlayout " << playout << " on channel "
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02001751 << ch.second->channel() << " failed";
solenberg1ac56142015-10-13 03:58:19 -07001752 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001753 }
1754 }
solenberg1ac56142015-10-13 03:58:19 -07001755 playout_ = playout;
1756 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001757}
1758
1759bool WebRtcVoiceMediaChannel::SetSend(SendFlags send) {
1760 desired_send_ = send;
solenbergc96df772015-10-21 13:01:53 -07001761 if (!send_streams_.empty()) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001762 return ChangeSend(desired_send_);
solenbergc96df772015-10-21 13:01:53 -07001763 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001764 return true;
1765}
1766
1767bool WebRtcVoiceMediaChannel::PauseSend() {
1768 return ChangeSend(SEND_NOTHING);
1769}
1770
1771bool WebRtcVoiceMediaChannel::ResumeSend() {
1772 return ChangeSend(desired_send_);
1773}
1774
1775bool WebRtcVoiceMediaChannel::ChangeSend(SendFlags send) {
1776 if (send_ == send) {
1777 return true;
1778 }
1779
solenberg246b8172015-12-08 09:50:23 -08001780 // Apply channel specific options when channel is enabled for sending.
solenberg63b34542015-09-29 06:06:31 -07001781 if (send == SEND_MICROPHONE) {
1782 engine()->ApplyOptions(options_);
1783 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001784
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001785 // Change the settings on each send channel.
solenbergc96df772015-10-21 13:01:53 -07001786 for (const auto& ch : send_streams_) {
solenberg63b34542015-09-29 06:06:31 -07001787 if (!ChangeSend(ch.second->channel(), send)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001788 return false;
solenberg63b34542015-09-29 06:06:31 -07001789 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001790 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001791
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001792 send_ = send;
1793 return true;
1794}
1795
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001796bool WebRtcVoiceMediaChannel::ChangeSend(int channel, SendFlags send) {
1797 if (send == SEND_MICROPHONE) {
1798 if (engine()->voe()->base()->StartSend(channel) == -1) {
1799 LOG_RTCERR1(StartSend, channel);
1800 return false;
1801 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001802 } else { // SEND_NOTHING
henrikg91d6ede2015-09-17 00:24:34 -07001803 RTC_DCHECK(send == SEND_NOTHING);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001804 if (engine()->voe()->base()->StopSend(channel) == -1) {
1805 LOG_RTCERR1(StopSend, channel);
1806 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001807 }
1808 }
1809
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001810 return true;
1811}
1812
Peter Boström0c4e06b2015-10-07 12:23:21 +02001813bool WebRtcVoiceMediaChannel::SetAudioSend(uint32_t ssrc,
1814 bool enable,
solenberg1dd98f32015-09-10 01:57:14 -07001815 const AudioOptions* options,
1816 AudioRenderer* renderer) {
solenberg566ef242015-11-06 15:34:49 -08001817 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg1dd98f32015-09-10 01:57:14 -07001818 // TODO(solenberg): The state change should be fully rolled back if any one of
1819 // these calls fail.
1820 if (!SetLocalRenderer(ssrc, renderer)) {
1821 return false;
1822 }
solenbergdfc8f4f2015-10-01 02:31:10 -07001823 if (!MuteStream(ssrc, !enable)) {
solenberg1dd98f32015-09-10 01:57:14 -07001824 return false;
1825 }
solenbergdfc8f4f2015-10-01 02:31:10 -07001826 if (enable && options) {
solenberg1dd98f32015-09-10 01:57:14 -07001827 return SetOptions(*options);
1828 }
1829 return true;
1830}
1831
solenberg0a617e22015-10-20 15:49:38 -07001832int WebRtcVoiceMediaChannel::CreateVoEChannel() {
1833 int id = engine()->CreateVoEChannel();
1834 if (id == -1) {
1835 LOG_RTCERR0(CreateVoEChannel);
1836 return -1;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001837 }
solenberg0a617e22015-10-20 15:49:38 -07001838 if (engine()->voe()->network()->RegisterExternalTransport(id, *this) == -1) {
1839 LOG_RTCERR2(RegisterExternalTransport, id, this);
1840 engine()->voe()->base()->DeleteChannel(id);
1841 return -1;
1842 }
1843 return id;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001844}
1845
solenberg7add0582015-11-20 09:59:34 -08001846bool WebRtcVoiceMediaChannel::DeleteVoEChannel(int channel) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001847 if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) {
1848 LOG_RTCERR1(DeRegisterExternalTransport, channel);
1849 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001850 if (engine()->voe()->base()->DeleteChannel(channel) == -1) {
1851 LOG_RTCERR1(DeleteChannel, channel);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001852 return false;
1853 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001854 return true;
1855}
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001856
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001857bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
solenberg566ef242015-11-06 15:34:49 -08001858 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -07001859 LOG(LS_INFO) << "AddSendStream: " << sp.ToString();
1860
1861 uint32_t ssrc = sp.first_ssrc();
1862 RTC_DCHECK(0 != ssrc);
1863
1864 if (GetSendChannelId(ssrc) != -1) {
1865 LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001866 return false;
1867 }
1868
solenberg0a617e22015-10-20 15:49:38 -07001869 // Create a new channel for sending audio data.
1870 int channel = CreateVoEChannel();
1871 if (channel == -1) {
1872 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001873 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001874
solenbergc96df772015-10-21 13:01:53 -07001875 // Save the channel to send_streams_, so that RemoveSendStream() can still
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001876 // delete the channel in case failure happens below.
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001877 webrtc::AudioTransport* audio_transport =
1878 engine()->voe()->base()->audio_transport();
solenberg3a941542015-11-16 07:34:50 -08001879 send_streams_.insert(std::make_pair(ssrc, new WebRtcAudioSendStream(
1880 channel, audio_transport, ssrc, sp.cname, send_rtp_extensions_, call_)));
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001881
solenberg0a617e22015-10-20 15:49:38 -07001882 // Set the current codecs to be used for the new channel. We need to do this
1883 // after adding the channel to send_channels_, because of how max bitrate is
1884 // currently being configured by SetSendCodec().
1885 if (!send_codecs_.empty() && !SetSendCodecs(channel, send_codecs_)) {
1886 RemoveSendStream(ssrc);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001887 return false;
1888 }
1889
1890 // At this point the channel's local SSRC has been updated. If the channel is
solenberg0a617e22015-10-20 15:49:38 -07001891 // the first send channel make sure that all the receive channels are updated
1892 // with the same SSRC in order to send receiver reports.
solenbergc96df772015-10-21 13:01:53 -07001893 if (send_streams_.size() == 1) {
solenberg0a617e22015-10-20 15:49:38 -07001894 receiver_reports_ssrc_ = ssrc;
solenberg7add0582015-11-20 09:59:34 -08001895 for (const auto& stream : recv_streams_) {
1896 int recv_channel = stream.second->channel();
solenberg0a617e22015-10-20 15:49:38 -07001897 if (engine()->voe()->rtp()->SetLocalSSRC(recv_channel, ssrc) != 0) {
solenberg7add0582015-11-20 09:59:34 -08001898 LOG_RTCERR2(SetLocalSSRC, recv_channel, ssrc);
solenberg1ac56142015-10-13 03:58:19 -07001899 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001900 }
solenberg0a617e22015-10-20 15:49:38 -07001901 engine()->voe()->base()->AssociateSendChannel(recv_channel, channel);
1902 LOG(LS_INFO) << "VoiceEngine channel #" << recv_channel
1903 << " is associated with channel #" << channel << ".";
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001904 }
1905 }
1906
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001907 return ChangeSend(channel, desired_send_);
1908}
1909
Peter Boström0c4e06b2015-10-07 12:23:21 +02001910bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32_t ssrc) {
solenberg566ef242015-11-06 15:34:49 -08001911 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg3a941542015-11-16 07:34:50 -08001912 LOG(LS_INFO) << "RemoveSendStream: " << ssrc;
1913
solenbergc96df772015-10-21 13:01:53 -07001914 auto it = send_streams_.find(ssrc);
1915 if (it == send_streams_.end()) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001916 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
1917 << " which doesn't exist.";
1918 return false;
1919 }
1920
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00001921 int channel = it->second->channel();
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001922 ChangeSend(channel, SEND_NOTHING);
1923
solenberg7add0582015-11-20 09:59:34 -08001924 // Clean up and delete the send stream+channel.
solenberg0a617e22015-10-20 15:49:38 -07001925 LOG(LS_INFO) << "Removing audio send stream " << ssrc
1926 << " with VoiceEngine channel #" << channel << ".";
solenberg7add0582015-11-20 09:59:34 -08001927 delete it->second;
1928 send_streams_.erase(it);
1929 if (!DeleteVoEChannel(channel)) {
solenberg0a617e22015-10-20 15:49:38 -07001930 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001931 }
solenbergc96df772015-10-21 13:01:53 -07001932 if (send_streams_.empty()) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00001933 ChangeSend(SEND_NOTHING);
solenberg0a617e22015-10-20 15:49:38 -07001934 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001935 return true;
1936}
1937
1938bool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
solenberg566ef242015-11-06 15:34:49 -08001939 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergd97ec302015-10-07 01:40:33 -07001940 LOG(LS_INFO) << "AddRecvStream: " << sp.ToString();
1941
solenberg0b675462015-10-09 01:37:09 -07001942 if (!ValidateStreamParams(sp)) {
wu@webrtc.org78187522013-10-07 23:32:02 +00001943 return false;
1944 }
1945
solenberg7add0582015-11-20 09:59:34 -08001946 const uint32_t ssrc = sp.first_ssrc();
solenberg0b675462015-10-09 01:37:09 -07001947 if (ssrc == 0) {
1948 LOG(LS_WARNING) << "AddRecvStream with ssrc==0 is not supported.";
1949 return false;
1950 }
1951
solenberg1ac56142015-10-13 03:58:19 -07001952 // Remove the default receive stream if one had been created with this ssrc;
1953 // we'll recreate it then.
1954 if (IsDefaultRecvStream(ssrc)) {
1955 RemoveRecvStream(ssrc);
1956 }
solenberg0b675462015-10-09 01:37:09 -07001957
solenberg7add0582015-11-20 09:59:34 -08001958 if (GetReceiveChannelId(ssrc) != -1) {
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001959 LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001960 return false;
1961 }
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02001962
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001963 // Create a new channel for receiving audio data.
solenberg7add0582015-11-20 09:59:34 -08001964 const int channel = CreateVoEChannel();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001965 if (channel == -1) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001966 return false;
1967 }
Minyue2013aec2015-05-13 14:14:42 +02001968
solenberg1ac56142015-10-13 03:58:19 -07001969 // Turn off all supported codecs.
solenberg26c8c912015-11-27 04:00:25 -08001970 // TODO(solenberg): Remove once "no codecs" is the default state of a stream.
1971 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) {
1972 voe_codec.pltype = -1;
1973 if (engine()->voe()->codec()->SetRecPayloadType(channel, voe_codec) == -1) {
1974 LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
1975 DeleteVoEChannel(channel);
1976 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977 }
1978 }
1979
solenberg1ac56142015-10-13 03:58:19 -07001980 // Only enable those configured for this channel.
1981 for (const auto& codec : recv_codecs_) {
1982 webrtc::CodecInst voe_codec;
solenberg26c8c912015-11-27 04:00:25 -08001983 if (WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) {
solenberg1ac56142015-10-13 03:58:19 -07001984 voe_codec.pltype = codec.id;
1985 if (engine()->voe()->codec()->SetRecPayloadType(
1986 channel, voe_codec) == -1) {
1987 LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
solenberg7add0582015-11-20 09:59:34 -08001988 DeleteVoEChannel(channel);
solenberg1ac56142015-10-13 03:58:19 -07001989 return false;
1990 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00001991 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001992 }
solenberg8fb30c32015-10-13 03:06:58 -07001993
solenberg7add0582015-11-20 09:59:34 -08001994 const int send_channel = GetSendChannelId(receiver_reports_ssrc_);
1995 if (send_channel != -1) {
1996 // Associate receive channel with first send channel (so the receive channel
1997 // can obtain RTT from the send channel)
1998 engine()->voe()->base()->AssociateSendChannel(channel, send_channel);
1999 LOG(LS_INFO) << "VoiceEngine channel #" << channel
2000 << " is associated with channel #" << send_channel << ".";
buildbot@webrtc.org150835e2014-05-06 15:54:38 +00002001 }
2002
solenberg7add0582015-11-20 09:59:34 -08002003 recv_streams_.insert(std::make_pair(ssrc, new WebRtcAudioReceiveStream(
2004 channel, ssrc, receiver_reports_ssrc_,
2005 options_.combined_audio_video_bwe.value_or(false), sp.sync_label,
2006 recv_rtp_extensions_, call_)));
2007
2008 SetNack(channel, nack_enabled_);
solenberg1ac56142015-10-13 03:58:19 -07002009 SetPlayout(channel, playout_);
solenberg7add0582015-11-20 09:59:34 -08002010
solenberg1ac56142015-10-13 03:58:19 -07002011 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002012}
2013
Peter Boström0c4e06b2015-10-07 12:23:21 +02002014bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) {
solenberg566ef242015-11-06 15:34:49 -08002015 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergd97ec302015-10-07 01:40:33 -07002016 LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
2017
solenberg7add0582015-11-20 09:59:34 -08002018 const auto it = recv_streams_.find(ssrc);
2019 if (it == recv_streams_.end()) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002020 LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
2021 << " which doesn't exist.";
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002022 return false;
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002023 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002024
solenberg1ac56142015-10-13 03:58:19 -07002025 // Deregister default channel, if that's the one being destroyed.
2026 if (IsDefaultRecvStream(ssrc)) {
2027 default_recv_ssrc_ = -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002028 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002029
solenberg7add0582015-11-20 09:59:34 -08002030 const int channel = it->second->channel();
2031
2032 // Clean up and delete the receive stream+channel.
2033 LOG(LS_INFO) << "Removing audio receive stream " << ssrc
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002034 << " with VoiceEngine channel #" << channel << ".";
solenberg7add0582015-11-20 09:59:34 -08002035 delete it->second;
2036 recv_streams_.erase(it);
2037 return DeleteVoEChannel(channel);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002038}
2039
Peter Boström0c4e06b2015-10-07 12:23:21 +02002040bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32_t ssrc,
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002041 AudioRenderer* renderer) {
solenbergc96df772015-10-21 13:01:53 -07002042 auto it = send_streams_.find(ssrc);
2043 if (it == send_streams_.end()) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002044 if (renderer) {
2045 // Return an error if trying to set a valid renderer with an invalid ssrc.
2046 LOG(LS_ERROR) << "SetLocalRenderer failed with ssrc "<< ssrc;
2047 return false;
2048 }
2049
2050 // The channel likely has gone away, do nothing.
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002051 return true;
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002052 }
2053
solenberg1ac56142015-10-13 03:58:19 -07002054 if (renderer) {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002055 it->second->Start(renderer);
solenberg1ac56142015-10-13 03:58:19 -07002056 } else {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002057 it->second->Stop();
solenberg1ac56142015-10-13 03:58:19 -07002058 }
henrike@webrtc.org1e09a712013-07-26 19:17:59 +00002059
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002060 return true;
2061}
2062
2063bool WebRtcVoiceMediaChannel::GetActiveStreams(
2064 AudioInfo::StreamList* actives) {
solenberg566ef242015-11-06 15:34:49 -08002065 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002066 actives->clear();
solenberg7add0582015-11-20 09:59:34 -08002067 for (const auto& ch : recv_streams_) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002068 int level = GetOutputLevel(ch.second->channel());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002069 if (level > 0) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002070 actives->push_back(std::make_pair(ch.first, level));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002071 }
2072 }
2073 return true;
2074}
2075
2076int WebRtcVoiceMediaChannel::GetOutputLevel() {
solenberg566ef242015-11-06 15:34:49 -08002077 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg1ac56142015-10-13 03:58:19 -07002078 int highest = 0;
solenberg7add0582015-11-20 09:59:34 -08002079 for (const auto& ch : recv_streams_) {
solenberg8fb30c32015-10-13 03:06:58 -07002080 highest = std::max(GetOutputLevel(ch.second->channel()), highest);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081 }
2082 return highest;
2083}
2084
2085int WebRtcVoiceMediaChannel::GetTimeSinceLastTyping() {
2086 int ret;
2087 if (engine()->voe()->processing()->TimeSinceLastTyping(ret) == -1) {
2088 // In case of error, log the info and continue
2089 LOG_RTCERR0(TimeSinceLastTyping);
2090 ret = -1;
2091 } else {
2092 ret *= 1000; // We return ms, webrtc returns seconds.
2093 }
2094 return ret;
2095}
2096
2097void WebRtcVoiceMediaChannel::SetTypingDetectionParameters(int time_window,
2098 int cost_per_typing, int reporting_threshold, int penalty_decay,
2099 int type_event_delay) {
2100 if (engine()->voe()->processing()->SetTypingDetectionParameters(
2101 time_window, cost_per_typing,
2102 reporting_threshold, penalty_decay, type_event_delay) == -1) {
2103 // In case of error, log the info and continue
2104 LOG_RTCERR5(SetTypingDetectionParameters, time_window,
2105 cost_per_typing, reporting_threshold, penalty_decay,
2106 type_event_delay);
2107 }
2108}
2109
solenberg4bac9c52015-10-09 02:32:53 -07002110bool WebRtcVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) {
solenberg566ef242015-11-06 15:34:49 -08002111 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg1ac56142015-10-13 03:58:19 -07002112 if (ssrc == 0) {
2113 default_recv_volume_ = volume;
2114 if (default_recv_ssrc_ == -1) {
2115 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002116 }
solenberg1ac56142015-10-13 03:58:19 -07002117 ssrc = static_cast<uint32_t>(default_recv_ssrc_);
2118 }
2119 int ch_id = GetReceiveChannelId(ssrc);
2120 if (ch_id < 0) {
2121 LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc;
2122 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002123 }
2124
solenberg1ac56142015-10-13 03:58:19 -07002125 if (-1 == engine()->voe()->volume()->SetChannelOutputVolumeScaling(ch_id,
2126 volume)) {
2127 LOG_RTCERR2(SetChannelOutputVolumeScaling, ch_id, volume);
2128 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002129 }
solenberg1ac56142015-10-13 03:58:19 -07002130 LOG(LS_INFO) << "SetOutputVolume to " << volume
2131 << " for channel " << ch_id << " and ssrc " << ssrc;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002132 return true;
2133}
2134
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002135bool WebRtcVoiceMediaChannel::CanInsertDtmf() {
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002136 return dtmf_payload_type_ ? true : false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002137}
2138
solenberg1d63dd02015-12-02 12:35:09 -08002139bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event,
2140 int duration) {
solenberg566ef242015-11-06 15:34:49 -08002141 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002142 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::InsertDtmf";
2143 if (!dtmf_payload_type_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002144 return false;
2145 }
2146
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002147 // Figure out which WebRtcAudioSendStream to send the event on.
2148 auto it = ssrc != 0 ? send_streams_.find(ssrc) : send_streams_.begin();
2149 if (it == send_streams_.end()) {
2150 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
solenberg1d63dd02015-12-02 12:35:09 -08002151 return false;
2152 }
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002153 if (event < kMinTelephoneEventCode ||
2154 event > kMaxTelephoneEventCode) {
2155 LOG(LS_WARNING) << "DTMF event code " << event << " out of range.";
solenberg1d63dd02015-12-02 12:35:09 -08002156 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002157 }
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002158 if (duration < kMinTelephoneEventDuration ||
2159 duration > kMaxTelephoneEventDuration) {
2160 LOG(LS_WARNING) << "DTMF event duration " << duration << " out of range.";
2161 return false;
2162 }
2163 return it->second->SendTelephoneEvent(*dtmf_payload_type_, event, duration);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002164}
2165
wu@webrtc.orga9890802013-12-13 00:21:03 +00002166void WebRtcVoiceMediaChannel::OnPacketReceived(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002167 rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
solenberg566ef242015-11-06 15:34:49 -08002168 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02002169
solenberg1ac56142015-10-13 03:58:19 -07002170 uint32_t ssrc = 0;
2171 if (!GetRtpSsrc(packet->data(), packet->size(), &ssrc)) {
2172 return;
2173 }
2174
solenberg7e63ef02015-11-20 00:19:43 -08002175 // If we don't have a default channel, and the SSRC is unknown, create a
2176 // default channel.
2177 if (default_recv_ssrc_ == -1 && GetReceiveChannelId(ssrc) == -1) {
solenberg1ac56142015-10-13 03:58:19 -07002178 StreamParams sp;
2179 sp.ssrcs.push_back(ssrc);
2180 LOG(LS_INFO) << "Creating default receive stream for SSRC=" << ssrc << ".";
2181 if (!AddRecvStream(sp)) {
2182 LOG(LS_WARNING) << "Could not create default receive stream.";
2183 return;
2184 }
2185 default_recv_ssrc_ = ssrc;
2186 SetOutputVolume(default_recv_ssrc_, default_recv_volume_);
2187 }
2188
2189 // Forward packet to Call. If the SSRC is unknown we'll return after this.
Fredrik Solenberg709ed672015-09-15 12:26:33 +02002190 const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp,
2191 packet_time.not_before);
solenberg1ac56142015-10-13 03:58:19 -07002192 webrtc::PacketReceiver::DeliveryStatus delivery_result =
2193 call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO,
2194 reinterpret_cast<const uint8_t*>(packet->data()), packet->size(),
2195 webrtc_packet_time);
2196 if (webrtc::PacketReceiver::DELIVERY_OK != delivery_result) {
solenberg7e63ef02015-11-20 00:19:43 -08002197 // If the SSRC is unknown here, route it to the default channel, if we have
2198 // one. See: https://bugs.chromium.org/p/webrtc/issues/detail?id=5208
2199 if (default_recv_ssrc_ == -1) {
2200 return;
2201 } else {
2202 ssrc = default_recv_ssrc_;
2203 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002204 }
2205
solenberg1ac56142015-10-13 03:58:19 -07002206 // Find the channel to send this packet to. It must exist since webrtc::Call
2207 // was able to demux the packet.
2208 int channel = GetReceiveChannelId(ssrc);
2209 RTC_DCHECK(channel != -1);
2210
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002211 // Pass it off to the decoder.
henrike@webrtc.org28654cb2013-07-22 21:07:49 +00002212 engine()->voe()->network()->ReceivedRTPPacket(
solenberg1ac56142015-10-13 03:58:19 -07002213 channel, packet->data(), packet->size(), webrtc_packet_time);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002214}
2215
wu@webrtc.orga9890802013-12-13 00:21:03 +00002216void WebRtcVoiceMediaChannel::OnRtcpReceived(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002217 rtc::Buffer* packet, const rtc::PacketTime& packet_time) {
solenberg566ef242015-11-06 15:34:49 -08002218 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02002219
Fredrik Solenberg709ed672015-09-15 12:26:33 +02002220 // Forward packet to Call as well.
2221 const webrtc::PacketTime webrtc_packet_time(packet_time.timestamp,
2222 packet_time.not_before);
2223 call_->Receiver()->DeliverPacket(webrtc::MediaType::AUDIO,
2224 reinterpret_cast<const uint8_t*>(packet->data()), packet->size(),
2225 webrtc_packet_time);
Fredrik Solenberg4b60c732015-05-07 14:07:48 +02002226
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002227 // Sending channels need all RTCP packets with feedback information.
2228 // Even sender reports can contain attached report blocks.
2229 // Receiving channels need sender reports in order to create
2230 // correct receiver reports.
2231 int type = 0;
kwiberg@webrtc.orgeebcab52015-03-24 09:19:06 +00002232 if (!GetRtcpType(packet->data(), packet->size(), &type)) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002233 LOG(LS_WARNING) << "Failed to parse type from received RTCP packet";
2234 return;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002235 }
2236
solenberg0b675462015-10-09 01:37:09 -07002237 // If it is a sender report, find the receive channel that is listening.
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002238 if (type == kRtcpTypeSR) {
solenberg0b675462015-10-09 01:37:09 -07002239 uint32_t ssrc = 0;
2240 if (!GetRtcpSsrc(packet->data(), packet->size(), &ssrc)) {
2241 return;
2242 }
2243 int recv_channel_id = GetReceiveChannelId(ssrc);
2244 if (recv_channel_id != -1) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002245 engine()->voe()->network()->ReceivedRTCPPacket(
solenberg0b675462015-10-09 01:37:09 -07002246 recv_channel_id, packet->data(), packet->size());
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002247 }
2248 }
2249
2250 // SR may continue RR and any RR entry may correspond to any one of the send
2251 // channels. So all RTCP packets must be forwarded all send channels. VoE
2252 // will filter out RR internally.
solenbergc96df772015-10-21 13:01:53 -07002253 for (const auto& ch : send_streams_) {
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002254 engine()->voe()->network()->ReceivedRTCPPacket(
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002255 ch.second->channel(), packet->data(), packet->size());
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002256 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002257}
2258
Peter Boström0c4e06b2015-10-07 12:23:21 +02002259bool WebRtcVoiceMediaChannel::MuteStream(uint32_t ssrc, bool muted) {
solenberg566ef242015-11-06 15:34:49 -08002260 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg0a617e22015-10-20 15:49:38 -07002261 int channel = GetSendChannelId(ssrc);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002262 if (channel == -1) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002263 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
2264 return false;
2265 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002266 if (engine()->voe()->volume()->SetInputMute(channel, muted) == -1) {
2267 LOG_RTCERR2(SetInputMute, channel, muted);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002268 return false;
2269 }
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002270 // We set the AGC to mute state only when all the channels are muted.
2271 // This implementation is not ideal, instead we should signal the AGC when
2272 // the mic channel is muted/unmuted. We can't do it today because there
2273 // is no good way to know which stream is mapping to the mic channel.
2274 bool all_muted = muted;
solenbergc96df772015-10-21 13:01:53 -07002275 for (const auto& ch : send_streams_) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002276 if (!all_muted) {
2277 break;
2278 }
2279 if (engine()->voe()->volume()->GetInputMute(ch.second->channel(),
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002280 all_muted)) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002281 LOG_RTCERR1(GetInputMute, ch.second->channel());
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002282 return false;
2283 }
2284 }
2285
2286 webrtc::AudioProcessing* ap = engine()->voe()->base()->audio_processing();
solenberg0a617e22015-10-20 15:49:38 -07002287 if (ap) {
buildbot@webrtc.org6b21b712014-07-31 15:08:53 +00002288 ap->set_output_will_be_muted(all_muted);
solenberg0a617e22015-10-20 15:49:38 -07002289 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002290 return true;
2291}
2292
minyue@webrtc.org26236952014-10-29 02:27:08 +00002293// TODO(minyue): SetMaxSendBandwidth() is subject to be renamed to
2294// SetMaxSendBitrate() in future.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002295bool WebRtcVoiceMediaChannel::SetMaxSendBandwidth(int bps) {
minyue@webrtc.org26236952014-10-29 02:27:08 +00002296 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetMaxSendBandwidth.";
minyue@webrtc.org26236952014-10-29 02:27:08 +00002297 return SetSendBitrateInternal(bps);
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002298}
2299
minyue@webrtc.org26236952014-10-29 02:27:08 +00002300bool WebRtcVoiceMediaChannel::SetSendBitrateInternal(int bps) {
2301 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetSendBitrateInternal.";
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002302
minyue@webrtc.org26236952014-10-29 02:27:08 +00002303 send_bitrate_setting_ = true;
2304 send_bitrate_bps_ = bps;
wu@webrtc.org1d1ffc92013-10-16 18:12:02 +00002305
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002306 if (!send_codec_) {
wu@webrtc.org1d1ffc92013-10-16 18:12:02 +00002307 LOG(LS_INFO) << "The send codec has not been set up yet. "
minyue@webrtc.org26236952014-10-29 02:27:08 +00002308 << "The send bitrate setting will be applied later.";
wu@webrtc.org1d1ffc92013-10-16 18:12:02 +00002309 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002310 }
2311
minyue@webrtc.org26236952014-10-29 02:27:08 +00002312 // Bitrate is auto by default.
sergeyu@chromium.org4b26e2e2014-01-15 23:15:54 +00002313 // TODO(bemasc): Fix this so that if SetMaxSendBandwidth(50) is followed by
2314 // SetMaxSendBandwith(0), the second call removes the previous limit.
2315 if (bps <= 0)
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002316 return true;
2317
2318 webrtc::CodecInst codec = *send_codec_;
solenberg26c8c912015-11-27 04:00:25 -08002319 bool is_multi_rate = WebRtcVoiceCodecs::IsCodecMultiRate(codec);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002320
2321 if (is_multi_rate) {
2322 // If codec is multi-rate then just set the bitrate.
2323 codec.rate = bps;
solenbergc96df772015-10-21 13:01:53 -07002324 for (const auto& ch : send_streams_) {
solenberg0a617e22015-10-20 15:49:38 -07002325 if (!SetSendCodec(ch.second->channel(), codec)) {
2326 LOG(LS_INFO) << "Failed to set codec " << codec.plname
2327 << " to bitrate " << bps << " bps.";
2328 return false;
2329 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002330 }
2331 return true;
2332 } else {
2333 // If codec is not multi-rate and |bps| is less than the fixed bitrate
2334 // then fail. If codec is not multi-rate and |bps| exceeds or equal the
2335 // fixed bitrate then ignore.
2336 if (bps < codec.rate) {
2337 LOG(LS_INFO) << "Failed to set codec " << codec.plname
2338 << " to bitrate " << bps << " bps"
2339 << ", requires at least " << codec.rate << " bps.";
2340 return false;
2341 }
2342 return true;
2343 }
2344}
2345
2346bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
solenberg566ef242015-11-06 15:34:49 -08002347 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg85a04962015-10-27 03:35:21 -07002348 RTC_DCHECK(info);
solenbergd97ec302015-10-07 01:40:33 -07002349
solenberg85a04962015-10-27 03:35:21 -07002350 // Get SSRC and stats for each sender.
2351 RTC_DCHECK(info->senders.size() == 0);
2352 for (const auto& stream : send_streams_) {
2353 webrtc::AudioSendStream::Stats stats = stream.second->GetStats();
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002354 VoiceSenderInfo sinfo;
solenberg85a04962015-10-27 03:35:21 -07002355 sinfo.add_ssrc(stats.local_ssrc);
2356 sinfo.bytes_sent = stats.bytes_sent;
2357 sinfo.packets_sent = stats.packets_sent;
2358 sinfo.packets_lost = stats.packets_lost;
2359 sinfo.fraction_lost = stats.fraction_lost;
2360 sinfo.codec_name = stats.codec_name;
2361 sinfo.ext_seqnum = stats.ext_seqnum;
2362 sinfo.jitter_ms = stats.jitter_ms;
2363 sinfo.rtt_ms = stats.rtt_ms;
2364 sinfo.audio_level = stats.audio_level;
2365 sinfo.aec_quality_min = stats.aec_quality_min;
2366 sinfo.echo_delay_median_ms = stats.echo_delay_median_ms;
2367 sinfo.echo_delay_std_ms = stats.echo_delay_std_ms;
2368 sinfo.echo_return_loss = stats.echo_return_loss;
2369 sinfo.echo_return_loss_enhancement = stats.echo_return_loss_enhancement;
solenberg566ef242015-11-06 15:34:49 -08002370 sinfo.typing_noise_detected =
2371 (send_ == SEND_NOTHING ? false : stats.typing_noise_detected);
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002372 info->senders.push_back(sinfo);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002373 }
2374
solenberg85a04962015-10-27 03:35:21 -07002375 // Get SSRC and stats for each receiver.
2376 RTC_DCHECK(info->receivers.size() == 0);
solenberg7add0582015-11-20 09:59:34 -08002377 for (const auto& stream : recv_streams_) {
Fredrik Solenberg4f4ec0a2015-10-22 10:49:27 +02002378 webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats();
2379 VoiceReceiverInfo rinfo;
2380 rinfo.add_ssrc(stats.remote_ssrc);
2381 rinfo.bytes_rcvd = stats.bytes_rcvd;
2382 rinfo.packets_rcvd = stats.packets_rcvd;
2383 rinfo.packets_lost = stats.packets_lost;
2384 rinfo.fraction_lost = stats.fraction_lost;
2385 rinfo.codec_name = stats.codec_name;
2386 rinfo.ext_seqnum = stats.ext_seqnum;
2387 rinfo.jitter_ms = stats.jitter_ms;
2388 rinfo.jitter_buffer_ms = stats.jitter_buffer_ms;
2389 rinfo.jitter_buffer_preferred_ms = stats.jitter_buffer_preferred_ms;
2390 rinfo.delay_estimate_ms = stats.delay_estimate_ms;
2391 rinfo.audio_level = stats.audio_level;
2392 rinfo.expand_rate = stats.expand_rate;
2393 rinfo.speech_expand_rate = stats.speech_expand_rate;
2394 rinfo.secondary_decoded_rate = stats.secondary_decoded_rate;
2395 rinfo.accelerate_rate = stats.accelerate_rate;
2396 rinfo.preemptive_expand_rate = stats.preemptive_expand_rate;
2397 rinfo.decoding_calls_to_silence_generator =
2398 stats.decoding_calls_to_silence_generator;
2399 rinfo.decoding_calls_to_neteq = stats.decoding_calls_to_neteq;
2400 rinfo.decoding_normal = stats.decoding_normal;
2401 rinfo.decoding_plc = stats.decoding_plc;
2402 rinfo.decoding_cng = stats.decoding_cng;
2403 rinfo.decoding_plc_cng = stats.decoding_plc_cng;
2404 rinfo.capture_start_ntp_time_ms = stats.capture_start_ntp_time_ms;
2405 info->receivers.push_back(rinfo);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002406 }
2407
2408 return true;
2409}
2410
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002411int WebRtcVoiceMediaChannel::GetOutputLevel(int channel) {
solenbergd97ec302015-10-07 01:40:33 -07002412 unsigned int ulevel = 0;
2413 int ret = engine()->voe()->volume()->GetSpeechOutputLevel(channel, ulevel);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002414 return (ret == 0) ? static_cast<int>(ulevel) : -1;
2415}
2416
Peter Boström0c4e06b2015-10-07 12:23:21 +02002417int WebRtcVoiceMediaChannel::GetReceiveChannelId(uint32_t ssrc) const {
solenberg566ef242015-11-06 15:34:49 -08002418 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenberg7add0582015-11-20 09:59:34 -08002419 const auto it = recv_streams_.find(ssrc);
2420 if (it != recv_streams_.end()) {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002421 return it->second->channel();
solenberg8fb30c32015-10-13 03:06:58 -07002422 }
solenberg1ac56142015-10-13 03:58:19 -07002423 return -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002424}
2425
Peter Boström0c4e06b2015-10-07 12:23:21 +02002426int WebRtcVoiceMediaChannel::GetSendChannelId(uint32_t ssrc) const {
solenberg566ef242015-11-06 15:34:49 -08002427 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
solenbergc96df772015-10-21 13:01:53 -07002428 const auto it = send_streams_.find(ssrc);
2429 if (it != send_streams_.end()) {
mallinath@webrtc.org67ee6b92014-02-03 16:57:16 +00002430 return it->second->channel();
solenberg8fb30c32015-10-13 03:06:58 -07002431 }
wu@webrtc.org9dba5252013-08-05 20:36:57 +00002432 return -1;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002433}
2434
2435bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec,
2436 const std::vector<AudioCodec>& all_codecs, webrtc::CodecInst* send_codec) {
2437 // Get the RED encodings from the parameter with no name. This may
2438 // change based on what is discussed on the Jingle list.
2439 // The encoding parameter is of the form "a/b"; we only support where
2440 // a == b. Verify this and parse out the value into red_pt.
2441 // If the parameter value is absent (as it will be until we wire up the
2442 // signaling of this message), use the second codec specified (i.e. the
2443 // one after "red") as the encoding parameter.
2444 int red_pt = -1;
2445 std::string red_params;
2446 CodecParameterMap::const_iterator it = red_codec.params.find("");
2447 if (it != red_codec.params.end()) {
2448 red_params = it->second;
2449 std::vector<std::string> red_pts;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002450 if (rtc::split(red_params, '/', &red_pts) != 2 ||
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002451 red_pts[0] != red_pts[1] ||
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00002452 !rtc::FromString(red_pts[0], &red_pt)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002453 LOG(LS_WARNING) << "RED params " << red_params << " not supported.";
2454 return false;
2455 }
2456 } else if (red_codec.params.empty()) {
2457 LOG(LS_WARNING) << "RED params not present, using defaults";
2458 if (all_codecs.size() > 1) {
2459 red_pt = all_codecs[1].id;
2460 }
2461 }
2462
2463 // Try to find red_pt in |codecs|.
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002464 for (const AudioCodec& codec : all_codecs) {
2465 if (codec.id == red_pt) {
2466 // If we find the right codec, that will be the codec we pass to
2467 // SetSendCodec, with the desired payload type.
solenberg26c8c912015-11-27 04:00:25 -08002468 if (WebRtcVoiceEngine::ToCodecInst(codec, send_codec)) {
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002469 return true;
2470 } else {
2471 break;
2472 }
2473 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002474 }
Fredrik Solenbergaf9fb212015-08-26 10:45:53 +02002475 LOG(LS_WARNING) << "RED params " << red_params << " are invalid.";
2476 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002477}
2478
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002479bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) {
2480 if (playout) {
2481 LOG(LS_INFO) << "Starting playout for channel #" << channel;
2482 if (engine()->voe()->base()->StartPlayout(channel) == -1) {
2483 LOG_RTCERR1(StartPlayout, channel);
2484 return false;
2485 }
2486 } else {
2487 LOG(LS_INFO) << "Stopping playout for channel #" << channel;
2488 engine()->voe()->base()->StopPlayout(channel);
2489 }
2490 return true;
2491}
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002492} // namespace cricket
2493
2494#endif // HAVE_WEBRTC_VOICE