| /* | 
 |  *  Copyright 2017 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "pc/rtptransceiver.h" | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "pc/rtpmediautils.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | RtpTransceiver::RtpTransceiver(cricket::MediaType media_type) | 
 |     : unified_plan_(false), media_type_(media_type) { | 
 |   RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO || | 
 |              media_type == cricket::MEDIA_TYPE_VIDEO); | 
 | } | 
 |  | 
 | RtpTransceiver::RtpTransceiver( | 
 |     rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender, | 
 |     rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> | 
 |         receiver) | 
 |     : unified_plan_(true), media_type_(sender->media_type()) { | 
 |   RTC_DCHECK(media_type_ == cricket::MEDIA_TYPE_AUDIO || | 
 |              media_type_ == cricket::MEDIA_TYPE_VIDEO); | 
 |   RTC_DCHECK_EQ(sender->media_type(), receiver->media_type()); | 
 |   senders_.push_back(sender); | 
 |   receivers_.push_back(receiver); | 
 | } | 
 |  | 
 | RtpTransceiver::~RtpTransceiver() { | 
 |   Stop(); | 
 | } | 
 |  | 
 | void RtpTransceiver::SetChannel(cricket::BaseChannel* channel) { | 
 |   if (channel) { | 
 |     RTC_DCHECK_EQ(media_type(), channel->media_type()); | 
 |   } | 
 |  | 
 |   if (channel_) { | 
 |     channel_->SignalFirstPacketReceived.disconnect(this); | 
 |   } | 
 |  | 
 |   channel_ = channel; | 
 |  | 
 |   if (channel_) { | 
 |     channel_->SignalFirstPacketReceived.connect( | 
 |         this, &RtpTransceiver::OnFirstPacketReceived); | 
 |   } | 
 |  | 
 |   for (auto sender : senders_) { | 
 |     if (media_type() == cricket::MEDIA_TYPE_AUDIO) { | 
 |       auto* voice_channel = static_cast<cricket::VoiceChannel*>(channel); | 
 |       sender->internal()->SetVoiceMediaChannel( | 
 |           voice_channel ? voice_channel->media_channel() : nullptr); | 
 |     } else { | 
 |       auto* video_channel = static_cast<cricket::VideoChannel*>(channel); | 
 |       sender->internal()->SetVideoMediaChannel( | 
 |           video_channel ? video_channel->media_channel() : nullptr); | 
 |     } | 
 |   } | 
 |  | 
 |   for (auto receiver : receivers_) { | 
 |     if (!channel) { | 
 |       receiver->internal()->Stop(); | 
 |     } | 
 |     if (media_type() == cricket::MEDIA_TYPE_AUDIO) { | 
 |       auto* voice_channel = static_cast<cricket::VoiceChannel*>(channel); | 
 |       receiver->internal()->SetVoiceMediaChannel( | 
 |           voice_channel ? voice_channel->media_channel() : nullptr); | 
 |     } else { | 
 |       auto* video_channel = static_cast<cricket::VideoChannel*>(channel); | 
 |       receiver->internal()->SetVideoMediaChannel( | 
 |           video_channel ? video_channel->media_channel() : nullptr); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void RtpTransceiver::AddSender( | 
 |     rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> sender) { | 
 |   RTC_DCHECK(!unified_plan_); | 
 |   RTC_DCHECK(sender); | 
 |   RTC_DCHECK_EQ(media_type(), sender->media_type()); | 
 |   RTC_DCHECK(std::find(senders_.begin(), senders_.end(), sender) == | 
 |              senders_.end()); | 
 |   senders_.push_back(sender); | 
 | } | 
 |  | 
 | bool RtpTransceiver::RemoveSender(RtpSenderInterface* sender) { | 
 |   RTC_DCHECK(!unified_plan_); | 
 |   if (sender) { | 
 |     RTC_DCHECK_EQ(media_type(), sender->media_type()); | 
 |   } | 
 |   auto it = std::find(senders_.begin(), senders_.end(), sender); | 
 |   if (it == senders_.end()) { | 
 |     return false; | 
 |   } | 
 |   (*it)->internal()->Stop(); | 
 |   senders_.erase(it); | 
 |   return true; | 
 | } | 
 |  | 
 | void RtpTransceiver::AddReceiver( | 
 |     rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>> | 
 |         receiver) { | 
 |   RTC_DCHECK(!unified_plan_); | 
 |   RTC_DCHECK(receiver); | 
 |   RTC_DCHECK_EQ(media_type(), receiver->media_type()); | 
 |   RTC_DCHECK(std::find(receivers_.begin(), receivers_.end(), receiver) == | 
 |              receivers_.end()); | 
 |   receivers_.push_back(receiver); | 
 | } | 
 |  | 
 | bool RtpTransceiver::RemoveReceiver(RtpReceiverInterface* receiver) { | 
 |   RTC_DCHECK(!unified_plan_); | 
 |   if (receiver) { | 
 |     RTC_DCHECK_EQ(media_type(), receiver->media_type()); | 
 |   } | 
 |   auto it = std::find(receivers_.begin(), receivers_.end(), receiver); | 
 |   if (it == receivers_.end()) { | 
 |     return false; | 
 |   } | 
 |   (*it)->internal()->Stop(); | 
 |   receivers_.erase(it); | 
 |   return true; | 
 | } | 
 |  | 
 | rtc::scoped_refptr<RtpSenderInternal> RtpTransceiver::sender_internal() const { | 
 |   RTC_DCHECK(unified_plan_); | 
 |   RTC_CHECK_EQ(1u, senders_.size()); | 
 |   return senders_[0]->internal(); | 
 | } | 
 |  | 
 | rtc::scoped_refptr<RtpReceiverInternal> RtpTransceiver::receiver_internal() | 
 |     const { | 
 |   RTC_DCHECK(unified_plan_); | 
 |   RTC_CHECK_EQ(1u, receivers_.size()); | 
 |   return receivers_[0]->internal(); | 
 | } | 
 |  | 
 | cricket::MediaType RtpTransceiver::media_type() const { | 
 |   return media_type_; | 
 | } | 
 |  | 
 | absl::optional<std::string> RtpTransceiver::mid() const { | 
 |   return mid_; | 
 | } | 
 |  | 
 | void RtpTransceiver::OnFirstPacketReceived(cricket::BaseChannel* channel) { | 
 |   for (auto receiver : receivers_) { | 
 |     receiver->internal()->NotifyFirstPacketReceived(); | 
 |   } | 
 | } | 
 |  | 
 | rtc::scoped_refptr<RtpSenderInterface> RtpTransceiver::sender() const { | 
 |   RTC_DCHECK(unified_plan_); | 
 |   RTC_CHECK_EQ(1u, senders_.size()); | 
 |   return senders_[0]; | 
 | } | 
 |  | 
 | rtc::scoped_refptr<RtpReceiverInterface> RtpTransceiver::receiver() const { | 
 |   RTC_DCHECK(unified_plan_); | 
 |   RTC_CHECK_EQ(1u, receivers_.size()); | 
 |   return receivers_[0]; | 
 | } | 
 |  | 
 | void RtpTransceiver::set_current_direction(RtpTransceiverDirection direction) { | 
 |   RTC_LOG(LS_INFO) << "Changing transceiver (MID=" << mid_.value_or("<not set>") | 
 |                    << ") current direction from " | 
 |                    << (current_direction_ ? RtpTransceiverDirectionToString( | 
 |                                                 *current_direction_) | 
 |                                           : "<not set>") | 
 |                    << " to " << RtpTransceiverDirectionToString(direction) | 
 |                    << "."; | 
 |   current_direction_ = direction; | 
 |   if (RtpTransceiverDirectionHasSend(*current_direction_)) { | 
 |     has_ever_been_used_to_send_ = true; | 
 |   } | 
 | } | 
 |  | 
 | bool RtpTransceiver::stopped() const { | 
 |   return stopped_; | 
 | } | 
 |  | 
 | RtpTransceiverDirection RtpTransceiver::direction() const { | 
 |   return direction_; | 
 | } | 
 |  | 
 | void RtpTransceiver::SetDirection(RtpTransceiverDirection new_direction) { | 
 |   if (stopped()) { | 
 |     return; | 
 |   } | 
 |   if (new_direction == direction_) { | 
 |     return; | 
 |   } | 
 |   direction_ = new_direction; | 
 |   SignalNegotiationNeeded(); | 
 | } | 
 |  | 
 | absl::optional<RtpTransceiverDirection> RtpTransceiver::current_direction() | 
 |     const { | 
 |   return current_direction_; | 
 | } | 
 |  | 
 | void RtpTransceiver::Stop() { | 
 |   for (auto sender : senders_) { | 
 |     sender->internal()->Stop(); | 
 |   } | 
 |   for (auto receiver : receivers_) { | 
 |     receiver->internal()->Stop(); | 
 |   } | 
 |   stopped_ = true; | 
 |   current_direction_ = absl::nullopt; | 
 | } | 
 |  | 
 | void RtpTransceiver::SetCodecPreferences( | 
 |     rtc::ArrayView<RtpCodecCapability> codecs) { | 
 |   // TODO(steveanton): Implement this. | 
 |   RTC_NOTREACHED() << "Not implemented"; | 
 | } | 
 |  | 
 | }  // namespace webrtc |