xref: /aosp_15_r20/external/openscreen/cast/streaming/sender_session.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2020 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "cast/streaming/sender_session.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <openssl/rand.h>
8*3f982cf4SFabien Sanglard #include <stdint.h>
9*3f982cf4SFabien Sanglard 
10*3f982cf4SFabien Sanglard #include <algorithm>
11*3f982cf4SFabien Sanglard #include <iterator>
12*3f982cf4SFabien Sanglard #include <string>
13*3f982cf4SFabien Sanglard #include <utility>
14*3f982cf4SFabien Sanglard 
15*3f982cf4SFabien Sanglard #include "absl/strings/match.h"
16*3f982cf4SFabien Sanglard #include "absl/strings/numbers.h"
17*3f982cf4SFabien Sanglard #include "cast/streaming/capture_recommendations.h"
18*3f982cf4SFabien Sanglard #include "cast/streaming/environment.h"
19*3f982cf4SFabien Sanglard #include "cast/streaming/message_fields.h"
20*3f982cf4SFabien Sanglard #include "cast/streaming/offer_messages.h"
21*3f982cf4SFabien Sanglard #include "cast/streaming/sender.h"
22*3f982cf4SFabien Sanglard #include "cast/streaming/sender_message.h"
23*3f982cf4SFabien Sanglard #include "util/crypto/random_bytes.h"
24*3f982cf4SFabien Sanglard #include "util/json/json_helpers.h"
25*3f982cf4SFabien Sanglard #include "util/json/json_serialization.h"
26*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
27*3f982cf4SFabien Sanglard #include "util/stringprintf.h"
28*3f982cf4SFabien Sanglard 
29*3f982cf4SFabien Sanglard namespace openscreen {
30*3f982cf4SFabien Sanglard namespace cast {
31*3f982cf4SFabien Sanglard 
32*3f982cf4SFabien Sanglard namespace {
33*3f982cf4SFabien Sanglard 
CreateStream(int index,const AudioCaptureConfig & config,bool use_android_rtp_hack)34*3f982cf4SFabien Sanglard AudioStream CreateStream(int index,
35*3f982cf4SFabien Sanglard                          const AudioCaptureConfig& config,
36*3f982cf4SFabien Sanglard                          bool use_android_rtp_hack) {
37*3f982cf4SFabien Sanglard   return AudioStream{Stream{index,
38*3f982cf4SFabien Sanglard                             Stream::Type::kAudioSource,
39*3f982cf4SFabien Sanglard                             config.channels,
40*3f982cf4SFabien Sanglard                             GetPayloadType(config.codec, use_android_rtp_hack),
41*3f982cf4SFabien Sanglard                             GenerateSsrc(true /*high_priority*/),
42*3f982cf4SFabien Sanglard                             config.target_playout_delay,
43*3f982cf4SFabien Sanglard                             GenerateRandomBytes16(),
44*3f982cf4SFabien Sanglard                             GenerateRandomBytes16(),
45*3f982cf4SFabien Sanglard                             false /* receiver_rtcp_event_log */,
46*3f982cf4SFabien Sanglard                             {} /* receiver_rtcp_dscp */,
47*3f982cf4SFabien Sanglard                             config.sample_rate,
48*3f982cf4SFabien Sanglard                             config.codec_parameter},
49*3f982cf4SFabien Sanglard                      config.codec,
50*3f982cf4SFabien Sanglard                      std::max(config.bit_rate, kDefaultAudioMinBitRate)};
51*3f982cf4SFabien Sanglard }
52*3f982cf4SFabien Sanglard 
CreateStream(int index,const VideoCaptureConfig & config,bool use_android_rtp_hack)53*3f982cf4SFabien Sanglard VideoStream CreateStream(int index,
54*3f982cf4SFabien Sanglard                          const VideoCaptureConfig& config,
55*3f982cf4SFabien Sanglard                          bool use_android_rtp_hack) {
56*3f982cf4SFabien Sanglard   constexpr int kVideoStreamChannelCount = 1;
57*3f982cf4SFabien Sanglard   return VideoStream{
58*3f982cf4SFabien Sanglard       Stream{index,
59*3f982cf4SFabien Sanglard              Stream::Type::kVideoSource,
60*3f982cf4SFabien Sanglard              kVideoStreamChannelCount,
61*3f982cf4SFabien Sanglard              GetPayloadType(config.codec, use_android_rtp_hack),
62*3f982cf4SFabien Sanglard              GenerateSsrc(false /*high_priority*/),
63*3f982cf4SFabien Sanglard              config.target_playout_delay,
64*3f982cf4SFabien Sanglard              GenerateRandomBytes16(),
65*3f982cf4SFabien Sanglard              GenerateRandomBytes16(),
66*3f982cf4SFabien Sanglard              false /* receiver_rtcp_event_log */,
67*3f982cf4SFabien Sanglard              {} /* receiver_rtcp_dscp */,
68*3f982cf4SFabien Sanglard              kRtpVideoTimebase,
69*3f982cf4SFabien Sanglard              config.codec_parameter},
70*3f982cf4SFabien Sanglard       config.codec,
71*3f982cf4SFabien Sanglard       config.max_frame_rate,
72*3f982cf4SFabien Sanglard       (config.max_bit_rate >= kDefaultVideoMinBitRate)
73*3f982cf4SFabien Sanglard           ? config.max_bit_rate
74*3f982cf4SFabien Sanglard           : kDefaultVideoMaxBitRate,
75*3f982cf4SFabien Sanglard       {},  //  protection
76*3f982cf4SFabien Sanglard       {},  //  profile
77*3f982cf4SFabien Sanglard       {},  //  protection
78*3f982cf4SFabien Sanglard       config.resolutions,
79*3f982cf4SFabien Sanglard       {} /* error_recovery mode, always "castv2" */
80*3f982cf4SFabien Sanglard   };
81*3f982cf4SFabien Sanglard }
82*3f982cf4SFabien Sanglard 
83*3f982cf4SFabien Sanglard template <typename S, typename C>
CreateStreamList(int offset_index,const std::vector<C> & configs,bool use_android_rtp_hack,std::vector<S> * out)84*3f982cf4SFabien Sanglard void CreateStreamList(int offset_index,
85*3f982cf4SFabien Sanglard                       const std::vector<C>& configs,
86*3f982cf4SFabien Sanglard                       bool use_android_rtp_hack,
87*3f982cf4SFabien Sanglard                       std::vector<S>* out) {
88*3f982cf4SFabien Sanglard   out->reserve(configs.size());
89*3f982cf4SFabien Sanglard   for (size_t i = 0; i < configs.size(); ++i) {
90*3f982cf4SFabien Sanglard     out->emplace_back(
91*3f982cf4SFabien Sanglard         CreateStream(i + offset_index, configs[i], use_android_rtp_hack));
92*3f982cf4SFabien Sanglard   }
93*3f982cf4SFabien Sanglard }
94*3f982cf4SFabien Sanglard 
CreateMirroringOffer(const std::vector<AudioCaptureConfig> & audio_configs,const std::vector<VideoCaptureConfig> & video_configs,bool use_android_rtp_hack)95*3f982cf4SFabien Sanglard Offer CreateMirroringOffer(const std::vector<AudioCaptureConfig>& audio_configs,
96*3f982cf4SFabien Sanglard                            const std::vector<VideoCaptureConfig>& video_configs,
97*3f982cf4SFabien Sanglard                            bool use_android_rtp_hack) {
98*3f982cf4SFabien Sanglard   Offer offer;
99*3f982cf4SFabien Sanglard   offer.cast_mode = CastMode::kMirroring;
100*3f982cf4SFabien Sanglard 
101*3f982cf4SFabien Sanglard   // NOTE here: IDs will always follow the pattern:
102*3f982cf4SFabien Sanglard   // [0.. audio streams... N - 1][N.. video streams.. K]
103*3f982cf4SFabien Sanglard   CreateStreamList(0, audio_configs, use_android_rtp_hack,
104*3f982cf4SFabien Sanglard                    &offer.audio_streams);
105*3f982cf4SFabien Sanglard   CreateStreamList(audio_configs.size(), video_configs, use_android_rtp_hack,
106*3f982cf4SFabien Sanglard                    &offer.video_streams);
107*3f982cf4SFabien Sanglard 
108*3f982cf4SFabien Sanglard   return offer;
109*3f982cf4SFabien Sanglard }
110*3f982cf4SFabien Sanglard 
CreateRemotingOffer(const AudioCaptureConfig & audio_config,const VideoCaptureConfig & video_config,bool use_android_rtp_hack)111*3f982cf4SFabien Sanglard Offer CreateRemotingOffer(const AudioCaptureConfig& audio_config,
112*3f982cf4SFabien Sanglard                           const VideoCaptureConfig& video_config,
113*3f982cf4SFabien Sanglard                           bool use_android_rtp_hack) {
114*3f982cf4SFabien Sanglard   Offer offer;
115*3f982cf4SFabien Sanglard   offer.cast_mode = CastMode::kRemoting;
116*3f982cf4SFabien Sanglard 
117*3f982cf4SFabien Sanglard   AudioStream audio_stream =
118*3f982cf4SFabien Sanglard       CreateStream(0, audio_config, use_android_rtp_hack);
119*3f982cf4SFabien Sanglard   audio_stream.codec = AudioCodec::kNotSpecified;
120*3f982cf4SFabien Sanglard   audio_stream.stream.rtp_payload_type =
121*3f982cf4SFabien Sanglard       GetPayloadType(AudioCodec::kNotSpecified, use_android_rtp_hack);
122*3f982cf4SFabien Sanglard   offer.audio_streams.push_back(std::move(audio_stream));
123*3f982cf4SFabien Sanglard 
124*3f982cf4SFabien Sanglard   VideoStream video_stream =
125*3f982cf4SFabien Sanglard       CreateStream(1, video_config, use_android_rtp_hack);
126*3f982cf4SFabien Sanglard   video_stream.codec = VideoCodec::kNotSpecified;
127*3f982cf4SFabien Sanglard   video_stream.stream.rtp_payload_type =
128*3f982cf4SFabien Sanglard       GetPayloadType(VideoCodec::kNotSpecified, use_android_rtp_hack);
129*3f982cf4SFabien Sanglard   offer.video_streams.push_back(std::move(video_stream));
130*3f982cf4SFabien Sanglard 
131*3f982cf4SFabien Sanglard   return offer;
132*3f982cf4SFabien Sanglard }
133*3f982cf4SFabien Sanglard 
IsValidAudioCaptureConfig(const AudioCaptureConfig & config)134*3f982cf4SFabien Sanglard bool IsValidAudioCaptureConfig(const AudioCaptureConfig& config) {
135*3f982cf4SFabien Sanglard   return config.channels >= 1 && config.bit_rate >= 0;
136*3f982cf4SFabien Sanglard }
137*3f982cf4SFabien Sanglard 
138*3f982cf4SFabien Sanglard // We don't support resolutions below our minimums.
IsSupportedResolution(const Resolution & resolution)139*3f982cf4SFabien Sanglard bool IsSupportedResolution(const Resolution& resolution) {
140*3f982cf4SFabien Sanglard   return resolution.width > kMinVideoWidth &&
141*3f982cf4SFabien Sanglard          resolution.height > kMinVideoHeight;
142*3f982cf4SFabien Sanglard }
143*3f982cf4SFabien Sanglard 
IsValidVideoCaptureConfig(const VideoCaptureConfig & config)144*3f982cf4SFabien Sanglard bool IsValidVideoCaptureConfig(const VideoCaptureConfig& config) {
145*3f982cf4SFabien Sanglard   return config.max_frame_rate.is_positive() &&
146*3f982cf4SFabien Sanglard          ((config.max_bit_rate == 0) ||
147*3f982cf4SFabien Sanglard           (config.max_bit_rate >= kDefaultVideoMinBitRate)) &&
148*3f982cf4SFabien Sanglard          !config.resolutions.empty() &&
149*3f982cf4SFabien Sanglard          std::all_of(config.resolutions.begin(), config.resolutions.end(),
150*3f982cf4SFabien Sanglard                      IsSupportedResolution);
151*3f982cf4SFabien Sanglard }
152*3f982cf4SFabien Sanglard 
AreAllValid(const std::vector<AudioCaptureConfig> & audio_configs,const std::vector<VideoCaptureConfig> & video_configs)153*3f982cf4SFabien Sanglard bool AreAllValid(const std::vector<AudioCaptureConfig>& audio_configs,
154*3f982cf4SFabien Sanglard                  const std::vector<VideoCaptureConfig>& video_configs) {
155*3f982cf4SFabien Sanglard   return std::all_of(audio_configs.begin(), audio_configs.end(),
156*3f982cf4SFabien Sanglard                      IsValidAudioCaptureConfig) &&
157*3f982cf4SFabien Sanglard          std::all_of(video_configs.begin(), video_configs.end(),
158*3f982cf4SFabien Sanglard                      IsValidVideoCaptureConfig);
159*3f982cf4SFabien Sanglard }
160*3f982cf4SFabien Sanglard 
ToCapabilities(const ReceiverCapability & capability)161*3f982cf4SFabien Sanglard RemotingCapabilities ToCapabilities(const ReceiverCapability& capability) {
162*3f982cf4SFabien Sanglard   RemotingCapabilities out;
163*3f982cf4SFabien Sanglard   for (MediaCapability c : capability.media_capabilities) {
164*3f982cf4SFabien Sanglard     switch (c) {
165*3f982cf4SFabien Sanglard       case MediaCapability::kAudio:
166*3f982cf4SFabien Sanglard         out.audio.push_back(AudioCapability::kBaselineSet);
167*3f982cf4SFabien Sanglard         break;
168*3f982cf4SFabien Sanglard       case MediaCapability::kAac:
169*3f982cf4SFabien Sanglard         out.audio.push_back(AudioCapability::kAac);
170*3f982cf4SFabien Sanglard         break;
171*3f982cf4SFabien Sanglard       case MediaCapability::kOpus:
172*3f982cf4SFabien Sanglard         out.audio.push_back(AudioCapability::kOpus);
173*3f982cf4SFabien Sanglard         break;
174*3f982cf4SFabien Sanglard       case MediaCapability::k4k:
175*3f982cf4SFabien Sanglard         out.video.push_back(VideoCapability::kSupports4k);
176*3f982cf4SFabien Sanglard         break;
177*3f982cf4SFabien Sanglard       case MediaCapability::kH264:
178*3f982cf4SFabien Sanglard         out.video.push_back(VideoCapability::kH264);
179*3f982cf4SFabien Sanglard         break;
180*3f982cf4SFabien Sanglard       case MediaCapability::kVp8:
181*3f982cf4SFabien Sanglard         out.video.push_back(VideoCapability::kVp8);
182*3f982cf4SFabien Sanglard         break;
183*3f982cf4SFabien Sanglard       case MediaCapability::kVp9:
184*3f982cf4SFabien Sanglard         out.video.push_back(VideoCapability::kVp9);
185*3f982cf4SFabien Sanglard         break;
186*3f982cf4SFabien Sanglard       case MediaCapability::kHevc:
187*3f982cf4SFabien Sanglard         out.video.push_back(VideoCapability::kHevc);
188*3f982cf4SFabien Sanglard         break;
189*3f982cf4SFabien Sanglard       case MediaCapability::kAv1:
190*3f982cf4SFabien Sanglard         out.video.push_back(VideoCapability::kAv1);
191*3f982cf4SFabien Sanglard         break;
192*3f982cf4SFabien Sanglard       case MediaCapability::kVideo:
193*3f982cf4SFabien Sanglard         // noop, as "video" is ignored by Chrome remoting.
194*3f982cf4SFabien Sanglard         break;
195*3f982cf4SFabien Sanglard 
196*3f982cf4SFabien Sanglard       default:
197*3f982cf4SFabien Sanglard         OSP_NOTREACHED();
198*3f982cf4SFabien Sanglard     }
199*3f982cf4SFabien Sanglard   }
200*3f982cf4SFabien Sanglard   return out;
201*3f982cf4SFabien Sanglard }
202*3f982cf4SFabien Sanglard 
203*3f982cf4SFabien Sanglard }  // namespace
204*3f982cf4SFabien Sanglard 
205*3f982cf4SFabien Sanglard SenderSession::Client::~Client() = default;
206*3f982cf4SFabien Sanglard 
SenderSession(Configuration config)207*3f982cf4SFabien Sanglard SenderSession::SenderSession(Configuration config)
208*3f982cf4SFabien Sanglard     : config_(config),
209*3f982cf4SFabien Sanglard       messenger_(
210*3f982cf4SFabien Sanglard           config_.message_port,
211*3f982cf4SFabien Sanglard           config_.message_source_id,
212*3f982cf4SFabien Sanglard           config_.message_destination_id,
213*3f982cf4SFabien Sanglard           [this](Error error) {
214*3f982cf4SFabien Sanglard             OSP_DLOG_WARN << "SenderSession message port error: " << error;
215*3f982cf4SFabien Sanglard             config_.client->OnError(this, error);
216*3f982cf4SFabien Sanglard           },
217*3f982cf4SFabien Sanglard           config_.environment->task_runner()),
__anon1c56a2130302(std::vector<uint8_t> message) 218*3f982cf4SFabien Sanglard       rpc_messenger_([this](std::vector<uint8_t> message) {
219*3f982cf4SFabien Sanglard         SendRpcMessage(std::move(message));
220*3f982cf4SFabien Sanglard       }),
221*3f982cf4SFabien Sanglard       packet_router_(config_.environment) {
222*3f982cf4SFabien Sanglard   OSP_DCHECK(config_.client);
223*3f982cf4SFabien Sanglard   OSP_DCHECK(config_.environment);
224*3f982cf4SFabien Sanglard 
225*3f982cf4SFabien Sanglard   // We may or may not do remoting this session, however our RPC handler
226*3f982cf4SFabien Sanglard   // is not negotiation-specific and registering on construction here allows us
227*3f982cf4SFabien Sanglard   // to record any unexpected RPC messages.
228*3f982cf4SFabien Sanglard   messenger_.SetHandler(ReceiverMessage::Type::kRpc,
__anon1c56a2130402(ReceiverMessage message) 229*3f982cf4SFabien Sanglard                         [this](ReceiverMessage message) {
230*3f982cf4SFabien Sanglard                           this->OnRpcMessage(std::move(message));
231*3f982cf4SFabien Sanglard                         });
232*3f982cf4SFabien Sanglard }
233*3f982cf4SFabien Sanglard 
234*3f982cf4SFabien Sanglard SenderSession::~SenderSession() = default;
235*3f982cf4SFabien Sanglard 
Negotiate(std::vector<AudioCaptureConfig> audio_configs,std::vector<VideoCaptureConfig> video_configs)236*3f982cf4SFabien Sanglard Error SenderSession::Negotiate(std::vector<AudioCaptureConfig> audio_configs,
237*3f982cf4SFabien Sanglard                                std::vector<VideoCaptureConfig> video_configs) {
238*3f982cf4SFabien Sanglard   // Negotiating with no streams doesn't make any sense.
239*3f982cf4SFabien Sanglard   if (audio_configs.empty() && video_configs.empty()) {
240*3f982cf4SFabien Sanglard     return Error(Error::Code::kParameterInvalid,
241*3f982cf4SFabien Sanglard                  "Need at least one audio or video config to negotiate.");
242*3f982cf4SFabien Sanglard   }
243*3f982cf4SFabien Sanglard   if (!AreAllValid(audio_configs, video_configs)) {
244*3f982cf4SFabien Sanglard     return Error(Error::Code::kParameterInvalid, "Invalid configs provided.");
245*3f982cf4SFabien Sanglard   }
246*3f982cf4SFabien Sanglard 
247*3f982cf4SFabien Sanglard   Offer offer = CreateMirroringOffer(audio_configs, video_configs,
248*3f982cf4SFabien Sanglard                                      config_.use_android_rtp_hack);
249*3f982cf4SFabien Sanglard   return StartNegotiation(std::move(audio_configs), std::move(video_configs),
250*3f982cf4SFabien Sanglard                           std::move(offer));
251*3f982cf4SFabien Sanglard }
252*3f982cf4SFabien Sanglard 
NegotiateRemoting(AudioCaptureConfig audio_config,VideoCaptureConfig video_config)253*3f982cf4SFabien Sanglard Error SenderSession::NegotiateRemoting(AudioCaptureConfig audio_config,
254*3f982cf4SFabien Sanglard                                        VideoCaptureConfig video_config) {
255*3f982cf4SFabien Sanglard   // Remoting requires both an audio and a video configuration.
256*3f982cf4SFabien Sanglard   if (!IsValidAudioCaptureConfig(audio_config) ||
257*3f982cf4SFabien Sanglard       !IsValidVideoCaptureConfig(video_config)) {
258*3f982cf4SFabien Sanglard     return Error(Error::Code::kParameterInvalid,
259*3f982cf4SFabien Sanglard                  "Passed invalid audio or video config.");
260*3f982cf4SFabien Sanglard   }
261*3f982cf4SFabien Sanglard 
262*3f982cf4SFabien Sanglard   Offer offer = CreateRemotingOffer(audio_config, video_config,
263*3f982cf4SFabien Sanglard                                     config_.use_android_rtp_hack);
264*3f982cf4SFabien Sanglard   return StartNegotiation({audio_config}, {video_config}, std::move(offer));
265*3f982cf4SFabien Sanglard }
266*3f982cf4SFabien Sanglard 
GetEstimatedNetworkBandwidth() const267*3f982cf4SFabien Sanglard int SenderSession::GetEstimatedNetworkBandwidth() const {
268*3f982cf4SFabien Sanglard   return packet_router_.ComputeNetworkBandwidth();
269*3f982cf4SFabien Sanglard }
270*3f982cf4SFabien Sanglard 
ResetState()271*3f982cf4SFabien Sanglard void SenderSession::ResetState() {
272*3f982cf4SFabien Sanglard   state_ = State::kIdle;
273*3f982cf4SFabien Sanglard   current_negotiation_.reset();
274*3f982cf4SFabien Sanglard   current_audio_sender_.reset();
275*3f982cf4SFabien Sanglard   current_video_sender_.reset();
276*3f982cf4SFabien Sanglard }
277*3f982cf4SFabien Sanglard 
StartNegotiation(std::vector<AudioCaptureConfig> audio_configs,std::vector<VideoCaptureConfig> video_configs,Offer offer)278*3f982cf4SFabien Sanglard Error SenderSession::StartNegotiation(
279*3f982cf4SFabien Sanglard     std::vector<AudioCaptureConfig> audio_configs,
280*3f982cf4SFabien Sanglard     std::vector<VideoCaptureConfig> video_configs,
281*3f982cf4SFabien Sanglard     Offer offer) {
282*3f982cf4SFabien Sanglard   current_negotiation_ =
283*3f982cf4SFabien Sanglard       std::unique_ptr<InProcessNegotiation>(new InProcessNegotiation{
284*3f982cf4SFabien Sanglard           offer, std::move(audio_configs), std::move(video_configs)});
285*3f982cf4SFabien Sanglard 
286*3f982cf4SFabien Sanglard   return messenger_.SendRequest(
287*3f982cf4SFabien Sanglard       SenderMessage{SenderMessage::Type::kOffer, ++current_sequence_number_,
288*3f982cf4SFabien Sanglard                     true, std::move(offer)},
289*3f982cf4SFabien Sanglard       ReceiverMessage::Type::kAnswer,
290*3f982cf4SFabien Sanglard       [this](ReceiverMessage message) { OnAnswer(message); });
291*3f982cf4SFabien Sanglard }
292*3f982cf4SFabien Sanglard 
OnAnswer(ReceiverMessage message)293*3f982cf4SFabien Sanglard void SenderSession::OnAnswer(ReceiverMessage message) {
294*3f982cf4SFabien Sanglard   if (!message.valid) {
295*3f982cf4SFabien Sanglard     HandleErrorMessage(message, "Invalid answer response message");
296*3f982cf4SFabien Sanglard     return;
297*3f982cf4SFabien Sanglard   }
298*3f982cf4SFabien Sanglard 
299*3f982cf4SFabien Sanglard   // There isn't an obvious way to tell from the Answer whether it is mirroring
300*3f982cf4SFabien Sanglard   // or remoting specific--the only clues are in the original offer message.
301*3f982cf4SFabien Sanglard   const Answer& answer = absl::get<Answer>(message.body);
302*3f982cf4SFabien Sanglard   if (current_negotiation_->offer.cast_mode == CastMode::kMirroring) {
303*3f982cf4SFabien Sanglard     ConfiguredSenders senders = SpawnSenders(answer);
304*3f982cf4SFabien Sanglard     // If we didn't select any senders, the negotiation was unsuccessful.
305*3f982cf4SFabien Sanglard     if (senders.audio_sender == nullptr && senders.video_sender == nullptr) {
306*3f982cf4SFabien Sanglard       return;
307*3f982cf4SFabien Sanglard     }
308*3f982cf4SFabien Sanglard 
309*3f982cf4SFabien Sanglard     state_ = State::kStreaming;
310*3f982cf4SFabien Sanglard     config_.client->OnNegotiated(
311*3f982cf4SFabien Sanglard         this, std::move(senders),
312*3f982cf4SFabien Sanglard         capture_recommendations::GetRecommendations(answer));
313*3f982cf4SFabien Sanglard   } else {
314*3f982cf4SFabien Sanglard     state_ = State::kRemoting;
315*3f982cf4SFabien Sanglard 
316*3f982cf4SFabien Sanglard     // We don't want to spawn senders yet, since we don't know what the
317*3f982cf4SFabien Sanglard     // receiver's capabilities are. So, we cache the Answer until the
318*3f982cf4SFabien Sanglard     // capabilites request is completed.
319*3f982cf4SFabien Sanglard     current_negotiation_->answer = answer;
320*3f982cf4SFabien Sanglard     const Error result = messenger_.SendRequest(
321*3f982cf4SFabien Sanglard         SenderMessage{SenderMessage::Type::kGetCapabilities,
322*3f982cf4SFabien Sanglard                       ++current_sequence_number_, true},
323*3f982cf4SFabien Sanglard         ReceiverMessage::Type::kCapabilitiesResponse,
324*3f982cf4SFabien Sanglard         [this](ReceiverMessage message) { OnCapabilitiesResponse(message); });
325*3f982cf4SFabien Sanglard     if (!result.ok()) {
326*3f982cf4SFabien Sanglard       config_.client->OnError(
327*3f982cf4SFabien Sanglard           this, Error(Error::Code::kNegotiationFailure,
328*3f982cf4SFabien Sanglard                       "Failed to set a GET_CAPABILITIES request"));
329*3f982cf4SFabien Sanglard     }
330*3f982cf4SFabien Sanglard   }
331*3f982cf4SFabien Sanglard }
332*3f982cf4SFabien Sanglard 
OnCapabilitiesResponse(ReceiverMessage message)333*3f982cf4SFabien Sanglard void SenderSession::OnCapabilitiesResponse(ReceiverMessage message) {
334*3f982cf4SFabien Sanglard   if (!current_negotiation_ || !current_negotiation_->answer.IsValid()) {
335*3f982cf4SFabien Sanglard     OSP_LOG_INFO
336*3f982cf4SFabien Sanglard         << "Received a capabilities response, but not negotiating anything.";
337*3f982cf4SFabien Sanglard     return;
338*3f982cf4SFabien Sanglard   }
339*3f982cf4SFabien Sanglard 
340*3f982cf4SFabien Sanglard   if (!message.valid) {
341*3f982cf4SFabien Sanglard     HandleErrorMessage(
342*3f982cf4SFabien Sanglard         message,
343*3f982cf4SFabien Sanglard         "Bad CAPABILITIES_RESPONSE, assuming remoting is not supported");
344*3f982cf4SFabien Sanglard     return;
345*3f982cf4SFabien Sanglard   }
346*3f982cf4SFabien Sanglard 
347*3f982cf4SFabien Sanglard   const ReceiverCapability& caps = absl::get<ReceiverCapability>(message.body);
348*3f982cf4SFabien Sanglard   int remoting_version = caps.remoting_version;
349*3f982cf4SFabien Sanglard   // If not set, we assume it is version 1.
350*3f982cf4SFabien Sanglard   if (remoting_version == ReceiverCapability::kRemotingVersionUnknown) {
351*3f982cf4SFabien Sanglard     remoting_version = 1;
352*3f982cf4SFabien Sanglard   }
353*3f982cf4SFabien Sanglard 
354*3f982cf4SFabien Sanglard   if (remoting_version > kSupportedRemotingVersion) {
355*3f982cf4SFabien Sanglard     std::string message = StringPrintf(
356*3f982cf4SFabien Sanglard         "Receiver is using too new of a version for remoting (%d > %d)",
357*3f982cf4SFabien Sanglard         remoting_version, kSupportedRemotingVersion);
358*3f982cf4SFabien Sanglard     config_.client->OnError(
359*3f982cf4SFabien Sanglard         this, Error(Error::Code::kRemotingNotSupported, std::move(message)));
360*3f982cf4SFabien Sanglard     return;
361*3f982cf4SFabien Sanglard   }
362*3f982cf4SFabien Sanglard 
363*3f982cf4SFabien Sanglard   ConfiguredSenders senders = SpawnSenders(current_negotiation_->answer);
364*3f982cf4SFabien Sanglard   // If we didn't select any senders, the negotiation was unsuccessful.
365*3f982cf4SFabien Sanglard   if (senders.audio_sender == nullptr && senders.video_sender == nullptr) {
366*3f982cf4SFabien Sanglard     config_.client->OnError(this,
367*3f982cf4SFabien Sanglard                             Error(Error::Code::kNegotiationFailure,
368*3f982cf4SFabien Sanglard                                   "Failed to negotiate a remoting session."));
369*3f982cf4SFabien Sanglard     return;
370*3f982cf4SFabien Sanglard   }
371*3f982cf4SFabien Sanglard 
372*3f982cf4SFabien Sanglard   config_.client->OnRemotingNegotiated(
373*3f982cf4SFabien Sanglard       this, RemotingNegotiation{std::move(senders), ToCapabilities(caps)});
374*3f982cf4SFabien Sanglard }
375*3f982cf4SFabien Sanglard 
OnRpcMessage(ReceiverMessage message)376*3f982cf4SFabien Sanglard void SenderSession::OnRpcMessage(ReceiverMessage message) {
377*3f982cf4SFabien Sanglard   if (!message.valid) {
378*3f982cf4SFabien Sanglard     HandleErrorMessage(
379*3f982cf4SFabien Sanglard         message,
380*3f982cf4SFabien Sanglard         "Bad RPC message. This may or may not represent a serious problem");
381*3f982cf4SFabien Sanglard     return;
382*3f982cf4SFabien Sanglard   }
383*3f982cf4SFabien Sanglard 
384*3f982cf4SFabien Sanglard   const auto& body = absl::get<std::vector<uint8_t>>(message.body);
385*3f982cf4SFabien Sanglard   rpc_messenger_.ProcessMessageFromRemote(body.data(), body.size());
386*3f982cf4SFabien Sanglard }
387*3f982cf4SFabien Sanglard 
HandleErrorMessage(ReceiverMessage message,const std::string & text)388*3f982cf4SFabien Sanglard void SenderSession::HandleErrorMessage(ReceiverMessage message,
389*3f982cf4SFabien Sanglard                                        const std::string& text) {
390*3f982cf4SFabien Sanglard   OSP_DCHECK(!message.valid);
391*3f982cf4SFabien Sanglard   if (absl::holds_alternative<ReceiverError>(message.body)) {
392*3f982cf4SFabien Sanglard     const ReceiverError& error = absl::get<ReceiverError>(message.body);
393*3f982cf4SFabien Sanglard     std::string error_text =
394*3f982cf4SFabien Sanglard         StringPrintf("%s. Error code: %d, description: %s", text.c_str(),
395*3f982cf4SFabien Sanglard                      error.code, error.description.c_str());
396*3f982cf4SFabien Sanglard     config_.client->OnError(
397*3f982cf4SFabien Sanglard         this, Error(Error::Code::kParameterInvalid, std::move(error_text)));
398*3f982cf4SFabien Sanglard   } else {
399*3f982cf4SFabien Sanglard     config_.client->OnError(this, Error(Error::Code::kJsonParseError, text));
400*3f982cf4SFabien Sanglard   }
401*3f982cf4SFabien Sanglard }
402*3f982cf4SFabien Sanglard 
CreateSender(Ssrc receiver_ssrc,const Stream & stream,RtpPayloadType type)403*3f982cf4SFabien Sanglard std::unique_ptr<Sender> SenderSession::CreateSender(Ssrc receiver_ssrc,
404*3f982cf4SFabien Sanglard                                                     const Stream& stream,
405*3f982cf4SFabien Sanglard                                                     RtpPayloadType type) {
406*3f982cf4SFabien Sanglard   // Session config is currently only for mirroring.
407*3f982cf4SFabien Sanglard   SessionConfig config{stream.ssrc,
408*3f982cf4SFabien Sanglard                        receiver_ssrc,
409*3f982cf4SFabien Sanglard                        stream.rtp_timebase,
410*3f982cf4SFabien Sanglard                        stream.channels,
411*3f982cf4SFabien Sanglard                        stream.target_delay,
412*3f982cf4SFabien Sanglard                        stream.aes_key,
413*3f982cf4SFabien Sanglard                        stream.aes_iv_mask,
414*3f982cf4SFabien Sanglard                        /* is_pli_enabled*/ true};
415*3f982cf4SFabien Sanglard 
416*3f982cf4SFabien Sanglard   return std::make_unique<Sender>(config_.environment, &packet_router_,
417*3f982cf4SFabien Sanglard                                   std::move(config), type);
418*3f982cf4SFabien Sanglard }
419*3f982cf4SFabien Sanglard 
SpawnAudioSender(ConfiguredSenders * senders,Ssrc receiver_ssrc,int send_index,int config_index)420*3f982cf4SFabien Sanglard void SenderSession::SpawnAudioSender(ConfiguredSenders* senders,
421*3f982cf4SFabien Sanglard                                      Ssrc receiver_ssrc,
422*3f982cf4SFabien Sanglard                                      int send_index,
423*3f982cf4SFabien Sanglard                                      int config_index) {
424*3f982cf4SFabien Sanglard   const AudioCaptureConfig& config =
425*3f982cf4SFabien Sanglard       current_negotiation_->audio_configs[config_index];
426*3f982cf4SFabien Sanglard   const RtpPayloadType payload_type =
427*3f982cf4SFabien Sanglard       GetPayloadType(config.codec, config_.use_android_rtp_hack);
428*3f982cf4SFabien Sanglard   for (const AudioStream& stream : current_negotiation_->offer.audio_streams) {
429*3f982cf4SFabien Sanglard     if (stream.stream.index == send_index) {
430*3f982cf4SFabien Sanglard       current_audio_sender_ =
431*3f982cf4SFabien Sanglard           CreateSender(receiver_ssrc, stream.stream, payload_type);
432*3f982cf4SFabien Sanglard       senders->audio_sender = current_audio_sender_.get();
433*3f982cf4SFabien Sanglard       senders->audio_config = config;
434*3f982cf4SFabien Sanglard       break;
435*3f982cf4SFabien Sanglard     }
436*3f982cf4SFabien Sanglard   }
437*3f982cf4SFabien Sanglard }
438*3f982cf4SFabien Sanglard 
SpawnVideoSender(ConfiguredSenders * senders,Ssrc receiver_ssrc,int send_index,int config_index)439*3f982cf4SFabien Sanglard void SenderSession::SpawnVideoSender(ConfiguredSenders* senders,
440*3f982cf4SFabien Sanglard                                      Ssrc receiver_ssrc,
441*3f982cf4SFabien Sanglard                                      int send_index,
442*3f982cf4SFabien Sanglard                                      int config_index) {
443*3f982cf4SFabien Sanglard   const VideoCaptureConfig& config =
444*3f982cf4SFabien Sanglard       current_negotiation_->video_configs[config_index];
445*3f982cf4SFabien Sanglard   const RtpPayloadType payload_type =
446*3f982cf4SFabien Sanglard       GetPayloadType(config.codec, config_.use_android_rtp_hack);
447*3f982cf4SFabien Sanglard   for (const VideoStream& stream : current_negotiation_->offer.video_streams) {
448*3f982cf4SFabien Sanglard     if (stream.stream.index == send_index) {
449*3f982cf4SFabien Sanglard       current_video_sender_ =
450*3f982cf4SFabien Sanglard           CreateSender(receiver_ssrc, stream.stream, payload_type);
451*3f982cf4SFabien Sanglard       senders->video_sender = current_video_sender_.get();
452*3f982cf4SFabien Sanglard       senders->video_config = config;
453*3f982cf4SFabien Sanglard       break;
454*3f982cf4SFabien Sanglard     }
455*3f982cf4SFabien Sanglard   }
456*3f982cf4SFabien Sanglard }
457*3f982cf4SFabien Sanglard 
SpawnSenders(const Answer & answer)458*3f982cf4SFabien Sanglard SenderSession::ConfiguredSenders SenderSession::SpawnSenders(
459*3f982cf4SFabien Sanglard     const Answer& answer) {
460*3f982cf4SFabien Sanglard   OSP_DCHECK(current_negotiation_);
461*3f982cf4SFabien Sanglard 
462*3f982cf4SFabien Sanglard   // Although we already have a message port set up with the TLS
463*3f982cf4SFabien Sanglard   // address of the receiver, we don't know where to send the separate UDP
464*3f982cf4SFabien Sanglard   // stream until we get the ANSWER message here.
465*3f982cf4SFabien Sanglard   config_.environment->set_remote_endpoint(IPEndpoint{
466*3f982cf4SFabien Sanglard       config_.remote_address, static_cast<uint16_t>(answer.udp_port)});
467*3f982cf4SFabien Sanglard   OSP_LOG_INFO << "Streaming to " << config_.environment->remote_endpoint()
468*3f982cf4SFabien Sanglard                << "...";
469*3f982cf4SFabien Sanglard 
470*3f982cf4SFabien Sanglard   ConfiguredSenders senders;
471*3f982cf4SFabien Sanglard   for (size_t i = 0; i < answer.send_indexes.size(); ++i) {
472*3f982cf4SFabien Sanglard     const Ssrc receiver_ssrc = answer.ssrcs[i];
473*3f982cf4SFabien Sanglard     const size_t send_index = static_cast<size_t>(answer.send_indexes[i]);
474*3f982cf4SFabien Sanglard 
475*3f982cf4SFabien Sanglard     const auto audio_size = current_negotiation_->audio_configs.size();
476*3f982cf4SFabien Sanglard     const auto video_size = current_negotiation_->video_configs.size();
477*3f982cf4SFabien Sanglard     if (send_index < audio_size) {
478*3f982cf4SFabien Sanglard       SpawnAudioSender(&senders, receiver_ssrc, send_index, send_index);
479*3f982cf4SFabien Sanglard     } else if (send_index < (audio_size + video_size)) {
480*3f982cf4SFabien Sanglard       SpawnVideoSender(&senders, receiver_ssrc, send_index,
481*3f982cf4SFabien Sanglard                        send_index - audio_size);
482*3f982cf4SFabien Sanglard     }
483*3f982cf4SFabien Sanglard   }
484*3f982cf4SFabien Sanglard   return senders;
485*3f982cf4SFabien Sanglard }
486*3f982cf4SFabien Sanglard 
SendRpcMessage(std::vector<uint8_t> message_body)487*3f982cf4SFabien Sanglard void SenderSession::SendRpcMessage(std::vector<uint8_t> message_body) {
488*3f982cf4SFabien Sanglard   Error error = this->messenger_.SendOutboundMessage(SenderMessage{
489*3f982cf4SFabien Sanglard       SenderMessage::Type::kRpc, ++(this->current_sequence_number_), true,
490*3f982cf4SFabien Sanglard       std::move(message_body)});
491*3f982cf4SFabien Sanglard 
492*3f982cf4SFabien Sanglard   if (!error.ok()) {
493*3f982cf4SFabien Sanglard     OSP_LOG_WARN << "Failed to send RPC message: " << error;
494*3f982cf4SFabien Sanglard   }
495*3f982cf4SFabien Sanglard }
496*3f982cf4SFabien Sanglard 
497*3f982cf4SFabien Sanglard }  // namespace cast
498*3f982cf4SFabien Sanglard }  // namespace openscreen
499