blob: 4df9a992dc9eb8eb0ae8f54115e36df2ca7ef70b [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/mirroring/service/mirror_settings.h"
#include <algorithm>
#include <string>
#include <utility>
#include "base/environment.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "components/mirroring/service/mirroring_features.h"
#include "media/base/audio_codecs.h"
#include "media/base/audio_parameters.h"
#include "media/base/video_codecs.h"
using media::ResolutionChangePolicy;
using media::cast::AudioCodecParams;
using media::cast::FrameSenderConfig;
using media::cast::VideoCodecParams;
namespace mirroring {
namespace {
constexpr int kAudioTimebase = 48000;
constexpr int kVideoTimebase = 90000;
constexpr int kAudioChannels = 2;
constexpr int kAudioFramerate = 100; // 100 FPS for 10ms packets.
constexpr int kMinVideoBitrate = 300000;
constexpr int kMaxVideoBitrate = 5000000;
constexpr int kAudioBitrate = 0; // 0 means automatic.
constexpr int kMaxFrameRate = 30; // The maximum frame rate for captures.
constexpr int kMaxWidth = 1920; // Maximum video width in pixels.
constexpr int kMaxHeight = 1080; // Maximum video height in pixels.
constexpr int kMinWidth = 180; // Minimum video frame width in pixels.
constexpr int kMinHeight = 180; // Minimum video frame height in pixels.
base::TimeDelta GetPlayoutDelayImpl() {
// Currently min, max, and animated playout delay are the same.
constexpr char kPlayoutDelayVariable[] = "CHROME_MIRRORING_PLAYOUT_DELAY";
auto environment = base::Environment::Create();
std::optional<std::string> playout_delay_arg =
environment->GetVar(kPlayoutDelayVariable);
if (!playout_delay_arg.has_value() || playout_delay_arg->empty()) {
return kDefaultPlayoutDelay;
}
int playout_delay;
if (!base::StringToInt(playout_delay_arg.value(), &playout_delay) ||
playout_delay < 1 || playout_delay > 65535) {
VLOG(1) << "Invalid custom mirroring playout delay passed, must be between "
"1 and 65535 milliseconds. Using default value instead.";
return kDefaultPlayoutDelay;
}
VLOG(1) << "Using custom mirroring playout delay value of: " << playout_delay
<< "ms...";
return base::Milliseconds(playout_delay);
}
base::TimeDelta GetPlayoutDelay() {
static base::TimeDelta playout_delay = GetPlayoutDelayImpl();
return playout_delay;
}
} // namespace
MirrorSettings::MirrorSettings()
: min_width_(kMinWidth),
min_height_(kMinHeight),
max_width_(kMaxWidth),
max_height_(kMaxHeight) {}
MirrorSettings::~MirrorSettings() = default;
// static
FrameSenderConfig MirrorSettings::GetDefaultAudioConfig(
media::AudioCodec codec) {
FrameSenderConfig config;
config.sender_ssrc = 1;
config.receiver_ssrc = 2;
const base::TimeDelta playout_delay = GetPlayoutDelay();
config.min_playout_delay = playout_delay;
config.max_playout_delay = playout_delay;
config.rtp_timebase = (codec == media::AudioCodec::kUnknown)
? media::cast::kRemotingRtpTimebase
: kAudioTimebase;
config.channels = kAudioChannels;
config.min_bitrate = config.max_bitrate = config.start_bitrate =
kAudioBitrate;
config.max_frame_rate = kAudioFramerate; // 10 ms audio frames
config.audio_codec_params = AudioCodecParams{.codec = codec};
return config;
}
// static
FrameSenderConfig MirrorSettings::GetDefaultVideoConfig(
media::VideoCodec codec) {
FrameSenderConfig config;
config.sender_ssrc = 11;
config.receiver_ssrc = 12;
const base::TimeDelta playout_delay = GetPlayoutDelay();
config.min_playout_delay = playout_delay;
config.max_playout_delay = playout_delay;
config.rtp_timebase = (codec == media::VideoCodec::kUnknown)
? media::cast::kRemotingRtpTimebase
: kVideoTimebase;
config.channels = 1;
config.min_bitrate = kMinVideoBitrate;
config.max_bitrate = kMaxVideoBitrate;
config.start_bitrate = kMinVideoBitrate;
config.max_frame_rate = kMaxFrameRate;
config.video_codec_params = VideoCodecParams(codec);
return config;
}
void MirrorSettings::SetResolutionConstraints(int max_width, int max_height) {
max_width_ = std::max(max_width, min_width_);
max_height_ = std::max(max_height, min_height_);
}
void MirrorSettings::SetSenderSideLetterboxingEnabled(bool enabled) {
enable_sender_side_letterboxing_ = enabled;
}
media::VideoCaptureParams MirrorSettings::GetVideoCaptureParams() {
media::VideoCaptureParams params;
params.requested_format =
media::VideoCaptureFormat(gfx::Size(max_width_, max_height_),
kMaxFrameRate, media::PIXEL_FORMAT_I420);
if (max_height_ == min_height_ && max_width_ == min_width_) {
params.resolution_change_policy = ResolutionChangePolicy::FIXED_RESOLUTION;
} else if (enable_sender_side_letterboxing_) {
params.resolution_change_policy =
ResolutionChangePolicy::FIXED_ASPECT_RATIO;
} else {
params.resolution_change_policy = ResolutionChangePolicy::ANY_WITHIN_LIMIT;
}
params.is_high_dpi_enabled =
base::FeatureList::IsEnabled(features::kCastEnableStreamingWithHiDPI);
DCHECK(params.IsValid());
return params;
}
media::AudioParameters MirrorSettings::GetAudioCaptureParams() {
media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
media::ChannelLayoutConfig::Stereo(),
kAudioTimebase, kAudioTimebase / 100);
DCHECK(params.IsValid());
return params;
}
} // namespace mirroring