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