1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/standalone_receiver/streaming_playback_controller.h"
6
7 #include <string>
8
9 #if defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
10 #include "cast/standalone_receiver/sdl_audio_player.h" // nogncheck
11 #include "cast/standalone_receiver/sdl_glue.h" // nogncheck
12 #include "cast/standalone_receiver/sdl_video_player.h" // nogncheck
13 #else
14 #include "cast/standalone_receiver/dummy_player.h" // nogncheck
15 #endif // defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
16
17 #include "util/trace_logging.h"
18
19 namespace openscreen {
20 namespace cast {
21
22 StreamingPlaybackController::Client::~Client() = default;
23
24 #if defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
StreamingPlaybackController(TaskRunner * task_runner,StreamingPlaybackController::Client * client)25 StreamingPlaybackController::StreamingPlaybackController(
26 TaskRunner* task_runner,
27 StreamingPlaybackController::Client* client)
28 : task_runner_(task_runner),
29 client_(client),
30 sdl_event_loop_(task_runner_, [this] {
31 client_->OnPlaybackError(this,
32 Error{Error::Code::kOperationCancelled,
33 std::string("SDL event loop closed.")});
34 }) {
35 OSP_DCHECK(task_runner_ != nullptr);
36 OSP_DCHECK(client_ != nullptr);
37 constexpr int kDefaultWindowWidth = 1280;
38 constexpr int kDefaultWindowHeight = 720;
39 window_ = MakeUniqueSDLWindow(
40 "Cast Streaming Receiver Demo",
41 SDL_WINDOWPOS_UNDEFINED /* initial X position */,
42 SDL_WINDOWPOS_UNDEFINED /* initial Y position */, kDefaultWindowWidth,
43 kDefaultWindowHeight, SDL_WINDOW_RESIZABLE);
44 OSP_CHECK(window_) << "Failed to create SDL window: " << SDL_GetError();
45 renderer_ = MakeUniqueSDLRenderer(window_.get(), -1, 0);
46 OSP_CHECK(renderer_) << "Failed to create SDL renderer: " << SDL_GetError();
47
48 sdl_event_loop_.RegisterForKeyboardEvent(
__anonbb8123350202(const SDL_KeyboardEvent& event) 49 [this](const SDL_KeyboardEvent& event) {
50 this->HandleKeyboardEvent(event);
51 });
52 }
53 #else
StreamingPlaybackController(TaskRunner * task_runner,StreamingPlaybackController::Client * client)54 StreamingPlaybackController::StreamingPlaybackController(
55 TaskRunner* task_runner,
56 StreamingPlaybackController::Client* client)
57 : task_runner_(task_runner), client_(client) {
58 OSP_DCHECK(task_runner_ != nullptr);
59 OSP_DCHECK(client_ != nullptr);
60 }
61 #endif // defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
62
OnNegotiated(const ReceiverSession * session,ReceiverSession::ConfiguredReceivers receivers)63 void StreamingPlaybackController::OnNegotiated(
64 const ReceiverSession* session,
65 ReceiverSession::ConfiguredReceivers receivers) {
66 TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneReceiver);
67 Initialize(receivers);
68 }
69
OnRemotingNegotiated(const ReceiverSession * session,ReceiverSession::RemotingNegotiation negotiation)70 void StreamingPlaybackController::OnRemotingNegotiated(
71 const ReceiverSession* session,
72 ReceiverSession::RemotingNegotiation negotiation) {
73 remoting_receiver_ =
74 std::make_unique<SimpleRemotingReceiver>(negotiation.messenger);
75 remoting_receiver_->SendInitializeMessage(
76 [this, receivers = negotiation.receivers](AudioCodec audio_codec,
77 VideoCodec video_codec) {
78 // The configurations in |negotiation| do not have the actual codecs,
79 // only REMOTE_AUDIO and REMOTE_VIDEO. Once we receive the
80 // initialization callback method, we can override with the actual
81 // codecs here.
82 auto mutable_receivers = receivers;
83 mutable_receivers.audio_config.codec = audio_codec;
84 mutable_receivers.video_config.codec = video_codec;
85 Initialize(mutable_receivers);
86 });
87 }
88
OnReceiversDestroying(const ReceiverSession * session,ReceiversDestroyingReason reason)89 void StreamingPlaybackController::OnReceiversDestroying(
90 const ReceiverSession* session,
91 ReceiversDestroyingReason reason) {
92 OSP_LOG_INFO << "Receivers are currently destroying, resetting SDL players.";
93 audio_player_.reset();
94 video_player_.reset();
95 }
96
OnError(const ReceiverSession * session,Error error)97 void StreamingPlaybackController::OnError(const ReceiverSession* session,
98 Error error) {
99 client_->OnPlaybackError(this, error);
100 }
101
Initialize(ReceiverSession::ConfiguredReceivers receivers)102 void StreamingPlaybackController::Initialize(
103 ReceiverSession::ConfiguredReceivers receivers) {
104 #if defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
105 OSP_LOG_INFO << "Successfully negotiated a session, creating SDL players.";
106 if (receivers.audio_receiver) {
107 audio_player_ = std::make_unique<SDLAudioPlayer>(
108 &Clock::now, task_runner_, receivers.audio_receiver,
109 receivers.audio_config.codec, [this] {
110 client_->OnPlaybackError(this, audio_player_->error_status());
111 });
112 }
113 if (receivers.video_receiver) {
114 video_player_ = std::make_unique<SDLVideoPlayer>(
115 &Clock::now, task_runner_, receivers.video_receiver,
116 receivers.video_config.codec, renderer_.get(), [this] {
117 client_->OnPlaybackError(this, video_player_->error_status());
118 });
119 }
120 #else
121 if (receivers.audio_receiver) {
122 audio_player_ = std::make_unique<DummyPlayer>(receivers.audio_receiver);
123 }
124
125 if (receivers.video_receiver) {
126 video_player_ = std::make_unique<DummyPlayer>(receivers.video_receiver);
127 }
128 #endif // defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
129 }
130
131 #if defined(CAST_STANDALONE_RECEIVER_HAVE_EXTERNAL_LIBS)
HandleKeyboardEvent(const SDL_KeyboardEvent & event)132 void StreamingPlaybackController::HandleKeyboardEvent(
133 const SDL_KeyboardEvent& event) {
134 // We only handle keyboard events if we are remoting.
135 if (!remoting_receiver_) {
136 return;
137 }
138
139 switch (event.keysym.sym) {
140 // See codes here: https://wiki.libsdl.org/SDL_Scancode
141 case SDLK_KP_SPACE: // fallthrough, "Keypad Space"
142 case SDLK_SPACE: // "Space"
143 is_playing_ = !is_playing_;
144 remoting_receiver_->SendPlaybackRateMessage(is_playing_ ? 1.0 : 0.0);
145 break;
146 }
147 }
148 #endif
149
150 } // namespace cast
151 } // namespace openscreen
152