15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/*
25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle
35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2004 Google Inc.
45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without
65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met:
75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer.
105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer in the documentation
125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     and/or other materials provided with the distribution.
135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  3. The name of the author may not be used to endorse or promote products
145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     derived from this software without specific prior written permission.
155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */
275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef HAVE_CONFIG_H
295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <config.h>
305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef HAVE_WEBRTC_VOICE
335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/webrtc/webrtcvoiceengine.h"
355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <algorithm>
375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <cstdio>
385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <string>
395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <vector>
405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/base64.h"
425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/byteorder.h"
435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/common.h"
445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/helpers.h"
455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/logging.h"
465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/stringencode.h"
475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/stringutils.h"
485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/base/audiorenderer.h"
495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/base/constants.h"
505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/base/streamparams.h"
515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/base/voiceprocessor.h"
525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/webrtc/webrtcvoe.h"
53e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org#include "webrtc/common.h"
545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <objbase.h>  // NOLINT
585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace cricket {
615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstruct CodecPref {
635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const char* name;
645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int clockrate;
655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int channels;
665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int payload_type;
675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool is_multi_rate;
685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const CodecPref kCodecPrefs[] = {
715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "OPUS",   48000,  2, 111, true },
725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "ISAC",   16000,  1, 103, true },
735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "ISAC",   32000,  1, 104, true },
745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "CELT",   32000,  1, 109, true },
755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "CELT",   32000,  2, 110, true },
765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "G722",   16000,  1, 9,   false },
775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "ILBC",   8000,   1, 102, false },
785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "PCMU",   8000,   1, 0,   false },
795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "PCMA",   8000,   1, 8,   false },
805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "CN",     48000,  1, 107, false },
815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "CN",     32000,  1, 106, false },
825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "CN",     16000,  1, 105, false },
835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "CN",     8000,   1, 13,  false },
845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "red",    8000,   1, 127, false },
855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  { "telephone-event", 8000, 1, 126, false },
865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// For Linux/Mac, using the default device is done by specifying index 0 for
895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// VoE 4.0 and not -1 (which was the case for VoE 3.5).
905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// On Windows Vista and newer, Microsoft introduced the concept of "Default
925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Communications Device". This means that there are two types of default
935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// devices (old Wave Audio style default and Default Communications Device).
945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// On Windows systems which only support Wave Audio style default, uses either
965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// -1 or 0 to select the default device.
975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// On Windows systems which support both "Default Communication Device" and
995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// old Wave Audio style default, use -1 for Default Communications Device and
1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// -2 for Wave Audio style default, which is what we want to use for clips.
1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// It's not clear yet whether the -2 index is handled properly on other OSes.
1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kDefaultAudioDeviceId = -1;
1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kDefaultSoundclipDeviceId = -2;
1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#else
1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kDefaultAudioDeviceId = 0;
1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// extension header for audio levels, as defined in
1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-03
1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char kRtpAudioLevelHeaderExtension[] =
1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kRtpAudioLevelHeaderExtensionId = 1;
1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char kIsacCodecName[] = "ISAC";
1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char kL16CodecName[] = "L16";
1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Codec parameters for Opus.
1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kOpusMonoBitrate = 32000;
1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Parameter used for NACK.
1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// This value is equivalent to 5 seconds of audio data at 20 ms per packet.
1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kNackMaxPackets = 250;
1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kOpusStereoBitrate = 64000;
124c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org// draft-spittka-payload-rtp-opus-03
125c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org// Opus bitrate should be in the range between 6000 and 510000.
126c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgstatic const int kOpusMinBitrate = 6000;
127c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgstatic const int kOpusMaxBitrate = 510000;
1289ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org// Default audio dscp value.
1299ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org// See http://tools.ietf.org/html/rfc2474 for details.
1309ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org// See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00
1319ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.orgstatic const talk_base::DiffServCodePoint kAudioDscpValue = talk_base::DSCP_EF;
132c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
1333009c167e8b156618784610f0755fac079fb2162sergeyu@chromium.org// Ensure we open the file in a writeable path on ChromeOS and Android. This
1343009c167e8b156618784610f0755fac079fb2162sergeyu@chromium.org// workaround can be removed when it's possible to specify a filename for audio
1353009c167e8b156618784610f0755fac079fb2162sergeyu@chromium.org// option based AEC dumps.
136c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org//
137c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org// TODO(grunell): Use a string in the options instead of hardcoding it here
138c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org// and let the embedder choose the filename (crbug.com/264223).
139c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org//
1403009c167e8b156618784610f0755fac079fb2162sergeyu@chromium.org// NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified
1413009c167e8b156618784610f0755fac079fb2162sergeyu@chromium.org// below.
1423009c167e8b156618784610f0755fac079fb2162sergeyu@chromium.org#if defined(CHROMEOS)
143c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgstatic const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump";
1443009c167e8b156618784610f0755fac079fb2162sergeyu@chromium.org#elif defined(ANDROID)
1453009c167e8b156618784610f0755fac079fb2162sergeyu@chromium.orgstatic const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump";
146c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org#else
147c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgstatic const char kAecDumpByAudioOptionFilename[] = "audio.aecdump";
148c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org#endif
1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Dumps an AudioCodec in RFC 2327-ish format.
1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic std::string ToString(const AudioCodec& codec) {
1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::stringstream ss;
1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ss << codec.name << "/" << codec.clockrate << "/" << codec.channels
1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << " (" << codec.id << ")";
1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ss.str();
1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic std::string ToString(const webrtc::CodecInst& codec) {
1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::stringstream ss;
1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ss << codec.plname << "/" << codec.plfreq << "/" << codec.channels
1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << " (" << codec.pltype << ")";
1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ss.str();
1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic void LogMultiline(talk_base::LoggingSeverity sev, char* text) {
1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const char* delim = "\r\n";
1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) {
1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_V(sev) << tok;
1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Severity is an integer because it comes is assumed to be from command line.
1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic int SeverityToFilter(int severity) {
1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int filter = webrtc::kTraceNone;
1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  switch (severity) {
1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case talk_base::LS_VERBOSE:
1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      filter |= webrtc::kTraceAll;
1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case talk_base::LS_INFO:
1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      filter |= (webrtc::kTraceStateInfo | webrtc::kTraceInfo);
1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case talk_base::LS_WARNING:
1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      filter |= (webrtc::kTraceTerseInfo | webrtc::kTraceWarning);
1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case talk_base::LS_ERROR:
1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      filter |= (webrtc::kTraceError | webrtc::kTraceCritical);
1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return filter;
1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool IsCodecMultiRate(const webrtc::CodecInst& codec) {
1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (size_t i = 0; i < ARRAY_SIZE(kCodecPrefs); ++i) {
1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (_stricmp(kCodecPrefs[i].name, codec.plname) == 0 &&
1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        kCodecPrefs[i].clockrate == codec.plfreq) {
1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return kCodecPrefs[i].is_multi_rate;
1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool FindCodec(const std::vector<AudioCodec>& codecs,
1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      const AudioCodec& codec,
1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      AudioCodec* found_codec) {
2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       it != codecs.end(); ++it) {
2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (it->Matches(codec)) {
2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (found_codec != NULL) {
2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *found_codec = *it;
2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
211834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org
2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool IsNackEnabled(const AudioCodec& codec) {
2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack,
2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                              kParamValueEmpty));
2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
217834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org// Gets the default set of options applied to the engine. Historically, these
218834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org// were supplied as a combination of flags from the channel manager (ec, agc,
219834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org// ns, and highpass) and the rest hardcoded in InitInternal.
220834abe82dfc619d427cac9c095020734fe474257wu@webrtc.orgstatic AudioOptions GetDefaultEngineOptions() {
221834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  AudioOptions options;
222834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.echo_cancellation.Set(true);
223834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.auto_gain_control.Set(true);
224834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.noise_suppression.Set(true);
225834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.highpass_filter.Set(true);
226834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.stereo_swapping.Set(false);
227834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.typing_detection.Set(true);
228834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.conference_mode.Set(false);
229834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.adjust_agc_delta.Set(0);
230834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.experimental_agc.Set(false);
231834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.experimental_aec.Set(false);
232834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options.aec_dump.Set(false);
23385a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  options.experimental_acm.Set(false);
234834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  return options;
235834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org}
2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass WebRtcSoundclipMedia : public SoundclipMedia {
2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  explicit WebRtcSoundclipMedia(WebRtcVoiceEngine *engine)
2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      : engine_(engine), webrtc_channel_(-1) {
2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    engine_->RegisterSoundclip(this);
2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~WebRtcSoundclipMedia() {
2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    engine_->UnregisterSoundclip(this);
2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (webrtc_channel_ != -1) {
2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // We shouldn't have to call Disable() here. DeleteChannel() should call
2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // StopPlayout() while deleting the channel.  We should fix the bug
2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // inside WebRTC and remove the Disable() call bellow.  This work is
2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // tracked by bug http://b/issue?id=5382855.
2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      PlaySound(NULL, 0, 0);
2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      Disable();
2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (engine_->voe_sc()->base()->DeleteChannel(webrtc_channel_)
2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          == -1) {
2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG_RTCERR1(DeleteChannel, webrtc_channel_);
2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Init() {
26159a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    if (!engine_->voe_sc()) {
26259a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org      return false;
26359a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    }
26485a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    webrtc_channel_ = engine_->CreateSoundclipVoiceChannel();
2655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (webrtc_channel_ == -1) {
2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR0(CreateChannel);
2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Enable() {
2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine_->voe_sc()->base()->StartPlayout(webrtc_channel_) == -1) {
2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(StartPlayout, webrtc_channel_);
2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
2765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Disable() {
2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine_->voe_sc()->base()->StopPlayout(webrtc_channel_) == -1) {
2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(StopPlayout, webrtc_channel_);
2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool PlaySound(const char *buf, int len, int flags) {
2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // The voe file api is not available in chrome.
2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!engine_->voe_sc()->file()) {
2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Must stop playing the current sound (if any), because we are about to
2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // modify the stream.
2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine_->voe_sc()->file()->StopPlayingFileLocally(webrtc_channel_)
2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        == -1) {
2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(StopPlayingFileLocally, webrtc_channel_);
2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (buf) {
3025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      stream_.reset(new WebRtcSoundclipStream(buf, len));
3035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      stream_->set_loop((flags & SF_LOOP) != 0);
3045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      stream_->Rewind();
3055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Play it.
3075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (engine_->voe_sc()->file()->StartPlayingFileLocally(
3085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          webrtc_channel_, stream_.get()) == -1) {
3095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG_RTCERR2(StartPlayingFileLocally, webrtc_channel_, stream_.get());
3105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG(LS_ERROR) << "Unable to start soundclip";
3115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return false;
3125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
3135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
3145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      stream_.reset();
3155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
3175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int GetLastEngineError() const { return engine_->voe_sc()->error(); }
3205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private:
3225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  WebRtcVoiceEngine *engine_;
3235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int webrtc_channel_;
3245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::scoped_ptr<WebRtcSoundclipStream> stream_;
3255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
3265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWebRtcVoiceEngine::WebRtcVoiceEngine()
3285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : voe_wrapper_(new VoEWrapper()),
3295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      voe_wrapper_sc_(new VoEWrapper()),
33059a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org      voe_wrapper_sc_initialized_(false),
3315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      tracing_(new VoETraceWrapper()),
3325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      adm_(NULL),
3335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      adm_sc_(NULL),
3345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      log_filter_(SeverityToFilter(kDefaultLogSeverity)),
3355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      is_dumping_aec_(false),
3365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      desired_local_monitor_enable_(false),
33785a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org      use_experimental_acm_(false),
3385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      tx_processor_ssrc_(0),
3395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rx_processor_ssrc_(0) {
3405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Construct();
3415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper,
3445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                     VoEWrapper* voe_wrapper_sc,
3455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                     VoETraceWrapper* tracing)
3465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : voe_wrapper_(voe_wrapper),
3475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      voe_wrapper_sc_(voe_wrapper_sc),
34859a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org      voe_wrapper_sc_initialized_(false),
3495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      tracing_(tracing),
3505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      adm_(NULL),
3515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      adm_sc_(NULL),
3525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      log_filter_(SeverityToFilter(kDefaultLogSeverity)),
3535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      is_dumping_aec_(false),
3545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      desired_local_monitor_enable_(false),
35585a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org      use_experimental_acm_(false),
3565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      tx_processor_ssrc_(0),
3575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rx_processor_ssrc_(0) {
3585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Construct();
3595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::Construct() {
3625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetTraceFilter(log_filter_);
3635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  initialized_ = false;
3645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine";
3655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetTraceOptions("");
3665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (tracing_->SetTraceCallback(this) == -1) {
3675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR0(SetTraceCallback);
3685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_->base()->RegisterVoiceEngineObserver(*this) == -1) {
3705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR0(RegisterVoiceEngineObserver);
3715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Clear the default agc state.
3735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  memset(&default_agc_config_, 0, sizeof(default_agc_config_));
3745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Load our audio codec list.
3765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ConstructCodecs();
3775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Load our RTP Header extensions.
3795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  rtp_header_extensions_.push_back(
3805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      RtpHeaderExtension(kRtpAudioLevelHeaderExtension,
3815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                         kRtpAudioLevelHeaderExtensionId));
382834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  options_ = GetDefaultEngineOptions();
38385a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org
38485a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  // Initialize the VoE Configuration to the default ACM.
38585a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  voe_config_.Set<webrtc::AudioCodingModuleFactory>(
38685a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org      new webrtc::AudioCodingModuleFactory);
3875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool IsOpus(const AudioCodec& codec) {
3905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return (_stricmp(codec.name.c_str(), kOpusCodecName) == 0);
3915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool IsIsac(const AudioCodec& codec) {
3945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return (_stricmp(codec.name.c_str(), kIsacCodecName) == 0);
3955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// True if params["stereo"] == "1"
3985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool IsOpusStereoEnabled(const AudioCodec& codec) {
3995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CodecParameterMap::const_iterator param =
4005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      codec.params.find(kCodecParamStereo);
4015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (param == codec.params.end()) {
4025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
4035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return param->second == kParamValueTrue;
4055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
407c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgstatic bool IsValidOpusBitrate(int bitrate) {
408c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  return (bitrate >= kOpusMinBitrate && bitrate <= kOpusMaxBitrate);
409c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org}
410c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
411c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org// Returns 0 if params[kCodecParamMaxAverageBitrate] is not defined or invalid.
412c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org// Returns the value of params[kCodecParamMaxAverageBitrate] otherwise.
413c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgstatic int GetOpusBitrateFromParams(const AudioCodec& codec) {
414c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  int bitrate = 0;
415c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (!codec.GetParam(kCodecParamMaxAverageBitrate, &bitrate)) {
416c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    return 0;
417c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
418c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (!IsValidOpusBitrate(bitrate)) {
419c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    LOG(LS_WARNING) << "Codec parameter \"maxaveragebitrate\" has an "
420c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                    << "invalid value: " << bitrate;
421c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    return 0;
422c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
423c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  return bitrate;
424c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org}
425c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
4265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::ConstructCodecs() {
4275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
4285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
4295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (int i = 0; i < ncodecs; ++i) {
4305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    webrtc::CodecInst voe_codec;
4315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) {
4325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Skip uncompressed formats.
4335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (_stricmp(voe_codec.plname, kL16CodecName) == 0) {
4345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        continue;
4355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
4365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      const CodecPref* pref = NULL;
4385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      for (size_t j = 0; j < ARRAY_SIZE(kCodecPrefs); ++j) {
4395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (_stricmp(kCodecPrefs[j].name, voe_codec.plname) == 0 &&
4405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            kCodecPrefs[j].clockrate == voe_codec.plfreq &&
4415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            kCodecPrefs[j].channels == voe_codec.channels) {
4425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          pref = &kCodecPrefs[j];
4435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          break;
4445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
4455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
4465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (pref) {
4485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Use the payload type that we've configured in our pref table;
4495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // use the offset in our pref table to determine the sort order.
4505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        AudioCodec codec(pref->payload_type, voe_codec.plname, voe_codec.plfreq,
4515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                         voe_codec.rate, voe_codec.channels,
4525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                         ARRAY_SIZE(kCodecPrefs) - (pref - kCodecPrefs));
4535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG(LS_INFO) << ToString(codec);
4545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (IsIsac(codec)) {
4555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Indicate auto-bandwidth in signaling.
4565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          codec.bitrate = 0;
4575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
4585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (IsOpus(codec)) {
4595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Only add fmtp parameters that differ from the spec.
4605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (kPreferredMinPTime != kOpusDefaultMinPTime) {
4615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            codec.params[kCodecParamMinPTime] =
4625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                talk_base::ToString(kPreferredMinPTime);
4635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
4645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (kPreferredMaxPTime != kOpusDefaultMaxPTime) {
4655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            codec.params[kCodecParamMaxPTime] =
4665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                talk_base::ToString(kPreferredMaxPTime);
4675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
4685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // TODO(hellner): Add ptime, sprop-stereo, stereo and useinbandfec
4695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // when they can be set to values other than the default.
4705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
4715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        codecs_.push_back(codec);
4725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      } else {
4735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec);
4745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
4755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Make sure they are in local preference order.
4785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::sort(codecs_.begin(), codecs_.end(), &AudioCodec::Preferable);
4795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWebRtcVoiceEngine::~WebRtcVoiceEngine() {
4825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine";
4835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) {
4845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR0(DeRegisterVoiceEngineObserver);
4855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (adm_) {
4875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    voe_wrapper_.reset();
4885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_->Release();
4895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_ = NULL;
4905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (adm_sc_) {
4925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    voe_wrapper_sc_.reset();
4935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_sc_->Release();
4945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_sc_ = NULL;
4955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Test to see if the media processor was deregistered properly
4985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(SignalRxMediaFrame.is_empty());
4995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(SignalTxMediaFrame.is_empty());
5005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  tracing_->SetTraceCallback(NULL);
5025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
5035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::Init(talk_base::Thread* worker_thread) {
5055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "WebRtcVoiceEngine::Init";
5065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool res = InitInternal();
5075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (res) {
5085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!";
5095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
5105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_ERROR) << "WebRtcVoiceEngine::Init failed";
5115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    Terminate();
5125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return res;
5145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
5155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::InitInternal() {
5175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Temporarily turn logging level up for the Init call
5185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int old_filter = log_filter_;
5195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int extended_filter = log_filter_ | SeverityToFilter(talk_base::LS_INFO);
5205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetTraceFilter(extended_filter);
5215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetTraceOptions("");
5225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Init WebRtc VoiceEngine.
5245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_->base()->Init(adm_) == -1) {
5255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR0_EX(Init, voe_wrapper_->error());
5265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SetTraceFilter(old_filter);
5275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
5285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetTraceFilter(old_filter);
5315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetTraceOptions(log_options_);
5325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Log the VoiceEngine version info
5345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  char buffer[1024] = "";
5355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  voe_wrapper_->base()->GetVersion(buffer);
5365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "WebRtc VoiceEngine Version:";
5375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LogMultiline(talk_base::LS_INFO, buffer);
5385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Save the default AGC configuration settings. This must happen before
5405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // calling SetOptions or the default will be overwritten.
5415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_->processing()->GetAgcConfig(default_agc_config_) == -1) {
542582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    LOG_RTCERR0(GetAgcConfig);
5435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
5445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
546e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org  // Set defaults for options, so that ApplyOptions applies them explicitly
547e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org  // when we clear option (channel) overrides. External clients can still
548e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org  // modify the defaults via SetOptions (on the media engine).
549e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org  if (!SetOptions(GetDefaultEngineOptions())) {
5505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
5515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Print our codec list again for the call diagnostic log
5545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
5555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs_.begin();
5565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      it != codecs_.end(); ++it) {
5575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << ToString(*it);
5585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
56059a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  // Disable the DTMF playout when a tone is sent.
56159a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  // PlayDtmfTone will be used if local playout is needed.
56259a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) {
56359a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    LOG_RTCERR1(SetDtmfFeedbackStatus, false);
56459a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  }
56559a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org
56659a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  initialized_ = true;
56759a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  return true;
56859a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org}
56959a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org
57059a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.orgbool WebRtcVoiceEngine::EnsureSoundclipEngineInit() {
57159a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  if (voe_wrapper_sc_initialized_) {
57259a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    return true;
57359a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  }
57459a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  // Note that, if initialization fails, voe_wrapper_sc_initialized_ will still
57559a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  // be false, so subsequent calls to EnsureSoundclipEngineInit will
57659a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  // probably just fail again. That's acceptable behavior.
5775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(LINUX) && !defined(HAVE_LIBPULSE)
5785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  voe_wrapper_sc_->hw()->SetAudioDeviceLayer(webrtc::kAudioLinuxAlsa);
5795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
5805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Initialize the VoiceEngine instance that we'll use to play out sound clips.
5825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_sc_->base()->Init(adm_sc_) == -1) {
5835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR0_EX(Init, voe_wrapper_sc_->error());
5845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
5855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // On Windows, tell it to use the default sound (not communication) devices.
5885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // First check whether there is a valid sound device for playback.
5895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(juberti): Clean this up when we support setting the soundclip device.
5905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
5915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // The SetPlayoutDevice may not be implemented in the case of external ADM.
5925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(ronghuawu): We should only check the adm_sc_ here, but current
5935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // PeerConnection interface never set the adm_sc_, so need to check both
5945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // in order to determine if the external adm is used.
5955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!adm_ && !adm_sc_) {
5965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int num_of_devices = 0;
5975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe_wrapper_sc_->hw()->GetNumOfPlayoutDevices(num_of_devices) != -1 &&
5985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        num_of_devices > 0) {
5995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (voe_wrapper_sc_->hw()->SetPlayoutDevice(kDefaultSoundclipDeviceId)
6005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          == -1) {
6015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG_RTCERR1_EX(SetPlayoutDevice, kDefaultSoundclipDeviceId,
6025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                       voe_wrapper_sc_->error());
6035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return false;
6045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
6055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
6065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "No valid sound playout device found.";
6075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
6085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
61059a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  voe_wrapper_sc_initialized_ = true;
61159a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  LOG(LS_INFO) << "Initialized WebRtc soundclip engine.";
6125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
6135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
6145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::Terminate() {
6165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate";
6175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  initialized_ = false;
6185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  StopAecDump();
6205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
62159a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  if (voe_wrapper_sc_) {
62259a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    voe_wrapper_sc_initialized_ = false;
62359a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    voe_wrapper_sc_->base()->Terminate();
62459a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  }
6255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  voe_wrapper_->base()->Terminate();
6265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  desired_local_monitor_enable_ = false;
6275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
6285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcVoiceEngine::GetCapabilities() {
6305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return AUDIO_SEND | AUDIO_RECV;
6315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
6325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgVoiceMediaChannel *WebRtcVoiceEngine::CreateChannel() {
6345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  WebRtcVoiceMediaChannel* ch = new WebRtcVoiceMediaChannel(this);
6355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!ch->valid()) {
6365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delete ch;
6375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ch = NULL;
6385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ch;
6405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
6415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgSoundclipMedia *WebRtcVoiceEngine::CreateSoundclip() {
64359a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  if (!EnsureSoundclipEngineInit()) {
64459a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    LOG(LS_ERROR) << "Unable to create soundclip: soundclip engine failed to "
64559a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org                  << "initialize.";
64659a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    return NULL;
64759a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  }
6485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  WebRtcSoundclipMedia *soundclip = new WebRtcSoundclipMedia(this);
6495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!soundclip->Init() || !soundclip->Enable()) {
6505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delete soundclip;
6515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return NULL;
6525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return soundclip;
6545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
6555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
656e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.orgbool WebRtcVoiceEngine::SetOptions(const AudioOptions& options) {
6575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!ApplyOptions(options)) {
6585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
6595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  options_ = options;
6615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
6625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
6635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::SetOptionOverrides(const AudioOptions& overrides) {
6655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Setting option overrides: " << overrides.ToString();
6665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!ApplyOptions(overrides)) {
6675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
6685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  option_overrides_ = overrides;
6705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
6715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
6725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::ClearOptionOverrides() {
6745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Clearing option overrides.";
6755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  AudioOptions options = options_;
6765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Only call ApplyOptions if |options_overrides_| contains overrided options.
6775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // ApplyOptions affects NS, AGC other options that is shared between
6785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // all WebRtcVoiceEngineChannels.
6795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (option_overrides_ == AudioOptions()) {
6805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
6815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!ApplyOptions(options)) {
6845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
6855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  option_overrides_ = AudioOptions();
6875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
6885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
6895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// AudioOptions defaults are set in InitInternal (for options with corresponding
6915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// MediaEngineInterface flags) and in SetOptions(int) for flagless options.
6925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
6935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  AudioOptions options = options_in;  // The options are modified below.
6945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // kEcConference is AEC with high suppression.
6955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::EcModes ec_mode = webrtc::kEcConference;
6965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::AecmModes aecm_mode = webrtc::kAecmSpeakerphone;
6975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::AgcModes agc_mode = webrtc::kAgcAdaptiveAnalog;
6985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::NsModes ns_mode = webrtc::kNsHighSuppression;
6995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool aecm_comfort_noise = false;
700582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  if (options.aecm_generate_comfort_noise.Get(&aecm_comfort_noise)) {
701582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    LOG(LS_VERBOSE) << "Comfort noise explicitly set to "
702582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                    << aecm_comfort_noise << " (default is false).";
703582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  }
7045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(IOS)
7065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // On iOS, VPIO provides built-in EC and AGC.
7075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  options.echo_cancellation.Set(false);
7085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  options.auto_gain_control.Set(false);
7095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#elif defined(ANDROID)
7105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ec_mode = webrtc::kEcAecm;
7115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
7125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(IOS) || defined(ANDROID)
7145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Set the AGC mode for iOS as well despite disabling it above, to avoid
7155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // unsupported configuration errors from webrtc.
7165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  agc_mode = webrtc::kAgcFixedDigital;
7175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  options.typing_detection.Set(false);
7185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  options.experimental_agc.Set(false);
7195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  options.experimental_aec.Set(false);
7205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
7215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Applying audio options: " << options.ToString();
7235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
72485a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  // Configure whether ACM1 or ACM2 is used.
72585a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  bool enable_acm2 = false;
72685a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  if (options.experimental_acm.Get(&enable_acm2)) {
72785a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    EnableExperimentalAcm(enable_acm2);
72885a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  }
72985a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org
7305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing();
7315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool echo_cancellation;
7335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (options.echo_cancellation.Get(&echo_cancellation)) {
7345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voep->SetEcStatus(echo_cancellation, ec_mode) == -1) {
7355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR2(SetEcStatus, echo_cancellation, ec_mode);
7365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
737582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    } else {
738582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG(LS_VERBOSE) << "Echo control set to " << echo_cancellation
739582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                      << " with mode " << ec_mode;
7405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
7415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if !defined(ANDROID)
7425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO(ajm): Remove the error return on Android from webrtc.
7435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voep->SetEcMetricsStatus(echo_cancellation) == -1) {
7445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(SetEcMetricsStatus, echo_cancellation);
7455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
7465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
7475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
7485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (ec_mode == webrtc::kEcAecm) {
7495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (voep->SetAecmMode(aecm_mode, aecm_comfort_noise) != 0) {
7505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG_RTCERR2(SetAecmMode, aecm_mode, aecm_comfort_noise);
7515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return false;
7525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
7535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
7545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool auto_gain_control;
7575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (options.auto_gain_control.Get(&auto_gain_control)) {
7585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voep->SetAgcStatus(auto_gain_control, agc_mode) == -1) {
7595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR2(SetAgcStatus, auto_gain_control, agc_mode);
7605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
761582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    } else {
762582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG(LS_VERBOSE) << "Auto gain set to " << auto_gain_control
763582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                      << " with mode " << agc_mode;
764582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    }
765582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  }
766582fe818e571fa2571267f5e369715188472f352wu@webrtc.org
767582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  if (options.tx_agc_target_dbov.IsSet() ||
768582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      options.tx_agc_digital_compression_gain.IsSet() ||
769582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      options.tx_agc_limiter.IsSet()) {
770582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // Override default_agc_config_. Generally, an unset option means "leave
771582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // the VoE bits alone" in this function, so we want whatever is set to be
772582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // stored as the new "default". If we didn't, then setting e.g.
773582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // tx_agc_target_dbov would reset digital compression gain and limiter
774582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // settings.
775582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // Also, if we don't update default_agc_config_, then adjust_agc_delta
776582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // would be an offset from the original values, and not whatever was set
777582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // explicitly.
778582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    default_agc_config_.targetLeveldBOv =
779582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        options.tx_agc_target_dbov.GetWithDefaultIfUnset(
780582fe818e571fa2571267f5e369715188472f352wu@webrtc.org            default_agc_config_.targetLeveldBOv);
781582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    default_agc_config_.digitalCompressionGaindB =
782582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        options.tx_agc_digital_compression_gain.GetWithDefaultIfUnset(
783582fe818e571fa2571267f5e369715188472f352wu@webrtc.org            default_agc_config_.digitalCompressionGaindB);
784582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    default_agc_config_.limiterEnable =
785582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        options.tx_agc_limiter.GetWithDefaultIfUnset(
786582fe818e571fa2571267f5e369715188472f352wu@webrtc.org            default_agc_config_.limiterEnable);
787582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) {
788582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG_RTCERR3(SetAgcConfig,
789582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                  default_agc_config_.targetLeveldBOv,
790582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                  default_agc_config_.digitalCompressionGaindB,
791582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                  default_agc_config_.limiterEnable);
792582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      return false;
7935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
7945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool noise_suppression;
7975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (options.noise_suppression.Get(&noise_suppression)) {
7985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voep->SetNsStatus(noise_suppression, ns_mode) == -1) {
7995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR2(SetNsStatus, noise_suppression, ns_mode);
8005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
801582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    } else {
802582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG(LS_VERBOSE) << "Noise suppression set to " << noise_suppression
803582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                      << " with mode " << ns_mode;
8045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool highpass_filter;
8085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (options.highpass_filter.Get(&highpass_filter)) {
8095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voep->EnableHighPassFilter(highpass_filter) == -1) {
8105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(SetHighpassFilterStatus, highpass_filter);
8115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
8125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool stereo_swapping;
8165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (options.stereo_swapping.Get(&stereo_swapping)) {
8175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    voep->EnableStereoChannelSwapping(stereo_swapping);
8185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voep->IsStereoChannelSwappingEnabled() != stereo_swapping) {
8195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(EnableStereoChannelSwapping, stereo_swapping);
8205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
8215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool typing_detection;
8255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (options.typing_detection.Get(&typing_detection)) {
8265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voep->SetTypingDetectionStatus(typing_detection) == -1) {
8275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // In case of error, log the info and continue
8285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(SetTypingDetectionStatus, typing_detection);
8295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int adjust_agc_delta;
8335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (options.adjust_agc_delta.Get(&adjust_agc_delta)) {
8345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!AdjustAgcLevel(adjust_agc_delta)) {
8355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
8365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool aec_dump;
8405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (options.aec_dump.Get(&aec_dump)) {
8415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (aec_dump)
842c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      StartAecDump(kAecDumpByAudioOptionFilename);
8435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    else
8445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      StopAecDump();
8455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
847e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org  bool experimental_aec;
848e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org  if (options.experimental_aec.Get(&experimental_aec)) {
849e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org    webrtc::AudioProcessing* audioproc =
850e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org        voe_wrapper_->base()->audio_processing();
851e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org    // We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
852e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org    // returns NULL on audio_processing().
853e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org    if (audioproc) {
854e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org      webrtc::Config config;
855e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org      config.Set<webrtc::DelayCorrection>(
856e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org          new webrtc::DelayCorrection(experimental_aec));
857e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org      audioproc->SetExtraOptions(config);
858e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org    }
859e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org  }
860e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org
861582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  uint32 recording_sample_rate;
862582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  if (options.recording_sample_rate.Get(&recording_sample_rate)) {
863582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    if (voe_wrapper_->hw()->SetRecordingSampleRate(recording_sample_rate)) {
864582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG_RTCERR1(SetRecordingSampleRate, recording_sample_rate);
865582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    }
866582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  }
867582fe818e571fa2571267f5e369715188472f352wu@webrtc.org
868582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  uint32 playout_sample_rate;
869582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  if (options.playout_sample_rate.Get(&playout_sample_rate)) {
870582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    if (voe_wrapper_->hw()->SetPlayoutSampleRate(playout_sample_rate)) {
871582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG_RTCERR1(SetPlayoutSampleRate, playout_sample_rate);
872582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    }
873582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  }
874582fe818e571fa2571267f5e369715188472f352wu@webrtc.org
8755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
8775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
8785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::SetDelayOffset(int offset) {
8805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  voe_wrapper_->processing()->SetDelayOffsetMs(offset);
8815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_->processing()->DelayOffsetMs() != offset) {
8825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR1(SetDelayOffsetMs, offset);
8835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
8845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
8875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
8885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstruct ResumeEntry {
8905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ResumeEntry(WebRtcVoiceMediaChannel *c, bool p, SendFlags s)
8915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      : channel(c),
8925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        playout(p),
8935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        send(s) {
8945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  WebRtcVoiceMediaChannel *channel;
8975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool playout;
8985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SendFlags send;
8995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
9005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO(juberti): Refactor this so that the core logic can be used to set the
9025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// soundclip device. At that time, reinstate the soundclip pause/resume code.
9035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::SetDevices(const Device* in_device,
9045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                   const Device* out_device) {
905582fe818e571fa2571267f5e369715188472f352wu@webrtc.org#if !defined(IOS)
9065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int in_id = in_device ? talk_base::FromString<int>(in_device->id) :
9075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      kDefaultAudioDeviceId;
9085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int out_id = out_device ? talk_base::FromString<int>(out_device->id) :
9095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      kDefaultAudioDeviceId;
9105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // The device manager uses -1 as the default device, which was the case for
9115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // VoE 3.5. VoE 4.0, however, uses 0 as the default in Linux and Mac.
9125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifndef WIN32
9135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (-1 == in_id) {
9145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    in_id = kDefaultAudioDeviceId;
9155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (-1 == out_id) {
9175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    out_id = kDefaultAudioDeviceId;
9185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
9205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string in_name = (in_id != kDefaultAudioDeviceId) ?
9225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      in_device->name : "Default device";
9235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string out_name = (out_id != kDefaultAudioDeviceId) ?
9245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      out_device->name : "Default device";
9255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Setting microphone to (id=" << in_id << ", name=" << in_name
9265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            << ") and speaker to (id=" << out_id << ", name=" << out_name
9275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            << ")";
9285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // If we're running the local monitor, we need to stop it first.
9305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool ret = true;
9315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!PauseLocalMonitor()) {
9325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "Failed to pause local monitor";
9335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ret = false;
9345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Must also pause all audio playback and capture.
9375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (ChannelList::const_iterator i = channels_.begin();
9385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       i != channels_.end(); ++i) {
9395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    WebRtcVoiceMediaChannel *channel = *i;
9405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!channel->PausePlayout()) {
9415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Failed to pause playout";
9425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ret = false;
9435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
9445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!channel->PauseSend()) {
9455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Failed to pause send";
9465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ret = false;
9475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
9485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Find the recording device id in VoiceEngine and set recording device.
9515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!FindWebRtcAudioDeviceId(true, in_name, in_id, &in_id)) {
9525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ret = false;
9535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (ret) {
9555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe_wrapper_->hw()->SetRecordingDevice(in_id) == -1) {
95685a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org      LOG_RTCERR2(SetRecordingDevice, in_name, in_id);
9575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ret = false;
9585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
9595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Find the playout device id in VoiceEngine and set playout device.
9625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!FindWebRtcAudioDeviceId(false, out_name, out_id, &out_id)) {
9635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "Failed to find VoiceEngine device id for " << out_name;
9645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ret = false;
9655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (ret) {
9675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe_wrapper_->hw()->SetPlayoutDevice(out_id) == -1) {
96885a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org      LOG_RTCERR2(SetPlayoutDevice, out_name, out_id);
9695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ret = false;
9705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
9715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Resume all audio playback and capture.
9745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (ChannelList::const_iterator i = channels_.begin();
9755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       i != channels_.end(); ++i) {
9765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    WebRtcVoiceMediaChannel *channel = *i;
9775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!channel->ResumePlayout()) {
9785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Failed to resume playout";
9795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ret = false;
9805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
9815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!channel->ResumeSend()) {
9825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Failed to resume send";
9835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ret = false;
9845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
9855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Resume local monitor.
9885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!ResumeLocalMonitor()) {
9895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "Failed to resume local monitor";
9905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ret = false;
9915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (ret) {
9945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Set microphone to (id=" << in_id <<" name=" << in_name
9955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 << ") and speaker to (id="<< out_id << " name=" << out_name
9965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 << ")";
9975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ret;
10005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#else
10015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
1002582fe818e571fa2571267f5e369715188472f352wu@webrtc.org#endif  // !IOS
10035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
10045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::FindWebRtcAudioDeviceId(
10065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool is_input, const std::string& dev_name, int dev_id, int* rtc_id) {
10075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // In Linux, VoiceEngine uses the same device dev_id as the device manager.
1008582fe818e571fa2571267f5e369715188472f352wu@webrtc.org#if defined(LINUX) || defined(ANDROID)
10095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *rtc_id = dev_id;
10105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
10115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#else
10125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // In Windows and Mac, we need to find the VoiceEngine device id by name
10135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // unless the input dev_id is the default device id.
10145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (kDefaultAudioDeviceId == dev_id) {
10155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    *rtc_id = dev_id;
10165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
10175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Get the number of VoiceEngine audio devices.
10205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int count = 0;
10215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (is_input) {
10225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (-1 == voe_wrapper_->hw()->GetNumOfRecordingDevices(count)) {
10235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR0(GetNumOfRecordingDevices);
10245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
10255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
10265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
10275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (-1 == voe_wrapper_->hw()->GetNumOfPlayoutDevices(count)) {
10285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR0(GetNumOfPlayoutDevices);
10295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
10305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
10315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (int i = 0; i < count; ++i) {
10345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    char name[128];
10355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    char guid[128];
10365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (is_input) {
10375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      voe_wrapper_->hw()->GetRecordingDeviceName(i, name, guid);
10385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_VERBOSE) << "VoiceEngine microphone " << i << ": " << name;
10395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
10405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      voe_wrapper_->hw()->GetPlayoutDeviceName(i, name, guid);
10415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_VERBOSE) << "VoiceEngine speaker " << i << ": " << name;
10425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
10435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    std::string webrtc_name(name);
10455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (dev_name.compare(0, webrtc_name.size(), webrtc_name) == 0) {
10465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      *rtc_id = i;
10475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
10485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
10495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_WARNING) << "VoiceEngine cannot find device: " << dev_name;
10515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
10525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
10535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
10545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::GetOutputVolume(int* level) {
10565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  unsigned int ulevel;
10575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_->volume()->GetSpeakerVolume(ulevel) == -1) {
10585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR1(GetSpeakerVolume, level);
10595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
10605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *level = ulevel;
10625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
10635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
10645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::SetOutputVolume(int level) {
10665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(level >= 0 && level <= 255);
10675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_->volume()->SetSpeakerVolume(level) == -1) {
10685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR1(SetSpeakerVolume, level);
10695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
10705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
10725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
10735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcVoiceEngine::GetInputLevel() {
10755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  unsigned int ulevel;
10765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return (voe_wrapper_->volume()->GetSpeechInputLevel(ulevel) != -1) ?
10775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      static_cast<int>(ulevel) : -1;
10785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
10795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::SetLocalMonitor(bool enable) {
10815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  desired_local_monitor_enable_ = enable;
10825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ChangeLocalMonitor(desired_local_monitor_enable_);
10835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
10845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::ChangeLocalMonitor(bool enable) {
10865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // The voe file api is not available in chrome.
10875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!voe_wrapper_->file()) {
10885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
10895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (enable && !monitor_) {
10915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    monitor_.reset(new WebRtcMonitorStream);
10925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe_wrapper_->file()->StartRecordingMicrophone(monitor_.get()) == -1) {
10935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(StartRecordingMicrophone, monitor_.get());
10945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Must call Stop() because there are some cases where Start will report
10955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // failure but still change the state, and if we leave VE in the on state
10965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // then it could crash later when trying to invoke methods on our monitor.
10975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      voe_wrapper_->file()->StopRecordingMicrophone();
10985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      monitor_.reset();
10995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
11005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
11015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else if (!enable && monitor_) {
11025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    voe_wrapper_->file()->StopRecordingMicrophone();
11035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    monitor_.reset();
11045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
11065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::PauseLocalMonitor() {
11095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ChangeLocalMonitor(false);
11105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::ResumeLocalMonitor() {
11135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ChangeLocalMonitor(desired_local_monitor_enable_);
11145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst std::vector<AudioCodec>& WebRtcVoiceEngine::codecs() {
11175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return codecs_;
11185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::FindCodec(const AudioCodec& in) {
11215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return FindWebRtcCodec(in, NULL);
11225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Get the VoiceEngine codec that matches |in|, with the supplied settings.
11255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in,
11265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        webrtc::CodecInst* out) {
11275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
11285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (int i = 0; i < ncodecs; ++i) {
11295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    webrtc::CodecInst voe_codec;
11305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) {
11315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq,
11325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                       voe_codec.rate, voe_codec.channels, 0);
11335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      bool multi_rate = IsCodecMultiRate(voe_codec);
11345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Allow arbitrary rates for ISAC to be specified.
11355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (multi_rate) {
11365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Set codec.bitrate to 0 so the check for codec.Matches() passes.
11375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        codec.bitrate = 0;
11385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
11395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (codec.Matches(in)) {
11405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (out) {
11415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Fixup the payload type.
11425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          voe_codec.pltype = in.id;
11435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Set bitrate if specified.
11455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (multi_rate && in.bitrate != 0) {
11465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            voe_codec.rate = in.bitrate;
11475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
11485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Apply codec-specific settings.
11505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (IsIsac(codec)) {
11515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            // If ISAC and an explicit bitrate is not specified,
11525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            // enable auto bandwidth adjustment.
11535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            voe_codec.rate = (in.bitrate > 0) ? in.bitrate : -1;
11545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
11555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          *out = voe_codec;
11565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
11575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return true;
11585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
11595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
11605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
11625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst std::vector<RtpHeaderExtension>&
11645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWebRtcVoiceEngine::rtp_header_extensions() const {
11655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return rtp_header_extensions_;
11665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::SetLogging(int min_sev, const char* filter) {
11695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // if min_sev == -1, we keep the current log level.
11705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (min_sev >= 0) {
11715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SetTraceFilter(SeverityToFilter(min_sev));
11725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  log_options_ = filter;
11745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SetTraceOptions(initialized_ ? log_options_ : "");
11755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcVoiceEngine::GetLastEngineError() {
11785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return voe_wrapper_->error();
11795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::SetTraceFilter(int filter) {
11825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  log_filter_ = filter;
11835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  tracing_->SetTraceFilter(filter);
11845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// We suppport three different logging settings for VoiceEngine:
11875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// 1. Observer callback that goes into talk diagnostic logfile.
11885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//    Use --logfile and --loglevel
11895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
11905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// 2. Encrypted VoiceEngine log for debugging VoiceEngine.
11915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//    Use --voice_loglevel --voice_logfilter "tracefile file_name"
11925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
11935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// 3. EC log and dump for debugging QualityEngine.
11945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//    Use --voice_loglevel --voice_logfilter "recordEC file_name"
11955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
11965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// For more details see: "https://sites.google.com/a/google.com/wavelet/Home/
11975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//    Magic-Flute--RTC-Engine-/Magic-Flute-Command-Line-Parameters"
11985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::SetTraceOptions(const std::string& options) {
11995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Set encrypted trace file.
12005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<std::string> opts;
12015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::tokenize(options, ' ', '"', '"', &opts);
12025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<std::string>::iterator tracefile =
12035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      std::find(opts.begin(), opts.end(), "tracefile");
12045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (tracefile != opts.end() && ++tracefile != opts.end()) {
12055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Write encrypted debug output (at same loglevel) to file
12065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // EncryptedTraceFile no longer supported.
12075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (tracing_->SetTraceFile(tracefile->c_str()) == -1) {
12085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(SetTraceFile, *tracefile);
12095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
12105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
12115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1212582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  // Allow trace options to override the trace filter. We default
1213582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  // it to log_filter_ (as a translation of libjingle log levels)
1214582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  // elsewhere, but this allows clients to explicitly set webrtc
1215582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  // log levels.
1216582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  std::vector<std::string>::iterator tracefilter =
1217582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      std::find(opts.begin(), opts.end(), "tracefilter");
1218582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  if (tracefilter != opts.end() && ++tracefilter != opts.end()) {
1219582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    if (!tracing_->SetTraceFilter(talk_base::FromString<int>(*tracefilter))) {
1220582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG_RTCERR1(SetTraceFilter, *tracefilter);
1221582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    }
1222582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  }
1223582fe818e571fa2571267f5e369715188472f352wu@webrtc.org
12245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Set AEC dump file
12255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<std::string>::iterator recordEC =
12265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      std::find(opts.begin(), opts.end(), "recordEC");
12275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (recordEC != opts.end()) {
12285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ++recordEC;
12295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (recordEC != opts.end())
12305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      StartAecDump(recordEC->c_str());
12315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    else
12325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      StopAecDump();
12335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
12345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Ignore spammy trace messages, mostly from the stats API when we haven't
12375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// gotten RTCP info yet from the remote side.
12385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::ShouldIgnoreTrace(const std::string& trace) {
12395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  static const char* kTracesToIgnore[] = {
12405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "\tfailed to GetReportBlockInformation",
12415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "GetRecCodec() failed to get received codec",
12425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "GetReceivedRtcpStatistics: Could not get received RTP statistics",
12435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "GetRemoteRTCPData() failed to measure statistics due to lack of received RTP and/or RTCP packets",  // NOLINT
12445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "GetRemoteRTCPData() failed to retrieve sender info for remote side",
12455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "GetRTPStatistics() failed to measure RTT since no RTP packets have been received yet",  // NOLINT
12465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "GetRTPStatistics() failed to read RTP statistics from the RTP/RTCP module",
12475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "GetRTPStatistics() failed to retrieve RTT from the RTP/RTCP module",
12485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "SenderInfoReceived No received SR",
12495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "StatisticsRTP() no statistics available",
12505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "TransmitMixer::TypingDetection() VE_TYPING_NOISE_WARNING message has been posted",  // NOLINT
12515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "TransmitMixer::TypingDetection() pending noise-saturation warning exists",  // NOLINT
12525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "GetRecPayloadType() failed to retrieve RX payload type (error=10026)", // NOLINT
12535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "StopPlayingFileAsMicrophone() isnot playing (error=8088)",
12545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    NULL
12555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  };
12565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (const char* const* p = kTracesToIgnore; *p; ++p) {
12575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (trace.find(*p) != std::string::npos) {
12585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
12595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
12605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
12615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
12625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
126485a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.orgvoid WebRtcVoiceEngine::EnableExperimentalAcm(bool enable) {
126585a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  if (enable == use_experimental_acm_)
126685a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    return;
126785a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  if (enable) {
126885a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    LOG(LS_INFO) << "VoiceEngine is set to use new ACM (ACM2 + NetEq4).";
126985a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    voe_config_.Set<webrtc::AudioCodingModuleFactory>(
127085a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org        new webrtc::NewAudioCodingModuleFactory());
127185a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  } else {
127285a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    LOG(LS_INFO) << "VoiceEngine is set to use legacy ACM (ACM1 + Neteq3).";
127385a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    voe_config_.Set<webrtc::AudioCodingModuleFactory>(
127485a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org        new webrtc::AudioCodingModuleFactory());
127585a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  }
127685a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  use_experimental_acm_ = enable;
127785a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org}
127885a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org
12795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace,
12805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                              int length) {
12815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::LoggingSeverity sev = talk_base::LS_VERBOSE;
12825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (level == webrtc::kTraceError || level == webrtc::kTraceCritical)
12835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sev = talk_base::LS_ERROR;
12845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  else if (level == webrtc::kTraceWarning)
12855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sev = talk_base::LS_WARNING;
12865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo)
12875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sev = talk_base::LS_INFO;
12885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  else if (level == webrtc::kTraceTerseInfo)
12895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sev = talk_base::LS_INFO;
12905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Skip past boilerplate prefix text
12925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (length < 72) {
12935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    std::string msg(trace, length);
12945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_ERROR) << "Malformed webrtc log message: ";
12955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_V(sev) << msg;
12965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
12975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    std::string msg(trace + 71, length - 72);
12985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!ShouldIgnoreTrace(msg)) {
12995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_V(sev) << "webrtc: " << msg;
13005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
13015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
13025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
13035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::CallbackOnError(int channel_num, int err_code) {
13055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::CritScope lock(&channels_cs_);
13065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  WebRtcVoiceMediaChannel* channel = NULL;
13075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32 ssrc = 0;
13085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_WARNING) << "VoiceEngine error " << err_code << " reported on channel "
13095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  << channel_num << ".";
13105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (FindChannelAndSsrc(channel_num, &channel, &ssrc)) {
13115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(channel != NULL);
13125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    channel->OnError(ssrc, err_code);
13135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
13145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_ERROR) << "VoiceEngine channel " << channel_num
13155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  << " could not be found in channel list when error reported.";
13165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
13175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
13185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::FindChannelAndSsrc(
13205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int channel_num, WebRtcVoiceMediaChannel** channel, uint32* ssrc) const {
13215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(channel != NULL && ssrc != NULL);
13225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *channel = NULL;
13245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *ssrc = 0;
13255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Find corresponding channel and ssrc
13265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (ChannelList::const_iterator it = channels_.begin();
13275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      it != channels_.end(); ++it) {
13285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(*it != NULL);
13295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((*it)->FindSsrc(channel_num, ssrc)) {
13305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      *channel = *it;
13315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
13325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
13335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
13345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
13365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
13375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// This method will search through the WebRtcVoiceMediaChannels and
13395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// obtain the voice engine's channel number.
13405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::FindChannelNumFromSsrc(
13415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    uint32 ssrc, MediaProcessorDirection direction, int* channel_num) {
13425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(channel_num != NULL);
13435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(direction == MPD_RX || direction == MPD_TX);
13445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *channel_num = -1;
13465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Find corresponding channel for ssrc.
13475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (ChannelList::const_iterator it = channels_.begin();
13485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      it != channels_.end(); ++it) {
13495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(*it != NULL);
13505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (direction & MPD_RX) {
13515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      *channel_num = (*it)->GetReceiveChannelNum(ssrc);
13525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
13535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (*channel_num == -1 && (direction & MPD_TX)) {
13545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      *channel_num = (*it)->GetSendChannelNum(ssrc);
13555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
13565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (*channel_num != -1) {
13575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
13585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
13595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
13605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_WARNING) << "FindChannelFromSsrc. No Channel Found for Ssrc: " << ssrc;
13615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
13625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
13635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel *channel) {
13655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::CritScope lock(&channels_cs_);
13665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  channels_.push_back(channel);
13675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
13685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel *channel) {
13705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::CritScope lock(&channels_cs_);
13715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ChannelList::iterator i = std::find(channels_.begin(),
13725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                      channels_.end(),
13735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                      channel);
13745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (i != channels_.end()) {
13755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    channels_.erase(i);
13765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
13775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
13785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::RegisterSoundclip(WebRtcSoundclipMedia *soundclip) {
13805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  soundclips_.push_back(soundclip);
13815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
13825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::UnregisterSoundclip(WebRtcSoundclipMedia *soundclip) {
13845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SoundclipList::iterator i = std::find(soundclips_.begin(),
13855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        soundclips_.end(),
13865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        soundclip);
13875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (i != soundclips_.end()) {
13885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    soundclips_.erase(i);
13895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
13905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
13915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Adjusts the default AGC target level by the specified delta.
13935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// NB: If we start messing with other config fields, we'll want
13945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// to save the current webrtc::AgcConfig as well.
13955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::AdjustAgcLevel(int delta) {
13965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::AgcConfig config = default_agc_config_;
13975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  config.targetLeveldBOv -= delta;
13985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Adjusting AGC level from default -"
14005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org               << default_agc_config_.targetLeveldBOv << "dB to -"
14015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org               << config.targetLeveldBOv << "dB";
14025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voe_wrapper_->processing()->SetAgcConfig(config) == -1) {
14045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR1(SetAgcConfig, config.targetLeveldBOv);
14055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
14065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
14085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
14095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm,
14115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    webrtc::AudioDeviceModule* adm_sc) {
14125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (initialized_) {
14135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "SetAudioDeviceModule can not be called after Init.";
14145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
14155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (adm_) {
14175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_->Release();
14185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_ = NULL;
14195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (adm) {
14215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_ = adm;
14225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_->AddRef();
14235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (adm_sc_) {
14265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_sc_->Release();
14275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_sc_ = NULL;
14285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (adm_sc) {
14305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_sc_ = adm_sc;
14315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    adm_sc_->AddRef();
14325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
14345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
14355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::RegisterProcessor(
14375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    uint32 ssrc,
14385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    VoiceProcessor* voice_processor,
14395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    MediaProcessorDirection direction) {
14405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool register_with_webrtc = false;
14415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int channel_id = -1;
14425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool success = false;
14435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32* processor_ssrc = NULL;
14445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool found_channel = FindChannelNumFromSsrc(ssrc, direction, &channel_id);
14455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voice_processor == NULL || !found_channel) {
14465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "Media Processing Registration Failed. ssrc: " << ssrc
14475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        << " foundChannel: " << found_channel;
14485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
14495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::ProcessingTypes processing_type;
14525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  {
14535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    talk_base::CritScope cs(&signal_media_critical_);
14545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (direction == MPD_RX) {
14555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      processing_type = webrtc::kPlaybackAllChannelsMixed;
14565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (SignalRxMediaFrame.is_empty()) {
14575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        register_with_webrtc = true;
14585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        processor_ssrc = &rx_processor_ssrc_;
14595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
14605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalRxMediaFrame.connect(voice_processor,
14615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                 &VoiceProcessor::OnFrame);
14625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
14635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      processing_type = webrtc::kRecordingPerChannel;
14645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (SignalTxMediaFrame.is_empty()) {
14655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        register_with_webrtc = true;
14665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        processor_ssrc = &tx_processor_ssrc_;
14675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
14685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalTxMediaFrame.connect(voice_processor,
14695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                 &VoiceProcessor::OnFrame);
14705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
14715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (register_with_webrtc) {
14735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO(janahan): when registering consider instantiating a
14745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // a VoeMediaProcess object and not make the engine extend the interface.
14755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe()->media() && voe()->media()->
14765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        RegisterExternalMediaProcessing(channel_id,
14775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        processing_type,
14785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        *this) != -1) {
14795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_INFO) << "Media Processing Registration Succeeded. channel:"
14805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   << channel_id;
14815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      *processor_ssrc = ssrc;
14825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      success = true;
14835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
14845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR2(RegisterExternalMediaProcessing,
14855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  channel_id,
14865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  processing_type);
14875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      success = false;
14885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
14895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
14905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // If we don't have to register with the engine, we just needed to
14915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // connect a new processor, set success to true;
14925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    success = true;
14935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return success;
14955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
14965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::UnregisterProcessorChannel(
14985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    MediaProcessorDirection channel_direction,
14995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    uint32 ssrc,
15005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    VoiceProcessor* voice_processor,
15015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    MediaProcessorDirection processor_direction) {
15025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool success = true;
15035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  FrameSignal* signal;
15045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::ProcessingTypes processing_type;
15055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32* processor_ssrc = NULL;
15065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (channel_direction == MPD_RX) {
15075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    signal = &SignalRxMediaFrame;
15085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    processing_type = webrtc::kPlaybackAllChannelsMixed;
15095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    processor_ssrc = &rx_processor_ssrc_;
15105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
15115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    signal = &SignalTxMediaFrame;
15125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    processing_type = webrtc::kRecordingPerChannel;
15135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    processor_ssrc = &tx_processor_ssrc_;
15145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
15155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int deregister_id = -1;
15175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  {
15185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    talk_base::CritScope cs(&signal_media_critical_);
15195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((processor_direction & channel_direction) != 0 && !signal->is_empty()) {
15205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      signal->disconnect(voice_processor);
15215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      int channel_id = -1;
15225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      bool found_channel = FindChannelNumFromSsrc(ssrc,
15235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                                  channel_direction,
15245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                                  &channel_id);
15255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (signal->is_empty() && found_channel) {
15265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        deregister_id = channel_id;
15275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
15285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
15295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
15305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (deregister_id != -1) {
15315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe()->media() &&
15325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        voe()->media()->DeRegisterExternalMediaProcessing(deregister_id,
15335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        processing_type) != -1) {
15345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      *processor_ssrc = 0;
15355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_INFO) << "Media Processing DeRegistration Succeeded. channel:"
15365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   << deregister_id;
15375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
15385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR2(DeRegisterExternalMediaProcessing,
15395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  deregister_id,
15405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  processing_type);
15415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      success = false;
15425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
15435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
15445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return success;
15455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
15465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceEngine::UnregisterProcessor(
15485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    uint32 ssrc,
15495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    VoiceProcessor* voice_processor,
15505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    MediaProcessorDirection direction) {
15515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool success = true;
15525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (voice_processor == NULL) {
15535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "Media Processing Deregistration Failed. ssrc: "
15545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                    << ssrc;
15555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
15565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
15575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!UnregisterProcessorChannel(MPD_RX, ssrc, voice_processor, direction)) {
15585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    success = false;
15595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
15605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!UnregisterProcessorChannel(MPD_TX, ssrc, voice_processor, direction)) {
15615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    success = false;
15625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
15635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return success;
15645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
15655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Implementing method from WebRtc VoEMediaProcess interface
15675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Do not lock mux_channel_cs_ in this callback.
15685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::Process(int channel,
15695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                webrtc::ProcessingTypes type,
15705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                int16_t audio10ms[],
15715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                int length,
15725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                int sampling_freq,
15735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                bool is_stereo) {
15745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    talk_base::CritScope cs(&signal_media_critical_);
15755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    AudioFrame frame(audio10ms, length, sampling_freq, is_stereo);
15765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (type == webrtc::kPlaybackAllChannelsMixed) {
15775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalRxMediaFrame(rx_processor_ssrc_, MPD_RX, &frame);
15785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else if (type == webrtc::kRecordingPerChannel) {
15795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalTxMediaFrame(tx_processor_ssrc_, MPD_TX, &frame);
15805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
15815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Media Processing invoked unexpectedly."
15825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << " channel: " << channel << " type: " << type
15835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << " tx_ssrc: " << tx_processor_ssrc_
15845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << " rx_ssrc: " << rx_processor_ssrc_;
15855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
15865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
15875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::StartAecDump(const std::string& filename) {
15895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!is_dumping_aec_) {
15905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Start dumping AEC when we are not dumping.
15915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe_wrapper_->processing()->StartDebugRecording(
15925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        filename.c_str()) != webrtc::AudioProcessing::kNoError) {
1593b2fe8ceddd31df40a273ba605ae6293abf9c9f7dhenrikg@webrtc.org      LOG_RTCERR0(StartDebugRecording);
15945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
15955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      is_dumping_aec_ = true;
15965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
15975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
15985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
15995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceEngine::StopAecDump() {
16015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (is_dumping_aec_) {
16025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Stop dumping AEC when we are dumping.
16035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (voe_wrapper_->processing()->StopDebugRecording() !=
16045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        webrtc::AudioProcessing::kNoError) {
16055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR0(StopDebugRecording);
16065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
16075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    is_dumping_aec_ = false;
16085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
16095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
16105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
161185a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.orgint WebRtcVoiceEngine::CreateVoiceChannel(VoEWrapper* voice_engine_wrapper) {
161285a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  return voice_engine_wrapper->base()->CreateChannel(voe_config_);
161385a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org}
161485a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org
161585a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.orgint WebRtcVoiceEngine::CreateMediaVoiceChannel() {
161685a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  return CreateVoiceChannel(voe_wrapper_.get());
161785a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org}
161885a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org
161985a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.orgint WebRtcVoiceEngine::CreateSoundclipVoiceChannel() {
162085a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  return CreateVoiceChannel(voe_wrapper_sc_.get());
162185a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org}
162285a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org
1623c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org// This struct relies on the generated copy constructor and assignment operator
1624c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org// since it is used in an stl::map.
1625c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgstruct WebRtcVoiceMediaChannel::WebRtcVoiceChannelInfo {
1626c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  WebRtcVoiceChannelInfo() : channel(-1), renderer(NULL) {}
1627c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  WebRtcVoiceChannelInfo(int ch, AudioRenderer* r)
1628c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      : channel(ch),
1629c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        renderer(r) {}
1630c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  ~WebRtcVoiceChannelInfo() {}
1631c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
1632c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  int channel;
1633c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  AudioRenderer* renderer;
1634c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org};
1635c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
16365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// WebRtcVoiceMediaChannel
16375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine *engine)
16385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : WebRtcMediaChannel<VoiceMediaChannel, WebRtcVoiceEngine>(
16395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          engine,
164085a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org          engine->CreateMediaVoiceChannel()),
1641834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org      send_bw_setting_(false),
1642834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org      send_autobw_(false),
1643834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org      send_bw_bps_(0),
16445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      options_(),
16455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      dtmf_allowed_(false),
16465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      desired_playout_(false),
16475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      nack_enabled_(false),
16485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      playout_(false),
1649204b178db6a965bcdee700f384174d4303e8e9d8stefan@webrtc.org      typing_noise_detected_(false),
16505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      desired_send_(SEND_NOTHING),
16515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      send_(SEND_NOTHING),
16525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      default_receive_ssrc_(0) {
16535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  engine->RegisterChannel(this);
16545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel "
16555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  << voe_channel();
16565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1657c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  ConfigureSendChannel(voe_channel());
16585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
16595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgWebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
16615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel "
16625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  << voe_channel();
16635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1664c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Remove any remaining send streams, the default channel will be deleted
1665c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // later.
1666c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  while (!send_channels_.empty())
1667c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    RemoveSendStream(send_channels_.begin()->first);
16685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Unregister ourselves from the engine.
16705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  engine()->UnregisterChannel(this);
16715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Remove any remaining streams.
1672c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  while (!receive_channels_.empty()) {
1673c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    RemoveRecvStream(receive_channels_.begin()->first);
16745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
16755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1676c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Delete the default channel.
1677c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  DeleteChannel(voe_channel());
16785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
16795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
16815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Setting voice channel options: "
16825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org               << options.ToString();
16835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16849ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org  // Check if DSCP value is changed from previous.
16859ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org  bool dscp_option_changed = (options_.dscp != options.dscp);
16869ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org
1687c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // TODO(xians): Add support to set different options for different send
1688c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // streams after we support multiple APMs.
1689c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
16905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // We retain all of the existing options, and apply the given ones
16915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // on top.  This means there is no way to "clear" options such that
16925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // they go back to the engine default.
16935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  options_.SetAll(options);
16945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (send_ != SEND_NOTHING) {
16965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!engine()->SetOptionOverrides(options_)) {
16975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) <<
16985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          "Failed to engine SetOptionOverrides during channel SetOptions.";
16995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
17005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
17015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
17025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Will be interpreted when appropriate.
17035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
17045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1705582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  // Receiver-side auto gain control happens per channel, so set it here from
1706582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  // options. Note that, like conference mode, setting it on the engine won't
1707582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  // have the desired effect, since voice channels don't inherit options from
1708582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  // the media engine when those options are applied per-channel.
1709582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  bool rx_auto_gain_control;
1710582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  if (options.rx_auto_gain_control.Get(&rx_auto_gain_control)) {
1711582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    if (engine()->voe()->processing()->SetRxAgcStatus(
1712582fe818e571fa2571267f5e369715188472f352wu@webrtc.org            voe_channel(), rx_auto_gain_control,
1713582fe818e571fa2571267f5e369715188472f352wu@webrtc.org            webrtc::kAgcFixedDigital) == -1) {
1714582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG_RTCERR1(SetRxAgcStatus, rx_auto_gain_control);
1715582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      return false;
1716582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    } else {
1717582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG(LS_VERBOSE) << "Rx auto gain set to " << rx_auto_gain_control
1718582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                      << " with mode " << webrtc::kAgcFixedDigital;
1719582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    }
1720582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  }
1721582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  if (options.rx_agc_target_dbov.IsSet() ||
1722582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      options.rx_agc_digital_compression_gain.IsSet() ||
1723582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      options.rx_agc_limiter.IsSet()) {
1724582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    webrtc::AgcConfig config;
1725582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // If only some of the options are being overridden, get the current
1726582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    // settings for the channel and bail if they aren't available.
1727582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    if (!options.rx_agc_target_dbov.IsSet() ||
1728582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        !options.rx_agc_digital_compression_gain.IsSet() ||
1729582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        !options.rx_agc_limiter.IsSet()) {
1730582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      if (engine()->voe()->processing()->GetRxAgcConfig(
1731582fe818e571fa2571267f5e369715188472f352wu@webrtc.org              voe_channel(), config) != 0) {
1732582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        LOG(LS_ERROR) << "Failed to get default rx agc configuration for "
1733582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                      << "channel " << voe_channel() << ". Since not all rx "
1734582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                      << "agc options are specified, unable to safely set rx "
1735582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                      << "agc options.";
1736582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        return false;
1737582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      }
1738582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    }
1739582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    config.targetLeveldBOv =
1740582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        options.rx_agc_target_dbov.GetWithDefaultIfUnset(
1741582fe818e571fa2571267f5e369715188472f352wu@webrtc.org            config.targetLeveldBOv);
1742582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    config.digitalCompressionGaindB =
1743582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        options.rx_agc_digital_compression_gain.GetWithDefaultIfUnset(
1744582fe818e571fa2571267f5e369715188472f352wu@webrtc.org            config.digitalCompressionGaindB);
1745582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    config.limiterEnable = options.rx_agc_limiter.GetWithDefaultIfUnset(
1746582fe818e571fa2571267f5e369715188472f352wu@webrtc.org        config.limiterEnable);
1747582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    if (engine()->voe()->processing()->SetRxAgcConfig(
1748582fe818e571fa2571267f5e369715188472f352wu@webrtc.org            voe_channel(), config) == -1) {
1749582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      LOG_RTCERR4(SetRxAgcConfig, voe_channel(), config.targetLeveldBOv,
1750582fe818e571fa2571267f5e369715188472f352wu@webrtc.org                  config.digitalCompressionGaindB, config.limiterEnable);
1751582fe818e571fa2571267f5e369715188472f352wu@webrtc.org      return false;
1752582fe818e571fa2571267f5e369715188472f352wu@webrtc.org    }
1753582fe818e571fa2571267f5e369715188472f352wu@webrtc.org  }
17549ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org  if (dscp_option_changed) {
17559ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org    talk_base::DiffServCodePoint dscp = talk_base::DSCP_DEFAULT;
17569ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org    if (options.dscp.GetWithDefaultIfUnset(false))
17579ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org      dscp = kAudioDscpValue;
17589ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org    if (MediaChannel::SetDscp(dscp) != 0) {
17599ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org      LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel";
17609ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org    }
17619ede6539f5855996228729eaef14e6039f3ecfc8wu@webrtc.org  }
1762582fe818e571fa2571267f5e369715188472f352wu@webrtc.org
17635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Set voice channel options.  Current options: "
17645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org               << options_.ToString();
17655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
17665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
17675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
17685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetRecvCodecs(
17695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const std::vector<AudioCodec>& codecs) {
17705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Set the payload types to be used for incoming media.
17715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Setting receive voice codecs:";
17725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
17735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<AudioCodec> new_codecs;
17745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Find all new codecs. We allow adding new codecs but don't allow changing
17755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // the payload type of codecs that is already configured since we might
17765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // already be receiving packets with that payload type.
17775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
1778c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org       it != codecs.end(); ++it) {
17795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    AudioCodec old_codec;
17805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (FindCodec(recv_codecs_, *it, &old_codec)) {
17815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (old_codec.id != it->id) {
17825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG(LS_ERROR) << it->name << " payload type changed.";
17835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return false;
17845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
17855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
17865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      new_codecs.push_back(*it);
17875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
17885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
17895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (new_codecs.empty()) {
17905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // There are no new codecs to configure. Already configured codecs are
17915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // never removed.
17925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
17935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
17945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
17955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (playout_) {
17965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Receive codecs can not be changed while playing. So we temporarily
17975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // pause playout.
17985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    PausePlayout();
17995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
18005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1801c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  bool ret = true;
18025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = new_codecs.begin();
18035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       it != new_codecs.end() && ret; ++it) {
18045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    webrtc::CodecInst voe_codec;
18055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->FindWebRtcCodec(*it, &voe_codec)) {
18065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_INFO) << ToString(*it);
18075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      voe_codec.pltype = it->id;
1808c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      if (default_receive_ssrc_ == 0) {
1809c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        // Set the receive codecs on the default channel explicitly if the
1810c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        // default channel is not used by |receive_channels_|, this happens in
1811c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        // conference mode or in non-conference mode when there is no playout
1812c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        // channel.
1813c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        // TODO(xians): Figure out how we use the default channel in conference
1814c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        // mode.
1815c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        if (engine()->voe()->codec()->SetRecPayloadType(
1816c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org            voe_channel(), voe_codec) == -1) {
1817c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org          LOG_RTCERR2(SetRecPayloadType, voe_channel(), ToString(voe_codec));
1818c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org          ret = false;
1819c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        }
18205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
18215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
18225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Set the receive codecs on all receiving channels.
1823c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      for (ChannelMap::iterator it = receive_channels_.begin();
1824c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org           it != receive_channels_.end() && ret; ++it) {
18255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (engine()->voe()->codec()->SetRecPayloadType(
1826c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                it->second.channel, voe_codec) == -1) {
1827c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org          LOG_RTCERR2(SetRecPayloadType, it->second.channel,
1828c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                      ToString(voe_codec));
18295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          ret = false;
18305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
18315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
18325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
18335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Unknown codec " << ToString(*it);
18345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ret = false;
18355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
18365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
18375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (ret) {
18385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    recv_codecs_ = codecs;
18395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
18405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
18415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (desired_playout_ && !playout_) {
18425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ResumePlayout();
18435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
18445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ret;
18455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
18465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
18475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendCodecs(
1848d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    int channel, const std::vector<AudioCodec>& codecs) {
1849d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  // Disable VAD, and FEC unless we know the other side wants them.
1850d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  engine()->voe()->codec()->SetVADStatus(channel, false);
1851d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
1852d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  engine()->voe()->rtp()->SetFECStatus(channel, false);
18535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
18545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Scan through the list to figure out the codec to use for sending, along
18555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // with the proper configuration for VAD and DTMF.
18565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool first = true;
18575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::CodecInst send_codec;
18585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  memset(&send_codec, 0, sizeof(send_codec));
18595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
18605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
18615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       it != codecs.end(); ++it) {
18625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Ignore codecs we don't know about. The negotiation step should prevent
18635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // this, but double-check to be sure.
18645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    webrtc::CodecInst voe_codec;
18655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!engine()->FindWebRtcCodec(*it, &voe_codec)) {
18665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Unknown codec " << ToString(voe_codec);
18675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      continue;
18685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
18695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
18705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // If OPUS, change what we send according to the "stereo" codec
18715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // parameter, and not the "channels" parameter.  We set
18725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // voe_codec.channels to 2 if "stereo=1" and 1 otherwise.  If
18735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // the bitrate is not specified, i.e. is zero, we set it to the
18745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // appropriate default value for mono or stereo Opus.
18755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (IsOpus(*it)) {
18765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (IsOpusStereoEnabled(*it)) {
18775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        voe_codec.channels = 2;
1878c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        if (!IsValidOpusBitrate(it->bitrate)) {
1879c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org          if (it->bitrate != 0) {
1880c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org            LOG(LS_WARNING) << "Overrides the invalid supplied bitrate("
1881c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                            << it->bitrate
1882c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                            << ") with default opus stereo bitrate: "
1883c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                            << kOpusStereoBitrate;
1884c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org          }
18855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          voe_codec.rate = kOpusStereoBitrate;
18865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
18875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      } else {
18885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        voe_codec.channels = 1;
1889c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        if (!IsValidOpusBitrate(it->bitrate)) {
1890c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org          if (it->bitrate != 0) {
1891c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org            LOG(LS_WARNING) << "Overrides the invalid supplied bitrate("
1892c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                            << it->bitrate
1893c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                            << ") with default opus mono bitrate: "
1894c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                            << kOpusMonoBitrate;
1895c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org          }
18965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          voe_codec.rate = kOpusMonoBitrate;
18975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
18985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
1899c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      int bitrate_from_params = GetOpusBitrateFromParams(*it);
1900c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      if (bitrate_from_params != 0) {
1901c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        voe_codec.rate = bitrate_from_params;
1902c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      }
19035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
19045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1905c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Find the DTMF telephone event "codec" and tell VoiceEngine channels
1906c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // about it.
19075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (_stricmp(it->name.c_str(), "telephone-event") == 0 ||
19085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        _stricmp(it->name.c_str(), "audio/telephone-event") == 0) {
1909d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType(
1910d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org              channel, it->id) == -1) {
1911d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, it->id);
1912d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        return false;
19135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
19145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
19155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
19165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Turn voice activity detection/comfort noise on if supported.
19175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Set the wideband CN payload type appropriately.
19185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // (narrowband always uses the static payload type 13).
19195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (_stricmp(it->name.c_str(), "CN") == 0) {
19205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      webrtc::PayloadFrequencies cn_freq;
19215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      switch (it->clockrate) {
19225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        case 8000:
19235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          cn_freq = webrtc::kFreq8000Hz;
19245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          break;
19255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        case 16000:
19265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          cn_freq = webrtc::kFreq16000Hz;
19275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          break;
19285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        case 32000:
19295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          cn_freq = webrtc::kFreq32000Hz;
19305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          break;
19315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        default:
19325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          LOG(LS_WARNING) << "CN frequency " << it->clockrate
19335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                          << " not supported.";
19345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          continue;
19355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
1936d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      // Set the CN payloadtype and the VAD status.
1937d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      // The CN payload type for 8000 Hz clockrate is fixed at 13.
1938d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      if (cn_freq != webrtc::kFreq8000Hz) {
1939d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        if (engine()->voe()->codec()->SetSendCNPayloadType(
1940d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org                channel, it->id, cn_freq) == -1) {
1941d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          LOG_RTCERR3(SetSendCNPayloadType, channel, it->id, cn_freq);
1942d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          // TODO(ajm): This failure condition will be removed from VoE.
1943d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          // Restore the return here when we update to a new enough webrtc.
1944d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          //
1945d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          // Not returning false because the SetSendCNPayloadType will fail if
1946d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          // the channel is already sending.
1947d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          // This can happen if the remote description is applied twice, for
1948d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          // example in the case of ROAP on top of JSEP, where both side will
1949d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          // send the offer.
19505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
1951d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      }
1952c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
1953d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      // Only turn on VAD if we have a CN payload type that matches the
1954d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      // clockrate for the codec we are going to use.
1955d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      if (it->clockrate == send_codec.plfreq) {
1956d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        LOG(LS_INFO) << "Enabling VAD";
1957d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        if (engine()->voe()->codec()->SetVADStatus(channel, true) == -1) {
1958d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          LOG_RTCERR2(SetVADStatus, channel, true);
1959d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          return false;
19605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
19615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
19625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
19635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
19645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // We'll use the first codec in the list to actually send audio data.
19655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Be sure to use the payload type requested by the remote side.
19665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // "red", for FEC audio, is a special case where the actual codec to be
19675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // used is specified in params.
19685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (first) {
19695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (_stricmp(it->name.c_str(), "red") == 0) {
19705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Parse out the RED parameters. If we fail, just ignore RED;
19715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // we don't support all possible params/usage scenarios.
19725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!GetRedSendCodec(*it, codecs, &send_codec)) {
19735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          continue;
19745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
19755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
19765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Enable redundant encoding of the specified codec. Treat any
19775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // failure as a fatal internal error.
19785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG(LS_INFO) << "Enabling FEC";
1979d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        if (engine()->voe()->rtp()->SetFECStatus(channel, true, it->id) == -1) {
1980d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          LOG_RTCERR3(SetFECStatus, channel, true, it->id);
1981d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          return false;
19825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
19835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      } else {
19845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        send_codec = voe_codec;
1985c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        nack_enabled_ = IsNackEnabled(*it);
1986d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        SetNack(channel, nack_enabled_);
19875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
19885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      first = false;
19895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Set the codec immediately, since SetVADStatus() depends on whether
19905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // the current codec is mono or stereo.
1991d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      if (!SetSendCodec(channel, send_codec))
19925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return false;
19935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
19945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
19955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
19965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // If we're being asked to set an empty list of codecs, due to a buggy client,
19975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // choose the most common format: PCMU
19985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (first) {
19995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "Received empty list of codecs; using PCMU/8000";
20005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    AudioCodec codec(0, "PCMU", 8000, 0, 1, 0);
20015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    engine()->FindWebRtcCodec(codec, &send_codec);
2002d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    if (!SetSendCodec(channel, send_codec))
2003d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      return false;
2004d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  }
2005d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org
2006d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  // Always update the |send_codec_| to the currently set send codec.
2007d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  send_codec_.reset(new webrtc::CodecInst(send_codec));
2008d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org
2009834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  if (send_bw_setting_) {
2010834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org    SetSendBandwidthInternal(send_autobw_, send_bw_bps_);
2011834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  }
2012834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org
2013d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  return true;
2014d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org}
2015d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org
2016d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendCodecs(
2017d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    const std::vector<AudioCodec>& codecs) {
2018d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  dtmf_allowed_ = false;
2019d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  for (std::vector<AudioCodec>::const_iterator it = codecs.begin();
2020d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org       it != codecs.end(); ++it) {
2021d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    // Find the DTMF telephone event "codec".
2022d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    if (_stricmp(it->name.c_str(), "telephone-event") == 0 ||
2023d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        _stricmp(it->name.c_str(), "audio/telephone-event") == 0) {
2024d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      dtmf_allowed_ = true;
2025d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    }
2026d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  }
2027d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org
2028d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  // Cache the codecs in order to configure the channel created later.
2029d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  send_codecs_ = codecs;
2030d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  for (ChannelMap::iterator iter = send_channels_.begin();
2031d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org       iter != send_channels_.end(); ++iter) {
2032d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    if (!SetSendCodecs(iter->second.channel, codecs)) {
20335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
2034d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    }
20355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
20365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2037d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  SetNack(receive_channels_, nack_enabled_);
2038d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org
20395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
20405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2041c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2042c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.orgvoid WebRtcVoiceMediaChannel::SetNack(const ChannelMap& channels,
2043c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org                                      bool nack_enabled) {
2044c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  for (ChannelMap::const_iterator it = channels.begin();
2045c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org       it != channels.end(); ++it) {
2046d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    SetNack(it->second.channel, nack_enabled);
2047c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2048c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org}
2049c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2050d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.orgvoid WebRtcVoiceMediaChannel::SetNack(int channel, bool nack_enabled) {
20515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (nack_enabled) {
2052d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    LOG(LS_INFO) << "Enabling NACK for channel " << channel;
20535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    engine()->voe()->rtp()->SetNACKStatus(channel, true, kNackMaxPackets);
20545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
2055d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    LOG(LS_INFO) << "Disabling NACK for channel " << channel;
20565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
20575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
20585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
20595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
20605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendCodec(
20615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const webrtc::CodecInst& send_codec) {
20625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Selected voice codec " << ToString(send_codec)
20635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org               << ", bitrate=" << send_codec.rate;
2064c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  for (ChannelMap::iterator iter = send_channels_.begin();
2065c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org       iter != send_channels_.end(); ++iter) {
2066c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (!SetSendCodec(iter->second.channel, send_codec))
2067c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      return false;
20685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2069c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2070c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  return true;
2071c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org}
2072c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2073c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendCodec(
2074c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    int channel, const webrtc::CodecInst& send_codec) {
2075c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  LOG(LS_INFO) << "Send channel " << channel <<  " selected voice codec "
2076c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org               << ToString(send_codec) << ", bitrate=" << send_codec.rate;
2077c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2078c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (engine()->voe()->codec()->SetSendCodec(channel, send_codec) == -1) {
2079c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG_RTCERR2(SetSendCodec, channel, ToString(send_codec));
2080c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    return false;
2081c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
20825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
20835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
20845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
20855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions(
20865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const std::vector<RtpHeaderExtension>& extensions) {
20875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // We don't support any incoming extensions headers right now.
20885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
20895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
20905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
20915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions(
20925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const std::vector<RtpHeaderExtension>& extensions) {
20935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Enable the audio level extension header if requested.
20945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<RtpHeaderExtension>::const_iterator it;
20955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (it = extensions.begin(); it != extensions.end(); ++it) {
20965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (it->uri == kRtpAudioLevelHeaderExtension) {
20975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      break;
20985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
20995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
21005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool enable = (it != extensions.end());
21025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int id = 0;
21035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (enable) {
21055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    id = it->id;
21065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (id < kMinRtpHeaderExtensionId ||
21075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        id > kMaxRtpHeaderExtensionId) {
21085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Invalid RTP header extension id " << id;
21095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
21105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
21115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
21125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "Enabling audio level header extension with ID " << id;
2114c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  for (ChannelMap::const_iterator iter = send_channels_.begin();
2115c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org       iter != send_channels_.end(); ++iter) {
2116c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (engine()->voe()->rtp()->SetRTPAudioLevelIndicationStatus(
2117c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org            iter->second.channel, enable, id) == -1) {
2118c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      LOG_RTCERR3(SetRTPAudioLevelIndicationStatus,
2119c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org                  iter->second.channel, enable, id);
2120c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      return false;
2121c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    }
21225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
21235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
21255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
21265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetPlayout(bool playout) {
21285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  desired_playout_ = playout;
21295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ChangePlayout(desired_playout_);
21305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
21315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::PausePlayout() {
21335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ChangePlayout(false);
21345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
21355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::ResumePlayout() {
21375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ChangePlayout(desired_playout_);
21385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
21395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) {
21415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (playout_ == playout) {
21425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
21435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
21445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2145c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // Change the playout of all channels to the new state.
21465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool result = true;
2147c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (receive_channels_.empty()) {
21485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Only toggle the default channel if we don't have any other channels.
21495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    result = SetPlayout(voe_channel(), playout);
21505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2151c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  for (ChannelMap::iterator it = receive_channels_.begin();
2152c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org       it != receive_channels_.end() && result; ++it) {
2153c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    if (!SetPlayout(it->second.channel, playout)) {
2154c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      LOG(LS_ERROR) << "SetPlayout " << playout << " on channel "
2155c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                    << it->second.channel << " failed";
21565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      result = false;
21575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
21585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
21595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (result) {
21615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    playout_ = playout;
21625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
21635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return result;
21645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
21655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetSend(SendFlags send) {
21675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  desired_send_ = send;
2168c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (!send_channels_.empty())
21695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return ChangeSend(desired_send_);
21705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
21715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
21725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::PauseSend() {
21745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ChangeSend(SEND_NOTHING);
21755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
21765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::ResumeSend() {
21785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ChangeSend(desired_send_);
21795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
21805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
21815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::ChangeSend(SendFlags send) {
21825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (send_ == send) {
21835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
21845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
21855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2186c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Change the settings on each send channel.
2187c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (send == SEND_MICROPHONE)
21885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    engine()->SetOptionOverrides(options_);
21895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2190c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Change the settings on each send channel.
2191c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  for (ChannelMap::iterator iter = send_channels_.begin();
2192c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org       iter != send_channels_.end(); ++iter) {
2193c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (!ChangeSend(iter->second.channel, send))
21945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
2195c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2196c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2197c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Clear up the options after stopping sending.
2198c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (send == SEND_NOTHING)
2199c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    engine()->ClearOptionOverrides();
2200c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2201c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  send_ = send;
2202c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  return true;
2203c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org}
2204c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2205c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.orgbool WebRtcVoiceMediaChannel::ChangeSend(int channel, SendFlags send) {
2206c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (send == SEND_MICROPHONE) {
2207c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (engine()->voe()->base()->StartSend(channel) == -1) {
2208c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      LOG_RTCERR1(StartSend, channel);
22095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
22105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
22115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->voe()->file() &&
2212c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        engine()->voe()->file()->StopPlayingFileAsMicrophone(channel) == -1) {
2213c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      LOG_RTCERR1(StopPlayingFileAsMicrophone, channel);
22145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
22155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
22165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {  // SEND_NOTHING
2217c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    ASSERT(send == SEND_NOTHING);
2218c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (engine()->voe()->base()->StopSend(channel) == -1) {
2219c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      LOG_RTCERR1(StopSend, channel);
2220c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      return false;
22215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2222c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
22235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2224c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  return true;
2225c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org}
2226c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2227c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.orgvoid WebRtcVoiceMediaChannel::ConfigureSendChannel(int channel) {
2228c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (engine()->voe()->network()->RegisterExternalTransport(
2229c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          channel, *this) == -1) {
2230c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG_RTCERR2(RegisterExternalTransport, channel, this);
22315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2232c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2233c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Enable RTCP (for quality stats and feedback messages)
2234c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  EnableRtcp(channel);
2235c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2236c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Reset all recv codecs; they will be enabled via SetRecvCodecs.
2237c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  ResetRecvCodecs(channel);
2238c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org}
2239c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2240c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.orgbool WebRtcVoiceMediaChannel::DeleteChannel(int channel) {
2241c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) {
2242c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG_RTCERR1(DeRegisterExternalTransport, channel);
2243c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2244c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2245c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (engine()->voe()->base()->DeleteChannel(channel) == -1) {
2246c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG_RTCERR1(DeleteChannel, channel);
2247c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    return false;
2248c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2249c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
22505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
22515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
22525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
22535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
2254c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // If the default channel is already used for sending create a new channel
2255c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // otherwise use the default channel for sending.
2256c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  int channel = GetSendChannelNum(sp.first_ssrc());
2257c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (channel != -1) {
2258c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG(LS_ERROR) << "Stream already exists with ssrc " << sp.first_ssrc();
22595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
22605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
22615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2262c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  bool default_channel_is_available = true;
2263c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  for (ChannelMap::const_iterator iter = send_channels_.begin();
2264c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org       iter != send_channels_.end(); ++iter) {
2265c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (IsDefaultChannel(iter->second.channel)) {
2266c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      default_channel_is_available = false;
2267c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      break;
2268c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    }
2269c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2270c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (default_channel_is_available) {
2271c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    channel = voe_channel();
2272c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  } else {
2273c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Create a new channel for sending audio data.
227485a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    channel = engine()->CreateMediaVoiceChannel();
2275c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (channel == -1) {
2276c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      LOG_RTCERR0(CreateChannel);
2277c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      return false;
2278c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    }
2279c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2280c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    ConfigureSendChannel(channel);
2281c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2282c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2283c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Save the channel to send_channels_, so that RemoveSendStream() can still
2284c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // delete the channel in case failure happens below.
2285c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  send_channels_[sp.first_ssrc()] = WebRtcVoiceChannelInfo(channel, NULL);
2286c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2287c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Set the send (local) SSRC.
2288c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // If there are multiple send SSRCs, we can only set the first one here, and
2289c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // the rest of the SSRC(s) need to be set after SetSendCodec has been called
2290c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // (with a codec requires multiple SSRC(s)).
2291c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (engine()->voe()->rtp()->SetLocalSSRC(channel, sp.first_ssrc()) == -1) {
2292c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG_RTCERR2(SetSendSSRC, channel, sp.first_ssrc());
22935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
22945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2295c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2296c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // At this point the channel's local SSRC has been updated. If the channel is
2297c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // the default channel make sure that all the receive channels are updated as
2298c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // well. Receive channels have to have the same SSRC as the default channel in
2299c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // order to send receiver reports with this SSRC.
2300c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (IsDefaultChannel(channel)) {
2301c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    for (ChannelMap::const_iterator it = receive_channels_.begin();
2302c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org         it != receive_channels_.end(); ++it) {
2303c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      // Only update the SSRC for non-default channels.
2304c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      if (!IsDefaultChannel(it->second.channel)) {
2305c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        if (engine()->voe()->rtp()->SetLocalSSRC(it->second.channel,
2306c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org                                                 sp.first_ssrc()) != 0) {
2307c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          LOG_RTCERR2(SetLocalSSRC, it->second.channel, sp.first_ssrc());
2308c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          return false;
2309c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        }
2310c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      }
23115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
23125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
23135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2314c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (engine()->voe()->rtp()->SetRTCP_CNAME(channel, sp.cname.c_str()) == -1) {
2315c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org     LOG_RTCERR2(SetRTCP_CNAME, channel, sp.cname);
23165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     return false;
23175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
23185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2319d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  // Set the current codecs to be used for the new channel.
2320d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  if (!send_codecs_.empty() && !SetSendCodecs(channel, send_codecs_))
2321c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    return false;
2322c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2323c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  return ChangeSend(channel, desired_send_);
23245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
23255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
23265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
2327c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  ChannelMap::iterator it = send_channels_.find(ssrc);
2328c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (it == send_channels_.end()) {
2329c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
2330c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org                    << " which doesn't exist.";
23315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
23325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2333c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2334c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  int channel = it->second.channel;
2335c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  ChangeSend(channel, SEND_NOTHING);
2336c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2337c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Notify the audio renderer that the send channel is going away.
2338c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (it->second.renderer)
2339c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    it->second.renderer->RemoveChannel(channel);
2340c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2341c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (IsDefaultChannel(channel)) {
2342c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Do not delete the default channel since the receive channels depend on
2343c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // the default channel, recycle it instead.
2344c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    ChangeSend(channel, SEND_NOTHING);
2345c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  } else {
2346c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Clean up and delete the send channel.
2347c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG(LS_INFO) << "Removing audio send stream " << ssrc
2348c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org                 << " with VoiceEngine channel #" << channel << ".";
2349c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (!DeleteChannel(channel))
2350c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      return false;
2351c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2352c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2353c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  send_channels_.erase(it);
2354c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (send_channels_.empty())
2355c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    ChangeSend(SEND_NOTHING);
2356c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
23575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
23585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
23595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
23605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
2361c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
23625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
23635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!VERIFY(sp.ssrcs.size() == 1))
23645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
23655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32 ssrc = sp.first_ssrc();
23665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
236759a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  if (ssrc == 0) {
236859a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    LOG(LS_WARNING) << "AddRecvStream with 0 ssrc is not supported.";
236959a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    return false;
237059a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  }
237159a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org
2372c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (receive_channels_.find(ssrc) != receive_channels_.end()) {
2373c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    LOG(LS_ERROR) << "Stream already exists with ssrc " << ssrc;
23745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
23755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
23765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2377c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // Reuse default channel for recv stream in non-conference mode call
2378c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // when the default channel is not being used.
2379c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (!InConferenceMode() && default_receive_ssrc_ == 0) {
2380c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    LOG(LS_INFO) << "Recv stream " << sp.first_ssrc()
2381c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                 << " reuse default channel";
2382c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    default_receive_ssrc_ = sp.first_ssrc();
2383c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    receive_channels_.insert(std::make_pair(
2384c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        default_receive_ssrc_, WebRtcVoiceChannelInfo(voe_channel(), NULL)));
2385c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    return SetPlayout(voe_channel(), playout_);
2386c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
2387c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
23885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Create a new channel for receiving audio data.
238985a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org  int channel = engine()->CreateMediaVoiceChannel();
23905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (channel == -1) {
23915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR0(CreateChannel);
23925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
23935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
23945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
239559a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  if (!ConfigureRecvChannel(channel)) {
239659a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    DeleteChannel(channel);
239759a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org    return false;
239859a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  }
239959a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org
240059a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  receive_channels_.insert(
240159a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org      std::make_pair(ssrc, WebRtcVoiceChannelInfo(channel, NULL)));
240259a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org
240359a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  LOG(LS_INFO) << "New audio stream " << ssrc
240459a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org               << " registered to VoiceEngine channel #"
240559a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org               << channel << ".";
240659a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org  return true;
240759a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org}
240859a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.org
240959a1e5569576b61b7ae1f0d7fe72c958c940e156wu@webrtc.orgbool WebRtcVoiceMediaChannel::ConfigureRecvChannel(int channel) {
24105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Configure to use external transport, like our default channel.
24115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (engine()->voe()->network()->RegisterExternalTransport(
24125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          channel, *this) == -1) {
24135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR2(SetExternalTransport, channel, this);
24145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
24155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
24165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
24175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Use the same SSRC as our default channel (so the RTCP reports are correct).
24185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  unsigned int send_ssrc;
24195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::VoERTP_RTCP* rtp = engine()->voe()->rtp();
24205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (rtp->GetLocalSSRC(voe_channel(), send_ssrc) == -1) {
24215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR2(GetSendSSRC, channel, send_ssrc);
24225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
24235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
24245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (rtp->SetLocalSSRC(channel, send_ssrc) == -1) {
24255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR2(SetSendSSRC, channel, send_ssrc);
24265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
24275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
24285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
24295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Use the same recv payload types as our default channel.
24305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ResetRecvCodecs(channel);
24315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!recv_codecs_.empty()) {
24325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    for (std::vector<AudioCodec>::const_iterator it = recv_codecs_.begin();
24335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        it != recv_codecs_.end(); ++it) {
24345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      webrtc::CodecInst voe_codec;
24355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (engine()->FindWebRtcCodec(*it, &voe_codec)) {
24365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        voe_codec.pltype = it->id;
24375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        voe_codec.rate = 0;  // Needed to make GetRecPayloadType work for ISAC
24385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (engine()->voe()->codec()->GetRecPayloadType(
24395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            voe_channel(), voe_codec) != -1) {
24405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (engine()->voe()->codec()->SetRecPayloadType(
24415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              channel, voe_codec) == -1) {
24425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
24435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            return false;
24445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
24455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
24465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
24475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
24485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
24495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2450c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (InConferenceMode()) {
2451c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // To be in par with the video, voe_channel() is not used for receiving in
2452c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // a conference call.
2453c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    if (receive_channels_.empty() && default_receive_ssrc_ == 0 && playout_) {
2454c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      // This is the first stream in a multi user meeting. We can now
2455c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      // disable playback of the default stream. This since the default
2456c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      // stream will probably have received some initial packets before
2457c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      // the new stream was added. This will mean that the CN state from
2458c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      // the default channel will be mixed in with the other streams
2459c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      // throughout the whole meeting, which might be disturbing.
2460c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      LOG(LS_INFO) << "Disabling playback on the default voice channel";
2461c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      SetPlayout(voe_channel(), false);
2462c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    }
24635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2464d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org  SetNack(channel, nack_enabled_);
24655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
24665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return SetPlayout(channel, playout_);
24675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
24685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
24695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32 ssrc) {
2470c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
2471c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  ChannelMap::iterator it = receive_channels_.find(ssrc);
2472c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (it == receive_channels_.end()) {
2473c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
2474c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org                    << " which doesn't exist.";
2475c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    return false;
2476c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
24775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2478c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (ssrc == default_receive_ssrc_) {
2479c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    ASSERT(IsDefaultChannel(it->second.channel));
2480c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // Recycle the default channel is for recv stream.
2481c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    if (playout_)
2482c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      SetPlayout(voe_channel(), false);
2483c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2484c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    if (it->second.renderer)
2485c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      it->second.renderer->RemoveChannel(voe_channel());
2486c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2487c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    default_receive_ssrc_ = 0;
2488c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    receive_channels_.erase(it);
2489c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    return true;
2490c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
2491c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2492c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // Non default channel.
2493c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // Notify the renderer that channel is going away.
2494c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (it->second.renderer)
2495c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    it->second.renderer->RemoveChannel(it->second.channel);
24965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2497c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  LOG(LS_INFO) << "Removing audio stream " << ssrc
2498c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org               << " with VoiceEngine channel #" << it->second.channel << ".";
2499c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (!DeleteChannel(it->second.channel)) {
2500c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // Erase the entry anyhow.
2501c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    receive_channels_.erase(it);
2502c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    return false;
2503c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
2504c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2505c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  receive_channels_.erase(it);
2506c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  bool enable_default_channel_playout = false;
2507c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (receive_channels_.empty()) {
2508c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // The last stream was removed. We can now enable the default
2509c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // channel for new channels to be played out immediately without
2510c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // waiting for AddStream messages.
2511c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // We do this for both conference mode and non-conference mode.
2512c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // TODO(oja): Does the default channel still have it's CN state?
2513c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    enable_default_channel_playout = true;
2514c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
2515c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (!InConferenceMode() && receive_channels_.size() == 1 &&
2516c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      default_receive_ssrc_ != 0) {
2517c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // Only the default channel is active, enable the playout on default
2518c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // channel.
2519c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    enable_default_channel_playout = true;
2520c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
2521c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (enable_default_channel_playout && playout_) {
2522c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    LOG(LS_INFO) << "Enabling playback on the default voice channel";
2523c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    SetPlayout(voe_channel(), true);
2524c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
2525c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2526c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  return true;
2527c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org}
2528c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2529c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetRemoteRenderer(uint32 ssrc,
2530c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                                                AudioRenderer* renderer) {
2531c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  ChannelMap::iterator it = receive_channels_.find(ssrc);
2532c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (it == receive_channels_.end()) {
2533c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    if (renderer) {
2534c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      // Return an error if trying to set a valid renderer with an invalid ssrc.
2535c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      LOG(LS_ERROR) << "SetRemoteRenderer failed with ssrc "<< ssrc;
25365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
25375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
25385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2539c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // The channel likely has gone away, do nothing.
2540c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    return true;
2541c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
2542c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2543c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  AudioRenderer* remote_renderer = it->second.renderer;
2544c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (renderer) {
2545c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    ASSERT(remote_renderer == NULL || remote_renderer == renderer);
2546c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (!remote_renderer) {
2547c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      renderer->AddChannel(it->second.channel);
25485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2549c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  } else if (remote_renderer) {
2550c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // |renderer| == NULL, remove the channel from the renderer.
2551c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    remote_renderer->RemoveChannel(it->second.channel);
25525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2553c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2554c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Assign the new value to the struct.
2555c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  it->second.renderer = renderer;
25565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
25575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
25585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2559c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.orgbool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32 ssrc,
2560c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org                                               AudioRenderer* renderer) {
2561c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  ChannelMap::iterator it = send_channels_.find(ssrc);
2562c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (it == send_channels_.end()) {
2563c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (renderer) {
2564c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      // Return an error if trying to set a valid renderer with an invalid ssrc.
2565c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      LOG(LS_ERROR) << "SetLocalRenderer failed with ssrc "<< ssrc;
2566c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      return false;
2567c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    }
2568c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2569c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // The channel likely has gone away, do nothing.
2570c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    return true;
2571c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
25725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2573c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  AudioRenderer* local_renderer = it->second.renderer;
2574c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (renderer) {
2575c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    ASSERT(local_renderer == NULL || local_renderer == renderer);
2576c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (!local_renderer)
2577c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      renderer->AddChannel(it->second.channel);
2578c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  } else if (local_renderer) {
2579c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    local_renderer->RemoveChannel(it->second.channel);
2580c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  }
2581c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org
2582c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Assign the new value to the struct.
2583c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  it->second.renderer = renderer;
25845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
25855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
25865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
25875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::GetActiveStreams(
25885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    AudioInfo::StreamList* actives) {
2589c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // In conference mode, the default channel should not be in
2590c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // |receive_channels_|.
25915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  actives->clear();
2592c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  for (ChannelMap::iterator it = receive_channels_.begin();
2593c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org       it != receive_channels_.end(); ++it) {
2594c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    int level = GetOutputLevel(it->second.channel);
25955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (level > 0) {
25965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      actives->push_back(std::make_pair(it->first, level));
25975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
25985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
25995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
26005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
26015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
26025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcVoiceMediaChannel::GetOutputLevel() {
26035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // return the highest output level of all streams
26045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int highest = GetOutputLevel(voe_channel());
2605c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  for (ChannelMap::iterator it = receive_channels_.begin();
2606c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org       it != receive_channels_.end(); ++it) {
2607c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    int level = GetOutputLevel(it->second.channel);
26085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    highest = talk_base::_max(level, highest);
26095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
26105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return highest;
26115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
26125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
26135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcVoiceMediaChannel::GetTimeSinceLastTyping() {
26145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int ret;
26155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (engine()->voe()->processing()->TimeSinceLastTyping(ret) == -1) {
26165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // In case of error, log the info and continue
26175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR0(TimeSinceLastTyping);
26185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ret = -1;
26195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
26205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ret *= 1000;  // We return ms, webrtc returns seconds.
26215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
26225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ret;
26235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
26245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
26255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceMediaChannel::SetTypingDetectionParameters(int time_window,
26265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int cost_per_typing, int reporting_threshold, int penalty_decay,
26275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int type_event_delay) {
26285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (engine()->voe()->processing()->SetTypingDetectionParameters(
26295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          time_window, cost_per_typing,
26305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          reporting_threshold, penalty_decay, type_event_delay) == -1) {
26315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // In case of error, log the info and continue
26325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR5(SetTypingDetectionParameters, time_window,
26335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                cost_per_typing, reporting_threshold, penalty_decay,
26345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                type_event_delay);
26355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
26365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
26375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
26385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetOutputScaling(
26395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    uint32 ssrc, double left, double right) {
2640c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
26415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Collect the channels to scale the output volume.
26425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<int> channels;
26435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (0 == ssrc) {  // Collect all channels, including the default one.
2644c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // Default channel is not in receive_channels_ if it is not being used for
2645c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    // playout.
2646c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    if (default_receive_ssrc_ == 0)
2647c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      channels.push_back(voe_channel());
2648c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    for (ChannelMap::const_iterator it = receive_channels_.begin();
2649c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org         it != receive_channels_.end(); ++it) {
2650c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      channels.push_back(it->second.channel);
26515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
26525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {  // Collect only the channel of the specified ssrc.
26535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int channel = GetReceiveChannelNum(ssrc);
26545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (-1 == channel) {
26555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc;
26565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
26575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
26585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    channels.push_back(channel);
26595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
26605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
26615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Scale the output volume for the collected channels. We first normalize to
26625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // scale the volume and then set the left and right pan.
26635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  float scale = static_cast<float>(talk_base::_max(left, right));
26645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (scale > 0.0001f) {
26655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    left /= scale;
26665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    right /= scale;
26675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
26685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (std::vector<int>::const_iterator it = channels.begin();
26695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      it != channels.end(); ++it) {
26705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (-1 == engine()->voe()->volume()->SetChannelOutputVolumeScaling(
26715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *it, scale)) {
26725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR2(SetChannelOutputVolumeScaling, *it, scale);
26735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
26745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
26755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (-1 == engine()->voe()->volume()->SetOutputVolumePan(
26765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *it, static_cast<float>(left), static_cast<float>(right))) {
26775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR3(SetOutputVolumePan, *it, left, right);
26785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Do not return if fails. SetOutputVolumePan is not available for all
26795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // pltforms.
26805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
26815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "SetOutputScaling to left=" << left * scale
26825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 << " right=" << right * scale
26835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 << " for channel " << *it << " and ssrc " << ssrc;
26845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
26855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
26865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
26875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
26885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::GetOutputScaling(
26895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    uint32 ssrc, double* left, double* right) {
26905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!left || !right) return false;
26915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2692c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
26935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Determine which channel based on ssrc.
26945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int channel = (0 == ssrc) ? voe_channel() : GetReceiveChannelNum(ssrc);
26955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (channel == -1) {
26965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc;
26975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
26985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
26995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  float scaling;
27015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (-1 == engine()->voe()->volume()->GetChannelOutputVolumeScaling(
27025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      channel, scaling)) {
27035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR2(GetChannelOutputVolumeScaling, channel, scaling);
27045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
27055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
27065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  float left_pan;
27085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  float right_pan;
27095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (-1 == engine()->voe()->volume()->GetOutputVolumePan(
27105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      channel, left_pan, right_pan)) {
27115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_RTCERR3(GetOutputVolumePan, channel, left_pan, right_pan);
27125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // If GetOutputVolumePan fails, we use the default left and right pan.
27135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    left_pan = 1.0f;
27145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    right_pan = 1.0f;
27155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
27165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *left = scaling * left_pan;
27185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *right = scaling * right_pan;
27195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
27205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
27215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetRingbackTone(const char *buf, int len) {
27235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ringback_tone_.reset(new WebRtcSoundclipStream(buf, len));
27245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
27255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
27265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::PlayRingbackTone(uint32 ssrc,
27285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                             bool play, bool loop) {
27295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!ringback_tone_) {
27305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
27315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
27325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // The voe file api is not available in chrome.
27345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!engine()->voe()->file()) {
27355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
27365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
27375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Determine which VoiceEngine channel to play on.
27395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int channel = (ssrc == 0) ? voe_channel() : GetReceiveChannelNum(ssrc);
27405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (channel == -1) {
27415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
27425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
27435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Make sure the ringtone is cued properly, and play it out.
27455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (play) {
27465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ringback_tone_->set_loop(loop);
27475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ringback_tone_->Rewind();
27485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->voe()->file()->StartPlayingFileLocally(channel,
27495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        ringback_tone_.get()) == -1) {
27505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR2(StartPlayingFileLocally, channel, ringback_tone_.get());
27515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Unable to start ringback tone";
27525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
27535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
27545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ringback_channels_.insert(channel);
27555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Started ringback on channel " << channel;
27565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
27575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->voe()->file()->IsPlayingFileLocally(channel) == 1 &&
27585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        engine()->voe()->file()->StopPlayingFileLocally(channel) == -1) {
27595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(StopPlayingFileLocally, channel);
27605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
27615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
27625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Stopped ringback on channel " << channel;
27635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ringback_channels_.erase(channel);
27645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
27655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
27675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
27685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::CanInsertDtmf() {
27705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return dtmf_allowed_;
27715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
27725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::InsertDtmf(uint32 ssrc, int event,
27745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                         int duration, int flags) {
27755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!dtmf_allowed_) {
27765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
27775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
27785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
27795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Send the event.
27805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (flags & cricket::DF_SEND) {
2781d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    int channel = -1;
2782d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    if (ssrc == 0) {
2783d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      bool default_channel_is_inuse = false;
2784d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      for (ChannelMap::const_iterator iter = send_channels_.begin();
2785d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org           iter != send_channels_.end(); ++iter) {
2786d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        if (IsDefaultChannel(iter->second.channel)) {
2787d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          default_channel_is_inuse = true;
2788d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org          break;
2789d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        }
2790d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      }
2791d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      if (default_channel_is_inuse) {
2792d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        channel = voe_channel();
2793d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      } else if (!send_channels_.empty()) {
2794d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org        channel = send_channels_.begin()->second.channel;
2795d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      }
2796d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    } else {
2797d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org      channel = GetSendChannelNum(ssrc);
2798d3ebe0273d84d577148cd4cdecc5753bd985d562wu@webrtc.org    }
2799c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (channel == -1) {
28005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "InsertDtmf - The specified ssrc "
28015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << ssrc << " is not in use.";
28025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
28035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
28045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Send DTMF using out-of-band DTMF. ("true", as 3rd arg)
2805c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (engine()->voe()->dtmf()->SendTelephoneEvent(
2806c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org            channel, event, true, duration) == -1) {
2807c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration);
28085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
28095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
28105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
28115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
28125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Play the event.
28135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (flags & cricket::DF_PLAY) {
28145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Play DTMF tone locally.
28155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->voe()->dtmf()->PlayDtmfTone(event, duration) == -1) {
28165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR2(PlayDtmfTone, event, duration);
28175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
28185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
28195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
28205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
28215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
28225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
28235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2824d3ecbb30dc2684653d61e8ec88a5382aecf62773wu@webrtc.orgvoid WebRtcVoiceMediaChannel::OnPacketReceived(
2825d3ecbb30dc2684653d61e8ec88a5382aecf62773wu@webrtc.org    talk_base::Buffer* packet, const talk_base::PacketTime& packet_time) {
28265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Pick which channel to send this packet to. If this packet doesn't match
28275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // any multiplexed streams, just send it to the default channel. Otherwise,
28285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // send it to the specific decoder instance for that stream.
28295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int which_channel = GetReceiveChannelNum(
28305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ParseSsrc(packet->data(), packet->length(), false));
28315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (which_channel == -1) {
28325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    which_channel = voe_channel();
28335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
28345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
28355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Stop any ringback that might be playing on the channel.
28365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // It's possible the ringback has already stopped, ih which case we'll just
28375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // use the opportunity to remove the channel from ringback_channels_.
28385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (engine()->voe()->file()) {
28395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const std::set<int>::iterator it = ringback_channels_.find(which_channel);
28405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (it != ringback_channels_.end()) {
28415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (engine()->voe()->file()->IsPlayingFileLocally(
28425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          which_channel) == 1) {
28435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        engine()->voe()->file()->StopPlayingFileLocally(which_channel);
28445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG(LS_INFO) << "Stopped ringback on channel " << which_channel
28455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                     << " due to incoming media";
28465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
28475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ringback_channels_.erase(which_channel);
28485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
28495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
28505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
28515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Pass it off to the decoder.
2852b30f5947ff2af0e3b77751bacec5dc7350c4dcd6sergeyu@chromium.org  engine()->voe()->network()->ReceivedRTPPacket(
2853b30f5947ff2af0e3b77751bacec5dc7350c4dcd6sergeyu@chromium.org      which_channel,
2854b30f5947ff2af0e3b77751bacec5dc7350c4dcd6sergeyu@chromium.org      packet->data(),
2855b30f5947ff2af0e3b77751bacec5dc7350c4dcd6sergeyu@chromium.org      static_cast<unsigned int>(packet->length()));
28565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
28575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2858d3ecbb30dc2684653d61e8ec88a5382aecf62773wu@webrtc.orgvoid WebRtcVoiceMediaChannel::OnRtcpReceived(
2859d3ecbb30dc2684653d61e8ec88a5382aecf62773wu@webrtc.org    talk_base::Buffer* packet, const talk_base::PacketTime& packet_time) {
2860c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Sending channels need all RTCP packets with feedback information.
2861c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Even sender reports can contain attached report blocks.
2862c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // Receiving channels need sender reports in order to create
2863c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // correct receiver reports.
2864c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  int type = 0;
2865c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (!GetRtcpType(packet->data(), packet->length(), &type)) {
2866c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG(LS_WARNING) << "Failed to parse type from received RTCP packet";
2867c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    return;
2868c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2869c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2870c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // If it is a sender report, find the channel that is listening.
2871c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  bool has_sent_to_default_channel = false;
2872c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (type == kRtcpTypeSR) {
2873c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    int which_channel = GetReceiveChannelNum(
2874c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        ParseSsrc(packet->data(), packet->length(), true));
2875c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (which_channel != -1) {
2876c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      engine()->voe()->network()->ReceivedRTCPPacket(
2877c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          which_channel,
2878c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          packet->data(),
2879c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          static_cast<unsigned int>(packet->length()));
2880c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2881c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      if (IsDefaultChannel(which_channel))
2882c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        has_sent_to_default_channel = true;
2883c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    }
2884c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
2885c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2886c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // SR may continue RR and any RR entry may correspond to any one of the send
2887c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // channels. So all RTCP packets must be forwarded all send channels. VoE
2888c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  // will filter out RR internally.
2889c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  for (ChannelMap::iterator iter = send_channels_.begin();
2890c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org       iter != send_channels_.end(); ++iter) {
2891c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Make sure not sending the same packet to default channel more than once.
2892c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (IsDefaultChannel(iter->second.channel) && has_sent_to_default_channel)
2893c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      continue;
28945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2895c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    engine()->voe()->network()->ReceivedRTCPPacket(
2896c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        iter->second.channel,
2897c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        packet->data(),
2898c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        static_cast<unsigned int>(packet->length()));
2899c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
29005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
29015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
29025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::MuteStream(uint32 ssrc, bool muted) {
2903c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  int channel = (ssrc == 0) ? voe_channel() : GetSendChannelNum(ssrc);
2904c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (channel == -1) {
29055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
29065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
29075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2908c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (engine()->voe()->volume()->SetInputMute(channel, muted) == -1) {
2909c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG_RTCERR2(SetInputMute, channel, muted);
29105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
29115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
29125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
29135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
29145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
29155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendBandwidth(bool autobw, int bps) {
29165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << "WebRtcVoiceMediaChanne::SetSendBandwidth.";
29175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2918834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  send_bw_setting_ = true;
2919834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  send_autobw_ = autobw;
2920834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  send_bw_bps_ = bps;
2921834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org
2922834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  return SetSendBandwidthInternal(send_autobw_, send_bw_bps_);
2923834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org}
2924834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org
2925834abe82dfc619d427cac9c095020734fe474257wu@webrtc.orgbool WebRtcVoiceMediaChannel::SetSendBandwidthInternal(bool autobw, int bps) {
2926834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org  LOG(LS_INFO) << "WebRtcVoiceMediaChanne::SetSendBandwidthInternal.";
2927834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org
29285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!send_codec_) {
2929834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org    LOG(LS_INFO) << "The send codec has not been set up yet. "
2930834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org                 << "The send bandwidth setting will be applied later.";
2931834abe82dfc619d427cac9c095020734fe474257wu@webrtc.org    return true;
29325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
29335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
29345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Bandwidth is auto by default.
29355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (autobw || bps <= 0)
29365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
29375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
29385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  webrtc::CodecInst codec = *send_codec_;
29395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool is_multi_rate = IsCodecMultiRate(codec);
29405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
29415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (is_multi_rate) {
29425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // If codec is multi-rate then just set the bitrate.
29435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    codec.rate = bps;
29445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!SetSendCodec(codec)) {
29455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_INFO) << "Failed to set codec " << codec.plname
29465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   << " to bitrate " << bps << " bps.";
29475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
29485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
29495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
29505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
29515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // If codec is not multi-rate and |bps| is less than the fixed bitrate
29525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // then fail. If codec is not multi-rate and |bps| exceeds or equal the
29535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // fixed bitrate then ignore.
29545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (bps < codec.rate) {
29555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_INFO) << "Failed to set codec " << codec.plname
29565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   << " to bitrate " << bps << " bps"
29575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   << ", requires at least " << codec.rate << " bps.";
29585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
29595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
29605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
29615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
29625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
29635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
29645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
29655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool echo_metrics_on = false;
29665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // These can take on valid negative values, so use the lowest possible level
29675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // as default rather than -1.
2968c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  int echo_return_loss = -100;
2969c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  int echo_return_loss_enhancement = -100;
29705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // These can also be negative, but in practice -1 is only used to signal
29715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // insufficient data, since the resolution is limited to multiples of 4 ms.
2972c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  int echo_delay_median_ms = -1;
2973c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  int echo_delay_std_ms = -1;
2974c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (engine()->voe()->processing()->GetEcMetricsStatus(
2975c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          echo_metrics_on) != -1 && echo_metrics_on) {
29765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
29775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // here, but it appears to be unsuitable currently. Revisit after this is
29785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // investigated: http://b/issue?id=5666755
29795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int erl, erle, rerl, anlp;
2980c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (engine()->voe()->processing()->GetEchoMetrics(
2981c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org            erl, erle, rerl, anlp) != -1) {
2982c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      echo_return_loss = erl;
2983c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      echo_return_loss_enhancement = erle;
29845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
29855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
29865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int median, std;
29875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->voe()->processing()->GetEcDelayMetrics(median, std) != -1) {
2988c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      echo_delay_median_ms = median;
2989c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      echo_delay_std_ms = std;
29905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
29915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
29925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2993c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  webrtc::CallStatistics cs;
2994c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  unsigned int ssrc;
2995c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  webrtc::CodecInst codec;
2996c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  unsigned int level;
2997c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
2998c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  for (ChannelMap::const_iterator channel_iter = send_channels_.begin();
2999c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org       channel_iter != send_channels_.end(); ++channel_iter) {
3000c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    const int channel = channel_iter->second.channel;
3001c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
3002c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Fill in the sender info, based on what we know, and what the
3003c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // remote side told us it got from its RTCP report.
3004c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    VoiceSenderInfo sinfo;
3005c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
3006c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (engine()->voe()->rtp()->GetRTCPStatistics(channel, cs) == -1 ||
3007c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        engine()->voe()->rtp()->GetLocalSSRC(channel, ssrc) == -1) {
3008c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      continue;
3009c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    }
3010c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
301185a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org    sinfo.add_ssrc(ssrc);
3012c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.codec_name = send_codec_.get() ? send_codec_->plname : "";
3013c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.bytes_sent = cs.bytesSent;
3014c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.packets_sent = cs.packetsSent;
3015c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // RTT isn't known until a RTCP report is received. Until then, VoiceEngine
3016c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // returns 0 to indicate an error value.
3017c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1;
3018c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
3019c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Get data from the last remote RTCP report. Use default values if no data
3020c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // available.
3021c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.fraction_lost = -1.0;
3022c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.jitter_ms = -1;
3023c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.packets_lost = -1;
3024c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.ext_seqnum = -1;
3025c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    std::vector<webrtc::ReportBlock> receive_blocks;
3026c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    if (engine()->voe()->rtp()->GetRemoteRTCPReportBlocks(
3027c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org            channel, &receive_blocks) != -1 &&
3028c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        engine()->voe()->codec()->GetSendCodec(channel, codec) != -1) {
3029c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      std::vector<webrtc::ReportBlock>::iterator iter;
3030c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      for (iter = receive_blocks.begin(); iter != receive_blocks.end();
3031c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org           ++iter) {
3032c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        // Lookup report for send ssrc only.
303385a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org        if (iter->source_SSRC == sinfo.ssrc()) {
3034c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          // Convert Q8 to floating point.
3035c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          sinfo.fraction_lost = static_cast<float>(iter->fraction_lost) / 256;
3036c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          // Convert samples to milliseconds.
3037c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          if (codec.plfreq / 1000 > 0) {
3038c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org            sinfo.jitter_ms = iter->interarrival_jitter / (codec.plfreq / 1000);
3039c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          }
3040c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          sinfo.packets_lost = iter->cumulative_num_packets_lost;
3041c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          sinfo.ext_seqnum = iter->extended_highest_sequence_number;
3042c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          break;
3043c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        }
3044c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      }
3045c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    }
3046c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
3047c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Local speech level.
3048c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.audio_level = (engine()->voe()->volume()->
3049c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        GetSpeechInputLevelFullRange(level) != -1) ? level : -1;
3050c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
3051c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // TODO(xians): We are injecting the same APM logging to all the send
3052c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // channels here because there is no good way to know which send channel
3053c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // is using the APM. The correct fix is to allow the send channels to have
3054c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // their own APM so that we can feed the correct APM logging to different
3055c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // send channels. See issue crbug/264611 .
3056c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.echo_return_loss = echo_return_loss;
3057c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.echo_return_loss_enhancement = echo_return_loss_enhancement;
3058c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.echo_delay_median_ms = echo_delay_median_ms;
3059c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    sinfo.echo_delay_std_ms = echo_delay_std_ms;
3060e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org    // TODO(ajm): Re-enable this metric once we have a reliable implementation.
3061e73fa366a56d0c3c46860c534db19fffe110f167mallinath@webrtc.org    sinfo.aec_quality_min = -1;
3062204b178db6a965bcdee700f384174d4303e8e9d8stefan@webrtc.org    sinfo.typing_noise_detected = typing_noise_detected_;
3063c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
3064c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    info->senders.push_back(sinfo);
3065c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  }
30665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3067c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // Build the list of receivers, one for each receiving channel, or 1 in
3068c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  // a 1:1 call.
30695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<int> channels;
3070c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  for (ChannelMap::const_iterator it = receive_channels_.begin();
3071c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org       it != receive_channels_.end(); ++it) {
3072c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    channels.push_back(it->second.channel);
30735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
30745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (channels.empty()) {
30755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    channels.push_back(voe_channel());
30765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
30775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
30785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Get the SSRC and stats for each receiver, based on our own calculations.
30795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (std::vector<int>::const_iterator it = channels.begin();
30805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       it != channels.end(); ++it) {
30815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    memset(&cs, 0, sizeof(cs));
30825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->voe()->rtp()->GetRemoteSSRC(*it, ssrc) != -1 &&
30835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        engine()->voe()->rtp()->GetRTCPStatistics(*it, cs) != -1 &&
30845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        engine()->voe()->codec()->GetRecCodec(*it, codec) != -1) {
30855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      VoiceReceiverInfo rinfo;
308685a56f7357d9a68fe6de51061d81849db77e5185sergeyu@chromium.org      rinfo.add_ssrc(ssrc);
30875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rinfo.bytes_rcvd = cs.bytesReceived;
30885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rinfo.packets_rcvd = cs.packetsReceived;
30895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // The next four fields are from the most recently sent RTCP report.
30905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Convert Q8 to floating point.
30915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rinfo.fraction_lost = static_cast<float>(cs.fractionLost) / (1 << 8);
30925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rinfo.packets_lost = cs.cumulativeLost;
30935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rinfo.ext_seqnum = cs.extendedMax;
30945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Convert samples to milliseconds.
30955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (codec.plfreq / 1000 > 0) {
30965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000);
30975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
30985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
30995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Get jitter buffer and total delay (alg + jitter + playout) stats.
31005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      webrtc::NetworkStatistics ns;
31015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (engine()->voe()->neteq() &&
31025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          engine()->voe()->neteq()->GetNetworkStatistics(
31035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              *it, ns) != -1) {
31045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        rinfo.jitter_buffer_ms = ns.currentBufferSize;
31055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        rinfo.jitter_buffer_preferred_ms = ns.preferredBufferSize;
31065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        rinfo.expand_rate =
3107b30f5947ff2af0e3b77751bacec5dc7350c4dcd6sergeyu@chromium.org            static_cast<float>(ns.currentExpandRate) / (1 << 14);
31085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
31095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (engine()->voe()->sync()) {
3110edac505d92ae2ab28b41f26f1a5b889d3e2a99f3sergeyu@chromium.org        int jitter_buffer_delay_ms = 0;
31115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        int playout_buffer_delay_ms = 0;
31125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        engine()->voe()->sync()->GetDelayEstimate(
3113edac505d92ae2ab28b41f26f1a5b889d3e2a99f3sergeyu@chromium.org            *it, &jitter_buffer_delay_ms, &playout_buffer_delay_ms);
3114edac505d92ae2ab28b41f26f1a5b889d3e2a99f3sergeyu@chromium.org        rinfo.delay_estimate_ms = jitter_buffer_delay_ms +
3115edac505d92ae2ab28b41f26f1a5b889d3e2a99f3sergeyu@chromium.org            playout_buffer_delay_ms;
31165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
31175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
31185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Get speech level.
31195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rinfo.audio_level = (engine()->voe()->volume()->
31205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          GetSpeechOutputLevelFullRange(*it, level) != -1) ? level : -1;
31215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      info->receivers.push_back(rinfo);
31225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
31235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
31245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
31255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
31265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
31275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
31285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceMediaChannel::GetLastMediaError(
31295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    uint32* ssrc, VoiceMediaChannel::Error* error) {
31305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(ssrc != NULL);
31315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(error != NULL);
31325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  FindSsrc(voe_channel(), ssrc);
31335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *error = WebRtcErrorToChannelError(GetLastEngineError());
31345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
31355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
31365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
3137c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  talk_base::CritScope lock(&receive_channels_cs_);
31385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(ssrc != NULL);
3139c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (channel_num == -1 && send_ != SEND_NOTHING) {
31405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Sometimes the VoiceEngine core will throw error with channel_num = -1.
31415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // This means the error is not limited to a specific channel.  Signal the
31425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // message using ssrc=0.  If the current channel is sending, use this
31435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // channel for sending the message.
31445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    *ssrc = 0;
31455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
31465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
3147c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    // Check whether this is a sending channel.
3148c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    for (ChannelMap::const_iterator it = send_channels_.begin();
3149c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org         it != send_channels_.end(); ++it) {
3150c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      if (it->second.channel == channel_num) {
3151c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        // This is a sending channel.
3152c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        uint32 local_ssrc = 0;
3153c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        if (engine()->voe()->rtp()->GetLocalSSRC(
3154c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org                channel_num, local_ssrc) != -1) {
3155c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org          *ssrc = local_ssrc;
3156c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        }
3157c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org        return true;
3158c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org      }
3159c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    }
3160c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
31615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Check whether this is a receiving channel.
3162c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    for (ChannelMap::const_iterator it = receive_channels_.begin();
3163c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org        it != receive_channels_.end(); ++it) {
3164c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org      if (it->second.channel == channel_num) {
31655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *ssrc = it->first;
31665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return true;
31675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
31685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
31695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
31705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return false;
31715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
31725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
31735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid WebRtcVoiceMediaChannel::OnError(uint32 ssrc, int error) {
3174204b178db6a965bcdee700f384174d4303e8e9d8stefan@webrtc.org  if (error == VE_TYPING_NOISE_WARNING) {
3175204b178db6a965bcdee700f384174d4303e8e9d8stefan@webrtc.org    typing_noise_detected_ = true;
3176204b178db6a965bcdee700f384174d4303e8e9d8stefan@webrtc.org  } else if (error == VE_TYPING_NOISE_OFF_WARNING) {
3177204b178db6a965bcdee700f384174d4303e8e9d8stefan@webrtc.org    typing_noise_detected_ = false;
3178204b178db6a965bcdee700f384174d4303e8e9d8stefan@webrtc.org  }
31795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SignalMediaError(ssrc, WebRtcErrorToChannelError(error));
31805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
31815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
31825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcVoiceMediaChannel::GetOutputLevel(int channel) {
31835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  unsigned int ulevel;
31845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int ret =
31855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      engine()->voe()->volume()->GetSpeechOutputLevel(channel, ulevel);
31865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return (ret == 0) ? static_cast<int>(ulevel) : -1;
31875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
31885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
31895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcVoiceMediaChannel::GetReceiveChannelNum(uint32 ssrc) {
3190c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  ChannelMap::iterator it = receive_channels_.find(ssrc);
3191c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org  if (it != receive_channels_.end())
3192c1c67e5a722135af4ca83ee4c7d2dbe3f26bae70henrike@webrtc.org    return it->second.channel;
31935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return (ssrc == default_receive_ssrc_) ?  voe_channel() : -1;
31945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
31955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
31965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcVoiceMediaChannel::GetSendChannelNum(uint32 ssrc) {
3197c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  ChannelMap::iterator it = send_channels_.find(ssrc);
3198c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  if (it != send_channels_.end())
3199c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    return it->second.channel;
3200c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org
3201c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org  return -1;
32025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
32035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
32045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec,
32055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const std::vector<AudioCodec>& all_codecs, webrtc::CodecInst* send_codec) {
32065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Get the RED encodings from the parameter with no name. This may
32075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // change based on what is discussed on the Jingle list.
32085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // The encoding parameter is of the form "a/b"; we only support where
32095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // a == b. Verify this and parse out the value into red_pt.
32105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // If the parameter value is absent (as it will be until we wire up the
32115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // signaling of this message), use the second codec specified (i.e. the
32125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // one after "red") as the encoding parameter.
32135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int red_pt = -1;
32145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string red_params;
32155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CodecParameterMap::const_iterator it = red_codec.params.find("");
32165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (it != red_codec.params.end()) {
32175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    red_params = it->second;
32185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    std::vector<std::string> red_pts;
32195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (talk_base::split(red_params, '/', &red_pts) != 2 ||
32205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        red_pts[0] != red_pts[1] ||
32215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        !talk_base::FromString(red_pts[0], &red_pt)) {
32225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "RED params " << red_params << " not supported.";
32235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
32245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
32255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else if (red_codec.params.empty()) {
32265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "RED params not present, using defaults";
32275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (all_codecs.size() > 1) {
32285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      red_pt = all_codecs[1].id;
32295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
32305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
32315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
32325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Try to find red_pt in |codecs|.
32335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<AudioCodec>::const_iterator codec;
32345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (codec = all_codecs.begin(); codec != all_codecs.end(); ++codec) {
32355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (codec->id == red_pt)
32365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      break;
32375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
32385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
32395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // If we find the right codec, that will be the codec we pass to
32405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // SetSendCodec, with the desired payload type.
32415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (codec != all_codecs.end() &&
32425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    engine()->FindWebRtcCodec(*codec, send_codec)) {
32435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
32445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "RED params " << red_params << " are invalid.";
32455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
32465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
32475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
32485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
32495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
32505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
32515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::EnableRtcp(int channel) {
32525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (engine()->voe()->rtp()->SetRTCPStatus(channel, true) == -1) {
3253c237f0ad875cde990bf9d89f41424b18809cc345henrike@webrtc.org    LOG_RTCERR2(SetRTCPStatus, channel, 1);
32545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
32555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
32565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(juberti): Enable VQMon and RTCP XR reports, once we know what
32575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // what we want to do with them.
32585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // engine()->voe().EnableVQMon(voe_channel(), true);
32595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // engine()->voe().EnableRTCP_XR(voe_channel(), true);
32605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
32615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
32625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
32635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::ResetRecvCodecs(int channel) {
32645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int ncodecs = engine()->voe()->codec()->NumOfCodecs();
32655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (int i = 0; i < ncodecs; ++i) {
32665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    webrtc::CodecInst voe_codec;
32675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) {
32685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      voe_codec.pltype = -1;
32695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (engine()->voe()->codec()->SetRecPayloadType(
32705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          channel, voe_codec) == -1) {
32715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec));
32725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return false;
32735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
32745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
32755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
32765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
32775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
32785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
32795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) {
32805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (playout) {
32815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Starting playout for channel #" << channel;
32825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (engine()->voe()->base()->StartPlayout(channel) == -1) {
32835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_RTCERR1(StartPlayout, channel);
32845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
32855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
32865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
32875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Stopping playout for channel #" << channel;
32885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    engine()->voe()->base()->StopPlayout(channel);
32895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
32905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
32915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
32925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
32935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orguint32 WebRtcVoiceMediaChannel::ParseSsrc(const void* data, size_t len,
32945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        bool rtcp) {
32955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  size_t ssrc_pos = (!rtcp) ? 8 : 4;
32965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32 ssrc = 0;
32975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (len >= (ssrc_pos + sizeof(ssrc))) {
32985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ssrc = talk_base::GetBE32(static_cast<const char*>(data) + ssrc_pos);
32995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
33005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ssrc;
33015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
33025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
33035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Convert VoiceEngine error code into VoiceMediaChannel::Error enum.
33045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgVoiceMediaChannel::Error
33055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    WebRtcVoiceMediaChannel::WebRtcErrorToChannelError(int err_code) {
33065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  switch (err_code) {
33075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case 0:
33085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return ERROR_NONE;
33095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_CANNOT_START_RECORDING:
33105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_MIC_VOL_ERROR:
33115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_GET_MIC_VOL_ERROR:
33125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_CANNOT_ACCESS_MIC_VOL:
33135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return ERROR_REC_DEVICE_OPEN_FAILED;
33145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_SATURATION_WARNING:
33155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return ERROR_REC_DEVICE_SATURATION;
33165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_REC_DEVICE_REMOVED:
33175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return ERROR_REC_DEVICE_REMOVED;
33185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_RUNTIME_REC_WARNING:
33195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_RUNTIME_REC_ERROR:
33205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return ERROR_REC_RUNTIME_ERROR;
33215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_CANNOT_START_PLAYOUT:
33225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_SPEAKER_VOL_ERROR:
33235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_GET_SPEAKER_VOL_ERROR:
33245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_CANNOT_ACCESS_SPEAKER_VOL:
33255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return ERROR_PLAY_DEVICE_OPEN_FAILED;
33265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_RUNTIME_PLAY_WARNING:
33275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_RUNTIME_PLAY_ERROR:
33285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return ERROR_PLAY_RUNTIME_ERROR;
33295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case VE_TYPING_NOISE_WARNING:
33305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return ERROR_REC_TYPING_NOISE_DETECTED;
33315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    default:
33325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return VoiceMediaChannel::ERROR_OTHER;
33335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
33345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
33355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
33365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcSoundclipStream::Read(void *buf, int len) {
33375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  size_t res = 0;
33385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  mem_.Read(buf, len, &res, NULL);
3339b30f5947ff2af0e3b77751bacec5dc7350c4dcd6sergeyu@chromium.org  return static_cast<int>(res);
33405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
33415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
33425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint WebRtcSoundclipStream::Rewind() {
33435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  mem_.Rewind();
33445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Return -1 to keep VoiceEngine from looping.
33455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return (loop_) ? 0 : -1;
33465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
33475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
33485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}  // namespace cricket
33495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
33505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // HAVE_WEBRTC_VOICE
3351