Remove cricket::RtpTransceiverDirection
Replaces cricket::RtpTransceiverDirection with
webrtc::RtpTransceiverDirection, which is part of the public API.
Bug: webrtc:8558
Change-Id: Ibfc9373e25187e98fb969e7ac937a1371c8fa4c7
Reviewed-on: https://webrtc-review.googlesource.com/24129
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Peter Thatcher <pthatcher@webrtc.org>
Reviewed-by: Zhi Huang <zhihuang@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20899}diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index da30976..165be56 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -48,6 +48,8 @@
"mediasession.h",
"rtcpmuxfilter.cc",
"rtcpmuxfilter.h",
+ "rtpmediautils.cc",
+ "rtpmediautils.h",
"rtptransport.cc",
"rtptransport.h",
"rtptransportinternal.h",
@@ -400,6 +402,7 @@
"proxy_unittest.cc",
"rtcstats_integrationtest.cc",
"rtcstatscollector_unittest.cc",
+ "rtpmediautils_unittest.cc",
"rtpsenderreceiver_unittest.cc",
"sctputils_unittest.cc",
"statscollector_unittest.cc",
diff --git a/pc/mediasession.cc b/pc/mediasession.cc
index e9b4c73..9c31f50 100644
--- a/pc/mediasession.cc
+++ b/pc/mediasession.cc
@@ -25,6 +25,7 @@
#include "media/base/mediaconstants.h"
#include "p2p/base/p2pconstants.h"
#include "pc/channelmanager.h"
+#include "pc/rtpmediautils.h"
#include "pc/srtpfilter.h"
#include "rtc_base/base64.h"
#include "rtc_base/checks.h"
@@ -33,6 +34,9 @@
#include "rtc_base/stringutils.h"
namespace {
+
+using webrtc::RtpTransceiverDirection;
+
const char kInline[] = "inline:";
void GetSupportedSdesCryptoSuiteNames(void (*func)(const rtc::CryptoOptions&,
@@ -97,30 +101,47 @@
return IsPlainSctp(protocol) || IsDtlsSctp(protocol);
}
-RtpTransceiverDirection RtpTransceiverDirection::FromMediaContentDirection(
- MediaContentDirection md) {
- const bool send = (md == MD_SENDRECV || md == MD_SENDONLY);
- const bool recv = (md == MD_SENDRECV || md == MD_RECVONLY);
- return RtpTransceiverDirection(send, recv);
+RtpTransceiverDirection RtpTransceiverDirectionFromMediaContentDirection(
+ MediaContentDirection direction) {
+ switch (direction) {
+ case MD_SENDRECV:
+ return RtpTransceiverDirection::kSendRecv;
+ case MD_SENDONLY:
+ return RtpTransceiverDirection::kSendOnly;
+ case MD_RECVONLY:
+ return RtpTransceiverDirection::kRecvOnly;
+ case MD_INACTIVE:
+ return RtpTransceiverDirection::kInactive;
+ }
+ RTC_NOTREACHED();
+ return RtpTransceiverDirection::kInactive;
}
-MediaContentDirection RtpTransceiverDirection::ToMediaContentDirection() const {
- if (send && recv) {
- return MD_SENDRECV;
- } else if (send) {
- return MD_SENDONLY;
- } else if (recv) {
- return MD_RECVONLY;
+MediaContentDirection MediaContentDirectionFromRtpTransceiverDirection(
+ RtpTransceiverDirection direction) {
+ switch (direction) {
+ case RtpTransceiverDirection::kSendRecv:
+ return MD_SENDRECV;
+ case RtpTransceiverDirection::kSendOnly:
+ return MD_SENDONLY;
+ case RtpTransceiverDirection::kRecvOnly:
+ return MD_RECVONLY;
+ case RtpTransceiverDirection::kInactive:
+ return MD_INACTIVE;
}
-
+ RTC_NOTREACHED();
return MD_INACTIVE;
}
-RtpTransceiverDirection
-NegotiateRtpTransceiverDirection(RtpTransceiverDirection offer,
- RtpTransceiverDirection wants) {
- return RtpTransceiverDirection(offer.recv && wants.send,
- offer.send && wants.recv);
+static RtpTransceiverDirection NegotiateRtpTransceiverDirection(
+ RtpTransceiverDirection offer,
+ RtpTransceiverDirection wants) {
+ bool offer_send = webrtc::RtpTransceiverDirectionHasSend(offer);
+ bool offer_recv = webrtc::RtpTransceiverDirectionHasRecv(offer);
+ bool wants_send = webrtc::RtpTransceiverDirectionHasSend(wants);
+ bool wants_recv = webrtc::RtpTransceiverDirectionHasRecv(wants);
+ return webrtc::RtpTransceiverDirectionFromSendRecv(offer_recv && wants_send,
+ offer_send && wants_recv);
}
static bool IsMediaContentOfType(const ContentInfo* content,
@@ -1156,11 +1177,12 @@
}
auto offer_rtd =
- RtpTransceiverDirection::FromMediaContentDirection(offer->direction());
+ RtpTransceiverDirectionFromMediaContentDirection(offer->direction());
- answer->set_direction(NegotiateRtpTransceiverDirection(
- offer_rtd, media_description_options.direction)
- .ToMediaContentDirection());
+ answer->set_direction(
+ cricket::MediaContentDirectionFromRtpTransceiverDirection(
+ NegotiateRtpTransceiverDirection(
+ offer_rtd, media_description_options.direction)));
return true;
}
@@ -1569,34 +1591,37 @@
const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForOffer(
const RtpTransceiverDirection& direction) const {
- // If stream is inactive - generate list as if sendrecv.
- if (direction.send == direction.recv) {
- return audio_sendrecv_codecs_;
- } else if (direction.send) {
- return audio_send_codecs_;
- } else {
- return audio_recv_codecs_;
+ switch (direction) {
+ // If stream is inactive - generate list as if sendrecv.
+ case RtpTransceiverDirection::kSendRecv:
+ case RtpTransceiverDirection::kInactive:
+ return audio_sendrecv_codecs_;
+ case RtpTransceiverDirection::kSendOnly:
+ return audio_send_codecs_;
+ case RtpTransceiverDirection::kRecvOnly:
+ return audio_recv_codecs_;
}
+ RTC_NOTREACHED();
+ return audio_sendrecv_codecs_;
}
const AudioCodecs& MediaSessionDescriptionFactory::GetAudioCodecsForAnswer(
const RtpTransceiverDirection& offer,
const RtpTransceiverDirection& answer) const {
- // For inactive and sendrecv answers, generate lists as if we were to accept
- // the offer's direction. See RFC 3264 Section 6.1.
- if (answer.send == answer.recv) {
- if (offer.send == offer.recv) {
- return audio_sendrecv_codecs_;
- } else if (offer.send) {
- return audio_recv_codecs_;
- } else {
+ switch (answer) {
+ // For inactive and sendrecv answers, generate lists as if we were to accept
+ // the offer's direction. See RFC 3264 Section 6.1.
+ case RtpTransceiverDirection::kSendRecv:
+ case RtpTransceiverDirection::kInactive:
+ return GetAudioCodecsForOffer(
+ webrtc::RtpTransceiverDirectionReversed(offer));
+ case RtpTransceiverDirection::kSendOnly:
return audio_send_codecs_;
- }
- } else if (answer.send) {
- return audio_send_codecs_;
- } else {
- return audio_recv_codecs_;
+ case RtpTransceiverDirection::kRecvOnly:
+ return audio_recv_codecs_;
}
+ RTC_NOTREACHED();
+ return audio_sendrecv_codecs_;
}
void MergeCodecsFromDescription(const SessionDescription* description,
@@ -1908,7 +1933,8 @@
SetMediaProtocol(secure_transport, audio.get());
audio->set_direction(
- media_description_options.direction.ToMediaContentDirection());
+ cricket::MediaContentDirectionFromRtpTransceiverDirection(
+ media_description_options.direction));
desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
media_description_options.stopped, audio.release());
@@ -1979,7 +2005,8 @@
SetMediaProtocol(secure_transport, video.get());
video->set_direction(
- media_description_options.direction.ToMediaContentDirection());
+ cricket::MediaContentDirectionFromRtpTransceiverDirection(
+ media_description_options.direction));
desc->AddContent(media_description_options.mid, NS_JINGLE_RTP,
media_description_options.stopped, video.release());
@@ -2098,7 +2125,7 @@
// and the selected direction in the answer.
// Note these will be filtered one final time in CreateMediaContentAnswer.
auto wants_rtd = media_description_options.direction;
- auto offer_rtd = RtpTransceiverDirection::FromMediaContentDirection(
+ auto offer_rtd = RtpTransceiverDirectionFromMediaContentDirection(
offer_audio_description->direction());
auto answer_rtd = NegotiateRtpTransceiverDirection(offer_rtd, wants_rtd);
AudioCodecs supported_audio_codecs =
diff --git a/pc/mediasession.h b/pc/mediasession.h
index 2277000..41e867b 100644
--- a/pc/mediasession.h
+++ b/pc/mediasession.h
@@ -20,13 +20,14 @@
#include "api/cryptoparams.h"
#include "api/mediatypes.h"
+#include "api/rtptransceiverinterface.h"
#include "media/base/codec.h"
#include "media/base/mediachannel.h"
#include "media/base/mediaconstants.h"
#include "media/base/mediaengine.h" // For DataChannelType
#include "media/base/streamparams.h"
-#include "p2p/base/sessiondescription.h"
#include "p2p/base/jseptransport.h"
+#include "p2p/base/sessiondescription.h"
#include "p2p/base/transportdescriptionfactory.h"
namespace cricket {
@@ -73,33 +74,11 @@
// Default RTCP CNAME for unit tests.
const char kDefaultRtcpCname[] = "DefaultRtcpCname";
-struct RtpTransceiverDirection {
- bool send;
- bool recv;
-
- RtpTransceiverDirection(bool send, bool recv) : send(send), recv(recv) {}
-
- bool operator==(const RtpTransceiverDirection& o) const {
- return send == o.send && recv == o.recv;
- }
-
- bool operator!=(const RtpTransceiverDirection& o) const {
- return !(*this == o);
- }
-
- static RtpTransceiverDirection FromMediaContentDirection(
- MediaContentDirection md);
-
- MediaContentDirection ToMediaContentDirection() const;
-
- RtpTransceiverDirection Reversed() const {
- return RtpTransceiverDirection(recv, send);
- }
-};
-
-RtpTransceiverDirection
-NegotiateRtpTransceiverDirection(RtpTransceiverDirection offer,
- RtpTransceiverDirection wants);
+webrtc::RtpTransceiverDirection
+RtpTransceiverDirectionFromMediaContentDirection(
+ MediaContentDirection direction);
+MediaContentDirection MediaContentDirectionFromRtpTransceiverDirection(
+ webrtc::RtpTransceiverDirection direction);
// Options for an RtpSender contained with an media description/"m=" section.
struct SenderOptions {
@@ -114,7 +93,7 @@
struct MediaDescriptionOptions {
MediaDescriptionOptions(MediaType type,
const std::string& mid,
- RtpTransceiverDirection direction,
+ webrtc::RtpTransceiverDirection direction,
bool stopped)
: type(type), mid(mid), direction(direction), stopped(stopped) {}
@@ -132,7 +111,7 @@
MediaType type;
std::string mid;
- RtpTransceiverDirection direction;
+ webrtc::RtpTransceiverDirection direction;
bool stopped;
TransportOptions transport_options;
// Note: There's no equivalent "RtpReceiverOptions" because only send
@@ -467,10 +446,10 @@
private:
const AudioCodecs& GetAudioCodecsForOffer(
- const RtpTransceiverDirection& direction) const;
+ const webrtc::RtpTransceiverDirection& direction) const;
const AudioCodecs& GetAudioCodecsForAnswer(
- const RtpTransceiverDirection& offer,
- const RtpTransceiverDirection& answer) const;
+ const webrtc::RtpTransceiverDirection& offer,
+ const webrtc::RtpTransceiverDirection& answer) const;
void GetCodecsForOffer(const SessionDescription* current_description,
AudioCodecs* audio_codecs,
VideoCodecs* video_codecs,
diff --git a/pc/mediasession_unittest.cc b/pc/mediasession_unittest.cc
index 09e8684..c2653df 100644
--- a/pc/mediasession_unittest.cc
+++ b/pc/mediasession_unittest.cc
@@ -18,6 +18,7 @@
#include "p2p/base/transportdescription.h"
#include "p2p/base/transportinfo.h"
#include "pc/mediasession.h"
+#include "pc/rtpmediautils.h"
#include "pc/srtpfilter.h"
#include "rtc_base/checks.h"
#include "rtc_base/fakesslidentity.h"
@@ -66,7 +67,6 @@
using cricket::SEC_DISABLED;
using cricket::SEC_ENABLED;
using cricket::SEC_REQUIRED;
-using cricket::RtpTransceiverDirection;
using rtc::CS_AES_CM_128_HMAC_SHA1_32;
using rtc::CS_AES_CM_128_HMAC_SHA1_80;
using rtc::CS_AEAD_AES_128_GCM;
@@ -276,7 +276,7 @@
MediaSessionOptions* opts) {
opts->media_description_options.push_back(MediaDescriptionOptions(
type, mid,
- cricket::RtpTransceiverDirection::FromMediaContentDirection(direction),
+ cricket::RtpTransceiverDirectionFromMediaContentDirection(direction),
stopped));
}
@@ -3608,7 +3608,7 @@
MediaSessionOptions opts;
AddMediaSection(MEDIA_TYPE_AUDIO, "audio", direction, kActive, &opts);
- if (RtpTransceiverDirection::FromMediaContentDirection(direction).send) {
+ if (direction == cricket::MD_SENDRECV || direction == cricket::MD_SENDONLY) {
AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
{kMediaStream1}, 1, &opts);
}
@@ -3707,8 +3707,8 @@
AddMediaSection(MEDIA_TYPE_AUDIO, "audio", offer_direction, kActive,
&offer_opts);
- if (RtpTransceiverDirection::FromMediaContentDirection(offer_direction)
- .send) {
+ if (webrtc::RtpTransceiverDirectionHasSend(
+ RtpTransceiverDirectionFromMediaContentDirection(offer_direction))) {
AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
{kMediaStream1}, 1, &offer_opts);
}
@@ -3721,8 +3721,8 @@
AddMediaSection(MEDIA_TYPE_AUDIO, "audio", answer_direction, kActive,
&answer_opts);
- if (RtpTransceiverDirection::FromMediaContentDirection(answer_direction)
- .send) {
+ if (webrtc::RtpTransceiverDirectionHasSend(
+ RtpTransceiverDirectionFromMediaContentDirection(answer_direction))) {
AttachSenderToMediaSection("audio", MEDIA_TYPE_AUDIO, kAudioTrack1,
{kMediaStream1}, 1, &answer_opts);
}
diff --git a/pc/peerconnection.cc b/pc/peerconnection.cc
index 2c6cc4b..0011ad7 100644
--- a/pc/peerconnection.cc
+++ b/pc/peerconnection.cc
@@ -31,6 +31,7 @@
#include "pc/mediastream.h"
#include "pc/mediastreamobserver.h"
#include "pc/remoteaudiosource.h"
+#include "pc/rtpmediautils.h"
#include "pc/rtpreceiver.h"
#include "pc/rtpsender.h"
#include "pc/sctputils.h"
@@ -2527,9 +2528,9 @@
if (local_description()) {
GenerateMediaDescriptionOptions(
local_description(),
- cricket::RtpTransceiverDirection(send_audio, recv_audio),
- cricket::RtpTransceiverDirection(send_video, recv_video), &audio_index,
- &video_index, &data_index, session_options);
+ RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
+ RtpTransceiverDirectionFromSendRecv(send_video, recv_video),
+ &audio_index, &video_index, &data_index, session_options);
}
// Add audio/video/data m= sections to the end if needed.
@@ -2537,21 +2538,23 @@
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO,
- cricket::RtpTransceiverDirection(send_audio, recv_audio), false));
+ RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
+ false));
audio_index = session_options->media_description_options.size() - 1;
}
if (!video_index && offer_new_video_description) {
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
- cricket::RtpTransceiverDirection(send_video, recv_video), false));
+ RtpTransceiverDirectionFromSendRecv(send_video, recv_video),
+ false));
video_index = session_options->media_description_options.size() - 1;
}
if (!data_index && offer_new_data_description) {
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_DATA, cricket::CN_DATA,
- cricket::RtpTransceiverDirection(true, true), false));
+ RtpTransceiverDirection::kSendRecv, false));
data_index = session_options->media_description_options.size() - 1;
}
@@ -2623,9 +2626,9 @@
// direction with the offered direction.
GenerateMediaDescriptionOptions(
remote_description(),
- cricket::RtpTransceiverDirection(send_audio, recv_audio),
- cricket::RtpTransceiverDirection(send_video, recv_video), &audio_index,
- &video_index, &data_index, session_options);
+ RtpTransceiverDirectionFromSendRecv(send_audio, recv_audio),
+ RtpTransceiverDirectionFromSendRecv(send_video, recv_video),
+ &audio_index, &video_index, &data_index, session_options);
}
cricket::MediaDescriptionOptions* audio_media_description_options =
@@ -2662,8 +2665,8 @@
void PeerConnection::GenerateMediaDescriptionOptions(
const SessionDescriptionInterface* session_desc,
- cricket::RtpTransceiverDirection audio_direction,
- cricket::RtpTransceiverDirection video_direction,
+ RtpTransceiverDirection audio_direction,
+ RtpTransceiverDirection video_direction,
rtc::Optional<size_t>* audio_index,
rtc::Optional<size_t>* video_index,
rtc::Optional<size_t>* data_index,
@@ -2676,12 +2679,12 @@
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_AUDIO, content.name,
- cricket::RtpTransceiverDirection(false, false), true));
+ RtpTransceiverDirection::kInactive, true));
} else {
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_AUDIO, content.name, audio_direction,
- !audio_direction.send && !audio_direction.recv));
+ audio_direction == RtpTransceiverDirection::kInactive));
*audio_index = session_options->media_description_options.size() - 1;
}
} else if (IsVideoContent(&content)) {
@@ -2690,12 +2693,12 @@
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_VIDEO, content.name,
- cricket::RtpTransceiverDirection(false, false), true));
+ RtpTransceiverDirection::kInactive, true));
} else {
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_VIDEO, content.name, video_direction,
- !video_direction.send && !video_direction.recv));
+ video_direction == RtpTransceiverDirection::kInactive));
*video_index = session_options->media_description_options.size() - 1;
}
} else {
@@ -2705,14 +2708,14 @@
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_DATA, content.name,
- cricket::RtpTransceiverDirection(false, false), true));
+ RtpTransceiverDirection::kInactive, true));
} else {
session_options->media_description_options.push_back(
cricket::MediaDescriptionOptions(
cricket::MEDIA_TYPE_DATA, content.name,
// Direction for data sections is meaningless, but legacy
// endpoints might expect sendrecv.
- cricket::RtpTransceiverDirection(true, true), false));
+ RtpTransceiverDirection::kSendRecv, false));
*data_index = session_options->media_description_options.size() - 1;
}
}
diff --git a/pc/peerconnection.h b/pc/peerconnection.h
index d262ede..0d7f5c9c 100644
--- a/pc/peerconnection.h
+++ b/pc/peerconnection.h
@@ -394,8 +394,8 @@
// local description or remote description.
void GenerateMediaDescriptionOptions(
const SessionDescriptionInterface* session_desc,
- cricket::RtpTransceiverDirection audio_direction,
- cricket::RtpTransceiverDirection video_direction,
+ RtpTransceiverDirection audio_direction,
+ RtpTransceiverDirection video_direction,
rtc::Optional<size_t>* audio_index,
rtc::Optional<size_t>* video_index,
rtc::Optional<size_t>* data_index,
diff --git a/pc/peerconnection_media_unittest.cc b/pc/peerconnection_media_unittest.cc
index 20690d2..9f4da02 100644
--- a/pc/peerconnection_media_unittest.cc
+++ b/pc/peerconnection_media_unittest.cc
@@ -20,6 +20,7 @@
#include "p2p/base/fakeportallocator.h"
#include "pc/mediasession.h"
#include "pc/peerconnectionwrapper.h"
+#include "pc/rtpmediautils.h"
#include "pc/sdputils.h"
#ifdef WEBRTC_ANDROID
#include "pc/test/androidtestinitializer.h"
@@ -429,16 +430,18 @@
// 2. Receive if the answerer has explicitly set the offer_to_receive to 1 or
// if it has been left as default.
auto offer_direction =
- cricket::RtpTransceiverDirection::FromMediaContentDirection(
+ cricket::RtpTransceiverDirectionFromMediaContentDirection(
offer_direction_);
+ bool offer_send = RtpTransceiverDirectionHasSend(offer_direction);
+ bool offer_recv = RtpTransceiverDirectionHasRecv(offer_direction);
// The negotiated components determine the direction set in the answer.
- bool negotiate_send = (send_media_ && offer_direction.recv);
- bool negotiate_recv = ((offer_to_receive_ != 0) && offer_direction.send);
+ bool negotiate_send = (send_media_ && offer_recv);
+ bool negotiate_recv = ((offer_to_receive_ != 0) && offer_send);
auto expected_direction =
- cricket::RtpTransceiverDirection(negotiate_send, negotiate_recv)
- .ToMediaContentDirection();
+ cricket::MediaContentDirectionFromRtpTransceiverDirection(
+ RtpTransceiverDirectionFromSendRecv(negotiate_send, negotiate_recv));
EXPECT_EQ(expected_direction,
GetMediaContentDirection(answer.get(), cricket::CN_AUDIO));
}
diff --git a/pc/rtpmediautils.cc b/pc/rtpmediautils.cc
new file mode 100644
index 0000000..ef86c0a
--- /dev/null
+++ b/pc/rtpmediautils.cc
@@ -0,0 +1,53 @@
+/*
+ * 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/rtpmediautils.h"
+
+namespace webrtc {
+
+RtpTransceiverDirection RtpTransceiverDirectionFromSendRecv(bool send,
+ bool recv) {
+ if (send && recv) {
+ return RtpTransceiverDirection::kSendRecv;
+ } else if (send && !recv) {
+ return RtpTransceiverDirection::kSendOnly;
+ } else if (!send && recv) {
+ return RtpTransceiverDirection::kRecvOnly;
+ } else {
+ return RtpTransceiverDirection::kInactive;
+ }
+}
+
+bool RtpTransceiverDirectionHasSend(RtpTransceiverDirection direction) {
+ return direction == RtpTransceiverDirection::kSendRecv ||
+ direction == RtpTransceiverDirection::kSendOnly;
+}
+
+bool RtpTransceiverDirectionHasRecv(RtpTransceiverDirection direction) {
+ return direction == RtpTransceiverDirection::kSendRecv ||
+ direction == RtpTransceiverDirection::kRecvOnly;
+}
+
+RtpTransceiverDirection RtpTransceiverDirectionReversed(
+ RtpTransceiverDirection direction) {
+ switch (direction) {
+ case RtpTransceiverDirection::kSendRecv:
+ case RtpTransceiverDirection::kInactive:
+ return direction;
+ case RtpTransceiverDirection::kSendOnly:
+ return RtpTransceiverDirection::kRecvOnly;
+ case RtpTransceiverDirection::kRecvOnly:
+ return RtpTransceiverDirection::kSendOnly;
+ }
+ RTC_NOTREACHED();
+ return direction;
+}
+
+} // namespace webrtc
diff --git a/pc/rtpmediautils.h b/pc/rtpmediautils.h
new file mode 100644
index 0000000..96426f4
--- /dev/null
+++ b/pc/rtpmediautils.h
@@ -0,0 +1,36 @@
+/*
+ * 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_RTPMEDIAUTILS_H_
+#define PC_RTPMEDIAUTILS_H_
+
+#include "api/rtptransceiverinterface.h"
+
+namespace webrtc {
+
+// Returns the RtpTransceiverDirection that satisfies specified send and receive
+// conditions.
+RtpTransceiverDirection RtpTransceiverDirectionFromSendRecv(bool send,
+ bool recv);
+
+// Returns true only if the direction will send media.
+bool RtpTransceiverDirectionHasSend(RtpTransceiverDirection direction);
+
+// Returns true only if the direction will receive media.
+bool RtpTransceiverDirectionHasRecv(RtpTransceiverDirection direction);
+
+// Returns the RtpTransceiverDirection which is the reverse of the given
+// direction.
+RtpTransceiverDirection RtpTransceiverDirectionReversed(
+ RtpTransceiverDirection direction);
+
+} // namespace webrtc
+
+#endif // PC_RTPMEDIAUTILS_H_
diff --git a/pc/rtpmediautils_unittest.cc b/pc/rtpmediautils_unittest.cc
new file mode 100644
index 0000000..d72f35b
--- /dev/null
+++ b/pc/rtpmediautils_unittest.cc
@@ -0,0 +1,59 @@
+/*
+ * 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/rtpmediautils.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+using ::testing::Values;
+
+class EnumerateAllDirectionsTest
+ : public ::testing::Test,
+ public ::testing::WithParamInterface<RtpTransceiverDirection> {};
+
+// Test that converting the direction to send/recv and back again results in the
+// same direction.
+TEST_P(EnumerateAllDirectionsTest, TestIdentity) {
+ RtpTransceiverDirection direction = GetParam();
+
+ bool send = RtpTransceiverDirectionHasSend(direction);
+ bool recv = RtpTransceiverDirectionHasRecv(direction);
+
+ EXPECT_EQ(direction, RtpTransceiverDirectionFromSendRecv(send, recv));
+}
+
+// Test that reversing the direction is equivalent to swapping send/recv.
+TEST_P(EnumerateAllDirectionsTest, TestReversedSwapped) {
+ RtpTransceiverDirection direction = GetParam();
+
+ bool send = RtpTransceiverDirectionHasSend(direction);
+ bool recv = RtpTransceiverDirectionHasRecv(direction);
+
+ EXPECT_EQ(RtpTransceiverDirectionFromSendRecv(recv, send),
+ RtpTransceiverDirectionReversed(direction));
+}
+
+// Test that reversing the direction twice results in the same direction.
+TEST_P(EnumerateAllDirectionsTest, TestReversedIdentity) {
+ RtpTransceiverDirection direction = GetParam();
+
+ EXPECT_EQ(direction, RtpTransceiverDirectionReversed(
+ RtpTransceiverDirectionReversed(direction)));
+}
+
+INSTANTIATE_TEST_CASE_P(RtpTransceiverDirectionTest,
+ EnumerateAllDirectionsTest,
+ Values(RtpTransceiverDirection::kSendRecv,
+ RtpTransceiverDirection::kSendOnly,
+ RtpTransceiverDirection::kRecvOnly,
+ RtpTransceiverDirection::kInactive));
+
+} // namespace webrtc