aboutsummaryrefslogtreecommitdiff
path: root/cast/standalone_sender
diff options
context:
space:
mode:
Diffstat (limited to 'cast/standalone_sender')
-rw-r--r--cast/standalone_sender/BUILD.gn2
-rw-r--r--cast/standalone_sender/looping_file_cast_agent.cc31
-rw-r--r--cast/standalone_sender/looping_file_cast_agent.h21
-rw-r--r--cast/standalone_sender/remoting_sender.cc95
-rw-r--r--cast/standalone_sender/remoting_sender.h67
5 files changed, 211 insertions, 5 deletions
diff --git a/cast/standalone_sender/BUILD.gn b/cast/standalone_sender/BUILD.gn
index afa73d7d..780e0609 100644
--- a/cast/standalone_sender/BUILD.gn
+++ b/cast/standalone_sender/BUILD.gn
@@ -49,6 +49,8 @@ if (!build_with_chromium) {
"looping_file_sender.h",
"receiver_chooser.cc",
"receiver_chooser.h",
+ "remoting_sender.cc",
+ "remoting_sender.h",
"simulated_capturer.cc",
"simulated_capturer.h",
"streaming_opus_encoder.cc",
diff --git a/cast/standalone_sender/looping_file_cast_agent.cc b/cast/standalone_sender/looping_file_cast_agent.cc
index ce9826de..bfb970bf 100644
--- a/cast/standalone_sender/looping_file_cast_agent.cc
+++ b/cast/standalone_sender/looping_file_cast_agent.cc
@@ -270,6 +270,10 @@ void LoopingFileCastAgent::CreateAndStartSession() {
OSP_VLOG << "Starting session negotiation.";
Error negotiation_error;
if (connection_settings_->use_remoting) {
+ remoting_sender_ = std::make_unique<RemotingSender>(
+ current_session_->rpc_messenger(), AudioCodec::kOpus, VideoCodec::kVp8,
+ [this]() { OnRemotingReceiverReady(); });
+
negotiation_error =
current_session_->NegotiateRemoting(audio_config, video_config);
} else {
@@ -298,17 +302,17 @@ void LoopingFileCastAgent::OnNegotiated(
void LoopingFileCastAgent::OnRemotingNegotiated(
const SenderSession* session,
SenderSession::RemotingNegotiation negotiation) {
- // TODO(jophba): this needs to be hashed out as part of
- // figuring out the embedder workflow.
if (negotiation.senders.audio_sender == nullptr &&
negotiation.senders.video_sender == nullptr) {
OSP_LOG_ERROR << "Missing both audio and video, so exiting...";
return;
}
- file_sender_ = std::make_unique<LoopingFileSender>(
- environment_.get(), connection_settings_.value(), session,
- std::move(negotiation.senders), [this]() { shutdown_callback_(); });
+ current_negotiation_ =
+ std::make_unique<SenderSession::RemotingNegotiation>(negotiation);
+ if (is_ready_for_remoting_) {
+ StartRemotingSenders();
+ }
}
void LoopingFileCastAgent::OnError(const SenderSession* session, Error error) {
@@ -316,6 +320,23 @@ void LoopingFileCastAgent::OnError(const SenderSession* session, Error error) {
Shutdown();
}
+void LoopingFileCastAgent::OnRemotingReceiverReady() {
+ is_ready_for_remoting_ = true;
+ if (current_negotiation_) {
+ StartRemotingSenders();
+ }
+}
+
+void LoopingFileCastAgent::StartRemotingSenders() {
+ OSP_DCHECK(current_negotiation_);
+ file_sender_ = std::make_unique<LoopingFileSender>(
+ environment_.get(), connection_settings_.value(), current_session_.get(),
+ std::move(current_negotiation_->senders),
+ [this]() { shutdown_callback_(); });
+ current_negotiation_.reset();
+ is_ready_for_remoting_ = false;
+}
+
void LoopingFileCastAgent::Shutdown() {
TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender);
diff --git a/cast/standalone_sender/looping_file_cast_agent.h b/cast/standalone_sender/looping_file_cast_agent.h
index cff0f6ba..895d1324 100644
--- a/cast/standalone_sender/looping_file_cast_agent.h
+++ b/cast/standalone_sender/looping_file_cast_agent.h
@@ -21,6 +21,7 @@
#include "cast/sender/public/sender_socket_factory.h"
#include "cast/standalone_sender/connection_settings.h"
#include "cast/standalone_sender/looping_file_sender.h"
+#include "cast/standalone_sender/remoting_sender.h"
#include "cast/streaming/environment.h"
#include "cast/streaming/sender_session.h"
#include "platform/api/scoped_wake_lock.h"
@@ -134,6 +135,15 @@ class LoopingFileCastAgent final
SenderSession::RemotingNegotiation negotiation) override;
void OnError(const SenderSession* session, Error error) override;
+ // Callback for when the RemotingSender indicates that the receiver
+ // is ready.
+ void OnRemotingReceiverReady();
+
+ // Starts the remoting sender. This may occur when remoting is "ready" if the
+ // session is already negotiated, or upon session negotiation if the receiver
+ // is already ready.
+ void StartRemotingSenders();
+
// Helper for stopping the current session, and/or unwinding a remote
// connection request (pre-session). This ensures LoopingFileCastAgent is in a
// terminal shutdown state.
@@ -168,6 +178,17 @@ class LoopingFileCastAgent final
std::unique_ptr<Environment> environment_;
std::unique_ptr<SenderSession> current_session_;
std::unique_ptr<LoopingFileSender> file_sender_;
+
+ // Remoting specific member variables.
+ std::unique_ptr<RemotingSender> remoting_sender_;
+
+ // Set when remoting is successfully negotiated. However, remoting streams
+ // won't start until |is_ready_for_remoting_| is true.
+ std::unique_ptr<SenderSession::RemotingNegotiation> current_negotiation_;
+
+ // Set to true when the remoting receiver is ready. However, remoting streams
+ // won't start until remoting is successfully negotiated.
+ bool is_ready_for_remoting_ = false;
};
} // namespace cast
diff --git a/cast/standalone_sender/remoting_sender.cc b/cast/standalone_sender/remoting_sender.cc
new file mode 100644
index 00000000..1566f0a7
--- /dev/null
+++ b/cast/standalone_sender/remoting_sender.cc
@@ -0,0 +1,95 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cast/standalone_sender/remoting_sender.h"
+
+#include <utility>
+
+#include "cast/streaming/message_fields.h"
+
+namespace openscreen {
+namespace cast {
+
+namespace {
+
+VideoDecoderConfig::Codec ToProtoCodec(VideoCodec value) {
+ switch (value) {
+ case VideoCodec::kHevc:
+ return VideoDecoderConfig_Codec_kCodecHEVC;
+ case VideoCodec::kH264:
+ return VideoDecoderConfig_Codec_kCodecH264;
+ case VideoCodec::kVp8:
+ return VideoDecoderConfig_Codec_kCodecVP8;
+ case VideoCodec::kVp9:
+ return VideoDecoderConfig_Codec_kCodecVP9;
+ default:
+ return VideoDecoderConfig_Codec_kUnknownVideoCodec;
+ }
+}
+
+AudioDecoderConfig::Codec ToProtoCodec(AudioCodec value) {
+ switch (value) {
+ case AudioCodec::kAac:
+ return AudioDecoderConfig_Codec_kCodecAAC;
+ case AudioCodec::kOpus:
+ return AudioDecoderConfig_Codec_kCodecOpus;
+ default:
+ return AudioDecoderConfig_Codec_kUnknownAudioCodec;
+ }
+}
+
+} // namespace
+
+RemotingSender::RemotingSender(RpcMessenger* messenger,
+ AudioCodec audio_codec,
+ VideoCodec video_codec,
+ ReadyCallback ready_cb)
+ : messenger_(messenger),
+ audio_codec_(audio_codec),
+ video_codec_(video_codec),
+ ready_cb_(std::move(ready_cb)) {
+ messenger_->RegisterMessageReceiverCallback(
+ RpcMessenger::kAcquireRendererHandle,
+ [this](std::unique_ptr<RpcMessage> message) {
+ OSP_DCHECK(message);
+ this->OnInitializeMessage(*message);
+ });
+}
+
+RemotingSender::~RemotingSender() {
+ messenger_->UnregisterMessageReceiverCallback(
+ RpcMessenger::kAcquireRendererHandle);
+}
+
+void RemotingSender::OnInitializeMessage(const RpcMessage& message) {
+ receiver_handle_ = message.integer_value();
+
+ RpcMessage callback_message;
+ callback_message.set_handle(receiver_handle_);
+ callback_message.set_proc(RpcMessage::RPC_DS_INITIALIZE_CALLBACK);
+
+ auto* callback_body =
+ callback_message.mutable_demuxerstream_initializecb_rpc();
+
+ // In Chrome, separate calls are used for the audio and video configs, but
+ // for simplicity's sake we combine them here.
+ callback_body->mutable_audio_decoder_config()->set_codec(
+ ToProtoCodec(audio_codec_));
+ callback_body->mutable_video_decoder_config()->set_codec(
+ ToProtoCodec(video_codec_));
+
+ OSP_DLOG_INFO << "Initializing receiver handle " << receiver_handle_
+ << " with audio codec " << CodecToString(audio_codec_)
+ << " and video codec " << CodecToString(video_codec_);
+ messenger_->SendMessageToRemote(callback_message);
+
+ if (ready_cb_) {
+ ready_cb_();
+ } else {
+ OSP_DLOG_INFO << "Received a ready message, but no ready callback.";
+ }
+}
+
+} // namespace cast
+} // namespace openscreen
diff --git a/cast/standalone_sender/remoting_sender.h b/cast/standalone_sender/remoting_sender.h
new file mode 100644
index 00000000..d331009b
--- /dev/null
+++ b/cast/standalone_sender/remoting_sender.h
@@ -0,0 +1,67 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CAST_STANDALONE_SENDER_REMOTING_SENDER_H_
+#define CAST_STANDALONE_SENDER_REMOTING_SENDER_H_
+
+#include <memory>
+
+#include "cast/streaming/constants.h"
+#include "cast/streaming/rpc_messenger.h"
+
+namespace openscreen {
+namespace cast {
+
+// This class behaves like a pared-down version of Chrome's StreamProvider (see
+// https://source.chromium.org/chromium/chromium/src/+/main:media/remoting/stream_provider.h
+// ). Instead of fully managing a media::DemuxerStream however, it just provides
+// an RPC initialization routine that notifies the standalone receiver's
+// SimpleRemotingReceiver instance (if configured) that initialization has been
+// complete and what codecs were selected.
+//
+// Due to the sheer complexity of remoting, we don't have a fully functional
+// implementation of remoting in the standalone_* components, instead Chrome is
+// the reference implementation and we have these simple classes to exercise
+// the public APIs.
+class RemotingSender {
+ public:
+ using ReadyCallback = std::function<void()>;
+ RemotingSender(RpcMessenger* messenger,
+ AudioCodec audio_codec,
+ VideoCodec video_codec,
+ ReadyCallback ready_cb);
+ ~RemotingSender();
+
+ private:
+ // When the receiver indicates that it is ready for initialization, it will
+ // The receiver sends us an "initialization" message that we respond to
+ // here with an "initialization callback" message that contains codec
+ // information.
+ void OnInitializeMessage(const RpcMessage& message);
+
+ // The messenger is the only caller of OnInitializeMessage, so there are no
+ // lifetime concerns. However, if this class outlives |messenger_|, it will
+ // no longer receive initialization messages.
+ RpcMessenger* messenger_;
+
+ // Unlike in Chrome, here we should know the video and audio codecs before any
+ // of the remoting code gets set up, and for simplicity's sake we can only
+ // populate the AudioDecoderConfig and VideoDecoderConfig objects with the
+ // codecs and use the rest of the fields as-is from the OFFER/ANSWER exchange.
+ const AudioCodec audio_codec_;
+ const VideoCodec video_codec_;
+
+ // The callback method to be called once we get the initialization message
+ // from the receiver.
+ ReadyCallback ready_cb_;
+
+ // The initialization message from the receiver contains the handle the
+ // callback should go to.
+ RpcMessenger::Handle receiver_handle_ = RpcMessenger::kInvalidHandle;
+};
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STANDALONE_SENDER_REMOTING_SENDER_H_