aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cast/streaming/receiver_session.cc31
-rw-r--r--cast/streaming/receiver_session.h28
-rw-r--r--cast/streaming/receiver_session_unittest.cc21
3 files changed, 63 insertions, 17 deletions
diff --git a/cast/streaming/receiver_session.cc b/cast/streaming/receiver_session.cc
index 0f6339e3..19abfa43 100644
--- a/cast/streaming/receiver_session.cc
+++ b/cast/streaming/receiver_session.cc
@@ -78,13 +78,13 @@ const Stream* SelectStream(const std::vector<Codec>& preferred_codecs,
} // namespace
ReceiverSession::ConfiguredReceivers::ConfiguredReceivers(
- std::unique_ptr<Receiver> audio_receiver,
+ Receiver* audio_receiver,
absl::optional<SessionConfig> audio_receiver_config,
- std::unique_ptr<Receiver> video_receiver,
+ Receiver* video_receiver,
absl::optional<SessionConfig> video_receiver_config)
- : audio_receiver_(std::move(audio_receiver)),
+ : audio_receiver_(audio_receiver),
audio_receiver_config_(std::move(audio_receiver_config)),
- video_receiver_(std::move(video_receiver)),
+ video_receiver_(video_receiver),
video_receiver_config_(std::move(video_receiver_config)) {}
ConfiguredReceivers::ConfiguredReceivers(ConfiguredReceivers&&) noexcept =
@@ -127,6 +127,7 @@ ReceiverSession::ReceiverSession(Client* const client,
}
ReceiverSession::~ReceiverSession() {
+ ResetReceivers();
message_port_->SetClient(nullptr);
}
@@ -229,25 +230,33 @@ openscreen::ErrorOr<ConfiguredReceivers> ReceiverSession::TrySpawningReceivers(
return openscreen::Error::Code::kParameterInvalid;
}
+ ResetReceivers();
+
absl::optional<SessionConfig> audio_config;
- std::unique_ptr<Receiver> audio_receiver;
if (audio) {
auto audio_pair = ConstructReceiver(audio->stream);
audio_config = std::move(audio_pair.first);
- audio_receiver = std::move(audio_pair.second);
+ current_audio_receiver_ = std::move(audio_pair.second);
}
absl::optional<SessionConfig> video_config;
- std::unique_ptr<Receiver> video_receiver;
if (video) {
auto video_pair = ConstructReceiver(video->stream);
video_config = std::move(video_pair.first);
- video_receiver = std::move(video_pair.second);
+ current_video_receiver_ = std::move(video_pair.second);
}
- return ConfiguredReceivers{std::move(audio_receiver), std::move(audio_config),
- std::move(video_receiver),
- std::move(video_config)};
+ return ConfiguredReceivers{
+ current_audio_receiver_.get(), std::move(audio_config),
+ current_video_receiver_.get(), std::move(video_config)};
+}
+
+void ReceiverSession::ResetReceivers() {
+ if (current_video_receiver_ || current_audio_receiver_) {
+ client_->OnReceiversDestroyed(this);
+ current_audio_receiver_.reset();
+ current_video_receiver_.reset();
+ }
}
Answer ReceiverSession::ConstructAnswer(
diff --git a/cast/streaming/receiver_session.h b/cast/streaming/receiver_session.h
index e148ede4..4ded8895 100644
--- a/cast/streaming/receiver_session.h
+++ b/cast/streaming/receiver_session.h
@@ -38,10 +38,15 @@ class ReceiverSession final : public MessagePort::Client {
// In practice, we may have 0, 1, or 2 receivers configured, depending
// on if the device supports audio and video, and if we were able to
// successfully negotiate a receiver configuration.
+
+ // NOTES ON LIFETIMES: The audio and video receiver pointers are expected
+ // to be valid until the OnReceiversDestroyed event is fired, at which
+ // point they become invalid and need to replaced by the results of
+ // the ensuing OnNegotiated call.
ConfiguredReceivers(
- std::unique_ptr<Receiver> audio_receiver,
+ Receiver* audio_receiver,
const absl::optional<SessionConfig> audio_receiver_config,
- std::unique_ptr<Receiver> video_receiver,
+ Receiver* video_receiver,
const absl::optional<SessionConfig> video_receiver_config);
ConfiguredReceivers(const ConfiguredReceivers&) = delete;
ConfiguredReceivers(ConfiguredReceivers&&) noexcept;
@@ -51,19 +56,19 @@ class ReceiverSession final : public MessagePort::Client {
// If the receiver is audio- or video-only, either of the receivers
// may be nullptr. However, in the majority of cases they will be populated.
- Receiver* audio_receiver() const { return audio_receiver_.get(); }
+ Receiver* audio_receiver() const { return audio_receiver_; }
const absl::optional<SessionConfig>& audio_session_config() const {
return audio_receiver_config_;
}
- Receiver* video_receiver() const { return video_receiver_.get(); }
+ Receiver* video_receiver() const { return video_receiver_; }
const absl::optional<SessionConfig>& video_session_config() const {
return video_receiver_config_;
}
private:
- std::unique_ptr<Receiver> audio_receiver_;
+ Receiver* audio_receiver_;
absl::optional<SessionConfig> audio_receiver_config_;
- std::unique_ptr<Receiver> video_receiver_;
+ Receiver* video_receiver_;
absl::optional<SessionConfig> video_receiver_config_;
};
@@ -71,8 +76,13 @@ class ReceiverSession final : public MessagePort::Client {
// When a connection is established, the OnNegotiated callback is called.
class Client {
public:
+ // This method is called when a new set of receivers has been negotiated.
virtual void OnNegotiated(ReceiverSession* session,
ConfiguredReceivers receivers) = 0;
+
+ // This method is called immediately preceding the invalidation of
+ // this session's receivers.
+ virtual void OnReceiversDestroyed(ReceiverSession* session) = 0;
virtual void OnError(ReceiverSession* session, openscreen::Error error) = 0;
};
@@ -151,6 +161,9 @@ class ReceiverSession final : public MessagePort::Client {
void SendMessage(Message* message);
+ // Handles resetting receivers and notifying the client.
+ void ResetReceivers();
+
Client* const client_;
const std::unique_ptr<Environment> environment_;
const std::unique_ptr<MessagePort> message_port_;
@@ -159,6 +172,9 @@ class ReceiverSession final : public MessagePort::Client {
CastMode cast_mode_;
bool supports_wifi_status_reporting_ = false;
ReceiverPacketRouter packet_router_;
+
+ std::unique_ptr<Receiver> current_audio_receiver_;
+ std::unique_ptr<Receiver> current_video_receiver_;
};
} // namespace streaming
diff --git a/cast/streaming/receiver_session_unittest.cc b/cast/streaming/receiver_session_unittest.cc
index 6c9434c2..4716a6a3 100644
--- a/cast/streaming/receiver_session_unittest.cc
+++ b/cast/streaming/receiver_session_unittest.cc
@@ -204,6 +204,7 @@ class FakeClient : public ReceiverSession::Client {
OnNegotiated,
(ReceiverSession*, ReceiverSession::ConfiguredReceivers),
(override));
+ MOCK_METHOD(void, OnReceiversDestroyed, (ReceiverSession*), (override));
MOCK_METHOD(void,
OnError,
(ReceiverSession*, openscreen::Error error),
@@ -279,6 +280,7 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithDefaultPreferences) {
EXPECT_EQ(cr.video_session_config().value().channels, 1);
EXPECT_EQ(cr.video_session_config().value().rtp_timebase, 90000);
});
+ EXPECT_CALL(client, OnReceiversDestroyed(&session)).Times(1);
raw_port->ReceiveMessage(kValidOfferMessage);
@@ -340,6 +342,7 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithCustomCodecPreferences) {
EXPECT_EQ(cr.video_session_config().value().channels, 1);
EXPECT_EQ(cr.video_session_config().value().rtp_timebase, 90000);
});
+ EXPECT_CALL(client, OnReceiversDestroyed(&session)).Times(1);
raw_port->ReceiveMessage(kValidOfferMessage);
}
@@ -366,6 +369,7 @@ TEST_F(ReceiverSessionTest, CanNegotiateWithCustomConstraints) {
std::move(display)});
EXPECT_CALL(client, OnNegotiated(&session, _)).Times(1);
+ EXPECT_CALL(client, OnReceiversDestroyed(&session)).Times(1);
raw_port->ReceiveMessage(kValidOfferMessage);
const auto& messages = raw_port->posted_messages();
@@ -422,6 +426,7 @@ TEST_F(ReceiverSessionTest, HandlesNoValidAudioStream) {
ReceiverSession::Preferences{});
EXPECT_CALL(client, OnNegotiated(&session, _)).Times(1);
+ EXPECT_CALL(client, OnReceiversDestroyed(&session)).Times(1);
raw_port->ReceiveMessage(kNoAudioOfferMessage);
const auto& messages = raw_port->posted_messages();
@@ -447,6 +452,7 @@ TEST_F(ReceiverSessionTest, HandlesNoValidVideoStream) {
ReceiverSession::Preferences{});
EXPECT_CALL(client, OnNegotiated(&session, _)).Times(1);
+ EXPECT_CALL(client, OnReceiversDestroyed(&session)).Times(1);
raw_port->ReceiveMessage(kNoVideoOfferMessage);
const auto& messages = raw_port->posted_messages();
@@ -473,6 +479,7 @@ TEST_F(ReceiverSessionTest, HandlesNoValidStreams) {
// We shouldn't call OnNegotiated if we failed to negotiate any streams.
EXPECT_CALL(client, OnNegotiated(&session, _)).Times(0);
+ EXPECT_CALL(client, OnReceiversDestroyed(&session)).Times(0);
raw_port->ReceiveMessage(kNoAudioOrVideoOfferMessage);
const auto& messages = raw_port->posted_messages();
@@ -493,6 +500,7 @@ TEST_F(ReceiverSessionTest, HandlesMalformedOffer) {
// Note that unlike when we simply don't select any streams, when the offer
// is actually completely invalid we call OnError.
EXPECT_CALL(client, OnNegotiated(&session, _)).Times(0);
+ EXPECT_CALL(client, OnReceiversDestroyed(&session)).Times(0);
EXPECT_CALL(client,
OnError(&session, openscreen::Error(
openscreen::Error::Code::kJsonParseError)))
@@ -501,5 +509,18 @@ TEST_F(ReceiverSessionTest, HandlesMalformedOffer) {
raw_port->ReceiveMessage(kInvalidJsonOfferMessage);
}
+TEST_F(ReceiverSessionTest, NotifiesReceiverDestruction) {
+ auto message_port = std::make_unique<SimpleMessagePort>();
+ SimpleMessagePort* raw_port = message_port.get();
+ StrictMock<FakeClient> client;
+ ReceiverSession session(&client, std::move(env_), std::move(message_port),
+ ReceiverSession::Preferences{});
+
+ EXPECT_CALL(client, OnNegotiated(&session, _)).Times(2);
+ EXPECT_CALL(client, OnReceiversDestroyed(&session)).Times(2);
+
+ raw_port->ReceiveMessage(kNoAudioOfferMessage);
+ raw_port->ReceiveMessage(kValidOfferMessage);
+}
} // namespace streaming
} // namespace cast