diff --git a/api/BUILD.gn b/api/BUILD.gn index 69e09db638..606e9d9917 100644 --- a/api/BUILD.gn +++ b/api/BUILD.gn @@ -61,6 +61,7 @@ rtc_static_library("libjingle_peerconnection_api") { "rtpparameters.h", "rtpreceiverinterface.h", "rtpsenderinterface.h", + "rtptransceiverinterface.h", "statstypes.cc", "statstypes.h", "turncustomizer.h", diff --git a/api/rtptransceiverinterface.h b/api/rtptransceiverinterface.h new file mode 100644 index 0000000000..3eb246a0cf --- /dev/null +++ b/api/rtptransceiverinterface.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#ifndef API_RTPTRANSCEIVERINTERFACE_H_ +#define API_RTPTRANSCEIVERINTERFACE_H_ + +#include + +#include "api/optional.h" +#include "api/rtpreceiverinterface.h" +#include "api/rtpsenderinterface.h" +#include "rtc_base/refcount.h" + +namespace webrtc { + +enum class RtpTransceiverDirection { + kSendRecv, + kSendOnly, + kRecvOnly, + kInactive +}; + +// The RtpTransceiverInterface maps to the RTCRtpTransceiver defined by the +// WebRTC specification. A transceiver represents a combination of an RtpSender +// and an RtpReceiver than share a common mid. As defined in JSEP, an +// RtpTransceiver is said to be associated with a media description if its mid +// property is non-null; otherwise, it is said to be disassociated. +// JSEP: https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24 +// +// Note that RtpTransceivers are only supported when using PeerConnection with +// Unified Plan SDP. +// +// This class is thread-safe. +// +// WebRTC specification for RTCRtpTransceiver, the JavaScript analog: +// https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver +class RtpTransceiverInterface : public rtc::RefCountInterface { + public: + // The mid attribute is the mid negotiated and present in the local and + // remote descriptions. Before negotiation is complete, the mid value may be + // null. After rollbacks, the value may change from a non-null value to null. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid + virtual rtc::Optional mid() const = 0; + + // The sender attribute exposes the RtpSender corresponding to the RTP media + // that may be sent with the transceiver's mid. The sender is always present, + // regardless of the direction of media. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-sender + virtual rtc::scoped_refptr sender() const = 0; + + // The receiver attribute exposes the RtpReceiver corresponding to the RTP + // media that may be received with the transceiver's mid. The receiver is + // always present, regardless of the direction of media. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-receiver + virtual rtc::scoped_refptr receiver() const = 0; + + // The stopped attribute indicates that the sender of this transceiver will no + // longer send, and that the receiver will no longer receive. It is true if + // either stop has been called or if setting the local or remote description + // has caused the RtpTransceiver to be stopped. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stopped + virtual bool stopped() const = 0; + + // The direction attribute indicates the preferred direction of this + // transceiver, which will be used in calls to CreateOffer and CreateAnswer. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction + virtual RtpTransceiverDirection direction() const = 0; + + // Sets the preferred direction of this transceiver. An update of + // directionality does not take effect immediately. Instead, future calls to + // CreateOffer and CreateAnswer mark the corresponding media descriptions as + // sendrecv, sendonly, recvonly, or inactive. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-direction + virtual void SetDirection(RtpTransceiverDirection new_direction) = 0; + + // The current_direction attribute indicates the current direction negotiated + // for this transceiver. If this transceiver has never been represented in an + // offer/answer exchange, or if the transceiver is stopped, the value is null. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection + virtual rtc::Optional current_direction() const = 0; + + // The Stop method irreversibly stops the RtpTransceiver. The sender of this + // transceiver will no longer send, the receiver will no longer receive. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-stop + virtual void Stop() = 0; + + // The SetCodecPreferences method overrides the default codec preferences used + // by WebRTC for this transceiver. + // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-setcodecpreferences + // TODO(steveanton): Not implemented. + virtual void SetCodecPreferences( + rtc::ArrayView codecs) = 0; + + protected: + virtual ~RtpTransceiverInterface() = default; +}; + +} // namespace webrtc + +#endif // API_RTPTRANSCEIVERINTERFACE_H_ diff --git a/pc/BUILD.gn b/pc/BUILD.gn index 8e0db29b74..01c571c660 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -137,6 +137,8 @@ rtc_static_library("peerconnection") { "rtpreceiver.h", "rtpsender.cc", "rtpsender.h", + "rtptransceiver.cc", + "rtptransceiver.h", "sctputils.cc", "sctputils.h", "sdputils.cc", diff --git a/pc/rtptransceiver.cc b/pc/rtptransceiver.cc new file mode 100644 index 0000000000..7f6ed6d29b --- /dev/null +++ b/pc/rtptransceiver.cc @@ -0,0 +1,154 @@ +/* + * 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 + +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() { + Stop(); +} + +void RtpTransceiver::SetChannel(cricket::BaseChannel* channel) { + if (channel) { + RTC_DCHECK_EQ(media_type(), channel->media_type()); + } + channel_ = channel; + for (auto sender : senders_) { + if (media_type() == cricket::MEDIA_TYPE_AUDIO) { + static_cast(sender->internal()) + ->SetChannel(static_cast(channel)); + } else { + static_cast(sender->internal()) + ->SetChannel(static_cast(channel)); + } + } + for (auto receiver : receivers_) { + if (!channel) { + receiver->internal()->Stop(); + } + if (media_type() == cricket::MEDIA_TYPE_AUDIO) { + static_cast(receiver->internal()) + ->SetChannel(static_cast(channel)); + } else { + static_cast(receiver->internal()) + ->SetChannel(static_cast(channel)); + } + } +} + +void RtpTransceiver::AddSender( + rtc::scoped_refptr> sender) { + RTC_DCHECK(!unified_plan_); + RTC_DCHECK(sender); + RTC_DCHECK_EQ(media_type(), sender->internal()->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> + receiver) { + RTC_DCHECK(!unified_plan_); + RTC_DCHECK(receiver); + RTC_DCHECK_EQ(media_type(), receiver->internal()->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::Optional RtpTransceiver::mid() const { + return mid_; +} + +rtc::scoped_refptr RtpTransceiver::sender() const { + RTC_DCHECK(unified_plan_); + RTC_CHECK_EQ(1u, senders_.size()); + return senders_[0]; +} + +rtc::scoped_refptr RtpTransceiver::receiver() const { + RTC_DCHECK(unified_plan_); + RTC_CHECK_EQ(1u, receivers_.size()); + return receivers_[0]; +} + +bool RtpTransceiver::stopped() const { + return stopped_; +} + +RtpTransceiverDirection RtpTransceiver::direction() const { + return direction_; +} + +void RtpTransceiver::SetDirection(RtpTransceiverDirection new_direction) { + // TODO(steveanton): This should fire OnNegotiationNeeded. + direction_ = new_direction; +} + +rtc::Optional 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; +} + +void RtpTransceiver::SetCodecPreferences( + rtc::ArrayView codecs) { + // TODO(steveanton): Implement this. + RTC_NOTREACHED() << "Not implemented"; +} + +} // namespace webrtc diff --git a/pc/rtptransceiver.h b/pc/rtptransceiver.h new file mode 100644 index 0000000000..9feaac77f5 --- /dev/null +++ b/pc/rtptransceiver.h @@ -0,0 +1,147 @@ +/* + * 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. + */ + +#ifndef PC_RTPTRANSCEIVER_H_ +#define PC_RTPTRANSCEIVER_H_ + +#include +#include + +#include "api/rtptransceiverinterface.h" +#include "pc/rtpreceiver.h" +#include "pc/rtpsender.h" + +namespace webrtc { + +// Implementation of the public RtpTransceiverInterface. +// +// The RtpTransceiverInterface is only intended to be used with a PeerConnection +// that enables Unified Plan SDP. Thus, the methods that only need to implement +// public API features and are not used internally can assume exactly one sender +// and receiver. +// +// Since the RtpTransceiver is used internally by PeerConnection for tracking +// RtpSenders, RtpReceivers, and BaseChannels, and PeerConnection needs to be +// backwards compatible with Plan B SDP, this implementation is more flexible +// than that required by the WebRTC specification. +// +// With Plan B SDP, an RtpTransceiver can have any number of senders and +// receivers which map to a=ssrc lines in the m= section. +// With Unified Plan SDP, an RtpTransceiver will have exactly one sender and one +// receiver which are encapsulated by the m= section. +// +// This class manages the RtpSenders, RtpReceivers, and BaseChannel associated +// with this m= section. Since the transceiver, senders, and receivers are +// reference counted and can be referenced from JavaScript (in Chromium), these +// objects must be ready to live for an arbitrary amount of time. The +// BaseChannel is not reference counted and is owned by the ChannelManager, so +// the PeerConnection must take care of creating/deleting the BaseChannel and +// setting the channel reference in the transceiver to null when it has been +// deleted. +// +// The RtpTransceiver is specialized to either audio or video according to the +// MediaType specified in the constructor. Audio RtpTransceivers will have +// AudioRtpSenders, AudioRtpReceivers, and a VoiceChannel. Video RtpTransceivers +// will have VideoRtpSenders, VideoRtpReceivers, and a VideoChannel. +class RtpTransceiver final + : public rtc::RefCountedObject { + public: + // Construct an RtpTransceiver with no senders, receivers, or channel set. + // |media_type| specifies the type of RtpTransceiver (and, by transitivity, + // the type of senders, receivers, and channel). Can either by audio or video. + explicit RtpTransceiver(cricket::MediaType media_type); + ~RtpTransceiver() override; + + cricket::MediaType media_type() const { return media_type_; } + + // Returns the Voice/VideoChannel set for this transceiver. May be null if + // the transceiver is not in the currently set local/remote description. + cricket::BaseChannel* channel() const { return channel_; } + + // Sets the Voice/VideoChannel. The caller must pass in the correct channel + // implementation based on the type of the transceiver. + void SetChannel(cricket::BaseChannel* channel); + + // Adds an RtpSender of the appropriate type to be owned by this transceiver. + // Must not be null. + void AddSender( + rtc::scoped_refptr> sender); + + // Removes the given RtpSender. Returns false if the sender is not owned by + // this transceiver. + bool RemoveSender(RtpSenderInterface* sender); + + // Returns a vector of the senders owned by this transceiver. + std::vector>> + senders() const { + return senders_; + } + + // Adds an RtpReceiver of the appropriate type to be owned by this + // transceiver. Must not be null. + void AddReceiver( + rtc::scoped_refptr> + receiver); + + // Removes the given RtpReceiver. Returns false if the sender is not owned by + // this transceiver. + bool RemoveReceiver(RtpReceiverInterface* receiver); + + // Returns a vector of the receivers owned by this transceiver. + std::vector< + rtc::scoped_refptr>> + receivers() const { + return receivers_; + } + + // RtpTransceiverInterface implementation. + rtc::Optional mid() const override; + rtc::scoped_refptr sender() const override; + rtc::scoped_refptr receiver() const override; + bool stopped() const override; + RtpTransceiverDirection direction() const override; + void SetDirection(RtpTransceiverDirection new_direction) override; + rtc::Optional current_direction() const override; + void Stop() override; + void SetCodecPreferences(rtc::ArrayView codecs) override; + + private: + const bool unified_plan_; + const cricket::MediaType media_type_; + std::vector>> + senders_; + std::vector< + rtc::scoped_refptr>> + receivers_; + + bool stopped_ = false; + RtpTransceiverDirection direction_ = RtpTransceiverDirection::kInactive; + rtc::Optional current_direction_; + rtc::Optional mid_; + + cricket::BaseChannel* channel_ = nullptr; +}; + +BEGIN_SIGNALING_PROXY_MAP(RtpTransceiver) +PROXY_SIGNALING_THREAD_DESTRUCTOR() +PROXY_CONSTMETHOD0(rtc::Optional, mid); +PROXY_CONSTMETHOD0(rtc::scoped_refptr, sender); +PROXY_CONSTMETHOD0(rtc::scoped_refptr, receiver); +PROXY_CONSTMETHOD0(bool, stopped); +PROXY_CONSTMETHOD0(RtpTransceiverDirection, direction); +PROXY_METHOD1(void, SetDirection, RtpTransceiverDirection); +PROXY_CONSTMETHOD0(rtc::Optional, current_direction); +PROXY_METHOD0(void, Stop); +PROXY_METHOD1(void, SetCodecPreferences, rtc::ArrayView); +END_PROXY_MAP(); + +} // namespace webrtc + +#endif // PC_RTPTRANSCEIVER_H_