aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cast/standalone_receiver/sdl_glue.cc11
-rw-r--r--cast/standalone_receiver/sdl_glue.h12
-rw-r--r--cast/standalone_receiver/simple_remoting_receiver.cc8
-rw-r--r--cast/standalone_receiver/simple_remoting_receiver.h4
-rw-r--r--cast/standalone_receiver/streaming_playback_controller.cc24
-rw-r--r--cast/standalone_receiver/streaming_playback_controller.h5
-rw-r--r--cast/standalone_sender/looping_file_cast_agent.cc8
-rw-r--r--cast/standalone_sender/looping_file_cast_agent.h11
-rw-r--r--cast/standalone_sender/looping_file_sender.cc5
-rw-r--r--cast/standalone_sender/looping_file_sender.h4
-rw-r--r--cast/standalone_sender/remoting_sender.cc32
-rw-r--r--cast/standalone_sender/remoting_sender.h26
-rw-r--r--cast/standalone_sender/simulated_capturer.cc11
-rw-r--r--cast/standalone_sender/simulated_capturer.h6
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.