Add OnTrack PeerConnection callback for Unified Plan

This adds a callback corresponding to the ontrack event as defined
in the WebRTC specification.

Bug: webrtc:7600
Change-Id: Ied8c55e11dcea864428fb194623c1595c21657c7
Reviewed-on: https://webrtc-review.googlesource.com/52660
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22066}
This commit is contained in:
Steve Anton
2018-02-16 16:14:42 -08:00
committed by Commit Bot
parent 36da6ff582
commit 8b815cddca
5 changed files with 130 additions and 13 deletions

View File

@ -1050,10 +1050,25 @@ class PeerConnectionObserver {
// This is called when a receiver and its track is created. // This is called when a receiver and its track is created.
// TODO(zhihuang): Make this pure virtual when all subclasses implement it. // TODO(zhihuang): Make this pure virtual when all subclasses implement it.
// Note: This is called with both Plan B and Unified Plan semantics. Unified
// Plan users should prefer OnTrack, OnAddTrack is only called as backwards
// compatibility (and is called in the exact same situations as OnTrack).
virtual void OnAddTrack( virtual void OnAddTrack(
rtc::scoped_refptr<RtpReceiverInterface> receiver, rtc::scoped_refptr<RtpReceiverInterface> receiver,
const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {} const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {}
// This is called when signaling indicates a transceiver will be receiving
// media from the remote endpoint. This is fired during a call to
// SetRemoteDescription. The receiving track can be accessed by:
// |transceiver->receiver()->track()| and its associated streams by
// |transceiver->receiver()->streams()|.
// Note: This will only be called if Unified Plan semantics are specified.
// This behavior is specified in section 2.2.8.2.5 of the "Set the
// RTCSessionDescription" algorithm:
// https://w3c.github.io/webrtc-pc/#set-description
virtual void OnTrack(
rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {}
// TODO(hbos,deadbeef): Add |OnAssociatedStreamsUpdated| with |receiver| and // TODO(hbos,deadbeef): Add |OnAssociatedStreamsUpdated| with |receiver| and
// |streams| as arguments. This should be called when an existing receiver its // |streams| as arguments. This should be called when an existing receiver its
// associated streams updated. https://crbug.com/webrtc/8315 // associated streams updated. https://crbug.com/webrtc/8315
@ -1065,7 +1080,7 @@ class PeerConnectionObserver {
// behavior that occurs when processing the removal of a remote track, and is // behavior that occurs when processing the removal of a remote track, and is
// called when the receiver is removed and the track is muted. When Unified // called when the receiver is removed and the track is muted. When Unified
// Plan SDP is supported, transceivers can change direction (and receivers // Plan SDP is supported, transceivers can change direction (and receivers
// stopped) but receivers are never removed. // stopped) but receivers are never removed, so this is never called.
// https://w3c.github.io/webrtc-pc/#process-remote-track-removal // https://w3c.github.io/webrtc-pc/#process-remote-track-removal
// TODO(hbos,deadbeef): When Unified Plan SDP is supported and receivers are // TODO(hbos,deadbeef): When Unified Plan SDP is supported and receivers are
// no longer removed, deprecate and remove this callback. // no longer removed, deprecate and remove this callback.

View File

@ -2155,7 +2155,8 @@ RTCError PeerConnection::ApplyRemoteDescription(
} }
if (IsUnifiedPlan()) { if (IsUnifiedPlan()) {
std::vector<TrackEvent> track_events; std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
receiving_transceivers;
std::vector<rtc::scoped_refptr<MediaStreamInterface>> added_streams; std::vector<rtc::scoped_refptr<MediaStreamInterface>> added_streams;
for (auto transceiver : transceivers_) { for (auto transceiver : transceivers_) {
const ContentInfo* content = const ContentInfo* content =
@ -2185,10 +2186,7 @@ RTCError PeerConnection::ApplyRemoteDescription(
added_streams.push_back(stream); added_streams.push_back(stream);
} }
transceiver->internal()->receiver_internal()->SetStreams({stream}); transceiver->internal()->receiver_internal()->SetStreams({stream});
TrackEvent track_event; receiving_transceivers.push_back(transceiver);
track_event.receiver = transceiver->receiver();
track_event.streams = transceiver->receiver()->streams();
track_events.push_back(std::move(track_event));
} }
// If direction is sendonly or inactive, and transceiver's current // If direction is sendonly or inactive, and transceiver's current
// direction is neither sendonly nor inactive, process the removal of a // direction is neither sendonly nor inactive, process the removal of a
@ -2210,8 +2208,10 @@ RTCError PeerConnection::ApplyRemoteDescription(
} }
} }
// Once all processing has finished, fire off callbacks. // Once all processing has finished, fire off callbacks.
for (auto event : track_events) { for (auto transceiver : receiving_transceivers) {
observer_->OnAddTrack(event.receiver, event.streams); observer_->OnTrack(transceiver);
observer_->OnAddTrack(transceiver->receiver(),
transceiver->receiver()->streams());
} }
for (auto stream : added_streams) { for (auto stream : added_streams) {
observer_->OnAddStream(stream); observer_->OnAddStream(stream);

View File

@ -292,11 +292,6 @@ class PeerConnection : public PeerConnectionInternal,
uint32_t first_ssrc; uint32_t first_ssrc;
}; };
struct TrackEvent {
rtc::scoped_refptr<RtpReceiverInterface> receiver;
std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams;
};
// Implements MessageHandler. // Implements MessageHandler.
void OnMessage(rtc::Message* msg) override; void OnMessage(rtc::Message* msg) override;

View File

@ -219,6 +219,106 @@ TEST_F(PeerConnectionRtpCallbacksTest,
callee->observer()->remove_track_events_); callee->observer()->remove_track_events_);
} }
// Tests that setting a remote description with sending transceivers will fire
// the OnTrack callback for each transceiver and setting a remote description
// with receive only transceivers will not call OnTrack.
TEST_F(PeerConnectionRtpCallbacksTest, UnifiedPlanAddTransceiverCallsOnTrack) {
auto caller = CreatePeerConnectionWithUnifiedPlan();
auto callee = CreatePeerConnectionWithUnifiedPlan();
auto audio_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
auto video_transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_VIDEO);
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
ASSERT_EQ(0u, caller->observer()->on_track_transceivers_.size());
ASSERT_EQ(2u, callee->observer()->on_track_transceivers_.size());
EXPECT_EQ(audio_transceiver->mid(),
callee->pc()->GetTransceivers()[0]->mid());
EXPECT_EQ(video_transceiver->mid(),
callee->pc()->GetTransceivers()[1]->mid());
}
// Test that doing additional offer/answer exchanges with no changes to tracks
// will cause no additional OnTrack calls after the tracks have been negotiated.
TEST_F(PeerConnectionRtpCallbacksTest, UnifiedPlanReofferDoesNotCallOnTrack) {
auto caller = CreatePeerConnectionWithUnifiedPlan();
auto callee = CreatePeerConnectionWithUnifiedPlan();
caller->AddAudioTrack("audio");
callee->AddAudioTrack("audio");
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
EXPECT_EQ(1u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(1u, callee->observer()->on_track_transceivers_.size());
// If caller reoffers with no changes expect no additional OnTrack calls.
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
EXPECT_EQ(1u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(1u, callee->observer()->on_track_transceivers_.size());
// Also if callee reoffers with no changes expect no additional OnTrack calls.
ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
EXPECT_EQ(1u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(1u, callee->observer()->on_track_transceivers_.size());
}
// Test that OnTrack is called when the transceiver direction changes to send
// the track.
TEST_F(PeerConnectionRtpCallbacksTest, UnifiedPlanSetDirectionCallsOnTrack) {
auto caller = CreatePeerConnectionWithUnifiedPlan();
auto callee = CreatePeerConnectionWithUnifiedPlan();
auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
transceiver->SetDirection(RtpTransceiverDirection::kInactive);
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
EXPECT_EQ(0u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(0u, callee->observer()->on_track_transceivers_.size());
transceiver->SetDirection(RtpTransceiverDirection::kSendOnly);
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
EXPECT_EQ(0u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(1u, callee->observer()->on_track_transceivers_.size());
// If the direction changes but it is still receiving on the remote side, then
// OnTrack should not be fired again.
transceiver->SetDirection(RtpTransceiverDirection::kSendRecv);
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
EXPECT_EQ(0u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(1u, callee->observer()->on_track_transceivers_.size());
}
// Test that OnTrack is called twice when a sendrecv call is started, the callee
// changes the direction to inactive, then changes it back to sendrecv.
TEST_F(PeerConnectionRtpCallbacksTest,
UnifiedPlanSetDirectionHoldCallsOnTrackTwice) {
auto caller = CreatePeerConnectionWithUnifiedPlan();
auto callee = CreatePeerConnectionWithUnifiedPlan();
auto transceiver = caller->AddTransceiver(cricket::MEDIA_TYPE_AUDIO);
ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
EXPECT_EQ(0u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(1u, callee->observer()->on_track_transceivers_.size());
// Put the call on hold by no longer receiving the track.
callee->pc()->GetTransceivers()[0]->SetDirection(
RtpTransceiverDirection::kInactive);
ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
EXPECT_EQ(0u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(1u, callee->observer()->on_track_transceivers_.size());
// Resume the call by changing the direction to recvonly. This should call
// OnTrack again on the callee side.
callee->pc()->GetTransceivers()[0]->SetDirection(
RtpTransceiverDirection::kRecvOnly);
ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
EXPECT_EQ(0u, caller->observer()->on_track_transceivers_.size());
EXPECT_EQ(2u, callee->observer()->on_track_transceivers_.size());
}
// These tests examine the state of the peer connection as a result of // These tests examine the state of the peer connection as a result of
// performing SetRemoteDescription(). // performing SetRemoteDescription().
class PeerConnectionRtpObserverTest : public PeerConnectionRtpTest {}; class PeerConnectionRtpObserverTest : public PeerConnectionRtpTest {};

View File

@ -132,6 +132,11 @@ class MockPeerConnectionObserver : public PeerConnectionObserver {
add_track_events_.push_back(AddTrackEvent(receiver, streams)); add_track_events_.push_back(AddTrackEvent(receiver, streams));
} }
void OnTrack(
rtc::scoped_refptr<RtpTransceiverInterface> transceiver) override {
on_track_transceivers_.push_back(transceiver);
}
void OnRemoveTrack( void OnRemoveTrack(
rtc::scoped_refptr<RtpReceiverInterface> receiver) override { rtc::scoped_refptr<RtpReceiverInterface> receiver) override {
remove_track_events_.push_back(receiver); remove_track_events_.push_back(receiver);
@ -209,6 +214,8 @@ class MockPeerConnectionObserver : public PeerConnectionObserver {
std::string last_added_track_label_; std::string last_added_track_label_;
std::vector<AddTrackEvent> add_track_events_; std::vector<AddTrackEvent> add_track_events_;
std::vector<rtc::scoped_refptr<RtpReceiverInterface>> remove_track_events_; std::vector<rtc::scoped_refptr<RtpReceiverInterface>> remove_track_events_;
std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>
on_track_transceivers_;
int num_candidates_removed_ = 0; int num_candidates_removed_ = 0;
private: private: