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/mirror_settings.h"
6 
7 #include <algorithm>
8 #include <string>
9 
10 #include "base/environment.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "media/base/audio_parameters.h"
14 
15 using media::ResolutionChangePolicy;
16 using media::cast::Codec;
17 using media::cast::FrameSenderConfig;
18 using media::cast::RtpPayloadType;
19 
20 namespace mirroring {
21 
22 namespace {
23 
24 // Default end-to-end latency. Currently adaptive latency control is disabled
25 // because of audio playout regressions (b/32876644).
26 // TODO(openscreen/44): Re-enable in port to Open Screen.
27 constexpr base::TimeDelta kDefaultPlayoutDelay =
28     base::TimeDelta::FromMilliseconds(400);
29 
30 constexpr int kAudioTimebase = 48000;
31 constexpr int kVidoTimebase = 90000;
32 constexpr int kAudioChannels = 2;
33 constexpr int kAudioFramerate = 100;  // 100 FPS for 10ms packets.
34 constexpr int kMinVideoBitrate = 300000;
35 constexpr int kMaxVideoBitrate = 5000000;
36 constexpr int kAudioBitrate = 0;   // 0 means automatic.
37 constexpr int kMaxFrameRate = 30;  // The maximum frame rate for captures.
38 constexpr int kMaxWidth = 1920;    // Maximum video width in pixels.
39 constexpr int kMaxHeight = 1080;   // Maximum video height in pixels.
40 constexpr int kMinWidth = 180;     // Minimum video frame width in pixels.
41 constexpr int kMinHeight = 180;    // Minimum video frame height in pixels.
42 
GetPlayoutDelayImpl()43 base::TimeDelta GetPlayoutDelayImpl() {
44   // Currently min, max, and animated playout delay are the same.
45   constexpr char kPlayoutDelayVariable[] = "CHROME_MIRRORING_PLAYOUT_DELAY";
46 
47   auto environment = base::Environment::Create();
48   if (!environment->HasVar(kPlayoutDelayVariable)) {
49     return kDefaultPlayoutDelay;
50   }
51 
52   std::string playout_delay_arg;
53   if (!environment->GetVar(kPlayoutDelayVariable, &playout_delay_arg) ||
54       playout_delay_arg.empty()) {
55     return kDefaultPlayoutDelay;
56   }
57 
58   int playout_delay;
59   if (!base::StringToInt(playout_delay_arg, &playout_delay) ||
60       playout_delay < 1 || playout_delay > 65535) {
61     VLOG(1) << "Invalid custom mirroring playout delay passed, must be between "
62                "1 and 65535 milliseconds. Using default value instead.";
63     return kDefaultPlayoutDelay;
64   }
65 
66   VLOG(1) << "Using custom mirroring playout delay value of: " << playout_delay
67           << "ms...";
68   return base::TimeDelta::FromMilliseconds(playout_delay);
69 }
70 
GetPlayoutDelay()71 base::TimeDelta GetPlayoutDelay() {
72   static base::TimeDelta playout_delay = GetPlayoutDelayImpl();
73   return playout_delay;
74 }
75 
76 }  // namespace
77 
MirrorSettings()78 MirrorSettings::MirrorSettings()
79     : min_width_(kMinWidth),
80       min_height_(kMinHeight),
81       max_width_(kMaxWidth),
82       max_height_(kMaxHeight) {}
83 
~MirrorSettings()84 MirrorSettings::~MirrorSettings() {}
85 
86 // static
GetDefaultAudioConfig(RtpPayloadType payload_type,Codec codec)87 FrameSenderConfig MirrorSettings::GetDefaultAudioConfig(
88     RtpPayloadType payload_type,
89     Codec codec) {
90   FrameSenderConfig config;
91   config.sender_ssrc = 1;
92   config.receiver_ssrc = 2;
93   const base::TimeDelta playout_delay = GetPlayoutDelay();
94   config.min_playout_delay = playout_delay;
95   config.max_playout_delay = playout_delay;
96   config.animated_playout_delay = playout_delay;
97   config.rtp_payload_type = payload_type;
98   config.rtp_timebase = kAudioTimebase;
99   config.channels = kAudioChannels;
100   config.min_bitrate = config.max_bitrate = config.start_bitrate =
101       kAudioBitrate;
102   config.max_frame_rate = kAudioFramerate;  // 10 ms audio frames
103   config.codec = codec;
104   return config;
105 }
106 
107 // static
GetDefaultVideoConfig(RtpPayloadType payload_type,Codec codec)108 FrameSenderConfig MirrorSettings::GetDefaultVideoConfig(
109     RtpPayloadType payload_type,
110     Codec codec) {
111   FrameSenderConfig config;
112   config.sender_ssrc = 11;
113   config.receiver_ssrc = 12;
114   const base::TimeDelta playout_delay = GetPlayoutDelay();
115   config.min_playout_delay = playout_delay;
116   config.max_playout_delay = playout_delay;
117   config.animated_playout_delay = playout_delay;
118   config.rtp_payload_type = payload_type;
119   config.rtp_timebase = kVidoTimebase;
120   config.channels = 1;
121   config.min_bitrate = kMinVideoBitrate;
122   config.max_bitrate = kMaxVideoBitrate;
123   config.start_bitrate = kMinVideoBitrate;
124   config.max_frame_rate = kMaxFrameRate;
125   config.codec = codec;
126   return config;
127 }
128 
SetResolutionConstraints(int max_width,int max_height)129 void MirrorSettings::SetResolutionConstraints(int max_width, int max_height) {
130   max_width_ = std::max(max_width, min_width_);
131   max_height_ = std::max(max_height, min_height_);
132 }
133 
SetSenderSideLetterboxingEnabled(bool enabled)134 void MirrorSettings::SetSenderSideLetterboxingEnabled(bool enabled) {
135   enable_sender_side_letterboxing_ = enabled;
136 }
137 
GetVideoCaptureParams()138 media::VideoCaptureParams MirrorSettings::GetVideoCaptureParams() {
139   media::VideoCaptureParams params;
140   params.requested_format =
141       media::VideoCaptureFormat(gfx::Size(max_width_, max_height_),
142                                 kMaxFrameRate, media::PIXEL_FORMAT_I420);
143   if (max_height_ == min_height_ && max_width_ == min_width_) {
144     params.resolution_change_policy = ResolutionChangePolicy::FIXED_RESOLUTION;
145   } else if (enable_sender_side_letterboxing_) {
146     params.resolution_change_policy =
147         ResolutionChangePolicy::FIXED_ASPECT_RATIO;
148   } else {
149     params.resolution_change_policy = ResolutionChangePolicy::ANY_WITHIN_LIMIT;
150   }
151   DCHECK(params.IsValid());
152   return params;
153 }
154 
GetAudioCaptureParams()155 media::AudioParameters MirrorSettings::GetAudioCaptureParams() {
156   media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
157                                 media::CHANNEL_LAYOUT_STEREO, kAudioTimebase,
158                                 kAudioTimebase / 100);
159   DCHECK(params.IsValid());
160   return params;
161 }
162 
163 }  // namespace mirroring
164