10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*
20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * libjingle
30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Copyright 2004 Google Inc.
40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Redistribution and use in source and binary forms, with or without
60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * modification, are permitted provided that the following conditions are met:
70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     this list of conditions and the following disclaimer.
100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     this list of conditions and the following disclaimer in the documentation
120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     and/or other materials provided with the distribution.
130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  3. The name of the author may not be used to endorse or promote products
140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     derived from this software without specific prior written permission.
150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org */
270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef HAVE_CONFIG_H
290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <config.h>
300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef HAVE_WEBRTC_VOICE
330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/webrtc/webrtcvoiceengine.h"
350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <algorithm>
370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <cstdio>
380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <string>
390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <vector>
400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/base64.h"
420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/byteorder.h"
430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/common.h"
440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/helpers.h"
450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/logging.h"
460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/stringencode.h"
470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/stringutils.h"
480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/audiorenderer.h"
490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/constants.h"
500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/streamparams.h"
510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/voiceprocessor.h"
520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/webrtc/webrtcvoe.h"
535528070a0c76057a000b877fc56ca4180ad2087bmallinath@webrtc.org#include "webrtc/common.h"
540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef WIN32
570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <objbase.h>  // NOLINT
580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace cricket {
610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstruct CodecPref {
630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const char* name;
640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int clockrate;
650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int channels;
660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int payload_type;
670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool is_multi_rate;
680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const CodecPref kCodecPrefs[] = {
710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "OPUS",   48000,  2, 111, true },
720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "ISAC",   16000,  1, 103, true },
730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "ISAC",   32000,  1, 104, true },
740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "CELT",   32000,  1, 109, true },
750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "CELT",   32000,  2, 110, true },
760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "G722",   16000,  1, 9,   false },
770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "ILBC",   8000,   1, 102, false },
780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "PCMU",   8000,   1, 0,   false },
790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "PCMA",   8000,   1, 8,   false },
800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "CN",     48000,  1, 107, false },
810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "CN",     32000,  1, 106, false },
820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "CN",     16000,  1, 105, false },
830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "CN",     8000,   1, 13,  false },
840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "red",    8000,   1, 127, false },
850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  { "telephone-event", 8000, 1, 126, false },
860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// For Linux/Mac, using the default device is done by specifying index 0 for
890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// VoE 4.0 and not -1 (which was the case for VoE 3.5).
900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// On Windows Vista and newer, Microsoft introduced the concept of "Default
920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Communications Device". This means that there are two types of default
930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// devices (old Wave Audio style default and Default Communications Device).
940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// On Windows systems which only support Wave Audio style default, uses either
960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// -1 or 0 to select the default device.
970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// On Windows systems which support both "Default Communication Device" and
990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// old Wave Audio style default, use -1 for Default Communications Device and
1000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// -2 for Wave Audio style default, which is what we want to use for clips.
1010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// It's not clear yet whether the -2 index is handled properly on other OSes.
1020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef WIN32
1040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int kDefaultAudioDeviceId = -1;
1050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int kDefaultSoundclipDeviceId = -2;
1060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#else
1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int kDefaultAudioDeviceId = 0;
1080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
1090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const char kIsacCodecName[] = "ISAC";
1110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const char kL16CodecName[] = "L16";
1120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Codec parameters for Opus.
1130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int kOpusMonoBitrate = 32000;
1140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Parameter used for NACK.
1150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// This value is equivalent to 5 seconds of audio data at 20 ms per packet.
1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int kNackMaxPackets = 250;
1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int kOpusStereoBitrate = 64000;
1187162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org// draft-spittka-payload-rtp-opus-03
1197162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org// Opus bitrate should be in the range between 6000 and 510000.
1207162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.orgstatic const int kOpusMinBitrate = 6000;
1217162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.orgstatic const int kOpusMaxBitrate = 510000;
12280303b162fe139828d0661df23e03f09126508acwu@webrtc.org// Default audio dscp value.
12380303b162fe139828d0661df23e03f09126508acwu@webrtc.org// See http://tools.ietf.org/html/rfc2474 for details.
12480303b162fe139828d0661df23e03f09126508acwu@webrtc.org// See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00
12580303b162fe139828d0661df23e03f09126508acwu@webrtc.orgstatic const talk_base::DiffServCodePoint kAudioDscpValue = talk_base::DSCP_EF;
1267162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
127ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org// Ensure we open the file in a writeable path on ChromeOS and Android. This
128ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org// workaround can be removed when it's possible to specify a filename for audio
129ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org// option based AEC dumps.
1307162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org//
1317162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org// TODO(grunell): Use a string in the options instead of hardcoding it here
1327162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org// and let the embedder choose the filename (crbug.com/264223).
1337162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org//
134ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org// NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified
135ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org// below.
136ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org#if defined(CHROMEOS)
1377162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.orgstatic const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump";
138ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.org#elif defined(ANDROID)
139ed274f89091f7acb8cacde3cae1d69cb2a19193dsergeyu@chromium.orgstatic const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump";
1407162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org#else
1417162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.orgstatic const char kAecDumpByAudioOptionFilename[] = "audio.aecdump";
1427162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org#endif
1430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Dumps an AudioCodec in RFC 2327-ish format.
1450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic std::string ToString(const AudioCodec& codec) {
1460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::stringstream ss;
1470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ss << codec.name << "/" << codec.clockrate << "/" << codec.channels
1480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org     << " (" << codec.id << ")";
1490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ss.str();
1500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic std::string ToString(const webrtc::CodecInst& codec) {
1520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::stringstream ss;
1530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ss << codec.plname << "/" << codec.plfreq << "/" << codec.channels
1540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org     << " (" << codec.pltype << ")";
1550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ss.str();
1560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic void LogMultiline(talk_base::LoggingSeverity sev, char* text) {
1590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const char* delim = "\r\n";
1600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) {
1610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_V(sev) << tok;
1620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Severity is an integer because it comes is assumed to be from command line.
1660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic int SeverityToFilter(int severity) {
1670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int filter = webrtc::kTraceNone;
1680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  switch (severity) {
1690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case talk_base::LS_VERBOSE:
1700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      filter |= webrtc::kTraceAll;
1710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case talk_base::LS_INFO:
1720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      filter |= (webrtc::kTraceStateInfo | webrtc::kTraceInfo);
1730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case talk_base::LS_WARNING:
1740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      filter |= (webrtc::kTraceTerseInfo | webrtc::kTraceWarning);
1750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case talk_base::LS_ERROR:
1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      filter |= (webrtc::kTraceError | webrtc::kTraceCritical);
1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return filter;
1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic bool IsCodecMultiRate(const webrtc::CodecInst& codec) {
1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (size_t i = 0; i < ARRAY_SIZE(kCodecPrefs); ++i) {
1830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (_stricmp(kCodecPrefs[i].name, codec.plname) == 0 &&
1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        kCodecPrefs[i].clockrate == codec.plfreq) {
1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return kCodecPrefs[i].is_multi_rate;
1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
1870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
1890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1917587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.orgstatic bool IsTelephoneEventCodec(const std::string& name) {
1927587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  return _stricmp(name.c_str(), "telephone-event") == 0;
1937587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org}
1947587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
1957587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.orgstatic bool IsCNCodec(const std::string& name) {
1967587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  return _stricmp(name.c_str(), "CN") == 0;
1977587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org}
1987587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
1997587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.orgstatic bool IsRedCodec(const std::string& name) {
2007587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  return _stricmp(name.c_str(), "red") == 0;
2017587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org}
2027587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
2030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic bool FindCodec(const std::vector<AudioCodec>& codecs,
2040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                      const AudioCodec& codec,
2050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                      AudioCodec* found_codec) {
2060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
2070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       it != codecs.end(); ++it) {
2080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (it->Matches(codec)) {
2090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (found_codec != NULL) {
2100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        *found_codec = *it;
2110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
2120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
2130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
2160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
217cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org
2180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic bool IsNackEnabled(const AudioCodec& codec) {
2190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack,
2200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                              kParamValueEmpty));
2210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
223cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org// Gets the default set of options applied to the engine. Historically, these
224cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org// were supplied as a combination of flags from the channel manager (ec, agc,
225cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org// ns, and highpass) and the rest hardcoded in InitInternal.
226cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.orgstatic AudioOptions GetDefaultEngineOptions() {
227cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  AudioOptions options;
228cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.echo_cancellation.Set(true);
229cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.auto_gain_control.Set(true);
230cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.noise_suppression.Set(true);
231cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.highpass_filter.Set(true);
232cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.stereo_swapping.Set(false);
233cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.typing_detection.Set(true);
234cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.conference_mode.Set(false);
235cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.adjust_agc_delta.Set(0);
236cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.experimental_agc.Set(false);
237cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.experimental_aec.Set(false);
23870022fa5eb218ec690774cc4a74558699a79600asergeyu@chromium.org  options.experimental_ns.Set(false);
239cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  options.aec_dump.Set(false);
24002632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  options.opus_fec.Set(false);
241cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  return options;
242cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org}
2430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgclass WebRtcSoundclipMedia : public SoundclipMedia {
2450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org public:
2460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  explicit WebRtcSoundclipMedia(WebRtcVoiceEngine *engine)
2470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      : engine_(engine), webrtc_channel_(-1) {
2480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    engine_->RegisterSoundclip(this);
2490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  virtual ~WebRtcSoundclipMedia() {
2520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    engine_->UnregisterSoundclip(this);
2530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (webrtc_channel_ != -1) {
2540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // We shouldn't have to call Disable() here. DeleteChannel() should call
2550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // StopPlayout() while deleting the channel.  We should fix the bug
2560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // inside WebRTC and remove the Disable() call bellow.  This work is
2570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // tracked by bug http://b/issue?id=5382855.
2580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      PlaySound(NULL, 0, 0);
2590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      Disable();
2600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (engine_->voe_sc()->base()->DeleteChannel(webrtc_channel_)
2610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          == -1) {
2620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        LOG_RTCERR1(DeleteChannel, webrtc_channel_);
2630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
2640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool Init() {
26862fe97f10a7a3200c9724851f6a18537ed270cddwu@webrtc.org    if (!engine_->voe_sc()) {
26962fe97f10a7a3200c9724851f6a18537ed270cddwu@webrtc.org      return false;
27062fe97f10a7a3200c9724851f6a18537ed270cddwu@webrtc.org    }
27197fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org    webrtc_channel_ = engine_->CreateSoundclipVoiceChannel();
2720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (webrtc_channel_ == -1) {
2730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR0(CreateChannel);
2740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
2770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool Enable() {
2800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine_->voe_sc()->base()->StartPlayout(webrtc_channel_) == -1) {
2810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR1(StartPlayout, webrtc_channel_);
2820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
2850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool Disable() {
2880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine_->voe_sc()->base()->StopPlayout(webrtc_channel_) == -1) {
2890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR1(StopPlayout, webrtc_channel_);
2900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
2930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  virtual bool PlaySound(const char *buf, int len, int flags) {
2960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // The voe file api is not available in chrome.
2970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!engine_->voe_sc()->file()) {
2980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Must stop playing the current sound (if any), because we are about to
3010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // modify the stream.
3020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine_->voe_sc()->file()->StopPlayingFileLocally(webrtc_channel_)
3030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        == -1) {
3040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR1(StopPlayingFileLocally, webrtc_channel_);
3050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
3060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (buf) {
3090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      stream_.reset(new WebRtcSoundclipStream(buf, len));
3100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      stream_->set_loop((flags & SF_LOOP) != 0);
3110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      stream_->Rewind();
3120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Play it.
3140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (engine_->voe_sc()->file()->StartPlayingFileLocally(
3150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          webrtc_channel_, stream_.get()) == -1) {
3160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        LOG_RTCERR2(StartPlayingFileLocally, webrtc_channel_, stream_.get());
3170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        LOG(LS_ERROR) << "Unable to start soundclip";
3180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return false;
3190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
3200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
3210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      stream_.reset();
3220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
3240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int GetLastEngineError() const { return engine_->voe_sc()->error(); }
3270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org private:
3290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  WebRtcVoiceEngine *engine_;
3300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int webrtc_channel_;
3310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  talk_base::scoped_ptr<WebRtcSoundclipStream> stream_;
3320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
3330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgWebRtcVoiceEngine::WebRtcVoiceEngine()
3350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : voe_wrapper_(new VoEWrapper()),
3360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      voe_wrapper_sc_(new VoEWrapper()),
33762fe97f10a7a3200c9724851f6a18537ed270cddwu@webrtc.org      voe_wrapper_sc_initialized_(false),
3380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      tracing_(new VoETraceWrapper()),
3390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      adm_(NULL),
3400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      adm_sc_(NULL),
3410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      log_filter_(SeverityToFilter(kDefaultLogSeverity)),
3420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      is_dumping_aec_(false),
3430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      desired_local_monitor_enable_(false),
3440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      tx_processor_ssrc_(0),
3450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      rx_processor_ssrc_(0) {
3460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Construct();
3470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgWebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper,
3500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                     VoEWrapper* voe_wrapper_sc,
3510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                     VoETraceWrapper* tracing)
3520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : voe_wrapper_(voe_wrapper),
3530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      voe_wrapper_sc_(voe_wrapper_sc),
35462fe97f10a7a3200c9724851f6a18537ed270cddwu@webrtc.org      voe_wrapper_sc_initialized_(false),
3550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      tracing_(tracing),
3560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      adm_(NULL),
3570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      adm_sc_(NULL),
3580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      log_filter_(SeverityToFilter(kDefaultLogSeverity)),
3590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      is_dumping_aec_(false),
3600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      desired_local_monitor_enable_(false),
361aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      tx_processor_ssrc_(0),
362aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      rx_processor_ssrc_(0) {
363aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  Construct();
364aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
365aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
366aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgvoid WebRtcVoiceEngine::Construct() {
367aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  SetTraceFilter(log_filter_);
368aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  initialized_ = false;
369aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine";
370aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  SetTraceOptions("");
371aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (tracing_->SetTraceCallback(this) == -1) {
372aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG_RTCERR0(SetTraceCallback);
373aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
374aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_->base()->RegisterVoiceEngineObserver(*this) == -1) {
375aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG_RTCERR0(RegisterVoiceEngineObserver);
376aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
377aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Clear the default agc state.
378aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  memset(&default_agc_config_, 0, sizeof(default_agc_config_));
379aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
380aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Load our audio codec list.
381aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  ConstructCodecs();
382aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
383aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Load our RTP Header extensions.
384aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  rtp_header_extensions_.push_back(
385aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      RtpHeaderExtension(kRtpAudioLevelHeaderExtension,
386aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                         kRtpAudioLevelHeaderExtensionDefaultId));
387aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  rtp_header_extensions_.push_back(
388aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
389aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                         kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
390aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  options_ = GetDefaultEngineOptions();
391aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
392aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
393aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgstatic bool IsOpus(const AudioCodec& codec) {
394aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return (_stricmp(codec.name.c_str(), kOpusCodecName) == 0);
395aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
396aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
397aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgstatic bool IsIsac(const AudioCodec& codec) {
398aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return (_stricmp(codec.name.c_str(), kIsacCodecName) == 0);
399aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
400aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
401aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org// True if params["stereo"] == "1"
402aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgstatic bool IsOpusStereoEnabled(const AudioCodec& codec) {
40302632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  int value;
40402632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  return codec.GetParam(kCodecParamStereo, &value) && value == 1;
405aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
406aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
407aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgstatic bool IsValidOpusBitrate(int bitrate) {
408aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return (bitrate >= kOpusMinBitrate && bitrate <= kOpusMaxBitrate);
409aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
410aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
411aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org// Returns 0 if params[kCodecParamMaxAverageBitrate] is not defined or invalid.
412aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org// Returns the value of params[kCodecParamMaxAverageBitrate] otherwise.
413aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgstatic int GetOpusBitrateFromParams(const AudioCodec& codec) {
414aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  int bitrate = 0;
415aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!codec.GetParam(kCodecParamMaxAverageBitrate, &bitrate)) {
416aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return 0;
417aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
418aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!IsValidOpusBitrate(bitrate)) {
419aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_WARNING) << "Codec parameter \"maxaveragebitrate\" has an "
420aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                    << "invalid value: " << bitrate;
421aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return 0;
422aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
423aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return bitrate;
424aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
425aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
42602632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org// Return true params[kCodecParamUseInbandFec] == kParamValueTrue, false
42702632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org// otherwise.
42807617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.orgstatic bool IsOpusFecEnabled(const AudioCodec& codec) {
42902632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  int value;
43002632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  return codec.GetParam(kCodecParamUseInbandFec, &value) && value == 1;
43102632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org}
43207617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org
43302632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org// Set params[kCodecParamUseInbandFec]. Caller should make sure codec is Opus.
43402632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.orgstatic void SetOpusFec(AudioCodec *codec, bool opus_fec) {
43502632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  if (opus_fec) {
43602632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org    codec->params[kCodecParamUseInbandFec] = kParamValueTrue;
43702632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  } else {
43802632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org    codec->params.erase(kCodecParamUseInbandFec);
43902632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  }
44007617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org}
44107617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org
442aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgvoid WebRtcVoiceEngine::ConstructCodecs() {
443aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
444aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
445aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  for (int i = 0; i < ncodecs; ++i) {
446aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    webrtc::CodecInst voe_codec;
447aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) {
448aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      // Skip uncompressed formats.
449aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      if (_stricmp(voe_codec.plname, kL16CodecName) == 0) {
450aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        continue;
451aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      }
452aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
453aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      const CodecPref* pref = NULL;
454aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      for (size_t j = 0; j < ARRAY_SIZE(kCodecPrefs); ++j) {
455aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        if (_stricmp(kCodecPrefs[j].name, voe_codec.plname) == 0 &&
456aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            kCodecPrefs[j].clockrate == voe_codec.plfreq &&
457aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            kCodecPrefs[j].channels == voe_codec.channels) {
458aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          pref = &kCodecPrefs[j];
459aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          break;
460aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        }
461aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      }
462aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
463aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      if (pref) {
464aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        // Use the payload type that we've configured in our pref table;
465aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        // use the offset in our pref table to determine the sort order.
466aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        AudioCodec codec(pref->payload_type, voe_codec.plname, voe_codec.plfreq,
467aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                         voe_codec.rate, voe_codec.channels,
468aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                         ARRAY_SIZE(kCodecPrefs) - (pref - kCodecPrefs));
469aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        LOG(LS_INFO) << ToString(codec);
470aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        if (IsIsac(codec)) {
471aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          // Indicate auto-bandwidth in signaling.
472aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          codec.bitrate = 0;
473aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        }
474aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        if (IsOpus(codec)) {
475aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          // Only add fmtp parameters that differ from the spec.
476aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          if (kPreferredMinPTime != kOpusDefaultMinPTime) {
477aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            codec.params[kCodecParamMinPTime] =
478aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                talk_base::ToString(kPreferredMinPTime);
479aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          }
480aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          if (kPreferredMaxPTime != kOpusDefaultMaxPTime) {
481aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            codec.params[kCodecParamMaxPTime] =
482aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                talk_base::ToString(kPreferredMaxPTime);
483aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          }
484aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          // TODO(hellner): Add ptime, sprop-stereo, stereo and useinbandfec
485aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          // when they can be set to values other than the default.
48602632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org          SetOpusFec(&codec, false);
487aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        }
488aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        codecs_.push_back(codec);
489aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      } else {
490aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec);
491aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      }
492aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
493aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
494aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Make sure they are in local preference order.
495aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  std::sort(codecs_.begin(), codecs_.end(), &AudioCodec::Preferable);
496aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
497aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
498aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgWebRtcVoiceEngine::~WebRtcVoiceEngine() {
499aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine";
500aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) {
501aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG_RTCERR0(DeRegisterVoiceEngineObserver);
502aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
503aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (adm_) {
504aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    voe_wrapper_.reset();
505aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    adm_->Release();
506aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    adm_ = NULL;
507aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
508aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (adm_sc_) {
509aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    voe_wrapper_sc_.reset();
510aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    adm_sc_->Release();
511aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    adm_sc_ = NULL;
512aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
513aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
514aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Test to see if the media processor was deregistered properly
515aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  ASSERT(SignalRxMediaFrame.is_empty());
516aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  ASSERT(SignalTxMediaFrame.is_empty());
517aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
518aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  tracing_->SetTraceCallback(NULL);
519aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
520aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
521aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::Init(talk_base::Thread* worker_thread) {
522aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "WebRtcVoiceEngine::Init";
523aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool res = InitInternal();
524aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (res) {
525aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!";
526aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  } else {
527aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_ERROR) << "WebRtcVoiceEngine::Init failed";
528aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    Terminate();
529aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
530aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return res;
531aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
532aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
533aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::InitInternal() {
534aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Temporarily turn logging level up for the Init call
535aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  int old_filter = log_filter_;
536aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  int extended_filter = log_filter_ | SeverityToFilter(talk_base::LS_INFO);
537aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  SetTraceFilter(extended_filter);
538aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  SetTraceOptions("");
539aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
540aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Init WebRtc VoiceEngine.
541aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_->base()->Init(adm_) == -1) {
542aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG_RTCERR0_EX(Init, voe_wrapper_->error());
543aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    SetTraceFilter(old_filter);
544aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return false;
545aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
546aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
547aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  SetTraceFilter(old_filter);
548aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  SetTraceOptions(log_options_);
549aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
550aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Log the VoiceEngine version info
551aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  char buffer[1024] = "";
552aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  voe_wrapper_->base()->GetVersion(buffer);
553aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "WebRtc VoiceEngine Version:";
554aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LogMultiline(talk_base::LS_INFO, buffer);
555aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
556aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Save the default AGC configuration settings. This must happen before
557aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // calling SetOptions or the default will be overwritten.
558aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) {
559aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG_RTCERR0(GetAgcConfig);
560aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return false;
561aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
562aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
563aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Set defaults for options, so that ApplyOptions applies them explicitly
564aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // when we clear option (channel) overrides. External clients can still
565aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // modify the defaults via SetOptions (on the media engine).
566aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!SetOptions(GetDefaultEngineOptions())) {
567aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return false;
568aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
569aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
570aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Print our codec list again for the call diagnostic log
571aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
572aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs_.begin();
573aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      it != codecs_.end(); ++it) {
574aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << ToString(*it);
575aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
576aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
577aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Disable the DTMF playout when a tone is sent.
578aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // PlayDtmfTone will be used if local playout is needed.
579aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) {
580aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG_RTCERR1(SetDtmfFeedbackStatus, false);
581aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
582aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
583aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  initialized_ = true;
584aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return true;
585aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
586aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
587aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::EnsureSoundclipEngineInit() {
588aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_sc_initialized_) {
589aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return true;
590aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
591aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Note that, if initialization fails, voe_wrapper_sc_initialized_ will still
592aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // be false, so subsequent calls to EnsureSoundclipEngineInit will
593aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // probably just fail again. That's acceptable behavior.
594aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#if defined(LINUX) && !defined(HAVE_LIBPULSE)
595aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  voe_wrapper_sc_->hw()->SetAudioDeviceLayer(webrtc::kAudioLinuxAlsa);
596aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#endif
597aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
598aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Initialize the VoiceEngine instance that we'll use to play out sound clips.
599aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_sc_->base()->Init(adm_sc_) == -1) {
600aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG_RTCERR0_EX(Init, voe_wrapper_sc_->error());
601aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return false;
602aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
603aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
604aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // On Windows, tell it to use the default sound (not communication) devices.
605aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // First check whether there is a valid sound device for playback.
606aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // TODO(juberti): Clean this up when we support setting the soundclip device.
607aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#ifdef WIN32
608aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // The SetPlayoutDevice may not be implemented in the case of external ADM.
609aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // TODO(ronghuawu): We should only check the adm_sc_ here, but current
610aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // PeerConnection interface never set the adm_sc_, so need to check both
611aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // in order to determine if the external adm is used.
612aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!adm_ && !adm_sc_) {
613aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    int num_of_devices = 0;
614aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voe_wrapper_sc_->hw()->GetNumOfPlayoutDevices(num_of_devices) != -1 &&
615aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        num_of_devices > 0) {
616aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      if (voe_wrapper_sc_->hw()->SetPlayoutDevice(kDefaultSoundclipDeviceId)
617aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          == -1) {
618aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        LOG_RTCERR1_EX(SetPlayoutDevice, kDefaultSoundclipDeviceId,
619aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                       voe_wrapper_sc_->error());
620aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        return false;
621aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      }
622aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    } else {
623aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG(LS_WARNING) << "No valid sound playout device found.";
624aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
625aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
626aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#endif
627aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  voe_wrapper_sc_initialized_ = true;
628aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "Initialized WebRtc soundclip engine.";
629aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return true;
630aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
631aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
632aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgvoid WebRtcVoiceEngine::Terminate() {
633aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate";
634aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  initialized_ = false;
635aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
636aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  StopAecDump();
637aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
638aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_sc_) {
639aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    voe_wrapper_sc_initialized_ = false;
640aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    voe_wrapper_sc_->base()->Terminate();
641aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
642aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  voe_wrapper_->base()->Terminate();
643aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  desired_local_monitor_enable_ = false;
644aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
645aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
646aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgint WebRtcVoiceEngine::GetCapabilities() {
647aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return AUDIO_SEND | AUDIO_RECV;
648aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
649aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
650aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgVoiceMediaChannel *WebRtcVoiceEngine::CreateChannel() {
651aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  WebRtcVoiceMediaChannel* ch = new WebRtcVoiceMediaChannel(this);
652aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!ch->valid()) {
653aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    delete ch;
654aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    ch = NULL;
655aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
656aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return ch;
657aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
658aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
659aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgSoundclipMedia *WebRtcVoiceEngine::CreateSoundclip() {
660aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!EnsureSoundclipEngineInit()) {
661aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_ERROR) << "Unable to create soundclip: soundclip engine failed to "
662aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                  << "initialize.";
663aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return NULL;
664aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
665aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  WebRtcSoundclipMedia *soundclip = new WebRtcSoundclipMedia(this);
666aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!soundclip->Init() || !soundclip->Enable()) {
667aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    delete soundclip;
668aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return NULL;
669aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
670aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return soundclip;
671aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
672aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
673aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::SetOptions(const AudioOptions& options) {
674aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!ApplyOptions(options)) {
675aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return false;
676aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
677aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  options_ = options;
678aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return true;
679aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
680aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
681aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::SetOptionOverrides(const AudioOptions& overrides) {
682aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "Setting option overrides: " << overrides.ToString();
683aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!ApplyOptions(overrides)) {
684aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return false;
685aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
686aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  option_overrides_ = overrides;
687aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return true;
688aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
689aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
690aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::ClearOptionOverrides() {
691aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "Clearing option overrides.";
692aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  AudioOptions options = options_;
693aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Only call ApplyOptions if |options_overrides_| contains overrided options.
694aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // ApplyOptions affects NS, AGC other options that is shared between
695aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // all WebRtcVoiceEngineChannels.
696aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (option_overrides_ == AudioOptions()) {
697aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return true;
698aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
699aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
700aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!ApplyOptions(options)) {
701aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return false;
702aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
703aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  option_overrides_ = AudioOptions();
704aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return true;
705aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
706aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
707aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org// AudioOptions defaults are set in InitInternal (for options with corresponding
708aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org// MediaEngineInterface flags) and in SetOptions(int) for flagless options.
709aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
710aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  AudioOptions options = options_in;  // The options are modified below.
711aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // kEcConference is AEC with high suppression.
712aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  webrtc::EcModes ec_mode = webrtc::kEcConference;
713aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone;
714aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog;
715aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  webrtc::NsModes ns_mode = webrtc::kNsHighSuppression;
716aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool aecm_comfort_noise = false;
717aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.aecm_generate_comfort_noise.Get(&aecm_comfort_noise)) {
718aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_VERBOSE) << "Comfort noise explicitly set to "
719aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                    << aecm_comfort_noise << " (default is false).";
720aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
721aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
722aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#if defined(IOS)
723aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // On iOS, VPIO provides built-in EC and AGC.
724aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  options.echo_cancellation.Set(false);
725aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  options.auto_gain_control.Set(false);
726aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#elif defined(ANDROID)
727aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  ec_mode = webrtc::kEcAecm;
728aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#endif
729aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
730aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#if defined(IOS) || defined(ANDROID)
731aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Set the AGC mode for iOS as well despite disabling it above, to avoid
732aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // unsupported configuration errors from webrtc.
733aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  agc_mode = webrtc::kAgcFixedDigital;
734aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  options.typing_detection.Set(false);
735aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  options.experimental_agc.Set(false);
736aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  options.experimental_aec.Set(false);
737aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  options.experimental_ns.Set(false);
738aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#endif
739aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
740aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "Applying audio options: " << options.ToString();
741aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
742aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing();
743aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
744aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool echo_cancellation;
745aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.echo_cancellation.Get(&echo_cancellation)) {
746aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voep->SetEcStatus(echo_cancellation, ec_mode) == -1) {
747aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR2(SetEcStatus, echo_cancellation, ec_mode);
748aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      return false;
749aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    } else {
750aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG(LS_VERBOSE) << "Echo control set to " << echo_cancellation
751aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                      << " with mode " << ec_mode;
752aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
753aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#if !defined(ANDROID)
754aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // TODO(ajm): Remove the error return on Android from webrtc.
755aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voep->SetEcMetricsStatus(echo_cancellation) == -1) {
756aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR1(SetEcMetricsStatus, echo_cancellation);
757aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      return false;
758aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
759aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#endif
760aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (ec_mode == webrtc::kEcAecm) {
761aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      if (voep->SetAecmMode(aecm_mode, aecm_comfort_noise) != 0) {
762aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        LOG_RTCERR2(SetAecmMode, aecm_mode, aecm_comfort_noise);
763aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        return false;
764aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      }
765aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
766aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
767aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
768aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool auto_gain_control;
769aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.auto_gain_control.Get(&auto_gain_control)) {
770aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voep->SetAgcStatus(auto_gain_control, agc_mode) == -1) {
771aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR2(SetAgcStatus, auto_gain_control, agc_mode);
772aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      return false;
773aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    } else {
774aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG(LS_VERBOSE) << "Auto gain set to " << auto_gain_control
775aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                      << " with mode " << agc_mode;
776aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
777aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
778aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
779aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.tx_agc_target_dbov.IsSet() ||
780aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      options.tx_agc_digital_compression_gain.IsSet() ||
781aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      options.tx_agc_limiter.IsSet()) {
782aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // Override default_agc_config_. Generally, an unset option means "leave
783aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // the VoE bits alone" in this function, so we want whatever is set to be
784aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // stored as the new "default". If we didn't, then setting e.g.
785aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // tx_agc_target_dbov would reset digital compression gain and limiter
786aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // settings.
787aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // Also, if we don't update default_agc_config_, then adjust_agc_delta
788aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // would be an offset from the original values, and not whatever was set
789aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // explicitly.
790aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    default_agc_config_.targetLeveldBOv =
791aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        options.tx_agc_target_dbov.GetWithDefaultIfUnset(
792aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            default_agc_config_.targetLeveldBOv);
793aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    default_agc_config_.digitalCompressionGaindB =
794aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        options.tx_agc_digital_compression_gain.GetWithDefaultIfUnset(
795aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            default_agc_config_.digitalCompressionGaindB);
796aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    default_agc_config_.limiterEnable =
797aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        options.tx_agc_limiter.GetWithDefaultIfUnset(
798aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            default_agc_config_.limiterEnable);
799aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) {
800aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR3(SetAgcConfig,
801aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                  default_agc_config_.targetLeveldBOv,
802aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                  default_agc_config_.digitalCompressionGaindB,
803aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                  default_agc_config_.limiterEnable);
804aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      return false;
805aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
806aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
807aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
808aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool noise_suppression;
809aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.noise_suppression.Get(&noise_suppression)) {
810aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voep->SetNsStatus(noise_suppression, ns_mode) == -1) {
811aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR2(SetNsStatus, noise_suppression, ns_mode);
812aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      return false;
813aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    } else {
814aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG(LS_VERBOSE) << "Noise suppression set to " << noise_suppression
815aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                      << " with mode " << ns_mode;
816aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
817aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
818aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
819aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool experimental_ns;
820aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.experimental_ns.Get(&experimental_ns)) {
821aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    webrtc::AudioProcessing* audioproc =
822aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        voe_wrapper_->base()->audio_processing();
823aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
824aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // returns NULL on audio_processing().
825aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (audioproc) {
826aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      if (audioproc->EnableExperimentalNs(experimental_ns) == -1) {
827aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        LOG_RTCERR1(EnableExperimentalNs, experimental_ns);
828aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        return false;
829aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      }
830aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    } else {
831aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG(LS_VERBOSE) << "Experimental noise suppression set to "
832aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                      << experimental_ns;
833aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
834aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
835aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
836aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool highpass_filter;
837aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.highpass_filter.Get(&highpass_filter)) {
838aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "High pass filter enabled? " << highpass_filter;
839aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voep->EnableHighPassFilter(highpass_filter) == -1) {
840aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR1(SetHighpassFilterStatus, highpass_filter);
841aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      return false;
842aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
843aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
844aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
845aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool stereo_swapping;
846aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.stereo_swapping.Get(&stereo_swapping)) {
847aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "Stereo swapping enabled? " << stereo_swapping;
848aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    voep->EnableStereoChannelSwapping(stereo_swapping);
849aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voep->IsStereoChannelSwappingEnabled() != stereo_swapping) {
850aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR1(EnableStereoChannelSwapping, stereo_swapping);
851aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      return false;
852aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
853aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
854aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
855aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool typing_detection;
856aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.typing_detection.Get(&typing_detection)) {
857aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "Typing detection is enabled? " << typing_detection;
858aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voep->SetTypingDetectionStatus(typing_detection) == -1) {
859aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      // In case of error, log the info and continue
860aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR1(SetTypingDetectionStatus, typing_detection);
861aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
862aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
863aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
864aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  int adjust_agc_delta;
865aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.adjust_agc_delta.Get(&adjust_agc_delta)) {
866aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "Adjust agc delta is " << adjust_agc_delta;
867aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (!AdjustAgcLevel(adjust_agc_delta)) {
868aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      return false;
869aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
870aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
871aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
872aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool aec_dump;
873aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.aec_dump.Get(&aec_dump)) {
874aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "Aec dump is enabled? " << aec_dump;
875aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (aec_dump)
876aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      StartAecDump(kAecDumpByAudioOptionFilename);
877aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    else
878aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      StopAecDump();
879aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
880aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
881aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool experimental_aec;
882aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.experimental_aec.Get(&experimental_aec)) {
883aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "Experimental aec is " << experimental_aec;
884aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    webrtc::AudioProcessing* audioproc =
885aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        voe_wrapper_->base()->audio_processing();
886aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
887aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    // returns NULL on audio_processing().
888aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (audioproc) {
889aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      webrtc::Config config;
890aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      config.Set<webrtc::DelayCorrection>(
891aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org          new webrtc::DelayCorrection(experimental_aec));
892aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      audioproc->SetExtraOptions(config);
893aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
894aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
895aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
896aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  uint32 recording_sample_rate;
897aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.recording_sample_rate.Get(&recording_sample_rate)) {
898aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "Recording sample rate is " << recording_sample_rate;
899aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voe_wrapper_->hw()->SetRecordingSampleRate(recording_sample_rate)) {
900aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR1(SetRecordingSampleRate, recording_sample_rate);
901aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
902aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
903aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
904aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  uint32 playout_sample_rate;
905aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (options.playout_sample_rate.Get(&playout_sample_rate)) {
906aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_INFO) << "Playout sample rate is " << playout_sample_rate;
907aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voe_wrapper_->hw()->SetPlayoutSampleRate(playout_sample_rate)) {
908aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR1(SetPlayoutSampleRate, playout_sample_rate);
909aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
910aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
911aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
91202632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  bool opus_fec = false;
91302632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  if (options.opus_fec.Get(&opus_fec)) {
91402632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org    LOG(LS_INFO) << "Opus FEC is enabled? " << opus_fec;
91502632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org    for (std::vector<AudioCodec>::iterator it = codecs_.begin();
91602632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org        it != codecs_.end(); ++it) {
91702632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org      if (IsOpus(*it))
91802632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org        SetOpusFec(&(*it), opus_fec);
91902632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org    }
92002632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org  }
92102632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org
922aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return true;
923aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
924aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
925aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::SetDelayOffset(int offset) {
926aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  voe_wrapper_->processing()->SetDelayOffsetMs(offset);
927aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (voe_wrapper_->processing()->DelayOffsetMs() != offset) {
928aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG_RTCERR1(SetDelayOffsetMs, offset);
929aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    return false;
930aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
931aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
932aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  return true;
933aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org}
934aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
935aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgstruct ResumeEntry {
936aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  ResumeEntry(WebRtcVoiceMediaChannel *c, bool p, SendFlags s)
937aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      : channel(c),
938aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        playout(p),
939aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org        send(s) {
940aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
941aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
942aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  WebRtcVoiceMediaChannel *channel;
943aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool playout;
944aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  SendFlags send;
945aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org};
946aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
947aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org// TODO(juberti): Refactor this so that the core logic can be used to set the
948aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org// soundclip device. At that time, reinstate the soundclip pause/resume code.
949aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.orgbool WebRtcVoiceEngine::SetDevices(const Device* in_device,
950aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org                                   const Device* out_device) {
951aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#if !defined(IOS)
952aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  int in_id = in_device ? talk_base::FromString<int>(in_device->id) :
953aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      kDefaultAudioDeviceId;
954aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  int out_id = out_device ? talk_base::FromString<int>(out_device->id) :
955aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      kDefaultAudioDeviceId;
956aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // The device manager uses -1 as the default device, which was the case for
957aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // VoE 3.5. VoE 4.0, however, uses 0 as the default in Linux and Mac.
958aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#ifndef WIN32
959aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (-1 == in_id) {
960aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    in_id = kDefaultAudioDeviceId;
961aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
962aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (-1 == out_id) {
963aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    out_id = kDefaultAudioDeviceId;
964aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
965aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org#endif
966aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
967aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  std::string in_name = (in_id != kDefaultAudioDeviceId) ?
968aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      in_device->name : "Default device";
969aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  std::string out_name = (out_id != kDefaultAudioDeviceId) ?
970aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      out_device->name : "Default device";
971aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  LOG(LS_INFO) << "Setting microphone to (id=" << in_id << ", name=" << in_name
972aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            << ") and speaker to (id=" << out_id << ", name=" << out_name
973aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org            << ")";
974aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
975aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // If we're running the local monitor, we need to stop it first.
976aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  bool ret = true;
977aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!PauseLocalMonitor()) {
978aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    LOG(LS_WARNING) << "Failed to pause local monitor";
979aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    ret = false;
980aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
981aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
982aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Must also pause all audio playback and capture.
983aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  for (ChannelList::const_iterator i = channels_.begin();
984aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org       i != channels_.end(); ++i) {
985aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    WebRtcVoiceMediaChannel *channel = *i;
986aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (!channel->PausePlayout()) {
987aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG(LS_WARNING) << "Failed to pause playout";
988aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      ret = false;
989aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
990aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (!channel->PauseSend()) {
991aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG(LS_WARNING) << "Failed to pause send";
992aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      ret = false;
993aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
994aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
995aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org
996aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  // Find the recording device id in VoiceEngine and set recording device.
997aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (!FindWebRtcAudioDeviceId(true, in_name, in_id, &in_id)) {
998aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    ret = false;
999aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  }
1000aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org  if (ret) {
1001aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    if (voe_wrapper_->hw()->SetRecordingDevice(in_id) == -1) {
1002aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      LOG_RTCERR2(SetRecordingDevice, in_name, in_id);
1003aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org      ret = false;
1004aa0311d805f9d06dd334d9750e42824e93ba707abuildbot@webrtc.org    }
10050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Find the playout device id in VoiceEngine and set playout device.
10080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!FindWebRtcAudioDeviceId(false, out_name, out_id, &out_id)) {
10090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "Failed to find VoiceEngine device id for " << out_name;
10100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ret = false;
10110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (ret) {
10130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (voe_wrapper_->hw()->SetPlayoutDevice(out_id) == -1) {
101497fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org      LOG_RTCERR2(SetPlayoutDevice, out_name, out_id);
10150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      ret = false;
10160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
10170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Resume all audio playback and capture.
10200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (ChannelList::const_iterator i = channels_.begin();
10210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       i != channels_.end(); ++i) {
10220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    WebRtcVoiceMediaChannel *channel = *i;
10230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!channel->ResumePlayout()) {
10240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "Failed to resume playout";
10250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      ret = false;
10260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
10270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!channel->ResumeSend()) {
10280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "Failed to resume send";
10290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      ret = false;
10300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
10310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Resume local monitor.
10340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ResumeLocalMonitor()) {
10350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "Failed to resume local monitor";
10360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ret = false;
10370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (ret) {
10400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << "Set microphone to (id=" << in_id <<" name=" << in_name
10410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                 << ") and speaker to (id="<< out_id << " name=" << out_name
10420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                 << ")";
10430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ret;
10460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#else
10470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
1048d1f631d5ec5c25dd0a63ed70d0ffa66037d8aa6awu@webrtc.org#endif  // !IOS
10490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
10500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::FindWebRtcAudioDeviceId(
10520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool is_input, const std::string& dev_name, int dev_id, int* rtc_id) {
10530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // In Linux, VoiceEngine uses the same device dev_id as the device manager.
1054d1f631d5ec5c25dd0a63ed70d0ffa66037d8aa6awu@webrtc.org#if defined(LINUX) || defined(ANDROID)
10550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *rtc_id = dev_id;
10560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
10570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#else
10580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // In Windows and Mac, we need to find the VoiceEngine device id by name
10590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // unless the input dev_id is the default device id.
10600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (kDefaultAudioDeviceId == dev_id) {
10610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    *rtc_id = dev_id;
10620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
10630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Get the number of VoiceEngine audio devices.
10660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int count = 0;
10670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (is_input) {
10680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (-1 == voe_wrapper_->hw()->GetNumOfRecordingDevices(count)) {
10690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR0(GetNumOfRecordingDevices);
10700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
10710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
10720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
10730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (-1 == voe_wrapper_->hw()->GetNumOfPlayoutDevices(count)) {
10740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR0(GetNumOfPlayoutDevices);
10750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
10760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
10770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (int i = 0; i < count; ++i) {
10800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    char name[128];
10810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    char guid[128];
10820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (is_input) {
10830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      voe_wrapper_->hw()->GetRecordingDeviceName(i, name, guid);
10840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_VERBOSE) << "VoiceEngine microphone " << i << ": " << name;
10850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
10860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      voe_wrapper_->hw()->GetPlayoutDeviceName(i, name, guid);
10870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_VERBOSE) << "VoiceEngine speaker " << i << ": " << name;
10880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
10890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::string webrtc_name(name);
10910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (dev_name.compare(0, webrtc_name.size(), webrtc_name) == 0) {
10920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *rtc_id = i;
10930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
10940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
10950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_WARNING) << "VoiceEngine cannot find device: " << dev_name;
10970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
10980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
10990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::GetOutputVolume(int* level) {
11020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  unsigned int ulevel;
11030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (voe_wrapper_->volume()->GetSpeakerVolume(ulevel) == -1) {
11040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR1(GetSpeakerVolume, level);
11050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
11060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
11070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *level = ulevel;
11080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
11090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::SetOutputVolume(int level) {
11120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(level >= 0 && level <= 255);
11130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (voe_wrapper_->volume()->SetSpeakerVolume(level) == -1) {
11140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR1(SetSpeakerVolume, level);
11150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
11160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
11170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
11180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcVoiceEngine::GetInputLevel() {
11210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  unsigned int ulevel;
11220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return (voe_wrapper_->volume()->GetSpeechInputLevel(ulevel) != -1) ?
11230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      static_cast<int>(ulevel) : -1;
11240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::SetLocalMonitor(bool enable) {
11270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  desired_local_monitor_enable_ = enable;
11280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ChangeLocalMonitor(desired_local_monitor_enable_);
11290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::ChangeLocalMonitor(bool enable) {
11320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // The voe file api is not available in chrome.
11330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!voe_wrapper_->file()) {
11340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
11350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
11360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (enable && !monitor_) {
11370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    monitor_.reset(new WebRtcMonitorStream);
11380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (voe_wrapper_->file()->StartRecordingMicrophone(monitor_.get()) == -1) {
11390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR1(StartRecordingMicrophone, monitor_.get());
11400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Must call Stop() because there are some cases where Start will report
11410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // failure but still change the state, and if we leave VE in the on state
11420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // then it could crash later when trying to invoke methods on our monitor.
11430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      voe_wrapper_->file()->StopRecordingMicrophone();
11440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      monitor_.reset();
11450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
11460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
11470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else if (!enable && monitor_) {
11480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    voe_wrapper_->file()->StopRecordingMicrophone();
11490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    monitor_.reset();
11500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
11510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
11520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::PauseLocalMonitor() {
11550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ChangeLocalMonitor(false);
11560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::ResumeLocalMonitor() {
11590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ChangeLocalMonitor(desired_local_monitor_enable_);
11600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst std::vector<AudioCodec>& WebRtcVoiceEngine::codecs() {
11630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return codecs_;
11640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::FindCodec(const AudioCodec& in) {
11670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return FindWebRtcCodec(in, NULL);
11680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Get the VoiceEngine codec that matches |in|, with the supplied settings.
11710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in,
11720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                        webrtc::CodecInst* out) {
11730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
11740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (int i = 0; i < ncodecs; ++i) {
11750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    webrtc::CodecInst voe_codec;
11760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) {
11770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq,
11780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                       voe_codec.rate, voe_codec.channels, 0);
11790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      bool multi_rate = IsCodecMultiRate(voe_codec);
11800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Allow arbitrary rates for ISAC to be specified.
11810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (multi_rate) {
11820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // Set codec.bitrate to 0 so the check for codec.Matches() passes.
11830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        codec.bitrate = 0;
11840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
11850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (codec.Matches(in)) {
11860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (out) {
11870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          // Fixup the payload type.
11880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          voe_codec.pltype = in.id;
11890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          // Set bitrate if specified.
11910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          if (multi_rate && in.bitrate != 0) {
11920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            voe_codec.rate = in.bitrate;
11930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          }
11940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          // Apply codec-specific settings.
11960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          if (IsIsac(codec)) {
11970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            // If ISAC and an explicit bitrate is not specified,
11980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            // enable auto bandwidth adjustment.
11990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            voe_codec.rate = (in.bitrate > 0) ? in.bitrate : -1;
12000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          }
12010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          *out = voe_codec;
12020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
12030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return true;
12040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
12050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
12060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
12070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
12080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
12090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst std::vector<RtpHeaderExtension>&
12100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgWebRtcVoiceEngine::rtp_header_extensions() const {
12110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return rtp_header_extensions_;
12120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
12130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
12140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::SetLogging(int min_sev, const char* filter) {
12150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // if min_sev == -1, we keep the current log level.
12160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (min_sev >= 0) {
12170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SetTraceFilter(SeverityToFilter(min_sev));
12180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
12190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  log_options_ = filter;
12200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SetTraceOptions(initialized_ ? log_options_ : "");
12210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
12220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
12230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcVoiceEngine::GetLastEngineError() {
12240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return voe_wrapper_->error();
12250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
12260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
12270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::SetTraceFilter(int filter) {
12280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  log_filter_ = filter;
12290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  tracing_->SetTraceFilter(filter);
12300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
12310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
12320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// We suppport three different logging settings for VoiceEngine:
12330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 1. Observer callback that goes into talk diagnostic logfile.
12340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//    Use --logfile and --loglevel
12350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
12360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 2. Encrypted VoiceEngine log for debugging VoiceEngine.
12370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//    Use --voice_loglevel --voice_logfilter "tracefile file_name"
12380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
12390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 3. EC log and dump for debugging QualityEngine.
12400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//    Use --voice_loglevel --voice_logfilter "recordEC file_name"
12410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
12420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// For more details see: "https://sites.google.com/a/google.com/wavelet/Home/
12430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//    Magic-Flute--RTC-Engine-/Magic-Flute-Command-Line-Parameters"
12440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::SetTraceOptions(const std::string& options) {
12450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Set encrypted trace file.
12460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<std::string> opts;
12470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  talk_base::tokenize(options, ' ', '"', '"', &opts);
12480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<std::string>::iterator tracefile =
12490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      std::find(opts.begin(), opts.end(), "tracefile");
12500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (tracefile != opts.end() && ++tracefile != opts.end()) {
12510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Write encrypted debug output (at same loglevel) to file
12520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // EncryptedTraceFile no longer supported.
12530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (tracing_->SetTraceFile(tracefile->c_str()) == -1) {
12540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR1(SetTraceFile, *tracefile);
12550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
12560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
12570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
12585c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  // Allow trace options to override the trace filter. We default
12595c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  // it to log_filter_ (as a translation of libjingle log levels)
12605c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  // elsewhere, but this allows clients to explicitly set webrtc
12615c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  // log levels.
12625c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  std::vector<std::string>::iterator tracefilter =
12635c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      std::find(opts.begin(), opts.end(), "tracefilter");
12645c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  if (tracefilter != opts.end() && ++tracefilter != opts.end()) {
12655c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    if (!tracing_->SetTraceFilter(talk_base::FromString<int>(*tracefilter))) {
12665c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      LOG_RTCERR1(SetTraceFilter, *tracefilter);
12675c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    }
12685c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  }
12695c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org
12700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Set AEC dump file
12710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<std::string>::iterator recordEC =
12720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      std::find(opts.begin(), opts.end(), "recordEC");
12730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (recordEC != opts.end()) {
12740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ++recordEC;
12750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (recordEC != opts.end())
12760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      StartAecDump(recordEC->c_str());
12770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    else
12780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      StopAecDump();
12790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
12800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
12810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
12820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Ignore spammy trace messages, mostly from the stats API when we haven't
12830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// gotten RTCP info yet from the remote side.
12840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::ShouldIgnoreTrace(const std::string& trace) {
12850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  static const char* kTracesToIgnore[] = {
12860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "\tfailed to GetReportBlockInformation",
12870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "GetRecCodec() failed to get received codec",
12880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "GetReceivedRtcpStatistics: Could not get received RTP statistics",
12890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "GetRemoteRTCPData() failed to measure statistics due to lack of received RTP and/or RTCP packets",  // NOLINT
12900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "GetRemoteRTCPData() failed to retrieve sender info for remote side",
12910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "GetRTPStatistics() failed to measure RTT since no RTP packets have been received yet",  // NOLINT
12920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "GetRTPStatistics() failed to read RTP statistics from the RTP/RTCP module",
12930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "GetRTPStatistics() failed to retrieve RTT from the RTP/RTCP module",
12940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "SenderInfoReceived No received SR",
12950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "StatisticsRTP() no statistics available",
12960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "TransmitMixer::TypingDetection() VE_TYPING_NOISE_WARNING message has been posted",  // NOLINT
12970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "TransmitMixer::TypingDetection() pending noise-saturation warning exists",  // NOLINT
12980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "GetRecPayloadType() failed to retrieve RX payload type (error=10026)", // NOLINT
12990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    "StopPlayingFileAsMicrophone() isnot playing (error=8088)",
13000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    NULL
13010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  };
13020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const char* const* p = kTracesToIgnore; *p; ++p) {
13030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (trace.find(*p) != std::string::npos) {
13040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
13050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
13060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
13070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
13080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
13090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace,
13110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                              int length) {
13120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  talk_base::LoggingSeverity sev = talk_base::LS_VERBOSE;
13130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (level == webrtc::kTraceError || level == webrtc::kTraceCritical)
13140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    sev = talk_base::LS_ERROR;
13150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  else if (level == webrtc::kTraceWarning)
13160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    sev = talk_base::LS_WARNING;
13170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo)
13180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    sev = talk_base::LS_INFO;
13190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  else if (level == webrtc::kTraceTerseInfo)
13200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    sev = talk_base::LS_INFO;
13210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Skip past boilerplate prefix text
13230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (length < 72) {
13240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::string msg(trace, length);
13250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_ERROR) << "Malformed webrtc log message: ";
13260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_V(sev) << msg;
13270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
13280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::string msg(trace + 71, length - 72);
13290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!ShouldIgnoreTrace(msg)) {
13300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_V(sev) << "webrtc: " << msg;
13310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
13320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
13330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
13340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::CallbackOnError(int channel_num, int err_code) {
13360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  talk_base::CritScope lock(&channels_cs_);
13370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  WebRtcVoiceMediaChannel* channel = NULL;
13380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  uint32 ssrc = 0;
13390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_WARNING) << "VoiceEngine error " << err_code << " reported on channel "
13400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << channel_num << ".";
13410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (FindChannelAndSsrc(channel_num, &channel, &ssrc)) {
13420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ASSERT(channel != NULL);
13430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    channel->OnError(ssrc, err_code);
13440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
13450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_ERROR) << "VoiceEngine channel " << channel_num
13460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << " could not be found in channel list when error reported.";
13470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
13480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
13490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::FindChannelAndSsrc(
13510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int channel_num, WebRtcVoiceMediaChannel** channel, uint32* ssrc) const {
13520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(channel != NULL && ssrc != NULL);
13530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *channel = NULL;
13550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *ssrc = 0;
13560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Find corresponding channel and ssrc
13570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (ChannelList::const_iterator it = channels_.begin();
13580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      it != channels_.end(); ++it) {
13590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ASSERT(*it != NULL);
13600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if ((*it)->FindSsrc(channel_num, ssrc)) {
13610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *channel = *it;
13620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
13630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
13640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
13650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
13670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
13680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// This method will search through the WebRtcVoiceMediaChannels and
13700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// obtain the voice engine's channel number.
13710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::FindChannelNumFromSsrc(
13720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32 ssrc, MediaProcessorDirection direction, int* channel_num) {
13730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(channel_num != NULL);
13740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(direction == MPD_RX || direction == MPD_TX);
13750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *channel_num = -1;
13770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Find corresponding channel for ssrc.
13780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (ChannelList::const_iterator it = channels_.begin();
13790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      it != channels_.end(); ++it) {
13800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ASSERT(*it != NULL);
13810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (direction & MPD_RX) {
13820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *channel_num = (*it)->GetReceiveChannelNum(ssrc);
13830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
13840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (*channel_num == -1 && (direction & MPD_TX)) {
13850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *channel_num = (*it)->GetSendChannelNum(ssrc);
13860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
13870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (*channel_num != -1) {
13880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
13890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
13900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
13910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_WARNING) << "FindChannelFromSsrc. No Channel Found for Ssrc: " << ssrc;
13920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
13930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
13940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
13950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel *channel) {
13960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  talk_base::CritScope lock(&channels_cs_);
13970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  channels_.push_back(channel);
13980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
13990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel *channel) {
14010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  talk_base::CritScope lock(&channels_cs_);
14020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ChannelList::iterator i = std::find(channels_.begin(),
14030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      channels_.end(),
14040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      channel);
14050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (i != channels_.end()) {
14060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    channels_.erase(i);
14070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
14080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
14090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::RegisterSoundclip(WebRtcSoundclipMedia *soundclip) {
14110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  soundclips_.push_back(soundclip);
14120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
14130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::UnregisterSoundclip(WebRtcSoundclipMedia *soundclip) {
14150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SoundclipList::iterator i = std::find(soundclips_.begin(),
14160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                        soundclips_.end(),
14170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                        soundclip);
14180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (i != soundclips_.end()) {
14190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    soundclips_.erase(i);
14200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
14210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
14220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Adjusts the default AGC target level by the specified delta.
14240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// NB: If we start messing with other config fields, we'll want
14250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// to save the current webrtc::AgcConfig as well.
14260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::AdjustAgcLevel(int delta) {
14270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  webrtc::AgcConfig config = default_agc_config_;
14280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  config.targetLeveldBOv -= delta;
14290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_INFO) << "Adjusting AGC level from default -"
14310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org               << default_agc_config_.targetLeveldBOv << "dB to -"
14320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org               << config.targetLeveldBOv << "dB";
14330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (voe_wrapper_->processing()->SetAgcConfig(config) == -1) {
14350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR1(SetAgcConfig, config.targetLeveldBOv);
14360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
14370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
14380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
14390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
14400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm,
14420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    webrtc::AudioDeviceModule* adm_sc) {
14430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (initialized_) {
14440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "SetAudioDeviceModule can not be called after Init.";
14450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
14460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
14470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (adm_) {
14480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    adm_->Release();
14490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    adm_ = NULL;
14500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
14510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (adm) {
14520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    adm_ = adm;
14530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    adm_->AddRef();
14540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
14550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (adm_sc_) {
14570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    adm_sc_->Release();
14580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    adm_sc_ = NULL;
14590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
14600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (adm_sc) {
14610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    adm_sc_ = adm_sc;
14620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    adm_sc_->AddRef();
14630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
14640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
14650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
14660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
14671b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.orgbool WebRtcVoiceEngine::StartAecDump(talk_base::PlatformFile file) {
14681b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org  FILE* aec_dump_file_stream = talk_base::FdopenPlatformFileForWriting(file);
14691b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org  if (!aec_dump_file_stream) {
14701b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org    LOG(LS_ERROR) << "Could not open AEC dump file stream.";
14711b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org    if (!talk_base::ClosePlatformFile(file))
14721b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org      LOG(LS_WARNING) << "Could not close file.";
14731b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org    return false;
14741b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org  }
1475f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org  StopAecDump();
14761b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org  if (voe_wrapper_->processing()->StartDebugRecording(aec_dump_file_stream) !=
1477f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org      webrtc::AudioProcessing::kNoError) {
14781b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org    LOG_RTCERR0(StartDebugRecording);
14791b5713169ff3f21791214c4500e5d775048c3ba9wu@webrtc.org    fclose(aec_dump_file_stream);
1480f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org    return false;
1481f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org  }
1482f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org  is_dumping_aec_ = true;
1483f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org  return true;
1484f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org}
1485f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org
14860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::RegisterProcessor(
14870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32 ssrc,
14880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    VoiceProcessor* voice_processor,
14890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    MediaProcessorDirection direction) {
14900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool register_with_webrtc = false;
14910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int channel_id = -1;
14920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool success = false;
14930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  uint32* processor_ssrc = NULL;
14940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool found_channel = FindChannelNumFromSsrc(ssrc, direction, &channel_id);
14950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (voice_processor == NULL || !found_channel) {
14960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "Media Processing Registration Failed. ssrc: " << ssrc
14970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        << " foundChannel: " << found_channel;
14980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
14990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
15000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
15010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  webrtc::ProcessingTypes processing_type;
15020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  {
15030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    talk_base::CritScope cs(&signal_media_critical_);
15040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (direction == MPD_RX) {
15050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      processing_type = webrtc::kPlaybackAllChannelsMixed;
15060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (SignalRxMediaFrame.is_empty()) {
15070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        register_with_webrtc = true;
15080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        processor_ssrc = &rx_processor_ssrc_;
15090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
15100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      SignalRxMediaFrame.connect(voice_processor,
15110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                 &VoiceProcessor::OnFrame);
15120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
15130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      processing_type = webrtc::kRecordingPerChannel;
15140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (SignalTxMediaFrame.is_empty()) {
15150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        register_with_webrtc = true;
15160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        processor_ssrc = &tx_processor_ssrc_;
15170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
15180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      SignalTxMediaFrame.connect(voice_processor,
15190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                 &VoiceProcessor::OnFrame);
15200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
15210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
15220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (register_with_webrtc) {
15230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(janahan): when registering consider instantiating a
15240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // a VoeMediaProcess object and not make the engine extend the interface.
15250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (voe()->media() && voe()->media()->
15260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        RegisterExternalMediaProcessing(channel_id,
15270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                        processing_type,
15280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                        *this) != -1) {
15290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Media Processing Registration Succeeded. channel:"
15300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                   << channel_id;
15310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *processor_ssrc = ssrc;
15320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      success = true;
15330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
15340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR2(RegisterExternalMediaProcessing,
15350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  channel_id,
15360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  processing_type);
15370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      success = false;
15380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
15390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
15400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // If we don't have to register with the engine, we just needed to
15410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // connect a new processor, set success to true;
15420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    success = true;
15430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
15440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return success;
15450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
15460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
15470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::UnregisterProcessorChannel(
15480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    MediaProcessorDirection channel_direction,
15490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32 ssrc,
15500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    VoiceProcessor* voice_processor,
15510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    MediaProcessorDirection processor_direction) {
15520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool success = true;
15530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  FrameSignal* signal;
15540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  webrtc::ProcessingTypes processing_type;
15550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  uint32* processor_ssrc = NULL;
15560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (channel_direction == MPD_RX) {
15570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    signal = &SignalRxMediaFrame;
15580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    processing_type = webrtc::kPlaybackAllChannelsMixed;
15590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    processor_ssrc = &rx_processor_ssrc_;
15600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
15610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    signal = &SignalTxMediaFrame;
15620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    processing_type = webrtc::kRecordingPerChannel;
15630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    processor_ssrc = &tx_processor_ssrc_;
15640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
15650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
15660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int deregister_id = -1;
15670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  {
15680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    talk_base::CritScope cs(&signal_media_critical_);
15690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if ((processor_direction & channel_direction) != 0 && !signal->is_empty()) {
15700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      signal->disconnect(voice_processor);
15710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      int channel_id = -1;
15720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      bool found_channel = FindChannelNumFromSsrc(ssrc,
15730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                                  channel_direction,
15740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                                  &channel_id);
15750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (signal->is_empty() && found_channel) {
15760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        deregister_id = channel_id;
15770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
15780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
15790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
15800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (deregister_id != -1) {
15810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (voe()->media() &&
15820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        voe()->media()->DeRegisterExternalMediaProcessing(deregister_id,
15830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        processing_type) != -1) {
15840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *processor_ssrc = 0;
15850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Media Processing DeRegistration Succeeded. channel:"
15860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                   << deregister_id;
15870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
15880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR2(DeRegisterExternalMediaProcessing,
15890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  deregister_id,
15900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  processing_type);
15910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      success = false;
15920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
15930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
15940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return success;
15950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
15960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
15970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceEngine::UnregisterProcessor(
15980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32 ssrc,
15990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    VoiceProcessor* voice_processor,
16000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    MediaProcessorDirection direction) {
16010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool success = true;
16020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (voice_processor == NULL) {
16030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "Media Processing Deregistration Failed. ssrc: "
16040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << ssrc;
16050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
16060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
16070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!UnregisterProcessorChannel(MPD_RX, ssrc, voice_processor, direction)) {
16080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    success = false;
16090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
16100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!UnregisterProcessorChannel(MPD_TX, ssrc, voice_processor, direction)) {
16110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    success = false;
16120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
16130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return success;
16140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
16150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
16160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementing method from WebRtc VoEMediaProcess interface
16170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Do not lock mux_channel_cs_ in this callback.
16180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::Process(int channel,
16190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                webrtc::ProcessingTypes type,
16200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                int16_t audio10ms[],
16210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                int length,
16220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                int sampling_freq,
16230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                bool is_stereo) {
16240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    talk_base::CritScope cs(&signal_media_critical_);
16250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AudioFrame frame(audio10ms, length, sampling_freq, is_stereo);
16260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (type == webrtc::kPlaybackAllChannelsMixed) {
16270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      SignalRxMediaFrame(rx_processor_ssrc_, MPD_RX, &frame);
16280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else if (type == webrtc::kRecordingPerChannel) {
16290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      SignalTxMediaFrame(tx_processor_ssrc_, MPD_TX, &frame);
16300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
16310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "Media Processing invoked unexpectedly."
16320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                      << " channel: " << channel << " type: " << type
16330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                      << " tx_ssrc: " << tx_processor_ssrc_
16340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                      << " rx_ssrc: " << rx_processor_ssrc_;
16350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
16360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
16370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
16380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::StartAecDump(const std::string& filename) {
16390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!is_dumping_aec_) {
16400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Start dumping AEC when we are not dumping.
16410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (voe_wrapper_->processing()->StartDebugRecording(
16420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        filename.c_str()) != webrtc::AudioProcessing::kNoError) {
1643f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org      LOG_RTCERR1(StartDebugRecording, filename.c_str());
16440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
16450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      is_dumping_aec_ = true;
16460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
16470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
16480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
16490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
16500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceEngine::StopAecDump() {
16510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (is_dumping_aec_) {
16520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Stop dumping AEC when we are dumping.
16530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (voe_wrapper_->processing()->StopDebugRecording() !=
16540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        webrtc::AudioProcessing::kNoError) {
16550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR0(StopDebugRecording);
16560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
16570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    is_dumping_aec_ = false;
16580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
16590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
16600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
166197fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.orgint WebRtcVoiceEngine::CreateVoiceChannel(VoEWrapper* voice_engine_wrapper) {
166297fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org  return voice_engine_wrapper->base()->CreateChannel(voe_config_);
166397fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org}
166497fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org
166597fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.orgint WebRtcVoiceEngine::CreateMediaVoiceChannel() {
166697fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org  return CreateVoiceChannel(voe_wrapper_.get());
166797fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org}
166897fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org
166997fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.orgint WebRtcVoiceEngine::CreateSoundclipVoiceChannel() {
167097fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org  return CreateVoiceChannel(voe_wrapper_sc_.get());
167197fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org}
167297fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org
1673b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.orgclass WebRtcVoiceMediaChannel::WebRtcVoiceChannelRenderer
1674b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    : public AudioRenderer::Sink {
1675b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org public:
1676b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  WebRtcVoiceChannelRenderer(int ch,
1677b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org                             webrtc::AudioTransport* voe_audio_transport)
1678b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      : channel_(ch),
1679b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        voe_audio_transport_(voe_audio_transport),
1680b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        renderer_(NULL) {
1681b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  }
1682b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  virtual ~WebRtcVoiceChannelRenderer() {
1683b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    Stop();
1684b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  }
1685b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
1686b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // Starts the rendering by setting a sink to the renderer to get data
1687b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // callback.
1688e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  // This method is called on the libjingle worker thread.
1689b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // TODO(xians): Make sure Start() is called only once.
1690b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  void Start(AudioRenderer* renderer) {
1691e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    talk_base::CritScope lock(&lock_);
1692b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    ASSERT(renderer != NULL);
1693e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    if (renderer_ != NULL) {
1694b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      ASSERT(renderer_ == renderer);
1695b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      return;
1696b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    }
1697b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
1698b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    // TODO(xians): Remove AddChannel() call after Chrome turns on APM
1699b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    // in getUserMedia by default.
1700b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    renderer->AddChannel(channel_);
1701b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    renderer->SetSink(this);
1702b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    renderer_ = renderer;
1703b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  }
1704b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
1705b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // Stops rendering by setting the sink of the renderer to NULL. No data
1706b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // callback will be received after this method.
1707e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  // This method is called on the libjingle worker thread.
1708b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  void Stop() {
1709e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    talk_base::CritScope lock(&lock_);
1710e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    if (renderer_ == NULL)
1711b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      return;
1712b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
1713b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    renderer_->RemoveChannel(channel_);
1714b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    renderer_->SetSink(NULL);
1715b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    renderer_ = NULL;
1716b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  }
1717b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
1718b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // AudioRenderer::Sink implementation.
1719e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  // This method is called on the audio thread.
1720b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  virtual void OnData(const void* audio_data,
1721b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org                      int bits_per_sample,
1722b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org                      int sample_rate,
1723b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org                      int number_of_channels,
1724b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org                      int number_of_frames) OVERRIDE {
1725e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    voe_audio_transport_->OnData(channel_,
1726e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org                                 audio_data,
1727e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org                                 bits_per_sample,
1728e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org                                 sample_rate,
1729e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org                                 number_of_channels,
1730e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org                                 number_of_frames);
1731e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  }
1732e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org
1733e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  // Callback from the |renderer_| when it is going away. In case Start() has
1734e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  // never been called, this callback won't be triggered.
1735e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  virtual void OnClose() OVERRIDE {
1736e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    talk_base::CritScope lock(&lock_);
1737e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    // Set |renderer_| to NULL to make sure no more callback will get into
1738e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    // the renderer.
1739e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    renderer_ = NULL;
1740b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  }
1741b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
1742b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // Accessor to the VoE channel ID.
1743b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  int channel() const { return channel_; }
1744b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
1745b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org private:
1746b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  const int channel_;
1747b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  webrtc::AudioTransport* const voe_audio_transport_;
1748b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
1749b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler.
1750b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // PeerConnection will make sure invalidating the pointer before the object
1751b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // goes away.
1752b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  AudioRenderer* renderer_;
1753e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org
1754e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  // Protects |renderer_| in Start(), Stop() and OnClose().
1755e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  talk_base::CriticalSection lock_;
17567162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org};
17577162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
17580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// WebRtcVoiceMediaChannel
17590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgWebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine *engine)
17600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : WebRtcMediaChannel<VoiceMediaChannel, WebRtcVoiceEngine>(
17610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          engine,
176297fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org          engine->CreateMediaVoiceChannel()),
1763cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org      send_bw_setting_(false),
1764cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org      send_bw_bps_(0),
17650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      options_(),
17660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      dtmf_allowed_(false),
17670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      desired_playout_(false),
17680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      nack_enabled_(false),
17690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      playout_(false),
17704ba8b9ea10385f43b19d6ed7408f4a09bdc1cbdawu@webrtc.org      typing_noise_detected_(false),
17710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      desired_send_(SEND_NOTHING),
17720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      send_(SEND_NOTHING),
17730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      default_receive_ssrc_(0) {
17740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  engine->RegisterChannel(this);
17750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel "
17760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << voe_channel();
17770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1778f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  ConfigureSendChannel(voe_channel());
17790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
17800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
17810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgWebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
17820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel "
17830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << voe_channel();
17840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1785f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Remove any remaining send streams, the default channel will be deleted
1786f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // later.
1787f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  while (!send_channels_.empty())
1788f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    RemoveSendStream(send_channels_.begin()->first);
17890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
17900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Unregister ourselves from the engine.
17910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  engine()->UnregisterChannel(this);
17920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Remove any remaining streams.
17937162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  while (!receive_channels_.empty()) {
17947162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    RemoveRecvStream(receive_channels_.begin()->first);
17950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
17960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1797f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Delete the default channel.
1798f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  DeleteChannel(voe_channel());
17990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
18000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
18010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
18020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_INFO) << "Setting voice channel options: "
18030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org               << options.ToString();
18040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
180580303b162fe139828d0661df23e03f09126508acwu@webrtc.org  // Check if DSCP value is changed from previous.
180680303b162fe139828d0661df23e03f09126508acwu@webrtc.org  bool dscp_option_changed = (options_.dscp != options.dscp);
180780303b162fe139828d0661df23e03f09126508acwu@webrtc.org
1808f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // TODO(xians): Add support to set different options for different send
1809f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // streams after we support multiple APMs.
1810f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
18110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // We retain all of the existing options, and apply the given ones
18120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // on top.  This means there is no way to "clear" options such that
18130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // they go back to the engine default.
18140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  options_.SetAll(options);
18150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
18160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (send_ != SEND_NOTHING) {
18170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!engine()->SetOptionOverrides(options_)) {
18180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) <<
18190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          "Failed to engine SetOptionOverrides during channel SetOptions.";
18200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
18210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
18220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
18230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Will be interpreted when appropriate.
18240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
18250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
18265c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  // Receiver-side auto gain control happens per channel, so set it here from
18275c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  // options. Note that, like conference mode, setting it on the engine won't
18285c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  // have the desired effect, since voice channels don't inherit options from
18295c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  // the media engine when those options are applied per-channel.
18305c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  bool rx_auto_gain_control;
18315c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  if (options.rx_auto_gain_control.Get(&rx_auto_gain_control)) {
18325c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    if (engine()->voe()->processing()->SetRxAgcStatus(
18335c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org            voe_channel(), rx_auto_gain_control,
18345c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org            webrtc::kAgcFixedDigital) == -1) {
18355c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      LOG_RTCERR1(SetRxAgcStatus, rx_auto_gain_control);
18365c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      return false;
18375c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    } else {
18385c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      LOG(LS_VERBOSE) << "Rx auto gain set to " << rx_auto_gain_control
18395c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org                      << " with mode " << webrtc::kAgcFixedDigital;
18405c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    }
18415c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  }
18425c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  if (options.rx_agc_target_dbov.IsSet() ||
18435c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      options.rx_agc_digital_compression_gain.IsSet() ||
18445c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      options.rx_agc_limiter.IsSet()) {
18455c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    webrtc::AgcConfig config;
18465c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    // If only some of the options are being overridden, get the current
18475c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    // settings for the channel and bail if they aren't available.
18485c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    if (!options.rx_agc_target_dbov.IsSet() ||
18495c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org        !options.rx_agc_digital_compression_gain.IsSet() ||
18505c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org        !options.rx_agc_limiter.IsSet()) {
18515c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      if (engine()->voe()->processing()->GetRxAgcConfig(
18525c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org              voe_channel(), config) != 0) {
18535c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org        LOG(LS_ERROR) << "Failed to get default rx agc configuration for "
18545c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org                      << "channel " << voe_channel() << ". Since not all rx "
18555c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org                      << "agc options are specified, unable to safely set rx "
18565c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org                      << "agc options.";
18575c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org        return false;
18585c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      }
18595c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    }
18605c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    config.targetLeveldBOv =
18615c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org        options.rx_agc_target_dbov.GetWithDefaultIfUnset(
18625c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org            config.targetLeveldBOv);
18635c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    config.digitalCompressionGaindB =
18645c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org        options.rx_agc_digital_compression_gain.GetWithDefaultIfUnset(
18655c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org            config.digitalCompressionGaindB);
18665c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    config.limiterEnable = options.rx_agc_limiter.GetWithDefaultIfUnset(
18675c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org        config.limiterEnable);
18685c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    if (engine()->voe()->processing()->SetRxAgcConfig(
18695c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org            voe_channel(), config) == -1) {
18705c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      LOG_RTCERR4(SetRxAgcConfig, voe_channel(), config.targetLeveldBOv,
18715c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org                  config.digitalCompressionGaindB, config.limiterEnable);
18725c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org      return false;
18735c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org    }
18745c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org  }
187580303b162fe139828d0661df23e03f09126508acwu@webrtc.org  if (dscp_option_changed) {
187680303b162fe139828d0661df23e03f09126508acwu@webrtc.org    talk_base::DiffServCodePoint dscp = talk_base::DSCP_DEFAULT;
18778485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org    if (options_.dscp.GetWithDefaultIfUnset(false))
187880303b162fe139828d0661df23e03f09126508acwu@webrtc.org      dscp = kAudioDscpValue;
187980303b162fe139828d0661df23e03f09126508acwu@webrtc.org    if (MediaChannel::SetDscp(dscp) != 0) {
188080303b162fe139828d0661df23e03f09126508acwu@webrtc.org      LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel";
188180303b162fe139828d0661df23e03f09126508acwu@webrtc.org    }
188280303b162fe139828d0661df23e03f09126508acwu@webrtc.org  }
18835c9dd59107e049112f2e9a62d08a02ef4448a957wu@webrtc.org
18840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_INFO) << "Set voice channel options.  Current options: "
18850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org               << options_.ToString();
18860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
18870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
18880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
18890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetRecvCodecs(
18900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::vector<AudioCodec>& codecs) {
18910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Set the payload types to be used for incoming media.
18920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_INFO) << "Setting receive voice codecs:";
18930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
18940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<AudioCodec> new_codecs;
18950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Find all new codecs. We allow adding new codecs but don't allow changing
18960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // the payload type of codecs that is already configured since we might
18970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // already be receiving packets with that payload type.
18980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
18997162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org       it != codecs.end(); ++it) {
19000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AudioCodec old_codec;
19010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (FindCodec(recv_codecs_, *it, &old_codec)) {
19020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (old_codec.id != it->id) {
19030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        LOG(LS_ERROR) << it->name << " payload type changed.";
19040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return false;
19050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
19060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
19070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new_codecs.push_back(*it);
19080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
19090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
19100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (new_codecs.empty()) {
19110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // There are no new codecs to configure. Already configured codecs are
19120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // never removed.
19130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
19140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
19150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
19160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (playout_) {
19170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Receive codecs can not be changed while playing. So we temporarily
19180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // pause playout.
19190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    PausePlayout();
19200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
19210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
19227162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  bool ret = true;
19230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = new_codecs.begin();
19240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       it != new_codecs.end() && ret; ++it) {
19250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    webrtc::CodecInst voe_codec;
19260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->FindWebRtcCodec(*it, &voe_codec)) {
19270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << ToString(*it);
19280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      voe_codec.pltype = it->id;
19297162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      if (default_receive_ssrc_ == 0) {
19307162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        // Set the receive codecs on the default channel explicitly if the
19317162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        // default channel is not used by |receive_channels_|, this happens in
19327162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        // conference mode or in non-conference mode when there is no playout
19337162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        // channel.
19347162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        // TODO(xians): Figure out how we use the default channel in conference
19357162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        // mode.
19367162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        if (engine()->voe()->codec()->SetRecPayloadType(
19377162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org            voe_channel(), voe_codec) == -1) {
19387162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org          LOG_RTCERR2(SetRecPayloadType, voe_channel(), ToString(voe_codec));
19397162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org          ret = false;
19407162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        }
19410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
19420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
19430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Set the receive codecs on all receiving channels.
19447162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      for (ChannelMap::iterator it = receive_channels_.begin();
19457162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org           it != receive_channels_.end() && ret; ++it) {
19460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (engine()->voe()->codec()->SetRecPayloadType(
1947b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org                it->second->channel(), voe_codec) == -1) {
1948b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org          LOG_RTCERR2(SetRecPayloadType, it->second->channel(),
19497162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                      ToString(voe_codec));
19500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          ret = false;
19510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
19520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
19530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
19540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "Unknown codec " << ToString(*it);
19550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      ret = false;
19560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
19570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
19580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (ret) {
19590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    recv_codecs_ = codecs;
19600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
19610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
19620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (desired_playout_ && !playout_) {
19630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ResumePlayout();
19640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
19650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ret;
19660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
19670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
19680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendCodecs(
1969952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    int channel, const std::vector<AudioCodec>& codecs) {
197007617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org  // Disable VAD, FEC, and RED unless we know the other side wants them.
1971952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  engine()->voe()->codec()->SetVADStatus(channel, false);
1972952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
197307617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org#ifdef USE_WEBRTC_DEV_BRANCH
197407617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org  engine()->voe()->rtp()->SetREDStatus(channel, false);
197507617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org  engine()->voe()->codec()->SetFECStatus(channel, false);
197607617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org#else
197707617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org  // TODO(minyue): Remove code under #else case after new WebRTC roll.
1978952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  engine()->voe()->rtp()->SetFECStatus(channel, false);
197907617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org#endif  // USE_WEBRTC_DEV_BRANCH
19800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
19810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Scan through the list to figure out the codec to use for sending, along
19820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // with the proper configuration for VAD and DTMF.
19837587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  bool found_send_codec = false;
19840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  webrtc::CodecInst send_codec;
19850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  memset(&send_codec, 0, sizeof(send_codec));
19860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1987a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org  bool nack_enabled = nack_enabled_;
1988a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org
19897587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  // Set send codec (the first non-telephone-event/CN codec)
19900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
19910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       it != codecs.end(); ++it) {
19920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Ignore codecs we don't know about. The negotiation step should prevent
19930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // this, but double-check to be sure.
19940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    webrtc::CodecInst voe_codec;
19950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!engine()->FindWebRtcCodec(*it, &voe_codec)) {
19968485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org      LOG(LS_WARNING) << "Unknown codec " << ToString(*it);
19970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      continue;
19980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
19990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
20007587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    if (IsTelephoneEventCodec(it->name) || IsCNCodec(it->name)) {
20017587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // Skip telephone-event/CN codec, which will be handled later.
20027587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      continue;
20037587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    }
20047587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
20050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // If OPUS, change what we send according to the "stereo" codec
20060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // parameter, and not the "channels" parameter.  We set
20070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // voe_codec.channels to 2 if "stereo=1" and 1 otherwise.  If
20080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // the bitrate is not specified, i.e. is zero, we set it to the
20090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // appropriate default value for mono or stereo Opus.
20100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (IsOpus(*it)) {
20110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (IsOpusStereoEnabled(*it)) {
20120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        voe_codec.channels = 2;
20137162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        if (!IsValidOpusBitrate(it->bitrate)) {
20147162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org          if (it->bitrate != 0) {
20157162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org            LOG(LS_WARNING) << "Overrides the invalid supplied bitrate("
20167162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                            << it->bitrate
20177162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                            << ") with default opus stereo bitrate: "
20187162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                            << kOpusStereoBitrate;
20197162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org          }
20200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          voe_codec.rate = kOpusStereoBitrate;
20210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
20220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      } else {
20230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        voe_codec.channels = 1;
20247162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        if (!IsValidOpusBitrate(it->bitrate)) {
20257162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org          if (it->bitrate != 0) {
20267162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org            LOG(LS_WARNING) << "Overrides the invalid supplied bitrate("
20277162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                            << it->bitrate
20287162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                            << ") with default opus mono bitrate: "
20297162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                            << kOpusMonoBitrate;
20307162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org          }
20310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          voe_codec.rate = kOpusMonoBitrate;
20320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
20330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
20347162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      int bitrate_from_params = GetOpusBitrateFromParams(*it);
20357162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      if (bitrate_from_params != 0) {
20367162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        voe_codec.rate = bitrate_from_params;
20377162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      }
203807617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org
203902632fd0ce3e3625079f6472bd55370ed58509debuildbot@webrtc.org      // For Opus, we also enable inband FEC if it is requested.
204007617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org      if (IsOpusFecEnabled(*it)) {
204107617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org        LOG(LS_INFO) << "Enabling Opus FEC on channel " << channel;
204207617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org#ifdef USE_WEBRTC_DEV_BRANCH
204307617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org        if (engine()->voe()->codec()->SetFECStatus(channel, true) == -1) {
204407617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org          // Enable in-band FEC of the Opus codec. Treat any failure as a fatal
204507617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org          // internal error.
204607617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org          LOG_RTCERR2(SetFECStatus, channel, true);
204707617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org          return false;
204807617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org        }
204907617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org#endif  // USE_WEBRTC_DEV_BRANCH
205007617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org      }
20510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
20520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
20537587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    // We'll use the first codec in the list to actually send audio data.
20547587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    // Be sure to use the payload type requested by the remote side.
205507617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org    // "red", for RED audio, is a special case where the actual codec to be
20567587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    // used is specified in params.
20577587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    if (IsRedCodec(it->name)) {
20587587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // Parse out the RED parameters. If we fail, just ignore RED;
20597587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // we don't support all possible params/usage scenarios.
20607587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      if (!GetRedSendCodec(*it, codecs, &send_codec)) {
20617587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org        continue;
20627587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      }
20637587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
20647587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // Enable redundant encoding of the specified codec. Treat any
20657587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // failure as a fatal internal error.
206607617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org#ifdef USE_WEBRTC_DEV_BRANCH
206707617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org      LOG(LS_INFO) << "Enabling RED on channel " << channel;
206807617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org      if (engine()->voe()->rtp()->SetREDStatus(channel, true, it->id) == -1) {
206907617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org        LOG_RTCERR3(SetREDStatus, channel, true, it->id);
207007617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org#else
207107617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org      // TODO(minyue): Remove code under #else case after new WebRTC roll.
20727587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      LOG(LS_INFO) << "Enabling FEC";
20737587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      if (engine()->voe()->rtp()->SetFECStatus(channel, true, it->id) == -1) {
20747587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org        LOG_RTCERR3(SetFECStatus, channel, true, it->id);
207507617d70029b9232bf7a5d8af375a3ac18a03836buildbot@webrtc.org#endif  // USE_WEBRTC_DEV_BRANCH
20767587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org        return false;
20777587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      }
20787587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    } else {
20797587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      send_codec = voe_codec;
2080a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org      nack_enabled = IsNackEnabled(*it);
20817587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    }
20827587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    found_send_codec = true;
20837587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    break;
20847587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  }
20857587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
2086a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org  if (nack_enabled_ != nack_enabled) {
2087a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org    SetNack(channel, nack_enabled);
2088a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org    nack_enabled_ = nack_enabled;
2089a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org  }
2090a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org
20917587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  if (!found_send_codec) {
20927587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    LOG(LS_WARNING) << "Received empty list of codecs.";
20937587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    return false;
20947587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  }
20957587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
20967587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  // Set the codec immediately, since SetVADStatus() depends on whether
20977587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  // the current codec is mono or stereo.
20987587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  if (!SetSendCodec(channel, send_codec))
20997587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    return false;
21007587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
21017587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  // Always update the |send_codec_| to the currently set send codec.
21027587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  send_codec_.reset(new webrtc::CodecInst(send_codec));
21037587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
21047587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  if (send_bw_setting_) {
21057587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    SetSendBandwidthInternal(send_bw_bps_);
21067587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  }
21077587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
21087587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  // Loop through the codecs list again to config the telephone-event/CN codec.
21097587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
21107587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org       it != codecs.end(); ++it) {
21117587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    // Ignore codecs we don't know about. The negotiation step should prevent
21127587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    // this, but double-check to be sure.
21137587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    webrtc::CodecInst voe_codec;
21147587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    if (!engine()->FindWebRtcCodec(*it, &voe_codec)) {
21157587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      LOG(LS_WARNING) << "Unknown codec " << ToString(*it);
21167587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      continue;
21177587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    }
21187587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
2119f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Find the DTMF telephone event "codec" and tell VoiceEngine channels
2120f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // about it.
21217587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    if (IsTelephoneEventCodec(it->name)) {
2122952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType(
2123952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org              channel, it->id) == -1) {
2124952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org        LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, it->id);
2125952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org        return false;
21260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
21277587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    } else if (IsCNCodec(it->name)) {
21287587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // Turn voice activity detection/comfort noise on if supported.
21297587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // Set the wideband CN payload type appropriately.
21307587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // (narrowband always uses the static payload type 13).
21310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      webrtc::PayloadFrequencies cn_freq;
21320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      switch (it->clockrate) {
21330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        case 8000:
21340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          cn_freq = webrtc::kFreq8000Hz;
21350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          break;
21360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        case 16000:
21370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          cn_freq = webrtc::kFreq16000Hz;
21380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          break;
21390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        case 32000:
21400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          cn_freq = webrtc::kFreq32000Hz;
21410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          break;
21420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        default:
21430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          LOG(LS_WARNING) << "CN frequency " << it->clockrate
21440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                          << " not supported.";
21450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          continue;
21460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
2147952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      // Set the CN payloadtype and the VAD status.
2148952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      // The CN payload type for 8000 Hz clockrate is fixed at 13.
2149952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      if (cn_freq != webrtc::kFreq8000Hz) {
2150952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org        if (engine()->voe()->codec()->SetSendCNPayloadType(
2151952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org                channel, it->id, cn_freq) == -1) {
2152952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          LOG_RTCERR3(SetSendCNPayloadType, channel, it->id, cn_freq);
2153952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          // TODO(ajm): This failure condition will be removed from VoE.
2154952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          // Restore the return here when we update to a new enough webrtc.
2155952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          //
2156952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          // Not returning false because the SetSendCNPayloadType will fail if
2157952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          // the channel is already sending.
2158952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          // This can happen if the remote description is applied twice, for
2159952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          // example in the case of ROAP on top of JSEP, where both side will
2160952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          // send the offer.
21610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
2162952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      }
2163952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      // Only turn on VAD if we have a CN payload type that matches the
2164952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      // clockrate for the codec we are going to use.
2165952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      if (it->clockrate == send_codec.plfreq) {
2166952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org        LOG(LS_INFO) << "Enabling VAD";
2167952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org        if (engine()->voe()->codec()->SetVADStatus(channel, true) == -1) {
2168952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          LOG_RTCERR2(SetVADStatus, channel, true);
2169952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          return false;
21700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
21710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
21720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2173cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org  }
2174952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  return true;
2175952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org}
2176952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org
2177952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendCodecs(
2178952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    const std::vector<AudioCodec>& codecs) {
2179952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  dtmf_allowed_ = false;
2180952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
2181952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org       it != codecs.end(); ++it) {
2182952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    // Find the DTMF telephone event "codec".
2183952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    if (_stricmp(it->name.c_str(), "telephone-event") == 0 ||
2184952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org        _stricmp(it->name.c_str(), "audio/telephone-event") == 0) {
2185952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      dtmf_allowed_ = true;
2186952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    }
2187952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  }
2188952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org
2189952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  // Cache the codecs in order to configure the channel created later.
2190952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  send_codecs_ = codecs;
2191952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  for (ChannelMap::iterator iter = send_channels_.begin();
2192952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org       iter != send_channels_.end(); ++iter) {
2193b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    if (!SetSendCodecs(iter->second->channel(), codecs)) {
21940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2195952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    }
21960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
21970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2198a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org  // Set nack status on receive channels and update |nack_enabled_|.
2199952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  SetNack(receive_channels_, nack_enabled_);
22000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
22010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2202f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2203f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.orgvoid WebRtcVoiceMediaChannel::SetNack(const ChannelMap& channels,
2204f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org                                      bool nack_enabled) {
2205f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  for (ChannelMap::const_iterator it = channels.begin();
2206f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org       it != channels.end(); ++it) {
2207b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    SetNack(it->second->channel(), nack_enabled);
2208f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
2209f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org}
2210f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2211952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.orgvoid WebRtcVoiceMediaChannel::SetNack(int channel, bool nack_enabled) {
22120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (nack_enabled) {
2213952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    LOG(LS_INFO) << "Enabling NACK for channel " << channel;
22140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    engine()->voe()->rtp()->SetNACKStatus(channel, true, kNackMaxPackets);
22150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
2216952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    LOG(LS_INFO) << "Disabling NACK for channel " << channel;
22170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
22180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
22190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
22200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
22210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendCodec(
22220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const webrtc::CodecInst& send_codec) {
22230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_INFO) << "Selected voice codec " << ToString(send_codec)
22240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org               << ", bitrate=" << send_codec.rate;
2225f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  for (ChannelMap::iterator iter = send_channels_.begin();
2226f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org       iter != send_channels_.end(); ++iter) {
2227b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    if (!SetSendCodec(iter->second->channel(), send_codec))
2228f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      return false;
22290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2230f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2231f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  return true;
2232f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org}
2233f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2234f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendCodec(
2235f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    int channel, const webrtc::CodecInst& send_codec) {
2236f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  LOG(LS_INFO) << "Send channel " << channel <<  " selected voice codec "
2237f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org               << ToString(send_codec) << ", bitrate=" << send_codec.rate;
2238f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2239a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org  webrtc::CodecInst current_codec;
2240a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org  if (engine()->voe()->codec()->GetSendCodec(channel, current_codec) == 0 &&
2241a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org      (send_codec == current_codec)) {
2242a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org    // Codec is already configured, we can return without setting it again.
2243a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org    return true;
2244a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org  }
2245a32dfc68b5624bdc8e3901c1a91adb869f919ef8wu@webrtc.org
2246f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (engine()->voe()->codec()->SetSendCodec(channel, send_codec) == -1) {
2247f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG_RTCERR2(SetSendCodec, channel, ToString(send_codec));
2248f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    return false;
2249f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
22500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
22510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
22520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
22530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions(
22540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::vector<RtpHeaderExtension>& extensions) {
22552ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  if (receive_extensions_ == extensions) {
22562ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    return true;
22572ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  }
22582ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
22592ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  // The default channel may or may not be in |receive_channels_|. Set the rtp
22602ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  // header extensions for default channel regardless.
22612ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  if (!SetChannelRecvRtpHeaderExtensions(voe_channel(), extensions)) {
22622ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    return false;
22632ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  }
22643ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org
22653ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  // Loop through all receive channels and enable/disable the extensions.
22663ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  for (ChannelMap::const_iterator channel_it = receive_channels_.begin();
22673ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org       channel_it != receive_channels_.end(); ++channel_it) {
22682ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    if (!SetChannelRecvRtpHeaderExtensions(channel_it->second->channel(),
22692ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org                                           extensions)) {
22703ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org      return false;
22713ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org    }
22723ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  }
22732ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
22742ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  receive_extensions_ = extensions;
22750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
22760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
22770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
22782ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.orgbool WebRtcVoiceMediaChannel::SetChannelRecvRtpHeaderExtensions(
22792ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    int channel_id, const std::vector<RtpHeaderExtension>& extensions) {
22802ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org#ifdef USE_WEBRTC_DEV_BRANCH
22813ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  const RtpHeaderExtension* audio_level_extension =
22823ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org      FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension);
22833ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  if (!SetHeaderExtension(
22842ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      &webrtc::VoERTP_RTCP::SetReceiveAudioLevelIndicationStatus, channel_id,
22853ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org      audio_level_extension)) {
22863ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org    return false;
22873ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  }
22882ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org#endif  // USE_WEBRTC_DEV_BRANCH
22892ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
22902ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  const RtpHeaderExtension* send_time_extension =
22912ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
22923ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  if (!SetHeaderExtension(
22932ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      &webrtc::VoERTP_RTCP::SetReceiveAbsoluteSenderTimeStatus, channel_id,
22943ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org      send_time_extension)) {
22953ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org    return false;
22963ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  }
22972ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  return true;
22982ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org}
22992ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
23002ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions(
23012ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    const std::vector<RtpHeaderExtension>& extensions) {
23022ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  if (send_extensions_ == extensions) {
23032ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    return true;
23042ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  }
23052ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
23062ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  // The default channel may or may not be in |send_channels_|. Set the rtp
23072ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  // header extensions for default channel regardless.
23082ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
23092ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  if (!SetChannelSendRtpHeaderExtensions(voe_channel(), extensions)) {
23102ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    return false;
23112ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  }
23120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23132ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  // Loop through all send channels and enable/disable the extensions.
23143ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  for (ChannelMap::const_iterator channel_it = send_channels_.begin();
23153ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org       channel_it != send_channels_.end(); ++channel_it) {
23162ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    if (!SetChannelSendRtpHeaderExtensions(channel_it->second->channel(),
23172ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org                                           extensions)) {
23183ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org      return false;
23193ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org    }
23200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
23212ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
23222ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  send_extensions_ = extensions;
23232ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  return true;
23242ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org}
23252ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
23262ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.orgbool WebRtcVoiceMediaChannel::SetChannelSendRtpHeaderExtensions(
23272ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    int channel_id, const std::vector<RtpHeaderExtension>& extensions) {
23282ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  const RtpHeaderExtension* audio_level_extension =
23292ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      FindHeaderExtension(extensions, kRtpAudioLevelHeaderExtension);
23302ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
23312ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  if (!SetHeaderExtension(
23322ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      &webrtc::VoERTP_RTCP::SetSendAudioLevelIndicationStatus, channel_id,
23332ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      audio_level_extension)) {
23342ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    return false;
23352ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  }
23362ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
23372ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  const RtpHeaderExtension* send_time_extension =
23382ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      FindHeaderExtension(extensions, kRtpAbsoluteSenderTimeHeaderExtension);
23392ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  if (!SetHeaderExtension(
23402ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      &webrtc::VoERTP_RTCP::SetSendAbsoluteSenderTimeStatus, channel_id,
23412ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org      send_time_extension)) {
23422ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    return false;
23432ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  }
23442ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
23450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
23460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
23470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetPlayout(bool playout) {
23490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  desired_playout_ = playout;
23500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ChangePlayout(desired_playout_);
23510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
23520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::PausePlayout() {
23540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ChangePlayout(false);
23550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
23560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::ResumePlayout() {
23580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ChangePlayout(desired_playout_);
23590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
23600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
23620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (playout_ == playout) {
23630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
23640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
23650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23667162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  // Change the playout of all channels to the new state.
23670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool result = true;
23687162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (receive_channels_.empty()) {
23690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Only toggle the default channel if we don't have any other channels.
23700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    result = SetPlayout(voe_channel(), playout);
23710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
23727162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  for (ChannelMap::iterator it = receive_channels_.begin();
23737162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org       it != receive_channels_.end() && result; ++it) {
2374b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    if (!SetPlayout(it->second->channel(), playout)) {
23757162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      LOG(LS_ERROR) << "SetPlayout " << playout << " on channel "
2376b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org                    << it->second->channel() << " failed";
23770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      result = false;
23780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
23790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
23800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (result) {
23820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    playout_ = playout;
23830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
23840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return result;
23850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
23860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetSend(SendFlags send) {
23880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  desired_send_ = send;
2389f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (!send_channels_.empty())
23900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return ChangeSend(desired_send_);
23910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
23920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
23930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::PauseSend() {
23950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ChangeSend(SEND_NOTHING);
23960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
23970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
23980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::ResumeSend() {
23990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ChangeSend(desired_send_);
24000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
24010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
24020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::ChangeSend(SendFlags send) {
24030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (send_ == send) {
24040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
24050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
24060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2407f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Change the settings on each send channel.
2408f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (send == SEND_MICROPHONE)
24090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    engine()->SetOptionOverrides(options_);
24100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2411f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Change the settings on each send channel.
2412f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  for (ChannelMap::iterator iter = send_channels_.begin();
2413f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org       iter != send_channels_.end(); ++iter) {
2414b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    if (!ChangeSend(iter->second->channel(), send))
24150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2416f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
2417f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2418f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Clear up the options after stopping sending.
2419f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (send == SEND_NOTHING)
2420f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    engine()->ClearOptionOverrides();
2421f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2422f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  send_ = send;
2423f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  return true;
2424f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org}
2425f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2426f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.orgbool WebRtcVoiceMediaChannel::ChangeSend(int channel, SendFlags send) {
2427f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (send == SEND_MICROPHONE) {
2428f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (engine()->voe()->base()->StartSend(channel) == -1) {
2429f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      LOG_RTCERR1(StartSend, channel);
24300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
24310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
24320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->voe()->file() &&
2433f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        engine()->voe()->file()->StopPlayingFileAsMicrophone(channel) == -1) {
2434f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      LOG_RTCERR1(StopPlayingFileAsMicrophone, channel);
24350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
24360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
24370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {  // SEND_NOTHING
2438f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    ASSERT(send == SEND_NOTHING);
2439f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (engine()->voe()->base()->StopSend(channel) == -1) {
2440f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      LOG_RTCERR1(StopSend, channel);
2441f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      return false;
24420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2443f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
24440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2445f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  return true;
2446f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org}
2447f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
24482ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org// TODO(ronghuawu): Change this method to return bool.
2449f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.orgvoid WebRtcVoiceMediaChannel::ConfigureSendChannel(int channel) {
2450f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (engine()->voe()->network()->RegisterExternalTransport(
2451f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          channel, *this) == -1) {
2452f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG_RTCERR2(RegisterExternalTransport, channel, this);
24530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2454f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2455f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Enable RTCP (for quality stats and feedback messages)
2456f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  EnableRtcp(channel);
2457f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2458f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Reset all recv codecs; they will be enabled via SetRecvCodecs.
2459f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  ResetRecvCodecs(channel);
24602ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
24612ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  // Set RTP header extension for the new channel.
24622ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  SetChannelSendRtpHeaderExtensions(channel, send_extensions_);
2463f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org}
2464f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2465f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.orgbool WebRtcVoiceMediaChannel::DeleteChannel(int channel) {
2466f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) {
2467f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG_RTCERR1(DeRegisterExternalTransport, channel);
2468f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
2469f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2470f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (engine()->voe()->base()->DeleteChannel(channel) == -1) {
2471f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG_RTCERR1(DeleteChannel, channel);
2472f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    return false;
2473f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
2474f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
24750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
24760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
24770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
24780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
2479f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // If the default channel is already used for sending create a new channel
2480f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // otherwise use the default channel for sending.
2481f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  int channel = GetSendChannelNum(sp.first_ssrc());
2482f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (channel != -1) {
2483f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG(LS_ERROR) << "Stream already exists with ssrc " << sp.first_ssrc();
24840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
24850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
24860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2487f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  bool default_channel_is_available = true;
2488f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  for (ChannelMap::const_iterator iter = send_channels_.begin();
2489f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org       iter != send_channels_.end(); ++iter) {
2490b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    if (IsDefaultChannel(iter->second->channel())) {
2491f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      default_channel_is_available = false;
2492f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      break;
2493f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    }
2494f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
2495f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (default_channel_is_available) {
2496f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    channel = voe_channel();
2497f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  } else {
2498f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Create a new channel for sending audio data.
249997fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org    channel = engine()->CreateMediaVoiceChannel();
2500f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (channel == -1) {
2501f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      LOG_RTCERR0(CreateChannel);
2502f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      return false;
2503f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    }
2504f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2505f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    ConfigureSendChannel(channel);
2506f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
2507f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2508f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Save the channel to send_channels_, so that RemoveSendStream() can still
2509f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // delete the channel in case failure happens below.
2510b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  webrtc::AudioTransport* audio_transport =
2511b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      engine()->voe()->base()->audio_transport();
2512b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  send_channels_.insert(std::make_pair(
2513b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      sp.first_ssrc(),
2514b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      new WebRtcVoiceChannelRenderer(channel, audio_transport)));
2515f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2516f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Set the send (local) SSRC.
2517f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // If there are multiple send SSRCs, we can only set the first one here, and
2518f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // the rest of the SSRC(s) need to be set after SetSendCodec has been called
2519f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // (with a codec requires multiple SSRC(s)).
2520f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (engine()->voe()->rtp()->SetLocalSSRC(channel, sp.first_ssrc()) == -1) {
2521f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG_RTCERR2(SetSendSSRC, channel, sp.first_ssrc());
25220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
25230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2524f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2525f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // At this point the channel's local SSRC has been updated. If the channel is
2526f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // the default channel make sure that all the receive channels are updated as
2527f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // well. Receive channels have to have the same SSRC as the default channel in
2528f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // order to send receiver reports with this SSRC.
2529f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (IsDefaultChannel(channel)) {
2530f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    for (ChannelMap::const_iterator it = receive_channels_.begin();
2531f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org         it != receive_channels_.end(); ++it) {
2532f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      // Only update the SSRC for non-default channels.
2533b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      if (!IsDefaultChannel(it->second->channel())) {
2534b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        if (engine()->voe()->rtp()->SetLocalSSRC(it->second->channel(),
2535f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org                                                 sp.first_ssrc()) != 0) {
2536b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org          LOG_RTCERR2(SetLocalSSRC, it->second->channel(), sp.first_ssrc());
2537f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          return false;
2538f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        }
25397162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      }
25400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
25410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
25420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2543f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (engine()->voe()->rtp()->SetRTCP_CNAME(channel, sp.cname.c_str()) == -1) {
2544f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org     LOG_RTCERR2(SetRTCP_CNAME, channel, sp.cname);
25450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org     return false;
25460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
25470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2548952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  // Set the current codecs to be used for the new channel.
2549952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  if (!send_codecs_.empty() && !SetSendCodecs(channel, send_codecs_))
2550f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    return false;
25517162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
2552f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  return ChangeSend(channel, desired_send_);
25530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
25540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
25550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
2556f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  ChannelMap::iterator it = send_channels_.find(ssrc);
2557f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (it == send_channels_.end()) {
2558f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
2559f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org                    << " which doesn't exist.";
25600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
25610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
25627162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
2563b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  int channel = it->second->channel();
2564f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  ChangeSend(channel, SEND_NOTHING);
2565f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2566b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // Delete the WebRtcVoiceChannelRenderer object connected to the channel,
2567b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // this will disconnect the audio renderer with the send channel.
2568b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  delete it->second;
2569b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  send_channels_.erase(it);
2570f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2571f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (IsDefaultChannel(channel)) {
2572f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Do not delete the default channel since the receive channels depend on
2573f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // the default channel, recycle it instead.
2574f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    ChangeSend(channel, SEND_NOTHING);
2575f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  } else {
2576f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Clean up and delete the send channel.
2577f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG(LS_INFO) << "Removing audio send stream " << ssrc
2578f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org                 << " with VoiceEngine channel #" << channel << ".";
2579f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (!DeleteChannel(channel))
2580f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      return false;
2581f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
2582f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
2583f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (send_channels_.empty())
2584f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    ChangeSend(SEND_NOTHING);
25857162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
25860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
25870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
25880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
25890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
25907162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
25910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
25920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!VERIFY(sp.ssrcs.size() == 1))
25930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
25940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  uint32 ssrc = sp.first_ssrc();
25950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2596861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  if (ssrc == 0) {
2597861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org    LOG(LS_WARNING) << "AddRecvStream with 0 ssrc is not supported.";
2598861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org    return false;
2599861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  }
2600861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org
26017162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (receive_channels_.find(ssrc) != receive_channels_.end()) {
26027162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
26030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
26040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
26050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
26067162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  // Reuse default channel for recv stream in non-conference mode call
26077162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  // when the default channel is not being used.
2608b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  webrtc::AudioTransport* audio_transport =
2609b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      engine()->voe()->base()->audio_transport();
26107162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (!InConferenceMode() && default_receive_ssrc_ == 0) {
26117162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    LOG(LS_INFO) << "Recv stream " << sp.first_ssrc()
26127162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                 << " reuse default channel";
26137162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    default_receive_ssrc_ = sp.first_ssrc();
26147162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    receive_channels_.insert(std::make_pair(
2615b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        default_receive_ssrc_,
2616b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        new WebRtcVoiceChannelRenderer(voe_channel(), audio_transport)));
26177162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    return SetPlayout(voe_channel(), playout_);
26187162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  }
26197162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
26200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Create a new channel for receiving audio data.
262197fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org  int channel = engine()->CreateMediaVoiceChannel();
26220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (channel == -1) {
26230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR0(CreateChannel);
26240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
26250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
26260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2627861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  if (!ConfigureRecvChannel(channel)) {
2628861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org    DeleteChannel(channel);
2629861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org    return false;
2630861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  }
2631861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org
2632861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  receive_channels_.insert(
2633b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      std::make_pair(
2634b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org          ssrc, new WebRtcVoiceChannelRenderer(channel, audio_transport)));
2635861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org
2636861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  LOG(LS_INFO) << "New audio stream " << ssrc
2637861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org               << " registered to VoiceEngine channel #"
2638861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org               << channel << ".";
2639861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org  return true;
2640861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org}
2641861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.org
2642861d07361a4559a72e96236f27b758a56f6f59f0wu@webrtc.orgbool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
26430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Configure to use external transport, like our default channel.
26440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (engine()->voe()->network()->RegisterExternalTransport(
26450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          channel, *this) == -1) {
26460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR2(SetExternalTransport, channel, this);
26470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
26480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
26490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
26500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Use the same SSRC as our default channel (so the RTCP reports are correct).
26518485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org  unsigned int send_ssrc = 0;
26520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  webrtc::VoERTP_RTCP* rtp = engine()->voe()->rtp();
26530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (rtp->GetLocalSSRC(voe_channel(), send_ssrc) == -1) {
26548485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org    LOG_RTCERR1(GetSendSSRC, channel);
26550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
26560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
26570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (rtp->SetLocalSSRC(channel, send_ssrc) == -1) {
26588485ec698cd13d65354e2f81132b5763a3d216a4henrika@webrtc.org    LOG_RTCERR1(SetSendSSRC, channel);
26590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
26600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
26610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
26620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Use the same recv payload types as our default channel.
26630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ResetRecvCodecs(channel);
26640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!recv_codecs_.empty()) {
26650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    for (std::vector<AudioCodec>::const_iterator it = recv_codecs_.begin();
26660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        it != recv_codecs_.end(); ++it) {
26670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      webrtc::CodecInst voe_codec;
26680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (engine()->FindWebRtcCodec(*it, &voe_codec)) {
26690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        voe_codec.pltype = it->id;
26700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        voe_codec.rate = 0;  // Needed to make GetRecPayloadType work for ISAC
26710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (engine()->voe()->codec()->GetRecPayloadType(
26720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            voe_channel(), voe_codec) != -1) {
26730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          if (engine()->voe()->codec()->SetRecPayloadType(
26740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org              channel, voe_codec) == -1) {
26750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
26760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            return false;
26770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          }
26780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
26790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
26800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
26810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
26820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
26837162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (InConferenceMode()) {
26847162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // To be in par with the video, voe_channel() is not used for receiving in
26857162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // a conference call.
26867162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    if (receive_channels_.empty() && default_receive_ssrc_ == 0 && playout_) {
26877162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      // This is the first stream in a multi user meeting. We can now
26887162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      // disable playback of the default stream. This since the default
26897162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      // stream will probably have received some initial packets before
26907162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      // the new stream was added. This will mean that the CN state from
26917162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      // the default channel will be mixed in with the other streams
26927162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      // throughout the whole meeting, which might be disturbing.
26937162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      LOG(LS_INFO) << "Disabling playback on the default voice channel";
26947162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      SetPlayout(voe_channel(), false);
26957162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    }
26960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2697952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  SetNack(channel, nack_enabled_);
26980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
26992ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  // Set RTP header extension for the new channel.
27002ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  if (!SetChannelRecvRtpHeaderExtensions(channel, receive_extensions_)) {
27012ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    return false;
27022ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  }
27032ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org
27040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return SetPlayout(channel, playout_);
27050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
27060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
27070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32 ssrc) {
27087162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
27097162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  ChannelMap::iterator it = receive_channels_.find(ssrc);
2710f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (it == receive_channels_.end()) {
2711f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
2712f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org                    << " which doesn't exist.";
27137162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    return false;
2714f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
27150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2716b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // Delete the WebRtcVoiceChannelRenderer object connected to the channel, this
2717b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // will disconnect the audio renderer with the receive channel.
2718b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  // Cache the channel before the deletion.
2719b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  const int channel = it->second->channel();
2720b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  delete it->second;
2721b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  receive_channels_.erase(it);
2722b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
27237162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (ssrc == default_receive_ssrc_) {
2724b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    ASSERT(IsDefaultChannel(channel));
27257162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // Recycle the default channel is for recv stream.
27267162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    if (playout_)
27277162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      SetPlayout(voe_channel(), false);
27287162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
27297162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    default_receive_ssrc_ = 0;
27307162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    return true;
27317162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  }
27327162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
27337162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  LOG(LS_INFO) << "Removing audio stream " << ssrc
2734b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org               << " with VoiceEngine channel #" << channel << ".";
2735b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  if (!DeleteChannel(channel))
27367162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    return false;
27377162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
27387162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  bool enable_default_channel_playout = false;
27397162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (receive_channels_.empty()) {
27407162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // The last stream was removed. We can now enable the default
27417162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // channel for new channels to be played out immediately without
27427162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // waiting for AddStream messages.
27437162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // We do this for both conference mode and non-conference mode.
27447162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // TODO(oja): Does the default channel still have it's CN state?
27457162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    enable_default_channel_playout = true;
27467162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  }
27477162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (!InConferenceMode() && receive_channels_.size() == 1 &&
27487162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      default_receive_ssrc_ != 0) {
27497162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // Only the default channel is active, enable the playout on default
27507162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // channel.
27517162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    enable_default_channel_playout = true;
27527162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  }
27537162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (enable_default_channel_playout && playout_) {
27547162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    LOG(LS_INFO) << "Enabling playback on the default voice channel";
27557162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    SetPlayout(voe_channel(), true);
27567162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  }
27577162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
27587162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  return true;
27597162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org}
27607162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
27617162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetRemoteRenderer(uint32 ssrc,
27627162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                                                AudioRenderer* renderer) {
27637162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  ChannelMap::iterator it = receive_channels_.find(ssrc);
27647162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (it == receive_channels_.end()) {
27657162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    if (renderer) {
27667162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      // Return an error if trying to set a valid renderer with an invalid ssrc.
2767f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      LOG(LS_ERROR) << "SetRemoteRenderer failed with ssrc "<< ssrc;
27680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
27690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
27700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
27717162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // The channel likely has gone away, do nothing.
27727162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    return true;
27737162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  }
27747162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
2775b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  if (renderer)
2776b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    it->second->Start(renderer);
2777b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  else
2778b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    it->second->Stop();
27797162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
27800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
27810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
27820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
27837162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32 ssrc,
27847162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                                               AudioRenderer* renderer) {
2785f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  ChannelMap::iterator it = send_channels_.find(ssrc);
2786f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (it == send_channels_.end()) {
2787f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (renderer) {
2788f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      // Return an error if trying to set a valid renderer with an invalid ssrc.
2789f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      LOG(LS_ERROR) << "SetLocalRenderer failed with ssrc "<< ssrc;
2790f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      return false;
2791f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    }
27927162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
2793f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // The channel likely has gone away, do nothing.
2794f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    return true;
27957162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  }
27960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2797b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  if (renderer)
2798b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    it->second->Start(renderer);
2799b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  else
2800b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    it->second->Stop();
28017162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org
28020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
28030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
28040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
28050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::GetActiveStreams(
28060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AudioInfo::StreamList* actives) {
28077162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  // In conference mode, the default channel should not be in
28087162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  // |receive_channels_|.
28090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  actives->clear();
28107162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  for (ChannelMap::iterator it = receive_channels_.begin();
28117162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org       it != receive_channels_.end(); ++it) {
2812b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    int level = GetOutputLevel(it->second->channel());
28130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (level > 0) {
28140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      actives->push_back(std::make_pair(it->first, level));
28150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
28160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
28170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
28180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
28190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
28200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcVoiceMediaChannel::GetOutputLevel() {
28210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // return the highest output level of all streams
28220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int highest = GetOutputLevel(voe_channel());
28237162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  for (ChannelMap::iterator it = receive_channels_.begin();
28247162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org       it != receive_channels_.end(); ++it) {
2825b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    int level = GetOutputLevel(it->second->channel());
28260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    highest = talk_base::_max(level, highest);
28270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
28280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return highest;
28290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
28300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
28310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcVoiceMediaChannel::GetTimeSinceLastTyping() {
28320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int ret;
28330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (engine()->voe()->processing()->TimeSinceLastTyping(ret) == -1) {
28340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // In case of error, log the info and continue
28350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR0(TimeSinceLastTyping);
28360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ret = -1;
28370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
28380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ret *= 1000;  // We return ms, webrtc returns seconds.
28390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
28400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ret;
28410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
28420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
28430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceMediaChannel::SetTypingDetectionParameters(int time_window,
28440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int cost_per_typing, int reporting_threshold, int penalty_decay,
28450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int type_event_delay) {
28460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (engine()->voe()->processing()->SetTypingDetectionParameters(
28470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          time_window, cost_per_typing,
28480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          reporting_threshold, penalty_decay, type_event_delay) == -1) {
28490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // In case of error, log the info and continue
28500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR5(SetTypingDetectionParameters, time_window,
28510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                cost_per_typing, reporting_threshold, penalty_decay,
28520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                type_event_delay);
28530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
28540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
28550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
28560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetOutputScaling(
28570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32 ssrc, double left, double right) {
28587162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
28590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Collect the channels to scale the output volume.
28600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<int> channels;
28610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (0 == ssrc) {  // Collect all channels, including the default one.
28627162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // Default channel is not in receive_channels_ if it is not being used for
28637162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    // playout.
28647162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    if (default_receive_ssrc_ == 0)
28657162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      channels.push_back(voe_channel());
28667162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    for (ChannelMap::const_iterator it = receive_channels_.begin();
28677162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org         it != receive_channels_.end(); ++it) {
2868b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      channels.push_back(it->second->channel());
28690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
28700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {  // Collect only the channel of the specified ssrc.
28710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int channel = GetReceiveChannelNum(ssrc);
28720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (-1 == channel) {
28730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc;
28740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
28750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
28760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    channels.push_back(channel);
28770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
28780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
28790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Scale the output volume for the collected channels. We first normalize to
28800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // scale the volume and then set the left and right pan.
28810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  float scale = static_cast<float>(talk_base::_max(left, right));
28820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (scale > 0.0001f) {
28830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    left /= scale;
28840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    right /= scale;
28850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
28860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (std::vector<int>::const_iterator it = channels.begin();
28870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      it != channels.end(); ++it) {
28880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (-1 == engine()->voe()->volume()->SetChannelOutputVolumeScaling(
28890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        *it, scale)) {
28900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR2(SetChannelOutputVolumeScaling, *it, scale);
28910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
28920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
28930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (-1 == engine()->voe()->volume()->SetOutputVolumePan(
28940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        *it, static_cast<float>(left), static_cast<float>(right))) {
28950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR3(SetOutputVolumePan, *it, left, right);
28960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Do not return if fails. SetOutputVolumePan is not available for all
28970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // pltforms.
28980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
28990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << "SetOutputScaling to left=" << left * scale
29000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                 << " right=" << right * scale
29010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                 << " for channel " << *it << " and ssrc " << ssrc;
29020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
29040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
29050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::GetOutputScaling(
29070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32 ssrc, double* left, double* right) {
29080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!left || !right) return false;
29090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29107162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
29110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Determine which channel based on ssrc.
29120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int channel = (0 == ssrc) ? voe_channel() : GetReceiveChannelNum(ssrc);
29130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (channel == -1) {
29140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc;
29150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
29160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  float scaling;
29190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (-1 == engine()->voe()->volume()->GetChannelOutputVolumeScaling(
29200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      channel, scaling)) {
29210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR2(GetChannelOutputVolumeScaling, channel, scaling);
29220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
29230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  float left_pan;
29260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  float right_pan;
29270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (-1 == engine()->voe()->volume()->GetOutputVolumePan(
29280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      channel, left_pan, right_pan)) {
29290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG_RTCERR3(GetOutputVolumePan, channel, left_pan, right_pan);
29300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // If GetOutputVolumePan fails, we use the default left and right pan.
29310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    left_pan = 1.0f;
29320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    right_pan = 1.0f;
29330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *left = scaling * left_pan;
29360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *right = scaling * right_pan;
29370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
29380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
29390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetRingbackTone(const char *buf, int len) {
29410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ringback_tone_.reset(new WebRtcSoundclipStream(buf, len));
29420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
29430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
29440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::PlayRingbackTone(uint32 ssrc,
29460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                             bool play, bool loop) {
29470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ringback_tone_) {
29480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
29490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // The voe file api is not available in chrome.
29520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!engine()->voe()->file()) {
29530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
29540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Determine which VoiceEngine channel to play on.
29570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int channel = (ssrc == 0) ? voe_channel() : GetReceiveChannelNum(ssrc);
29580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (channel == -1) {
29590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
29600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Make sure the ringtone is cued properly, and play it out.
29630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (play) {
29640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ringback_tone_->set_loop(loop);
29650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ringback_tone_->Rewind();
29660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->voe()->file()->StartPlayingFileLocally(channel,
29670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        ringback_tone_.get()) == -1) {
29680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR2(StartPlayingFileLocally, channel, ringback_tone_.get());
29690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_ERROR) << "Unable to start ringback tone";
29700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
29710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
29720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ringback_channels_.insert(channel);
29730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << "Started ringback on channel " << channel;
29740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
29750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->voe()->file()->IsPlayingFileLocally(channel) == 1 &&
29760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        engine()->voe()->file()->StopPlayingFileLocally(channel) == -1) {
29770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR1(StopPlayingFileLocally, channel);
29780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
29790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
29800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << "Stopped ringback on channel " << channel;
29810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ringback_channels_.erase(channel);
29820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
29850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
29860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::CanInsertDtmf() {
29880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return dtmf_allowed_;
29890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
29900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::InsertDtmf(uint32 ssrc, int event,
29920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                         int duration, int flags) {
29930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!dtmf_allowed_) {
29940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
29950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
29960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
29970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Send the event.
29980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (flags & cricket::DF_SEND) {
2999952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    int channel = -1;
3000952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    if (ssrc == 0) {
3001952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      bool default_channel_is_inuse = false;
3002952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      for (ChannelMap::const_iterator iter = send_channels_.begin();
3003952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org           iter != send_channels_.end(); ++iter) {
3004b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        if (IsDefaultChannel(iter->second->channel())) {
3005952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          default_channel_is_inuse = true;
3006952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          break;
3007952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org        }
3008952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      }
3009952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      if (default_channel_is_inuse) {
3010952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org        channel = voe_channel();
3011952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      } else if (!send_channels_.empty()) {
3012b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        channel = send_channels_.begin()->second->channel();
3013952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      }
3014952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    } else {
3015952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      channel = GetSendChannelNum(ssrc);
3016952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    }
3017f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (channel == -1) {
30180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "InsertDtmf - The specified ssrc "
30190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                      << ssrc << " is not in use.";
30200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
30210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
30220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Send DTMF using out-of-band DTMF. ("true", as 3rd arg)
3023f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (engine()->voe()->dtmf()->SendTelephoneEvent(
3024f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org            channel, event, true, duration) == -1) {
3025f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration);
30260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
30270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
30280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
30290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
30300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Play the event.
30310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (flags & cricket::DF_PLAY) {
30320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Play DTMF tone locally.
30330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->voe()->dtmf()->PlayDtmfTone(event, duration) == -1) {
30340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR2(PlayDtmfTone, event, duration);
30350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
30360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
30370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
30380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
30390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
30400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
30410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3042f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.orgvoid WebRtcVoiceMediaChannel::OnPacketReceived(
3043f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org    talk_base::Buffer* packet, const talk_base::PacketTime& packet_time) {
30440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Pick which channel to send this packet to. If this packet doesn't match
30450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // any multiplexed streams, just send it to the default channel. Otherwise,
30460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // send it to the specific decoder instance for that stream.
30470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int which_channel = GetReceiveChannelNum(
30480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      ParseSsrc(packet->data(), packet->length(), false));
30490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (which_channel == -1) {
30500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    which_channel = voe_channel();
30510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
30520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
30530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Stop any ringback that might be playing on the channel.
30540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // It's possible the ringback has already stopped, ih which case we'll just
30550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // use the opportunity to remove the channel from ringback_channels_.
30560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (engine()->voe()->file()) {
30570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::set<int>::iterator it = ringback_channels_.find(which_channel);
30580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (it != ringback_channels_.end()) {
30590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (engine()->voe()->file()->IsPlayingFileLocally(
30600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          which_channel) == 1) {
30610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        engine()->voe()->file()->StopPlayingFileLocally(which_channel);
30620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        LOG(LS_INFO) << "Stopped ringback on channel " << which_channel
30630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                     << " due to incoming media";
30640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
30650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      ringback_channels_.erase(which_channel);
30660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
30670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
30680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
30690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Pass it off to the decoder.
30701a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org  engine()->voe()->network()->ReceivedRTPPacket(
30711a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org      which_channel,
30721a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org      packet->data(),
30731a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org      static_cast<unsigned int>(packet->length()));
30740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
30750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3076f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.orgvoid WebRtcVoiceMediaChannel::OnRtcpReceived(
3077f89a403cd8db88001322bbb0765c4636fd123700wu@webrtc.org    talk_base::Buffer* packet, const talk_base::PacketTime& packet_time) {
3078f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Sending channels need all RTCP packets with feedback information.
3079f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Even sender reports can contain attached report blocks.
3080f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // Receiving channels need sender reports in order to create
3081f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // correct receiver reports.
3082f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  int type = 0;
3083f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (!GetRtcpType(packet->data(), packet->length(), &type)) {
3084f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG(LS_WARNING) << "Failed to parse type from received RTCP packet";
3085f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    return;
3086f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
3087f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3088f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // If it is a sender report, find the channel that is listening.
3089f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  bool has_sent_to_default_channel = false;
3090f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (type == kRtcpTypeSR) {
3091f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    int which_channel = GetReceiveChannelNum(
3092f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        ParseSsrc(packet->data(), packet->length(), true));
3093f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (which_channel != -1) {
3094f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      engine()->voe()->network()->ReceivedRTCPPacket(
3095f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          which_channel,
3096f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          packet->data(),
3097f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          static_cast<unsigned int>(packet->length()));
3098f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3099f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      if (IsDefaultChannel(which_channel))
3100f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        has_sent_to_default_channel = true;
3101f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    }
3102f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
3103f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3104f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // SR may continue RR and any RR entry may correspond to any one of the send
3105f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // channels. So all RTCP packets must be forwarded all send channels. VoE
3106f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  // will filter out RR internally.
3107f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  for (ChannelMap::iterator iter = send_channels_.begin();
3108f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org       iter != send_channels_.end(); ++iter) {
3109f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Make sure not sending the same packet to default channel more than once.
3110b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    if (IsDefaultChannel(iter->second->channel()) &&
3111b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        has_sent_to_default_channel)
3112f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      continue;
31130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3114f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    engine()->voe()->network()->ReceivedRTCPPacket(
3115b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org        iter->second->channel(),
3116f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        packet->data(),
3117f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        static_cast<unsigned int>(packet->length()));
3118f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
31190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
31200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
31210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::MuteStream(uint32 ssrc, bool muted) {
3122f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  int channel = (ssrc == 0) ? voe_channel() : GetSendChannelNum(ssrc);
3123f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (channel == -1) {
31240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
31250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
31260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3127f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (engine()->voe()->volume()->SetInputMute(channel, muted) == -1) {
3128f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG_RTCERR2(SetInputMute, channel, muted);
31290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
31300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
31310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
31320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
31330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3134f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.orgbool WebRtcVoiceMediaChannel::SetStartSendBandwidth(int bps) {
3135f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  // TODO(andresp): Add support for setting an independent start bandwidth when
3136f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  // bandwidth estimation is enabled for voice engine.
3137f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  return false;
3138f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org}
31390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3140f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.orgbool WebRtcVoiceMediaChannel::SetMaxSendBandwidth(int bps) {
3141f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  LOG(LS_INFO) << "WebRtcVoiceMediaChanne::SetSendBandwidth.";
3142cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org
3143f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  return SetSendBandwidthInternal(bps);
3144cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org}
3145cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org
3146f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.orgbool WebRtcVoiceMediaChannel::SetSendBandwidthInternal(int bps) {
3147f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  LOG(LS_INFO) << "WebRtcVoiceMediaChannel::SetSendBandwidthInternal.";
3148f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org
3149f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  send_bw_setting_ = true;
3150f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  send_bw_bps_ = bps;
3151cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org
31520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!send_codec_) {
3153cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org    LOG(LS_INFO) << "The send codec has not been set up yet. "
3154cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org                 << "The send bandwidth setting will be applied later.";
3155cc712021a90cc93a68b4e65930cd0a0ad0a88d4ewu@webrtc.org    return true;
31560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
31570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
31580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Bandwidth is auto by default.
3159f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  // TODO(bemasc): Fix this so that if SetMaxSendBandwidth(50) is followed by
3160f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  // SetMaxSendBandwith(0), the second call removes the previous limit.
3161f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  if (bps <= 0)
31620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
31630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
31640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  webrtc::CodecInst codec = *send_codec_;
31650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool is_multi_rate = IsCodecMultiRate(codec);
31660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
31670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (is_multi_rate) {
31680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // If codec is multi-rate then just set the bitrate.
31690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    codec.rate = bps;
31700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!SetSendCodec(codec)) {
31710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Failed to set codec " << codec.plname
31720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                   << " to bitrate " << bps << " bps.";
31730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
31740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
31750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
31760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
31770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // If codec is not multi-rate and |bps| is less than the fixed bitrate
31780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // then fail. If codec is not multi-rate and |bps| exceeds or equal the
31790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // fixed bitrate then ignore.
31800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (bps < codec.rate) {
31810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_INFO) << "Failed to set codec " << codec.plname
31820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                   << " to bitrate " << bps << " bps"
31830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                   << ", requires at least " << codec.rate << " bps.";
31840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
31850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
31860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
31870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
31880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
31890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
31900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
31910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool echo_metrics_on = false;
31920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // These can take on valid negative values, so use the lowest possible level
31930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // as default rather than -1.
3194f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  int echo_return_loss = -100;
3195f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  int echo_return_loss_enhancement = -100;
31960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // These can also be negative, but in practice -1 is only used to signal
31970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // insufficient data, since the resolution is limited to multiples of 4 ms.
3198f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  int echo_delay_median_ms = -1;
3199f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  int echo_delay_std_ms = -1;
3200f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (engine()->voe()->processing()->GetEcMetricsStatus(
3201f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          echo_metrics_on) != -1 && echo_metrics_on) {
32020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
32030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // here, but it appears to be unsuitable currently. Revisit after this is
32040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // investigated: http://b/issue?id=5666755
32050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int erl, erle, rerl, anlp;
3206f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (engine()->voe()->processing()->GetEchoMetrics(
3207f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org            erl, erle, rerl, anlp) != -1) {
3208f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      echo_return_loss = erl;
3209f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      echo_return_loss_enhancement = erle;
32100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
32110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
32120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int median, std;
32130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->voe()->processing()->GetEcDelayMetrics(median, std) != -1) {
3214f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      echo_delay_median_ms = median;
3215f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      echo_delay_std_ms = std;
32160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
32170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
32180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3219f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  webrtc::CallStatistics cs;
3220f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  unsigned int ssrc;
3221f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  webrtc::CodecInst codec;
3222f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  unsigned int level;
3223f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3224f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  for (ChannelMap::const_iterator channel_iter = send_channels_.begin();
3225f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org       channel_iter != send_channels_.end(); ++channel_iter) {
3226b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    const int channel = channel_iter->second->channel();
3227f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3228f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Fill in the sender info, based on what we know, and what the
3229f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // remote side told us it got from its RTCP report.
3230f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    VoiceSenderInfo sinfo;
3231f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3232f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (engine()->voe()->rtp()->GetRTCPStatistics(channel, cs) == -1 ||
3233f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        engine()->voe()->rtp()->GetLocalSSRC(channel, ssrc) == -1) {
3234f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      continue;
3235f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    }
3236f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
323797fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org    sinfo.add_ssrc(ssrc);
3238f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.codec_name = send_codec_.get() ? send_codec_->plname : "";
3239f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.bytes_sent = cs.bytesSent;
3240f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.packets_sent = cs.packetsSent;
3241f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // RTT isn't known until a RTCP report is received. Until then, VoiceEngine
3242f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // returns 0 to indicate an error value.
3243f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1;
3244f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3245f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Get data from the last remote RTCP report. Use default values if no data
3246f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // available.
3247f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.fraction_lost = -1.0;
3248f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.jitter_ms = -1;
3249f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.packets_lost = -1;
3250f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.ext_seqnum = -1;
3251f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    std::vector<webrtc::ReportBlock> receive_blocks;
3252f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    if (engine()->voe()->rtp()->GetRemoteRTCPReportBlocks(
3253f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org            channel, &receive_blocks) != -1 &&
3254f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        engine()->voe()->codec()->GetSendCodec(channel, codec) != -1) {
3255f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      std::vector<webrtc::ReportBlock>::iterator iter;
3256f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      for (iter = receive_blocks.begin(); iter != receive_blocks.end();
3257f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org           ++iter) {
3258f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        // Lookup report for send ssrc only.
325997fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org        if (iter->source_SSRC == sinfo.ssrc()) {
3260f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          // Convert Q8 to floating point.
3261f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          sinfo.fraction_lost = static_cast<float>(iter->fraction_lost) / 256;
3262f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          // Convert samples to milliseconds.
3263f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          if (codec.plfreq / 1000 > 0) {
3264f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org            sinfo.jitter_ms = iter->interarrival_jitter / (codec.plfreq / 1000);
3265f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          }
3266f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          sinfo.packets_lost = iter->cumulative_num_packets_lost;
3267f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          sinfo.ext_seqnum = iter->extended_highest_sequence_number;
3268f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          break;
3269f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        }
3270f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      }
3271f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    }
3272f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3273f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Local speech level.
3274f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.audio_level = (engine()->voe()->volume()->
3275f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        GetSpeechInputLevelFullRange(level) != -1) ? level : -1;
3276f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3277f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // TODO(xians): We are injecting the same APM logging to all the send
3278f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // channels here because there is no good way to know which send channel
3279f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // is using the APM. The correct fix is to allow the send channels to have
3280f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // their own APM so that we can feed the correct APM logging to different
3281f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // send channels. See issue crbug/264611 .
3282f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.echo_return_loss = echo_return_loss;
3283f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.echo_return_loss_enhancement = echo_return_loss_enhancement;
3284f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.echo_delay_median_ms = echo_delay_median_ms;
3285f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    sinfo.echo_delay_std_ms = echo_delay_std_ms;
32865528070a0c76057a000b877fc56ca4180ad2087bmallinath@webrtc.org    // TODO(ajm): Re-enable this metric once we have a reliable implementation.
32875528070a0c76057a000b877fc56ca4180ad2087bmallinath@webrtc.org    sinfo.aec_quality_min = -1;
32884ba8b9ea10385f43b19d6ed7408f4a09bdc1cbdawu@webrtc.org    sinfo.typing_noise_detected = typing_noise_detected_;
3289f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3290f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    info->senders.push_back(sinfo);
3291f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  }
32920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
32937162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  // Build the list of receivers, one for each receiving channel, or 1 in
32947162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  // a 1:1 call.
32950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<int> channels;
32967162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  for (ChannelMap::const_iterator it = receive_channels_.begin();
32977162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org       it != receive_channels_.end(); ++it) {
3298b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    channels.push_back(it->second->channel());
32990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
33000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (channels.empty()) {
33010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    channels.push_back(voe_channel());
33020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
33030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
33040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Get the SSRC and stats for each receiver, based on our own calculations.
33050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (std::vector<int>::const_iterator it = channels.begin();
33060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       it != channels.end(); ++it) {
33070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    memset(&cs, 0, sizeof(cs));
33080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->voe()->rtp()->GetRemoteSSRC(*it, ssrc) != -1 &&
33090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        engine()->voe()->rtp()->GetRTCPStatistics(*it, cs) != -1 &&
33100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        engine()->voe()->codec()->GetRecCodec(*it, codec) != -1) {
33110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      VoiceReceiverInfo rinfo;
331297fbd309a28be4e38d138b40662507d50cab6d26sergeyu@chromium.org      rinfo.add_ssrc(ssrc);
33130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      rinfo.bytes_rcvd = cs.bytesReceived;
33140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      rinfo.packets_rcvd = cs.packetsReceived;
33150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // The next four fields are from the most recently sent RTCP report.
33160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Convert Q8 to floating point.
33170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      rinfo.fraction_lost = static_cast<float>(cs.fractionLost) / (1 << 8);
33180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      rinfo.packets_lost = cs.cumulativeLost;
33190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      rinfo.ext_seqnum = cs.extendedMax;
3320842c369caaf7ab0115e101686ee5640a289da0e8buildbot@webrtc.org#ifdef USE_WEBRTC_DEV_BRANCH
3321842c369caaf7ab0115e101686ee5640a289da0e8buildbot@webrtc.org      rinfo.capture_start_ntp_time_ms = cs.capture_start_ntp_time_ms_;
3322842c369caaf7ab0115e101686ee5640a289da0e8buildbot@webrtc.org#endif
3323ec0b1b83d70e08f3bd47940d33ad69cb8bb0878fbuildbot@webrtc.org      if (codec.pltype != -1) {
3324ec0b1b83d70e08f3bd47940d33ad69cb8bb0878fbuildbot@webrtc.org        rinfo.codec_name = codec.plname;
3325ec0b1b83d70e08f3bd47940d33ad69cb8bb0878fbuildbot@webrtc.org      }
33260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Convert samples to milliseconds.
33270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (codec.plfreq / 1000 > 0) {
33280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000);
33290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
33300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
33310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Get jitter buffer and total delay (alg + jitter + playout) stats.
33320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      webrtc::NetworkStatistics ns;
33330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (engine()->voe()->neteq() &&
33340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          engine()->voe()->neteq()->GetNetworkStatistics(
33350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org              *it, ns) != -1) {
33360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        rinfo.jitter_buffer_ms = ns.currentBufferSize;
33370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        rinfo.jitter_buffer_preferred_ms = ns.preferredBufferSize;
33380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        rinfo.expand_rate =
33391a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org            static_cast<float>(ns.currentExpandRate) / (1 << 14);
33400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
334154caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org
334254caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org      webrtc::AudioDecodingCallStats ds;
334354caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org      if (engine()->voe()->neteq() &&
334454caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org          engine()->voe()->neteq()->GetDecodingCallStatistics(
334554caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org              *it, &ds) != -1) {
334654caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org        rinfo.decoding_calls_to_silence_generator =
334754caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org            ds.calls_to_silence_generator;
334854caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org        rinfo.decoding_calls_to_neteq = ds.calls_to_neteq;
334954caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org        rinfo.decoding_normal = ds.decoded_normal;
335054caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org        rinfo.decoding_plc = ds.decoded_plc;
335154caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org        rinfo.decoding_cng = ds.decoded_cng;
335254caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org        rinfo.decoding_plc_cng = ds.decoded_plc_cng;
335354caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org      }
335454caffdda86e16e40218943b755a502c23b0940dhenrike@webrtc.org
33550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (engine()->voe()->sync()) {
335619da4659bfe1cd99b6b1476cae9bc74e99e0b09dsergeyu@chromium.org        int jitter_buffer_delay_ms = 0;
33570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        int playout_buffer_delay_ms = 0;
33580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        engine()->voe()->sync()->GetDelayEstimate(
335919da4659bfe1cd99b6b1476cae9bc74e99e0b09dsergeyu@chromium.org            *it, &jitter_buffer_delay_ms, &playout_buffer_delay_ms);
336019da4659bfe1cd99b6b1476cae9bc74e99e0b09dsergeyu@chromium.org        rinfo.delay_estimate_ms = jitter_buffer_delay_ms +
336119da4659bfe1cd99b6b1476cae9bc74e99e0b09dsergeyu@chromium.org            playout_buffer_delay_ms;
33620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
33630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
33640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Get speech level.
33650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      rinfo.audio_level = (engine()->voe()->volume()->
33660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          GetSpeechOutputLevelFullRange(*it, level) != -1) ? level : -1;
33670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      info->receivers.push_back(rinfo);
33680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
33690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
33700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
33710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
33720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
33730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
33740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceMediaChannel::GetLastMediaError(
33750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32* ssrc, VoiceMediaChannel::Error* error) {
33760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(ssrc != NULL);
33770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(error != NULL);
33780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  FindSsrc(voe_channel(), ssrc);
33790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *error = WebRtcErrorToChannelError(GetLastEngineError());
33800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
33810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
33820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
33837162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
33840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(ssrc != NULL);
3385f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (channel_num == -1 && send_ != SEND_NOTHING) {
33860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Sometimes the VoiceEngine core will throw error with channel_num = -1.
33870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // This means the error is not limited to a specific channel.  Signal the
33880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // message using ssrc=0.  If the current channel is sending, use this
33890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // channel for sending the message.
33900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    *ssrc = 0;
33910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
33920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
3393f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    // Check whether this is a sending channel.
3394f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    for (ChannelMap::const_iterator it = send_channels_.begin();
3395f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org         it != send_channels_.end(); ++it) {
3396b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      if (it->second->channel() == channel_num) {
3397f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        // This is a sending channel.
3398f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        uint32 local_ssrc = 0;
3399f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        if (engine()->voe()->rtp()->GetLocalSSRC(
3400f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org                channel_num, local_ssrc) != -1) {
3401f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org          *ssrc = local_ssrc;
3402f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        }
3403f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org        return true;
3404f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org      }
3405f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    }
3406f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
34070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Check whether this is a receiving channel.
34087162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org    for (ChannelMap::const_iterator it = receive_channels_.begin();
34097162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org        it != receive_channels_.end(); ++it) {
3410b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org      if (it->second->channel() == channel_num) {
34110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        *ssrc = it->first;
34120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return true;
34130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
34140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
34150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
34160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return false;
34170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
34180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WebRtcVoiceMediaChannel::OnError(uint32 ssrc, int error) {
34204ba8b9ea10385f43b19d6ed7408f4a09bdc1cbdawu@webrtc.org  if (error == VE_TYPING_NOISE_WARNING) {
34214ba8b9ea10385f43b19d6ed7408f4a09bdc1cbdawu@webrtc.org    typing_noise_detected_ = true;
34224ba8b9ea10385f43b19d6ed7408f4a09bdc1cbdawu@webrtc.org  } else if (error == VE_TYPING_NOISE_OFF_WARNING) {
34234ba8b9ea10385f43b19d6ed7408f4a09bdc1cbdawu@webrtc.org    typing_noise_detected_ = false;
34244ba8b9ea10385f43b19d6ed7408f4a09bdc1cbdawu@webrtc.org  }
34250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SignalMediaError(ssrc, WebRtcErrorToChannelError(error));
34260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
34270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcVoiceMediaChannel::GetOutputLevel(int channel) {
34290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  unsigned int ulevel;
34300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int ret =
34310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      engine()->voe()->volume()->GetSpeechOutputLevel(channel, ulevel);
34320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return (ret == 0) ? static_cast<int>(ulevel) : -1;
34330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
34340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcVoiceMediaChannel::GetReceiveChannelNum(uint32 ssrc) {
34367162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  ChannelMap::iterator it = receive_channels_.find(ssrc);
34377162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (it != receive_channels_.end())
3438b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    return it->second->channel();
34390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return (ssrc == default_receive_ssrc_) ?  voe_channel() : -1;
34400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
34410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcVoiceMediaChannel::GetSendChannelNum(uint32 ssrc) {
3443f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  ChannelMap::iterator it = send_channels_.find(ssrc);
3444f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  if (it != send_channels_.end())
3445b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    return it->second->channel();
3446f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
3447f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  return -1;
34480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
34490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec,
34510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::vector<AudioCodec>& all_codecs, webrtc::CodecInst* send_codec) {
34520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Get the RED encodings from the parameter with no name. This may
34530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // change based on what is discussed on the Jingle list.
34540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // The encoding parameter is of the form "a/b"; we only support where
34550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // a == b. Verify this and parse out the value into red_pt.
34560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // If the parameter value is absent (as it will be until we wire up the
34570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // signaling of this message), use the second codec specified (i.e. the
34580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // one after "red") as the encoding parameter.
34590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int red_pt = -1;
34600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::string red_params;
34610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  CodecParameterMap::const_iterator it = red_codec.params.find("");
34620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (it != red_codec.params.end()) {
34630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    red_params = it->second;
34640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::vector<std::string> red_pts;
34650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (talk_base::split(red_params, '/', &red_pts) != 2 ||
34660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        red_pts[0] != red_pts[1] ||
34670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        !talk_base::FromString(red_pts[0], &red_pt)) {
34680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "RED params " << red_params << " not supported.";
34690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
34700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
34710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else if (red_codec.params.empty()) {
34720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "RED params not present, using defaults";
34730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (all_codecs.size() > 1) {
34740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      red_pt = all_codecs[1].id;
34750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
34760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
34770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Try to find red_pt in |codecs|.
34790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<AudioCodec>::const_iterator codec;
34800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (codec = all_codecs.begin(); codec != all_codecs.end(); ++codec) {
34810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (codec->id == red_pt)
34820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
34830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
34840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // If we find the right codec, that will be the codec we pass to
34860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // SetSendCodec, with the desired payload type.
34870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (codec != all_codecs.end() &&
34880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    engine()->FindWebRtcCodec(*codec, send_codec)) {
34890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
34900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "RED params " << red_params << " are invalid.";
34910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
34920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
34930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
34950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
34960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
34970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::EnableRtcp(int channel) {
34980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (engine()->voe()->rtp()->SetRTCPStatus(channel, true) == -1) {
3499f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org    LOG_RTCERR2(SetRTCPStatus, channel, 1);
35000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
35010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
35020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // TODO(juberti): Enable VQMon and RTCP XR reports, once we know what
35030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // what we want to do with them.
35040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // engine()->voe().EnableVQMon(voe_channel(), true);
35050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // engine()->voe().EnableRTCP_XR(voe_channel(), true);
35060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
35070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
35080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
35090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::ResetRecvCodecs(int channel) {
35100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int ncodecs = engine()->voe()->codec()->NumOfCodecs();
35110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (int i = 0; i < ncodecs; ++i) {
35120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    webrtc::CodecInst voe_codec;
35130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
35140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      voe_codec.pltype = -1;
35150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (engine()->voe()->codec()->SetRecPayloadType(
35160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          channel, voe_codec) == -1) {
35170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
35180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return false;
35190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
35200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
35210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
35220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
35230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
35240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
35250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) {
35260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (playout) {
35270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << "Starting playout for channel #" << channel;
35280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (engine()->voe()->base()->StartPlayout(channel) == -1) {
35290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG_RTCERR1(StartPlayout, channel);
35300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
35310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
35320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
35330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << "Stopping playout for channel #" << channel;
35340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    engine()->voe()->base()->StopPlayout(channel);
35350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
35360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
35370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
35380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
35390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orguint32 WebRtcVoiceMediaChannel::ParseSsrc(const void* data, size_t len,
35400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                        bool rtcp) {
35410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  size_t ssrc_pos = (!rtcp) ? 8 : 4;
35420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  uint32 ssrc = 0;
35430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (len >= (ssrc_pos + sizeof(ssrc))) {
35440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ssrc = talk_base::GetBE32(static_cast<const char*>(data) + ssrc_pos);
35450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
35460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ssrc;
35470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
35480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
35490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Convert VoiceEngine error code into VoiceMediaChannel::Error enum.
35500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgVoiceMediaChannel::Error
35510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    WebRtcVoiceMediaChannel::WebRtcErrorToChannelError(int err_code) {
35520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  switch (err_code) {
35530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case 0:
35540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ERROR_NONE;
35550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_CANNOT_START_RECORDING:
35560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_MIC_VOL_ERROR:
35570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_GET_MIC_VOL_ERROR:
35580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_CANNOT_ACCESS_MIC_VOL:
35590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ERROR_REC_DEVICE_OPEN_FAILED;
35600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_SATURATION_WARNING:
35610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ERROR_REC_DEVICE_SATURATION;
35620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_REC_DEVICE_REMOVED:
35630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ERROR_REC_DEVICE_REMOVED;
35640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_RUNTIME_REC_WARNING:
35650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_RUNTIME_REC_ERROR:
35660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ERROR_REC_RUNTIME_ERROR;
35670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_CANNOT_START_PLAYOUT:
35680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_SPEAKER_VOL_ERROR:
35690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_GET_SPEAKER_VOL_ERROR:
35700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_CANNOT_ACCESS_SPEAKER_VOL:
35710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ERROR_PLAY_DEVICE_OPEN_FAILED;
35720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_RUNTIME_PLAY_WARNING:
35730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_RUNTIME_PLAY_ERROR:
35740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ERROR_PLAY_RUNTIME_ERROR;
35750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case VE_TYPING_NOISE_WARNING:
35760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ERROR_REC_TYPING_NOISE_DETECTED;
35770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    default:
35780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return VoiceMediaChannel::ERROR_OTHER;
35790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
35800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
35810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
35823ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetHeaderExtension(ExtensionSetterFunction setter,
35833ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org    int channel_id, const RtpHeaderExtension* extension) {
35843ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  bool enable = false;
35852ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  int id = 0;
35862ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org  std::string uri;
35873ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  if (extension) {
35883ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org    enable = true;
35893ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org    id = extension->id;
35902ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    uri = extension->uri;
35913ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  }
35923ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  if ((engine()->voe()->rtp()->*setter)(channel_id, enable, id) != 0) {
35932ccf00b08449e81bc72367010d65f4210f7fb60ebuildbot@webrtc.org    LOG_RTCERR4(*setter, uri, channel_id, enable, id);
35943ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org    return false;
35953ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  }
35963ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org  return true;
35973ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org}
35983ca77cb43bc675f562521d4c90e8156a6e088cbchenrike@webrtc.org
35990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcSoundclipStream::Read(void *buf, int len) {
36000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  size_t res = 0;
36010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  mem_.Read(buf, len, &res, NULL);
36021a04b881e0ef480802fb01b4fbe9bcd5388d2c69henrike@webrtc.org  return static_cast<int>(res);
36030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
36040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
36050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint WebRtcSoundclipStream::Rewind() {
36060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  mem_.Rewind();
36070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Return -1 to keep VoiceEngine from looping.
36080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return (loop_) ? 0 : -1;
36090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
36100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
36110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}  // namespace cricket
36120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
36130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif  // HAVE_WEBRTC_VOICE
3614