diff options
-rw-r--r-- | cast/standalone_receiver/sdl_glue.cc | 11 | ||||
-rw-r--r-- | cast/standalone_receiver/sdl_glue.h | 12 | ||||
-rw-r--r-- | cast/standalone_receiver/simple_remoting_receiver.cc | 8 | ||||
-rw-r--r-- | cast/standalone_receiver/simple_remoting_receiver.h | 4 | ||||
-rw-r--r-- | cast/standalone_receiver/streaming_playback_controller.cc | 24 | ||||
-rw-r--r-- | cast/standalone_receiver/streaming_playback_controller.h | 5 | ||||
-rw-r--r-- | cast/standalone_sender/looping_file_cast_agent.cc | 8 | ||||
-rw-r--r-- | cast/standalone_sender/looping_file_cast_agent.h | 11 | ||||
-rw-r--r-- | cast/standalone_sender/looping_file_sender.cc | 5 | ||||
-rw-r--r-- | cast/standalone_sender/looping_file_sender.h | 4 | ||||
-rw-r--r-- | cast/standalone_sender/remoting_sender.cc | 32 | ||||
-rw-r--r-- | cast/standalone_sender/remoting_sender.h | 26 | ||||
-rw-r--r-- | cast/standalone_sender/simulated_capturer.cc | 11 | ||||
-rw-r--r-- | cast/standalone_sender/simulated_capturer.h | 6 |
14 files changed, 138 insertions, 29 deletions
diff --git a/cast/standalone_receiver/sdl_glue.cc b/cast/standalone_receiver/sdl_glue.cc index 7c2c94da..c4619f09 100644 --- a/cast/standalone_receiver/sdl_glue.cc +++ b/cast/standalone_receiver/sdl_glue.cc @@ -4,6 +4,8 @@ #include "cast/standalone_receiver/sdl_glue.h" +#include <utility> + #include "platform/api/task_runner.h" #include "platform/api/time.h" #include "util/osp_logging.h" @@ -21,6 +23,11 @@ SDLEventLoopProcessor::SDLEventLoopProcessor( SDLEventLoopProcessor::~SDLEventLoopProcessor() = default; +void SDLEventLoopProcessor::RegisterForKeyboardEvent( + SDLEventLoopProcessor::KeyboardEventCallback cb) { + keyboard_callbacks_.push_back(std::move(cb)); +} + void SDLEventLoopProcessor::ProcessPendingEvents() { // Process all pending events. SDL_Event event; @@ -30,6 +37,10 @@ void SDLEventLoopProcessor::ProcessPendingEvents() { if (quit_callback_) { quit_callback_(); } + } else if (event.type == SDL_KEYUP) { + for (auto& cb : keyboard_callbacks_) { + cb(event.key); + } } } diff --git a/cast/standalone_receiver/sdl_glue.h b/cast/standalone_receiver/sdl_glue.h index 59a3a020..7e136074 100644 --- a/cast/standalone_receiver/sdl_glue.h +++ b/cast/standalone_receiver/sdl_glue.h @@ -7,14 +7,16 @@ #include <stdint.h> -#include <functional> -#include <memory> - #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #include <SDL2/SDL.h> #pragma GCC diagnostic pop +#include <functional> +#include <memory> +#include <utility> +#include <vector> + #include "util/alarm.h" namespace openscreen { @@ -66,11 +68,15 @@ class SDLEventLoopProcessor { std::function<void()> quit_callback); ~SDLEventLoopProcessor(); + using KeyboardEventCallback = std::function<void(const SDL_KeyboardEvent&)>; + void RegisterForKeyboardEvent(KeyboardEventCallback cb); + private: void ProcessPendingEvents(); Alarm alarm_; std::function<void()> quit_callback_; + std::vector<KeyboardEventCallback> keyboard_callbacks_; }; } // namespace cast diff --git a/cast/standalone_receiver/simple_remoting_receiver.cc b/cast/standalone_receiver/simple_remoting_receiver.cc index 119be44f..b685d564 100644 --- a/cast/standalone_receiver/simple_remoting_receiver.cc +++ b/cast/standalone_receiver/simple_remoting_receiver.cc @@ -76,6 +76,14 @@ void SimpleRemotingReceiver::SendInitializeMessage( messenger_->SendMessageToRemote(rpc); } +void SimpleRemotingReceiver::SendPlaybackRateMessage(double playback_rate) { + openscreen::cast::RpcMessage rpc; + rpc.set_handle(RpcMessenger::kAcquireRendererHandle); + rpc.set_proc(openscreen::cast::RpcMessage::RPC_R_SETPLAYBACKRATE); + rpc.set_double_value(playback_rate); + messenger_->SendMessageToRemote(rpc); +} + void SimpleRemotingReceiver::OnInitializeCallbackMessage( std::unique_ptr<RpcMessage> message) { OSP_DCHECK(message->proc() == RpcMessage::RPC_DS_INITIALIZE_CALLBACK); diff --git a/cast/standalone_receiver/simple_remoting_receiver.h b/cast/standalone_receiver/simple_remoting_receiver.h index 52fe131f..8e672574 100644 --- a/cast/standalone_receiver/simple_remoting_receiver.h +++ b/cast/standalone_receiver/simple_remoting_receiver.h @@ -39,6 +39,10 @@ class SimpleRemotingReceiver { using InitializeCallback = std::function<void(AudioCodec, VideoCodec)>; void SendInitializeMessage(InitializeCallback initialize_cb); + // The speed at which the content is decoded is synchronized with the + // playback rate. Pausing is a special case with a playback rate of 0.0. + void SendPlaybackRateMessage(double playback_rate); + private: void OnInitializeCallbackMessage(std::unique_ptr<RpcMessage> message); diff --git a/cast/standalone_receiver/streaming_playback_controller.cc b/cast/standalone_receiver/streaming_playback_controller.cc index 8c931273..4a81c7ed 100644 --- a/cast/standalone_receiver/streaming_playback_controller.cc +++ b/cast/standalone_receiver/streaming_playback_controller.cc @@ -44,6 +44,11 @@ StreamingPlaybackController::StreamingPlaybackController( OSP_CHECK(window_) << "Failed to create SDL window: " << SDL_GetError(); renderer_ = MakeUniqueSDLRenderer(window_.get(), -1, 0); OSP_CHECK(renderer_) << "Failed to create SDL renderer: " << SDL_GetError(); + + sdl_event_loop_.RegisterForKeyboardEvent( + [this](const SDL_KeyboardEvent& event) { + this->HandleKeyboardEvent(event); + }); } #else StreamingPlaybackController::StreamingPlaybackController( @@ -121,5 +126,24 @@ void StreamingPlaybackController::Initialize( #endif // defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS) } +#if defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS) +void StreamingPlaybackController::HandleKeyboardEvent( + const SDL_KeyboardEvent& event) { + // We only handle keyboard events if we are remoting. + if (!remoting_receiver_) { + return; + } + + switch (event.keysym.sym) { + // See codes here: https://wiki.libsdl.org/SDL_Scancode + case SDLK_KP_SPACE: // fallthrough, "Keypad Space" + case SDLK_SPACE: // "Space" + is_playing_ = !is_playing_; + remoting_receiver_->SendPlaybackRateMessage(is_playing_ ? 1.0 : 0.0); + break; + } +} +#endif + } // namespace cast } // namespace openscreen diff --git a/cast/standalone_receiver/streaming_playback_controller.h b/cast/standalone_receiver/streaming_playback_controller.h index 68f3068d..109b8adb 100644 --- a/cast/standalone_receiver/streaming_playback_controller.h +++ b/cast/standalone_receiver/streaming_playback_controller.h @@ -53,17 +53,20 @@ class StreamingPlaybackController final : public ReceiverSession::Client { void Initialize(ReceiverSession::ConfiguredReceivers receivers); #if defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS) + void HandleKeyboardEvent(const SDL_KeyboardEvent& event); + // NOTE: member ordering is important, since the sub systems must be // first-constructed, last-destroyed. Make sure any new SDL related // members are added below the sub systems. const ScopedSDLSubSystem<SDL_INIT_AUDIO> sdl_audio_sub_system_; const ScopedSDLSubSystem<SDL_INIT_VIDEO> sdl_video_sub_system_; - const SDLEventLoopProcessor sdl_event_loop_; + SDLEventLoopProcessor sdl_event_loop_; SDLWindowUniquePtr window_; SDLRendererUniquePtr renderer_; std::unique_ptr<SDLAudioPlayer> audio_player_; std::unique_ptr<SDLVideoPlayer> video_player_; + double is_playing_ = true; #else std::unique_ptr<DummyPlayer> audio_player_; std::unique_ptr<DummyPlayer> video_player_; diff --git a/cast/standalone_sender/looping_file_cast_agent.cc b/cast/standalone_sender/looping_file_cast_agent.cc index 4ee2231a..0e17ecab 100644 --- a/cast/standalone_sender/looping_file_cast_agent.cc +++ b/cast/standalone_sender/looping_file_cast_agent.cc @@ -273,7 +273,7 @@ void LoopingFileCastAgent::CreateAndStartSession() { if (connection_settings_->use_remoting) { remoting_sender_ = std::make_unique<RemotingSender>( current_session_->rpc_messenger(), AudioCodec::kOpus, - connection_settings_->codec, [this]() { OnRemotingReceiverReady(); }); + connection_settings_->codec, this); negotiation_error = current_session_->NegotiateRemoting(audio_config, video_config); @@ -321,13 +321,17 @@ void LoopingFileCastAgent::OnError(const SenderSession* session, Error error) { Shutdown(); } -void LoopingFileCastAgent::OnRemotingReceiverReady() { +void LoopingFileCastAgent::OnReady() { is_ready_for_remoting_ = true; if (current_negotiation_) { StartRemotingSenders(); } } +void LoopingFileCastAgent::OnPlaybackRateChange(double rate) { + file_sender_->SetPlaybackRate(rate); +} + void LoopingFileCastAgent::StartRemotingSenders() { OSP_DCHECK(current_negotiation_); file_sender_ = std::make_unique<LoopingFileSender>( diff --git a/cast/standalone_sender/looping_file_cast_agent.h b/cast/standalone_sender/looping_file_cast_agent.h index 895d1324..3ec2e8fa 100644 --- a/cast/standalone_sender/looping_file_cast_agent.h +++ b/cast/standalone_sender/looping_file_cast_agent.h @@ -70,7 +70,8 @@ class LoopingFileCastAgent final public VirtualConnectionRouter::SocketErrorHandler, public ConnectionNamespaceHandler::VirtualConnectionPolicy, public CastMessageHandler, - public SenderSession::Client { + public SenderSession::Client, + public RemotingSender::Client { public: using ShutdownCallback = std::function<void()>; @@ -107,6 +108,10 @@ class LoopingFileCastAgent final CastSocket* socket, ::cast::channel::CastMessage message) override; + // RemotingSender::Client overrides. + void OnReady() override; + void OnPlaybackRateChange(double rate) override; + // Returns the Cast application ID for either A/V mirroring or audio-only // mirroring, as configured by the ConnectionSettings. const char* GetMirroringAppId() const; @@ -135,10 +140,6 @@ 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. diff --git a/cast/standalone_sender/looping_file_sender.cc b/cast/standalone_sender/looping_file_sender.cc index 9f6137dc..7ed5e3fe 100644 --- a/cast/standalone_sender/looping_file_sender.cc +++ b/cast/standalone_sender/looping_file_sender.cc @@ -44,6 +44,11 @@ LoopingFileSender::LoopingFileSender(Environment* environment, LoopingFileSender::~LoopingFileSender() = default; +void LoopingFileSender::SetPlaybackRate(double rate) { + video_capturer_->SetPlaybackRate(rate); + audio_capturer_->SetPlaybackRate(rate); +} + void LoopingFileSender::UpdateEncoderBitrates() { if (bandwidth_being_utilized_ >= kHighBandwidthThreshold) { audio_encoder_.UseHighQuality(); diff --git a/cast/standalone_sender/looping_file_sender.h b/cast/standalone_sender/looping_file_sender.h index 56a8aa45..7ad784b9 100644 --- a/cast/standalone_sender/looping_file_sender.h +++ b/cast/standalone_sender/looping_file_sender.h @@ -33,6 +33,8 @@ class LoopingFileSender final : public SimulatedAudioCapturer::Client, ~LoopingFileSender() final; + void SetPlaybackRate(double rate); + private: void UpdateEncoderBitrates(); void ControlForNetworkCongestion(); @@ -49,7 +51,7 @@ class LoopingFileSender final : public SimulatedAudioCapturer::Client, void UpdateStatusOnConsole(); - // SimulatedCapturer overrides. + // SimulatedCapturer::Client overrides. void OnEndOfFile(SimulatedCapturer* capturer) final; void OnError(SimulatedCapturer* capturer, std::string message) final; diff --git a/cast/standalone_sender/remoting_sender.cc b/cast/standalone_sender/remoting_sender.cc index 1566f0a7..741fb190 100644 --- a/cast/standalone_sender/remoting_sender.cc +++ b/cast/standalone_sender/remoting_sender.cc @@ -41,19 +41,22 @@ AudioDecoderConfig::Codec ToProtoCodec(AudioCodec value) { } // namespace +RemotingSender::Client::~Client() = default; + RemotingSender::RemotingSender(RpcMessenger* messenger, AudioCodec audio_codec, VideoCodec video_codec, - ReadyCallback ready_cb) + Client* client) : messenger_(messenger), audio_codec_(audio_codec), video_codec_(video_codec), - ready_cb_(std::move(ready_cb)) { + client_(client) { + OSP_DCHECK(client_); messenger_->RegisterMessageReceiverCallback( RpcMessenger::kAcquireRendererHandle, [this](std::unique_ptr<RpcMessage> message) { OSP_DCHECK(message); - this->OnInitializeMessage(*message); + this->OnMessage(*message); }); } @@ -62,6 +65,19 @@ RemotingSender::~RemotingSender() { RpcMessenger::kAcquireRendererHandle); } +void RemotingSender::OnMessage(const RpcMessage& message) { + if (!message.has_proc()) { + return; + } + if (message.proc() == RpcMessage_RpcProc_RPC_DS_INITIALIZE) { + OSP_VLOG << "Received initialize message"; + OnInitializeMessage(message); + } else if (message.proc() == RpcMessage_RpcProc_RPC_R_SETPLAYBACKRATE) { + OSP_VLOG << "Received playback rate message: " << message.double_value(); + OnPlaybackRateMessage(message); + } +} + void RemotingSender::OnInitializeMessage(const RpcMessage& message) { receiver_handle_ = message.integer_value(); @@ -84,11 +100,11 @@ void RemotingSender::OnInitializeMessage(const RpcMessage& message) { << " 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."; - } + client_->OnReady(); +} + +void RemotingSender::OnPlaybackRateMessage(const RpcMessage& message) { + client_->OnPlaybackRateChange(message.double_value()); } } // namespace cast diff --git a/cast/standalone_sender/remoting_sender.h b/cast/standalone_sender/remoting_sender.h index d331009b..7d09dc69 100644 --- a/cast/standalone_sender/remoting_sender.h +++ b/cast/standalone_sender/remoting_sender.h @@ -26,19 +26,29 @@ namespace cast { // the public APIs. class RemotingSender { public: - using ReadyCallback = std::function<void()>; + // The remoting sender expects a valid client to handle received messages. + class Client { + public: + virtual ~Client(); + + // Executed when we receive the initialize message from the receiver. + virtual void OnReady() = 0; + + // Executed when we receive a playback rate message from the receiver. + virtual void OnPlaybackRateChange(double rate) = 0; + }; + RemotingSender(RpcMessenger* messenger, AudioCodec audio_codec, VideoCodec video_codec, - ReadyCallback ready_cb); + Client* client); ~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. + // Helper for parsing any received RPC messages. + void OnMessage(const RpcMessage& message); void OnInitializeMessage(const RpcMessage& message); + void OnPlaybackRateMessage(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 @@ -52,9 +62,7 @@ class RemotingSender { 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_; + Client* client_; // The initialization message from the receiver contains the handle the // callback should go to. diff --git a/cast/standalone_sender/simulated_capturer.cc b/cast/standalone_sender/simulated_capturer.cc index 87313010..713caa24 100644 --- a/cast/standalone_sender/simulated_capturer.cc +++ b/cast/standalone_sender/simulated_capturer.cc @@ -85,6 +85,14 @@ SimulatedCapturer::SimulatedCapturer(Environment* environment, SimulatedCapturer::~SimulatedCapturer() = default; +void SimulatedCapturer::SetPlaybackRate(double rate) { + playback_rate_is_non_zero_ = rate > 0; + if (playback_rate_is_non_zero_) { + // Restart playback now that playback rate is nonzero. + StartDecodingNextFrame(); + } +} + void SimulatedCapturer::SetAdditionalDecoderParameters( AVCodecContext* decoder_context) {} @@ -119,6 +127,9 @@ Clock::duration SimulatedCapturer::ToApproximateClockDuration( } void SimulatedCapturer::StartDecodingNextFrame() { + if (!playback_rate_is_non_zero_) { + return; + } const int read_frame_result = av_read_frame(format_context_.get(), packet_.get()); if (read_frame_result < 0) { diff --git a/cast/standalone_sender/simulated_capturer.h b/cast/standalone_sender/simulated_capturer.h index 8d32085a..61738e1f 100644 --- a/cast/standalone_sender/simulated_capturer.h +++ b/cast/standalone_sender/simulated_capturer.h @@ -40,6 +40,8 @@ class SimulatedCapturer { virtual ~Observer(); }; + void SetPlaybackRate(double rate); + protected: SimulatedCapturer(Environment* environment, const char* path, @@ -103,6 +105,10 @@ class SimulatedCapturer { // Used to schedule the next task to execute and when it should execute. There // is only ever one task scheduled/running at any time. Alarm next_task_; + + // Used to determine playback rate. Currently, we only support "playing" + // at 1x speed, or "pausing" at 0x speed. + bool playback_rate_is_non_zero_ = true; }; // Emits the primary audio stream from a file. |