* Update libjingle to 50389769.
* Together with "Add texture support for i420 video frame." from
wuchengli@chromium.org.
https://webrtc-codereview.appspot.com/1413004

RISK=P1
TESTED=try bots
R=fischman@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/1967004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4489 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index a974d0e..855a9e4 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -548,6 +548,12 @@
   }
 #endif
 
+  // Disable the DTMF playout when a tone is sent.
+  // PlayDtmfTone will be used if local playout is needed.
+  if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) {
+    LOG_RTCERR1(SetDtmfFeedbackStatus, false);
+  }
+
   initialized_ = true;
   return true;
 }
@@ -675,6 +681,7 @@
   options.experimental_aec.Set(false);
 #endif
 
+
   LOG(LS_INFO) << "Applying audio options: " << options.ToString();
 
   webrtc::VoEAudioProcessing* voep = voe_wrapper_->processing();
@@ -1490,41 +1497,22 @@
       playout_(false),
       desired_send_(SEND_NOTHING),
       send_(SEND_NOTHING),
-      send_ssrc_(0),
-      local_renderer_(NULL),
       default_receive_ssrc_(0) {
   engine->RegisterChannel(this);
   LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel "
                   << voe_channel();
 
-  // Register external transport
-  if (engine->voe()->network()->RegisterExternalTransport(
-      voe_channel(), *static_cast<Transport*>(this)) == -1) {
-    LOG_RTCERR2(RegisterExternalTransport, voe_channel(), this);
-  }
-
-  // Enable RTCP (for quality stats and feedback messages)
-  EnableRtcp(voe_channel());
-
-  // Reset all recv codecs; they will be enabled via SetRecvCodecs.
-  ResetRecvCodecs(voe_channel());
-
-  // Disable the DTMF playout when a tone is sent.
-  // PlayDtmfTone will be used if local playout is needed.
-  if (engine->voe()->dtmf()->SetDtmfFeedbackStatus(false) == -1) {
-    LOG_RTCERR1(SetDtmfFeedbackStatus, false);
-  }
+  ConfigureSendChannel(voe_channel());
 }
 
 WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() {
   LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel "
                   << voe_channel();
 
-  // DeRegister external transport
-  if (engine()->voe()->network()->DeRegisterExternalTransport(
-      voe_channel()) == -1) {
-    LOG_RTCERR1(DeRegisterExternalTransport, voe_channel());
-  }
+  // Remove any remaining send streams, the default channel will be deleted
+  // later.
+  while (!send_channels_.empty())
+    RemoveSendStream(send_channels_.begin()->first);
 
   // Unregister ourselves from the engine.
   engine()->UnregisterChannel(this);
@@ -1533,16 +1521,17 @@
     RemoveRecvStream(receive_channels_.begin()->first);
   }
 
-  // Delete the primary channel.
-  if (engine()->voe()->base()->DeleteChannel(voe_channel()) == -1) {
-    LOG_RTCERR1(DeleteChannel, voe_channel());
-  }
+  // Delete the default channel.
+  DeleteChannel(voe_channel());
 }
 
 bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) {
   LOG(LS_INFO) << "Setting voice channel options: "
                << options.ToString();
 
+  // TODO(xians): Add support to set different options for different send
+  // streams after we support multiple APMs.
+
   // We retain all of the existing options, and apply the given ones
   // on top.  This means there is no way to "clear" options such that
   // they go back to the engine default.
@@ -1644,11 +1633,17 @@
 
 bool WebRtcVoiceMediaChannel::SetSendCodecs(
     const std::vector<AudioCodec>& codecs) {
+  // TODO(xians): Break down this function into SetSendCodecs(channel, codecs)
+  // to support per-channel codecs.
+
   // Disable DTMF, VAD, and FEC unless we know the other side wants them.
   dtmf_allowed_ = false;
-  engine()->voe()->codec()->SetVADStatus(voe_channel(), false);
-  engine()->voe()->rtp()->SetNACKStatus(voe_channel(), false, 0);
-  engine()->voe()->rtp()->SetFECStatus(voe_channel(), false);
+  for (ChannelMap::iterator iter = send_channels_.begin();
+       iter != send_channels_.end(); ++iter) {
+    engine()->voe()->codec()->SetVADStatus(iter->second.channel, false);
+    engine()->voe()->rtp()->SetNACKStatus(iter->second.channel, false, 0);
+    engine()->voe()->rtp()->SetFECStatus(iter->second.channel, false);
+  }
 
   // Scan through the list to figure out the codec to use for sending, along
   // with the proper configuration for VAD and DTMF.
@@ -1701,13 +1696,18 @@
       }
     }
 
-    // Find the DTMF telephone event "codec" and tell VoiceEngine about it.
+    // Find the DTMF telephone event "codec" and tell VoiceEngine channels
+    // about it.
     if (_stricmp(it->name.c_str(), "telephone-event") == 0 ||
         _stricmp(it->name.c_str(), "audio/telephone-event") == 0) {
-      if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType(
-          voe_channel(), it->id) == -1) {
-        LOG_RTCERR2(SetSendTelephoneEventPayloadType, voe_channel(), it->id);
-        return false;
+      for (ChannelMap::iterator iter = send_channels_.begin();
+           iter != send_channels_.end(); ++iter) {
+        if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType(
+                iter->second.channel, it->id) == -1) {
+          LOG_RTCERR2(SetSendTelephoneEventPayloadType,
+                      iter->second.channel, it->id);
+          return false;
+        }
       }
       dtmf_allowed_ = true;
     }
@@ -1732,28 +1732,35 @@
                           << " not supported.";
           continue;
       }
-      // The CN payload type for 8000 Hz clockrate is fixed at 13.
-      if (cn_freq != webrtc::kFreq8000Hz) {
-        if (engine()->voe()->codec()->SetSendCNPayloadType(voe_channel(),
-            it->id, cn_freq) == -1) {
-          LOG_RTCERR3(SetSendCNPayloadType, voe_channel(), it->id, cn_freq);
-          // TODO(ajm): This failure condition will be removed from VoE.
-          // Restore the return here when we update to a new enough webrtc.
-          //
-          // Not returning false because the SetSendCNPayloadType will fail if
-          // the channel is already sending.
-          // This can happen if the remote description is applied twice, for
-          // example in the case of ROAP on top of JSEP, where both side will
-          // send the offer.
+      // Loop through the existing send channels and set the CN payloadtype
+      // and the VAD status.
+      for (ChannelMap::iterator iter = send_channels_.begin();
+           iter != send_channels_.end(); ++iter) {
+        int channel = iter->second.channel;
+        // The CN payload type for 8000 Hz clockrate is fixed at 13.
+        if (cn_freq != webrtc::kFreq8000Hz) {
+          if (engine()->voe()->codec()->SetSendCNPayloadType(
+                  channel, it->id, cn_freq) == -1) {
+            LOG_RTCERR3(SetSendCNPayloadType, channel, it->id, cn_freq);
+            // TODO(ajm): This failure condition will be removed from VoE.
+            // Restore the return here when we update to a new enough webrtc.
+            //
+            // Not returning false because the SetSendCNPayloadType will fail if
+            // the channel is already sending.
+            // This can happen if the remote description is applied twice, for
+            // example in the case of ROAP on top of JSEP, where both side will
+            // send the offer.
+          }
         }
-      }
-      // Only turn on VAD if we have a CN payload type that matches the
-      // clockrate for the codec we are going to use.
-      if (it->clockrate == send_codec.plfreq) {
-        LOG(LS_INFO) << "Enabling VAD";
-        if (engine()->voe()->codec()->SetVADStatus(voe_channel(), true) == -1) {
-          LOG_RTCERR2(SetVADStatus, voe_channel(), true);
-          return false;
+
+        // Only turn on VAD if we have a CN payload type that matches the
+        // clockrate for the codec we are going to use.
+        if (it->clockrate == send_codec.plfreq) {
+          LOG(LS_INFO) << "Enabling VAD";
+          if (engine()->voe()->codec()->SetVADStatus(channel, true) == -1) {
+            LOG_RTCERR2(SetVADStatus, channel, true);
+            return false;
+          }
         }
       }
     }
@@ -1773,15 +1780,18 @@
         // Enable redundant encoding of the specified codec. Treat any
         // failure as a fatal internal error.
         LOG(LS_INFO) << "Enabling FEC";
-        if (engine()->voe()->rtp()->SetFECStatus(voe_channel(),
-                                                 true, it->id) == -1) {
-          LOG_RTCERR3(SetFECStatus, voe_channel(), true, it->id);
-          return false;
+        for (ChannelMap::iterator iter = send_channels_.begin();
+             iter != send_channels_.end(); ++iter) {
+          if (engine()->voe()->rtp()->SetFECStatus(iter->second.channel,
+                                                   true, it->id) == -1) {
+            LOG_RTCERR3(SetFECStatus, iter->second.channel, true, it->id);
+            return false;
+          }
         }
       } else {
         send_codec = voe_codec;
         nack_enabled_ = IsNackEnabled(*it);
-        SetNack(send_ssrc_, voe_channel(), nack_enabled_);
+        SetNack(send_channels_, nack_enabled_);
       }
       first = false;
       // Set the codec immediately, since SetVADStatus() depends on whether
@@ -1790,10 +1800,7 @@
         return false;
     }
   }
-  for (ChannelMap::iterator it = receive_channels_.begin();
-       it != receive_channels_.end(); ++it) {
-    SetNack(it->first, it->second.channel, nack_enabled_);
-  }
+  SetNack(receive_channels_, nack_enabled_);
 
 
   // If we're being asked to set an empty list of codecs, due to a buggy client,
@@ -1808,6 +1815,15 @@
 
   return true;
 }
+
+void WebRtcVoiceMediaChannel::SetNack(const ChannelMap& channels,
+                                      bool nack_enabled) {
+  for (ChannelMap::const_iterator it = channels.begin();
+       it != channels.end(); ++it) {
+    SetNack(it->first, it->second.channel, nack_enabled_);
+  }
+}
+
 void WebRtcVoiceMediaChannel::SetNack(uint32 ssrc, int channel,
                                       bool nack_enabled) {
   if (nack_enabled) {
@@ -1819,17 +1835,32 @@
   }
 }
 
-
 bool WebRtcVoiceMediaChannel::SetSendCodec(
     const webrtc::CodecInst& send_codec) {
   LOG(LS_INFO) << "Selected voice codec " << ToString(send_codec)
                << ", bitrate=" << send_codec.rate;
-  if (engine()->voe()->codec()->SetSendCodec(voe_channel(),
-                                             send_codec) == -1) {
-    LOG_RTCERR2(SetSendCodec, voe_channel(), ToString(send_codec));
+  for (ChannelMap::iterator iter = send_channels_.begin();
+       iter != send_channels_.end(); ++iter) {
+    if (!SetSendCodec(iter->second.channel, send_codec))
+      return false;
+  }
+
+  // All SetSendCodec calls were successful. Update the global state
+  // accordingly.
+  send_codec_.reset(new webrtc::CodecInst(send_codec));
+
+  return true;
+}
+
+bool WebRtcVoiceMediaChannel::SetSendCodec(
+    int channel, const webrtc::CodecInst& send_codec) {
+  LOG(LS_INFO) << "Send channel " << channel <<  " selected voice codec "
+               << ToString(send_codec) << ", bitrate=" << send_codec.rate;
+
+  if (engine()->voe()->codec()->SetSendCodec(channel, send_codec) == -1) {
+    LOG_RTCERR2(SetSendCodec, channel, ToString(send_codec));
     return false;
   }
-  send_codec_.reset(new webrtc::CodecInst(send_codec));
   return true;
 }
 
@@ -1862,10 +1893,14 @@
   }
 
   LOG(LS_INFO) << "Enabling audio level header extension with ID " << id;
-  if (engine()->voe()->rtp()->SetRTPAudioLevelIndicationStatus(
-      voe_channel(), enable, id) == -1) {
-    LOG_RTCERR3(SetRTPAudioLevelIndicationStatus, voe_channel(), enable, id);
-    return false;
+  for (ChannelMap::const_iterator iter = send_channels_.begin();
+       iter != send_channels_.end(); ++iter) {
+    if (engine()->voe()->rtp()->SetRTPAudioLevelIndicationStatus(
+            iter->second.channel, enable, id) == -1) {
+      LOG_RTCERR3(SetRTPAudioLevelIndicationStatus,
+                  iter->second.channel, enable, id);
+      return false;
+    }
   }
 
   return true;
@@ -1912,7 +1947,7 @@
 
 bool WebRtcVoiceMediaChannel::SetSend(SendFlags send) {
   desired_send_ = send;
-  if (send_ssrc_ != 0)
+  if (!send_channels_.empty())
     return ChangeSend(desired_send_);
   return true;
 }
@@ -1930,131 +1965,177 @@
     return true;
   }
 
-  if (send == SEND_MICROPHONE) {
+  // Change the settings on each send channel.
+  if (send == SEND_MICROPHONE)
     engine()->SetOptionOverrides(options_);
 
-    // VoiceEngine resets sequence number when StopSend is called. This
-    // sometimes causes libSRTP to complain about packets being
-    // replayed. To get around this we store the last sent sequence
-    // number and initializes the channel with the next to continue on
-    // the same sequence.
-    if (sequence_number() != -1) {
-      LOG(LS_INFO) << "WebRtcVoiceMediaChannel restores seqnum="
-                   << sequence_number() + 1;
-      if (engine()->voe()->sync()->SetInitSequenceNumber(
-              voe_channel(), sequence_number() + 1) == -1) {
-        LOG_RTCERR2(SetInitSequenceNumber, voe_channel(),
-                    sequence_number() + 1);
-      }
-    }
-    if (engine()->voe()->base()->StartSend(voe_channel()) == -1) {
-      LOG_RTCERR1(StartSend, voe_channel());
+  // Change the settings on each send channel.
+  for (ChannelMap::iterator iter = send_channels_.begin();
+       iter != send_channels_.end(); ++iter) {
+    if (!ChangeSend(iter->second.channel, send))
       return false;
-    }
-    // It's OK not to have file() here, since we don't need to call Stop if
-    // no file is playing.
-    if (engine()->voe()->file() &&
-        engine()->voe()->file()->StopPlayingFileAsMicrophone(
-            voe_channel()) == -1) {
-      LOG_RTCERR1(StopPlayingFileAsMicrophone, voe_channel());
-      return false;
-    }
-  } else if (send == SEND_RINGBACKTONE) {
-    ASSERT(ringback_tone_);
-    if (!ringback_tone_) {
-      return false;
-    }
-    if (engine()->voe()->file() &&
-        engine()->voe()->file()->StartPlayingFileAsMicrophone(
-        voe_channel(), ringback_tone_.get(), false) != -1) {
-      LOG(LS_INFO) << "File StartPlayingFileAsMicrophone Succeeded. channel:"
-                   << voe_channel();
-    } else {
-      LOG_RTCERR3(StartPlayingFileAsMicrophone, voe_channel(),
-                  ringback_tone_.get(), false);
-      return false;
-    }
-    // VoiceEngine resets sequence number when StopSend is called. This
-    // sometimes causes libSRTP to complain about packets being
-    // replayed. To get around this we store the last sent sequence
-    // number and initializes the channel with the next to continue on
-    // the same sequence.
-    if (sequence_number() != -1) {
-      LOG(LS_INFO) << "WebRtcVoiceMediaChannel restores seqnum="
-                   << sequence_number() + 1;
-      if (engine()->voe()->sync()->SetInitSequenceNumber(
-              voe_channel(), sequence_number() + 1) == -1) {
-        LOG_RTCERR2(SetInitSequenceNumber, voe_channel(),
-                    sequence_number() + 1);
-      }
-    }
-    if (engine()->voe()->base()->StartSend(voe_channel()) == -1) {
-      LOG_RTCERR1(StartSend, voe_channel());
-      return false;
-    }
-  } else {  // SEND_NOTHING
-    if (engine()->voe()->base()->StopSend(voe_channel()) == -1) {
-      LOG_RTCERR1(StopSend, voe_channel());
-    }
-
-    engine()->ClearOptionOverrides();
   }
+
+  // Clear up the options after stopping sending.
+  if (send == SEND_NOTHING)
+    engine()->ClearOptionOverrides();
+
   send_ = send;
   return true;
 }
 
-bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
-  if (send_ssrc_ != 0) {
-    LOG(LS_ERROR) << "WebRtcVoiceMediaChannel supports one sending channel.";
-    return false;
-  }
-
-  if (engine()->voe()->rtp()->SetLocalSSRC(voe_channel(), sp.first_ssrc())
-        == -1) {
-    LOG_RTCERR2(SetSendSSRC, voe_channel(), sp.first_ssrc());
-    return false;
-  }
-  // Set the SSRC on the receive channels.
-  // Receive channels have to have the same SSRC in order to send receiver
-  // reports with this SSRC.
-  for (ChannelMap::const_iterator it = receive_channels_.begin();
-       it != receive_channels_.end(); ++it) {
-    int channel_id = it->second.channel;
-    if (channel_id != voe_channel()) {
-      if (engine()->voe()->rtp()->SetLocalSSRC(channel_id,
-                                               sp.first_ssrc()) != 0) {
-        LOG_RTCERR1(SetLocalSSRC, it->first);
-        return false;
-      }
+bool WebRtcVoiceMediaChannel::ChangeSend(int channel, SendFlags send) {
+  if (send == SEND_MICROPHONE) {
+    if (engine()->voe()->base()->StartSend(channel) == -1) {
+      LOG_RTCERR1(StartSend, channel);
+      return false;
+    }
+    if (engine()->voe()->file() &&
+        engine()->voe()->file()->StopPlayingFileAsMicrophone(channel) == -1) {
+      LOG_RTCERR1(StopPlayingFileAsMicrophone, channel);
+      return false;
+    }
+  } else {  // SEND_NOTHING
+    ASSERT(send == SEND_NOTHING);
+    if (engine()->voe()->base()->StopSend(channel) == -1) {
+      LOG_RTCERR1(StopSend, channel);
+      return false;
     }
   }
 
-  if (engine()->voe()->rtp()->SetRTCP_CNAME(voe_channel(),
-                                            sp.cname.c_str()) == -1) {
-     LOG_RTCERR2(SetRTCP_CNAME, voe_channel(), sp.cname);
-     return false;
-  }
-
-  send_ssrc_ = sp.first_ssrc();
-  if (desired_send_ != send_)
-    return ChangeSend(desired_send_);
-
-  if (local_renderer_)
-    local_renderer_->AddChannel(voe_channel());
-
   return true;
 }
 
-bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
-  if (ssrc != send_ssrc_) {
+void WebRtcVoiceMediaChannel::ConfigureSendChannel(int channel) {
+  if (engine()->voe()->network()->RegisterExternalTransport(
+          channel, *this) == -1) {
+    LOG_RTCERR2(RegisterExternalTransport, channel, this);
+  }
+
+  // Enable RTCP (for quality stats and feedback messages)
+  EnableRtcp(channel);
+
+  // Reset all recv codecs; they will be enabled via SetRecvCodecs.
+  ResetRecvCodecs(channel);
+}
+
+bool WebRtcVoiceMediaChannel::DeleteChannel(int channel) {
+  if (engine()->voe()->network()->DeRegisterExternalTransport(channel) == -1) {
+    LOG_RTCERR1(DeRegisterExternalTransport, channel);
+  }
+
+  if (engine()->voe()->base()->DeleteChannel(channel) == -1) {
+    LOG_RTCERR1(DeleteChannel, channel);
     return false;
   }
 
-  if (local_renderer_)
-    local_renderer_->RemoveChannel(voe_channel());
+  return true;
+}
 
-  send_ssrc_ = 0;
-  ChangeSend(SEND_NOTHING);
+bool WebRtcVoiceMediaChannel::AddSendStream(const StreamParams& sp) {
+  // If the default channel is already used for sending create a new channel
+  // otherwise use the default channel for sending.
+  int channel = GetSendChannelNum(sp.first_ssrc());
+  if (channel != -1) {
+    LOG(LS_ERROR) << "Stream already exists with ssrc " << sp.first_ssrc();
+    return false;
+  }
+
+  bool default_channel_is_available = true;
+  for (ChannelMap::const_iterator iter = send_channels_.begin();
+       iter != send_channels_.end(); ++iter) {
+    if (IsDefaultChannel(iter->second.channel)) {
+      default_channel_is_available = false;
+      break;
+    }
+  }
+  if (default_channel_is_available) {
+    channel = voe_channel();
+  } else {
+    // Create a new channel for sending audio data.
+    channel = engine()->voe()->base()->CreateChannel();
+    if (channel == -1) {
+      LOG_RTCERR0(CreateChannel);
+      return false;
+    }
+
+    ConfigureSendChannel(channel);
+  }
+
+  // Save the channel to send_channels_, so that RemoveSendStream() can still
+  // delete the channel in case failure happens below.
+  send_channels_[sp.first_ssrc()] = WebRtcVoiceChannelInfo(channel, NULL);
+
+  // Set the send (local) SSRC.
+  // If there are multiple send SSRCs, we can only set the first one here, and
+  // the rest of the SSRC(s) need to be set after SetSendCodec has been called
+  // (with a codec requires multiple SSRC(s)).
+  if (engine()->voe()->rtp()->SetLocalSSRC(channel, sp.first_ssrc()) == -1) {
+    LOG_RTCERR2(SetSendSSRC, channel, sp.first_ssrc());
+    return false;
+  }
+
+  // At this point the channel's local SSRC has been updated. If the channel is
+  // the default channel make sure that all the receive channels are updated as
+  // well. Receive channels have to have the same SSRC as the default channel in
+  // order to send receiver reports with this SSRC.
+  if (IsDefaultChannel(channel)) {
+    for (ChannelMap::const_iterator it = receive_channels_.begin();
+         it != receive_channels_.end(); ++it) {
+      // Only update the SSRC for non-default channels.
+      if (!IsDefaultChannel(it->second.channel)) {
+        if (engine()->voe()->rtp()->SetLocalSSRC(it->second.channel,
+                                                 sp.first_ssrc()) != 0) {
+          LOG_RTCERR2(SetLocalSSRC, it->second.channel, sp.first_ssrc());
+          return false;
+        }
+      }
+    }
+  }
+
+  if (engine()->voe()->rtp()->SetRTCP_CNAME(channel, sp.cname.c_str()) == -1) {
+     LOG_RTCERR2(SetRTCP_CNAME, channel, sp.cname);
+     return false;
+  }
+
+  // Set the current codec to be used for the new channel.
+  if (send_codec_ && !SetSendCodec(channel, *send_codec_))
+    return false;
+
+  return ChangeSend(channel, desired_send_);
+}
+
+bool WebRtcVoiceMediaChannel::RemoveSendStream(uint32 ssrc) {
+  ChannelMap::iterator it = send_channels_.find(ssrc);
+  if (it == send_channels_.end()) {
+    LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
+                    << " which doesn't exist.";
+    return false;
+  }
+
+  int channel = it->second.channel;
+  ChangeSend(channel, SEND_NOTHING);
+
+  // Notify the audio renderer that the send channel is going away.
+  if (it->second.renderer)
+    it->second.renderer->RemoveChannel(channel);
+
+  if (IsDefaultChannel(channel)) {
+    // Do not delete the default channel since the receive channels depend on
+    // the default channel, recycle it instead.
+    ChangeSend(channel, SEND_NOTHING);
+  } else {
+    // Clean up and delete the send channel.
+    LOG(LS_INFO) << "Removing audio send stream " << ssrc
+                 << " with VoiceEngine channel #" << channel << ".";
+    if (!DeleteChannel(channel))
+      return false;
+  }
+
+  send_channels_.erase(it);
+  if (send_channels_.empty())
+    ChangeSend(SEND_NOTHING);
+
   return true;
 }
 
@@ -2157,11 +2238,14 @@
 bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32 ssrc) {
   talk_base::CritScope lock(&receive_channels_cs_);
   ChannelMap::iterator it = receive_channels_.find(ssrc);
-  if (it == receive_channels_.end())
+  if (it == receive_channels_.end()) {
+    LOG(LS_WARNING) << "Try to remove stream with ssrc " << ssrc
+                    << " which doesn't exist.";
     return false;
+  }
 
   if (ssrc == default_receive_ssrc_) {
-    ASSERT(voe_channel() == it->second.channel);
+    ASSERT(IsDefaultChannel(it->second.channel));
     // Recycle the default channel is for recv stream.
     if (playout_)
       SetPlayout(voe_channel(), false);
@@ -2179,16 +2263,9 @@
   if (it->second.renderer)
     it->second.renderer->RemoveChannel(it->second.channel);
 
-  if (engine()->voe()->network()->DeRegisterExternalTransport(
-          it->second.channel) == -1) {
-    LOG_RTCERR1(DeRegisterExternalTransport, it->second.channel);
-  }
-
   LOG(LS_INFO) << "Removing audio stream " << ssrc
-               << " with VoiceEngine channel #"
-               << it->second.channel << ".";
-  if (engine()->voe()->base()->DeleteChannel(it->second.channel) == -1) {
-    LOG_RTCERR1(DeleteChannel, voe_channel());
+               << " with VoiceEngine channel #" << it->second.channel << ".";
+  if (!DeleteChannel(it->second.channel)) {
     // Erase the entry anyhow.
     receive_channels_.erase(it);
     return false;
@@ -2224,7 +2301,7 @@
   if (it == receive_channels_.end()) {
     if (renderer) {
       // Return an error if trying to set a valid renderer with an invalid ssrc.
-      LOG_RTCERR1(SetRemoteRenderer, ssrc);
+      LOG(LS_ERROR) << "SetRemoteRenderer failed with ssrc "<< ssrc;
       return false;
     }
 
@@ -2232,43 +2309,47 @@
     return true;
   }
 
+  AudioRenderer* remote_renderer = it->second.renderer;
   if (renderer) {
-    ASSERT(it->second.renderer == NULL || it->second.renderer == renderer);
-    if (!it->second.renderer) {
+    ASSERT(remote_renderer == NULL || remote_renderer == renderer);
+    if (!remote_renderer) {
       renderer->AddChannel(it->second.channel);
     }
-  } else if (it->second.renderer) {
+  } else if (remote_renderer) {
     // |renderer| == NULL, remove the channel from the renderer.
-    it->second.renderer->RemoveChannel(it->second.channel);
+    remote_renderer->RemoveChannel(it->second.channel);
   }
 
+  // Assign the new value to the struct.
   it->second.renderer = renderer;
   return true;
 }
 
 bool WebRtcVoiceMediaChannel::SetLocalRenderer(uint32 ssrc,
                                                AudioRenderer* renderer) {
-  if (!renderer && !local_renderer_)
+  ChannelMap::iterator it = send_channels_.find(ssrc);
+  if (it == send_channels_.end()) {
+    if (renderer) {
+      // Return an error if trying to set a valid renderer with an invalid ssrc.
+      LOG(LS_ERROR) << "SetLocalRenderer failed with ssrc "<< ssrc;
+      return false;
+    }
+
+    // The channel likely has gone away, do nothing.
     return true;
-
-  int channel = GetSendChannelNum(ssrc);
-  if (channel == -1) {
-    // Invalidate the |local_renderer_| before quitting.
-    if (!renderer)
-      local_renderer_ = NULL;
-
-    return false;
   }
 
+  AudioRenderer* local_renderer = it->second.renderer;
   if (renderer) {
-    ASSERT(local_renderer_ == NULL || local_renderer_ == renderer);
-    if (!local_renderer_)
-      renderer->AddChannel(channel);
-  } else {
-    local_renderer_->RemoveChannel(channel);
+    ASSERT(local_renderer == NULL || local_renderer == renderer);
+    if (!local_renderer)
+      renderer->AddChannel(it->second.channel);
+  } else if (local_renderer) {
+    local_renderer->RemoveChannel(it->second.channel);
   }
 
-  local_renderer_ = renderer;
+  // Assign the new value to the struct.
+  it->second.renderer = renderer;
   return true;
 }
 
@@ -2466,15 +2547,16 @@
 
   // Send the event.
   if (flags & cricket::DF_SEND) {
-    if (send_ssrc_ != ssrc && ssrc != 0) {
+    int channel = (ssrc == 0) ? voe_channel() : GetSendChannelNum(ssrc);
+    if (channel == -1) {
       LOG(LS_WARNING) << "InsertDtmf - The specified ssrc "
                       << ssrc << " is not in use.";
       return false;
     }
     // Send DTMF using out-of-band DTMF. ("true", as 3rd arg)
-    if (engine()->voe()->dtmf()->SendTelephoneEvent(voe_channel(),
-        event, true, duration) == -1) {
-      LOG_RTCERR4(SendTelephoneEvent, voe_channel(), event, true, duration);
+    if (engine()->voe()->dtmf()->SendTelephoneEvent(
+            channel, event, true, duration) == -1) {
+      LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration);
       return false;
     }
   }
@@ -2525,27 +2607,56 @@
 }
 
 void WebRtcVoiceMediaChannel::OnRtcpReceived(talk_base::Buffer* packet) {
-  // See above.
-  int which_channel = GetReceiveChannelNum(
-      ParseSsrc(packet->data(), packet->length(), true));
-  if (which_channel == -1) {
-    which_channel = voe_channel();
+  // Sending channels need all RTCP packets with feedback information.
+  // Even sender reports can contain attached report blocks.
+  // Receiving channels need sender reports in order to create
+  // correct receiver reports.
+  int type = 0;
+  if (!GetRtcpType(packet->data(), packet->length(), &type)) {
+    LOG(LS_WARNING) << "Failed to parse type from received RTCP packet";
+    return;
   }
 
-  engine()->voe()->network()->ReceivedRTCPPacket(
-      which_channel,
-      packet->data(),
-      static_cast<unsigned int>(packet->length()));
+  // If it is a sender report, find the channel that is listening.
+  bool has_sent_to_default_channel = false;
+  if (type == kRtcpTypeSR) {
+    int which_channel = GetReceiveChannelNum(
+        ParseSsrc(packet->data(), packet->length(), true));
+    if (which_channel != -1) {
+      engine()->voe()->network()->ReceivedRTCPPacket(
+          which_channel,
+          packet->data(),
+          static_cast<unsigned int>(packet->length()));
+
+      if (IsDefaultChannel(which_channel))
+        has_sent_to_default_channel = true;
+    }
+  }
+
+  // SR may continue RR and any RR entry may correspond to any one of the send
+  // channels. So all RTCP packets must be forwarded all send channels. VoE
+  // will filter out RR internally.
+  for (ChannelMap::iterator iter = send_channels_.begin();
+       iter != send_channels_.end(); ++iter) {
+    // Make sure not sending the same packet to default channel more than once.
+    if (IsDefaultChannel(iter->second.channel) && has_sent_to_default_channel)
+      continue;
+
+    engine()->voe()->network()->ReceivedRTCPPacket(
+        iter->second.channel,
+        packet->data(),
+        static_cast<unsigned int>(packet->length()));
+  }
 }
 
 bool WebRtcVoiceMediaChannel::MuteStream(uint32 ssrc, bool muted) {
-  if (send_ssrc_ != ssrc && ssrc != 0) {
+  int channel = (ssrc == 0) ? voe_channel() : GetSendChannelNum(ssrc);
+  if (channel == -1) {
     LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
     return false;
   }
-  if (engine()->voe()->volume()->SetInputMute(voe_channel(),
-      muted) == -1) {
-    LOG_RTCERR2(SetInputMute, voe_channel(), muted);
+  if (engine()->voe()->volume()->SetInputMute(channel, muted) == -1) {
+    LOG_RTCERR2(SetInputMute, channel, muted);
     return false;
   }
   return true;
@@ -2590,96 +2701,106 @@
 }
 
 bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
-  // In VoiceEngine 3.5, GetRTCPStatistics will return 0 even when it fails,
-  // causing the stats to contain garbage information. To prevent this, we
-  // zero the stats structure before calling this API.
-  // TODO(juberti): Remove this workaround.
+  bool echo_metrics_on = false;
+  // These can take on valid negative values, so use the lowest possible level
+  // as default rather than -1.
+  int echo_return_loss = -100;
+  int echo_return_loss_enhancement = -100;
+  // These can also be negative, but in practice -1 is only used to signal
+  // insufficient data, since the resolution is limited to multiples of 4 ms.
+  int echo_delay_median_ms = -1;
+  int echo_delay_std_ms = -1;
+  if (engine()->voe()->processing()->GetEcMetricsStatus(
+          echo_metrics_on) != -1 && echo_metrics_on) {
+    // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
+    // here, but it appears to be unsuitable currently. Revisit after this is
+    // investigated: http://b/issue?id=5666755
+    int erl, erle, rerl, anlp;
+    if (engine()->voe()->processing()->GetEchoMetrics(
+            erl, erle, rerl, anlp) != -1) {
+      echo_return_loss = erl;
+      echo_return_loss_enhancement = erle;
+    }
+
+    int median, std;
+    if (engine()->voe()->processing()->GetEcDelayMetrics(median, std) != -1) {
+      echo_delay_median_ms = median;
+      echo_delay_std_ms = std;
+    }
+  }
+
+
   webrtc::CallStatistics cs;
   unsigned int ssrc;
   webrtc::CodecInst codec;
   unsigned int level;
 
-  // Fill in the sender info, based on what we know, and what the
-  // remote side told us it got from its RTCP report.
-  VoiceSenderInfo sinfo;
+  for (ChannelMap::const_iterator channel_iter = send_channels_.begin();
+       channel_iter != send_channels_.end(); ++channel_iter) {
+    const int channel = channel_iter->second.channel;
 
-  // Data we obtain locally.
-  memset(&cs, 0, sizeof(cs));
-  if (engine()->voe()->rtp()->GetRTCPStatistics(voe_channel(), cs) == -1 ||
-      engine()->voe()->rtp()->GetLocalSSRC(voe_channel(), ssrc) == -1) {
-    return false;
-  }
+    // Fill in the sender info, based on what we know, and what the
+    // remote side told us it got from its RTCP report.
+    VoiceSenderInfo sinfo;
 
-  sinfo.ssrc = ssrc;
-  sinfo.codec_name = send_codec_.get() ? send_codec_->plname : "";
-  sinfo.bytes_sent = cs.bytesSent;
-  sinfo.packets_sent = cs.packetsSent;
-  // RTT isn't known until a RTCP report is received. Until then, VoiceEngine
-  // returns 0 to indicate an error value.
-  sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1;
+    if (engine()->voe()->rtp()->GetRTCPStatistics(channel, cs) == -1 ||
+        engine()->voe()->rtp()->GetLocalSSRC(channel, ssrc) == -1) {
+      continue;
+    }
 
-  // Get data from the last remote RTCP report. Use default values if no data
-  // available.
-  sinfo.fraction_lost = -1.0;
-  sinfo.jitter_ms = -1;
-  sinfo.packets_lost = -1;
-  sinfo.ext_seqnum = -1;
-  std::vector<webrtc::ReportBlock> receive_blocks;
-  if (engine()->voe()->rtp()->GetRemoteRTCPReportBlocks(
-      voe_channel(), &receive_blocks) != -1 &&
-      engine()->voe()->codec()->GetSendCodec(voe_channel(),
-          codec) != -1) {
-    std::vector<webrtc::ReportBlock>::iterator iter;
-    for (iter = receive_blocks.begin(); iter != receive_blocks.end(); ++iter) {
-      // Lookup report for send ssrc only.
-      if (iter->source_SSRC == sinfo.ssrc) {
-        // Convert Q8 to floating point.
-        sinfo.fraction_lost = static_cast<float>(iter->fraction_lost) / 256;
-        // Convert samples to milliseconds.
-        if (codec.plfreq / 1000 > 0) {
-          sinfo.jitter_ms = iter->interarrival_jitter / (codec.plfreq / 1000);
+    sinfo.ssrc = ssrc;
+    sinfo.codec_name = send_codec_.get() ? send_codec_->plname : "";
+    sinfo.bytes_sent = cs.bytesSent;
+    sinfo.packets_sent = cs.packetsSent;
+    // RTT isn't known until a RTCP report is received. Until then, VoiceEngine
+    // returns 0 to indicate an error value.
+    sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1;
+
+    // Get data from the last remote RTCP report. Use default values if no data
+    // available.
+    sinfo.fraction_lost = -1.0;
+    sinfo.jitter_ms = -1;
+    sinfo.packets_lost = -1;
+    sinfo.ext_seqnum = -1;
+    std::vector<webrtc::ReportBlock> receive_blocks;
+    if (engine()->voe()->rtp()->GetRemoteRTCPReportBlocks(
+            channel, &receive_blocks) != -1 &&
+        engine()->voe()->codec()->GetSendCodec(channel, codec) != -1) {
+      std::vector<webrtc::ReportBlock>::iterator iter;
+      for (iter = receive_blocks.begin(); iter != receive_blocks.end();
+           ++iter) {
+        // Lookup report for send ssrc only.
+        if (iter->source_SSRC == sinfo.ssrc) {
+          // Convert Q8 to floating point.
+          sinfo.fraction_lost = static_cast<float>(iter->fraction_lost) / 256;
+          // Convert samples to milliseconds.
+          if (codec.plfreq / 1000 > 0) {
+            sinfo.jitter_ms = iter->interarrival_jitter / (codec.plfreq / 1000);
+          }
+          sinfo.packets_lost = iter->cumulative_num_packets_lost;
+          sinfo.ext_seqnum = iter->extended_highest_sequence_number;
+          break;
         }
-        sinfo.packets_lost = iter->cumulative_num_packets_lost;
-        sinfo.ext_seqnum = iter->extended_highest_sequence_number;
-        break;
       }
     }
+
+    // Local speech level.
+    sinfo.audio_level = (engine()->voe()->volume()->
+        GetSpeechInputLevelFullRange(level) != -1) ? level : -1;
+
+    // TODO(xians): We are injecting the same APM logging to all the send
+    // channels here because there is no good way to know which send channel
+    // is using the APM. The correct fix is to allow the send channels to have
+    // their own APM so that we can feed the correct APM logging to different
+    // send channels. See issue crbug/264611 .
+    sinfo.echo_return_loss = echo_return_loss;
+    sinfo.echo_return_loss_enhancement = echo_return_loss_enhancement;
+    sinfo.echo_delay_median_ms = echo_delay_median_ms;
+    sinfo.echo_delay_std_ms = echo_delay_std_ms;
+
+    info->senders.push_back(sinfo);
   }
 
-  // Local speech level.
-  sinfo.audio_level = (engine()->voe()->volume()->
-      GetSpeechInputLevelFullRange(level) != -1) ? level : -1;
-
-  bool echo_metrics_on = false;
-  // These can take on valid negative values, so use the lowest possible level
-  // as default rather than -1.
-  sinfo.echo_return_loss = -100;
-  sinfo.echo_return_loss_enhancement = -100;
-  // These can also be negative, but in practice -1 is only used to signal
-  // insufficient data, since the resolution is limited to multiples of 4 ms.
-  sinfo.echo_delay_median_ms = -1;
-  sinfo.echo_delay_std_ms = -1;
-  if (engine()->voe()->processing()->GetEcMetricsStatus(echo_metrics_on) !=
-      -1 && echo_metrics_on) {
-    // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
-    // here, but it appears to be unsuitable currently. Revisit after this is
-    // investigated: http://b/issue?id=5666755
-    int erl, erle, rerl, anlp;
-    if (engine()->voe()->processing()->GetEchoMetrics(erl, erle, rerl, anlp) !=
-        -1) {
-      sinfo.echo_return_loss = erl;
-      sinfo.echo_return_loss_enhancement = erle;
-    }
-
-    int median, std;
-    if (engine()->voe()->processing()->GetEcDelayMetrics(median, std) != -1) {
-      sinfo.echo_delay_median_ms = median;
-      sinfo.echo_delay_std_ms = std;
-    }
-  }
-
-  info->senders.push_back(sinfo);
-
   // Build the list of receivers, one for each receiving channel, or 1 in
   // a 1:1 call.
   std::vector<int> channels;
@@ -2749,15 +2870,7 @@
 bool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
   talk_base::CritScope lock(&receive_channels_cs_);
   ASSERT(ssrc != NULL);
-  if (channel_num == voe_channel()) {
-    unsigned local_ssrc = 0;
-    // This is a sending channel.
-    if (engine()->voe()->rtp()->GetLocalSSRC(
-        channel_num, local_ssrc) != -1) {
-      *ssrc = local_ssrc;
-    }
-    return true;
-  } else if (channel_num == -1 && send_ != SEND_NOTHING) {
+  if (channel_num == -1 && send_ != SEND_NOTHING) {
     // Sometimes the VoiceEngine core will throw error with channel_num = -1.
     // This means the error is not limited to a specific channel.  Signal the
     // message using ssrc=0.  If the current channel is sending, use this
@@ -2765,6 +2878,20 @@
     *ssrc = 0;
     return true;
   } else {
+    // Check whether this is a sending channel.
+    for (ChannelMap::const_iterator it = send_channels_.begin();
+         it != send_channels_.end(); ++it) {
+      if (it->second.channel == channel_num) {
+        // This is a sending channel.
+        uint32 local_ssrc = 0;
+        if (engine()->voe()->rtp()->GetLocalSSRC(
+                channel_num, local_ssrc) != -1) {
+          *ssrc = local_ssrc;
+        }
+        return true;
+      }
+    }
+
     // Check whether this is a receiving channel.
     for (ChannelMap::const_iterator it = receive_channels_.begin();
         it != receive_channels_.end(); ++it) {
@@ -2796,7 +2923,11 @@
 }
 
 int WebRtcVoiceMediaChannel::GetSendChannelNum(uint32 ssrc) {
-  return (ssrc == send_ssrc_) ?  voe_channel() : -1;
+  ChannelMap::iterator it = send_channels_.find(ssrc);
+  if (it != send_channels_.end())
+    return it->second.channel;
+
+  return -1;
 }
 
 bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec,
@@ -2848,7 +2979,7 @@
 
 bool WebRtcVoiceMediaChannel::EnableRtcp(int channel) {
   if (engine()->voe()->rtp()->SetRTCPStatus(channel, true) == -1) {
-    LOG_RTCERR2(SetRTCPStatus, voe_channel(), 1);
+    LOG_RTCERR2(SetRTCPStatus, channel, 1);
     return false;
   }
   // TODO(juberti): Enable VQMon and RTCP XR reports, once we know what