1 // Copyright 2018 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 "components/mirroring/service/media_remoter.h"
6
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/strings/string_piece.h"
13 #include "base/values.h"
14 #include "components/mirroring/service/message_dispatcher.h"
15 #include "components/mirroring/service/remoting_sender.h"
16 #include "media/cast/net/cast_transport.h"
17
18 using media::cast::Codec;
19 using media::cast::FrameSenderConfig;
20
21 namespace mirroring {
22
MediaRemoter(Client * client,const media::mojom::RemotingSinkMetadata & sink_metadata,MessageDispatcher * message_dispatcher)23 MediaRemoter::MediaRemoter(
24 Client* client,
25 const media::mojom::RemotingSinkMetadata& sink_metadata,
26 MessageDispatcher* message_dispatcher)
27 : client_(client),
28 sink_metadata_(sink_metadata),
29 message_dispatcher_(message_dispatcher),
30 cast_environment_(nullptr),
31 transport_(nullptr),
32 state_(MIRRORING) {
33 DCHECK(client_);
34 DCHECK(message_dispatcher_);
35
36 client_->ConnectToRemotingSource(
37 receiver_.BindNewPipeAndPassRemote(),
38 remoting_source_.BindNewPipeAndPassReceiver());
39 remoting_source_->OnSinkAvailable(sink_metadata_.Clone());
40 }
41
~MediaRemoter()42 MediaRemoter::~MediaRemoter() {
43 // Stop this remoting session if mirroring is stopped during a remoting
44 // session. For example, user stops mirroring through the cast dialog or
45 // closes the tab.
46 Stop(media::mojom::RemotingStopReason::ROUTE_TERMINATED);
47 }
48
OnMessageFromSink(const ReceiverResponse & response)49 void MediaRemoter::OnMessageFromSink(const ReceiverResponse& response) {
50 DCHECK_EQ(ResponseType::RPC, response.type());
51 remoting_source_->OnMessageFromSink(
52 std::vector<uint8_t>(response.rpc().begin(), response.rpc().end()));
53 }
54
StartRpcMessaging(scoped_refptr<media::cast::CastEnvironment> cast_environment,media::cast::CastTransport * transport,const FrameSenderConfig & audio_config,const FrameSenderConfig & video_config)55 void MediaRemoter::StartRpcMessaging(
56 scoped_refptr<media::cast::CastEnvironment> cast_environment,
57 media::cast::CastTransport* transport,
58 const FrameSenderConfig& audio_config,
59 const FrameSenderConfig& video_config) {
60 DCHECK(!cast_environment_);
61 DCHECK(!transport_);
62 DCHECK_EQ(Codec::CODEC_UNKNOWN, audio_config_.codec);
63 DCHECK_EQ(Codec::CODEC_UNKNOWN, video_config_.codec);
64 DCHECK(audio_config.codec == Codec::CODEC_AUDIO_REMOTE ||
65 video_config.codec == Codec::CODEC_VIDEO_REMOTE);
66
67 if (state_ != STARTING_REMOTING)
68 return; // Start operation was canceled.
69 // A remoting streaming session started. Start RPC message transport and
70 // notify the remoting source to start data streaming.
71 cast_environment_ = std::move(cast_environment);
72 transport_ = transport;
73 audio_config_ = audio_config;
74 video_config_ = video_config;
75 message_dispatcher_->Subscribe(
76 ResponseType::RPC, base::BindRepeating(&MediaRemoter::OnMessageFromSink,
77 weak_factory_.GetWeakPtr()));
78 state_ = REMOTING_STARTED;
79 remoting_source_->OnStarted();
80 }
81
OnMirroringResumed()82 void MediaRemoter::OnMirroringResumed() {
83 if (state_ == REMOTING_DISABLED)
84 return;
85 DCHECK_EQ(STOPPING_REMOTING, state_);
86 state_ = MIRRORING;
87 // Notify the remoting source to enable starting media remoting again.
88 remoting_source_->OnSinkAvailable(sink_metadata_.Clone());
89 }
90
OnRemotingFailed()91 void MediaRemoter::OnRemotingFailed() {
92 DCHECK(state_ == STARTING_REMOTING || state_ == REMOTING_STARTED);
93 if (state_ == STARTING_REMOTING) {
94 remoting_source_->OnStartFailed(
95 media::mojom::RemotingStartFailReason::INVALID_ANSWER_MESSAGE);
96 }
97 state_ = REMOTING_DISABLED;
98 remoting_source_->OnSinkGone();
99 // Fallback to mirroring.
100 client_->RestartMirroringStreaming();
101 }
102
Stop(media::mojom::RemotingStopReason reason)103 void MediaRemoter::Stop(media::mojom::RemotingStopReason reason) {
104 if (state_ != STARTING_REMOTING && state_ != REMOTING_STARTED)
105 return;
106 if (state_ == REMOTING_STARTED) {
107 message_dispatcher_->Unsubscribe(ResponseType::RPC);
108 audio_sender_.reset();
109 video_sender_.reset();
110 cast_environment_ = nullptr;
111 transport_ = nullptr;
112 audio_config_ = FrameSenderConfig();
113 video_config_ = FrameSenderConfig();
114 }
115 state_ = STOPPING_REMOTING;
116 remoting_source_->OnStopped(reason);
117 // Prevent the start of remoting until switching completes.
118 remoting_source_->OnSinkGone();
119 // Switch to mirroring.
120 client_->RestartMirroringStreaming();
121 }
122
Start()123 void MediaRemoter::Start() {
124 if (state_ != MIRRORING) {
125 VLOG(2) << "Warning: Ignore start request. state=" << state_;
126 return;
127 }
128 state_ = STARTING_REMOTING;
129 client_->RequestRemotingStreaming();
130 }
131
StartDataStreams(mojo::ScopedDataPipeConsumerHandle audio_pipe,mojo::ScopedDataPipeConsumerHandle video_pipe,mojo::PendingReceiver<media::mojom::RemotingDataStreamSender> audio_sender_receiver,mojo::PendingReceiver<media::mojom::RemotingDataStreamSender> video_sender_receiver)132 void MediaRemoter::StartDataStreams(
133 mojo::ScopedDataPipeConsumerHandle audio_pipe,
134 mojo::ScopedDataPipeConsumerHandle video_pipe,
135 mojo::PendingReceiver<media::mojom::RemotingDataStreamSender>
136 audio_sender_receiver,
137 mojo::PendingReceiver<media::mojom::RemotingDataStreamSender>
138 video_sender_receiver) {
139 if (state_ != REMOTING_STARTED)
140 return; // Stop() was called before.
141 DCHECK(cast_environment_);
142 DCHECK(transport_);
143 if (audio_pipe.is_valid() &&
144 audio_config_.codec == Codec::CODEC_AUDIO_REMOTE) {
145 audio_sender_ = std::make_unique<RemotingSender>(
146 cast_environment_, transport_, audio_config_, std::move(audio_pipe),
147 std::move(audio_sender_receiver),
148 base::BindOnce(&MediaRemoter::OnRemotingDataStreamError,
149 base::Unretained(this)));
150 }
151 if (video_pipe.is_valid() &&
152 video_config_.codec == Codec::CODEC_VIDEO_REMOTE) {
153 video_sender_ = std::make_unique<RemotingSender>(
154 cast_environment_, transport_, video_config_, std::move(video_pipe),
155 std::move(video_sender_receiver),
156 base::BindOnce(&MediaRemoter::OnRemotingDataStreamError,
157 base::Unretained(this)));
158 }
159 }
160
SendMessageToSink(const std::vector<uint8_t> & message)161 void MediaRemoter::SendMessageToSink(const std::vector<uint8_t>& message) {
162 if (state_ != REMOTING_STARTED)
163 return;
164 std::string encoded_rpc;
165 base::Base64Encode(
166 base::StringPiece(reinterpret_cast<const char*>(message.data()),
167 message.size()),
168 &encoded_rpc);
169 base::Value rpc(base::Value::Type::DICTIONARY);
170 rpc.SetKey("type", base::Value("RPC"));
171 rpc.SetKey("rpc", base::Value(std::move(encoded_rpc)));
172 mojom::CastMessagePtr rpc_message = mojom::CastMessage::New();
173 rpc_message->message_namespace = mojom::kRemotingNamespace;
174 const bool did_serialize_rpc =
175 base::JSONWriter::Write(rpc, &rpc_message->json_format_data);
176 DCHECK(did_serialize_rpc);
177 message_dispatcher_->SendOutboundMessage(std::move(rpc_message));
178 }
179
EstimateTransmissionCapacity(media::mojom::Remoter::EstimateTransmissionCapacityCallback callback)180 void MediaRemoter::EstimateTransmissionCapacity(
181 media::mojom::Remoter::EstimateTransmissionCapacityCallback callback) {
182 NOTIMPLEMENTED();
183 std::move(callback).Run(0);
184 }
185
OnRemotingDataStreamError()186 void MediaRemoter::OnRemotingDataStreamError() {
187 if (state_ != REMOTING_STARTED)
188 return;
189 state_ = REMOTING_DISABLED;
190 Stop(media::mojom::RemotingStopReason::DATA_SEND_FAILED);
191 }
192
193 } // namespace mirroring
194