| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CAST_STREAMING_CAPTURE_RECOMMENDATIONS_H_ |
| #define CAST_STREAMING_CAPTURE_RECOMMENDATIONS_H_ |
| |
| #include <chrono> |
| #include <cmath> |
| #include <memory> |
| #include <tuple> |
| |
| #include "cast/streaming/constants.h" |
| |
| namespace openscreen { |
| namespace cast { |
| |
| struct Answer; |
| |
| // This namespace contains classes and functions to be used by senders for |
| // determining what constraints are recommended for the capture device, based on |
| // the limits reported by the receiver. |
| // |
| // A general note about recommendations: they are NOT maximum operational |
| // limits, instead they are targeted to provide a delightful cast experience. |
| // For example, if a receiver is connected to a 1080P display but cannot provide |
| // 1080P at a stable FPS with a good experience, 1080P will not be recommended. |
| namespace capture_recommendations { |
| |
| // Default maximum delay for both audio and video. Used if the sender fails |
| // to provide any constraints. |
| constexpr std::chrono::milliseconds kDefaultMaxDelayMs(4000); |
| |
| // Bit rate limits, used for both audio and video streams. |
| struct BitRateLimits { |
| bool operator==(const BitRateLimits& other) const; |
| |
| // Minimum bit rate, in bits per second. |
| int minimum; |
| |
| // Maximum bit rate, in bits per second. |
| int maximum; |
| }; |
| |
| // The mirroring control protocol specifies 32kbps as the absolute minimum |
| // for audio. Depending on the type of audio content (narrowband, fullband, |
| // etc.) Opus specifically can perform very well at this bitrate. |
| // See: https://research.google/pubs/pub41650/ |
| constexpr int kDefaultAudioMinBitRate = 32 * 1000; |
| |
| // Opus generally sees little improvement above 192kbps, but some older codecs |
| // that we may consider supporting improve at up to 256kbps. |
| constexpr int kDefaultAudioMaxBitRate = 256 * 1000; |
| constexpr BitRateLimits kDefaultAudioBitRateLimits{kDefaultAudioMinBitRate, |
| kDefaultAudioMaxBitRate}; |
| |
| // While generally audio should be captured at the maximum sample rate, 16kHz is |
| // the recommended absolute minimum. |
| constexpr int kDefaultAudioMinSampleRate = 16000; |
| |
| // Audio capture recommendations. Maximum delay is determined by buffer |
| // constraints, and capture bit rate may vary between limits as appropriate. |
| struct Audio { |
| bool operator==(const Audio& other) const; |
| |
| // Represents the recommended bit rate range. |
| BitRateLimits bit_rate_limits = kDefaultAudioBitRateLimits; |
| |
| // Represents the maximum audio delay, in milliseconds. |
| std::chrono::milliseconds max_delay = kDefaultMaxDelayMs; |
| |
| // Represents the maximum number of audio channels. |
| int max_channels = kDefaultAudioChannels; |
| |
| // Represents the maximum samples per second. |
| int max_sample_rate = kDefaultAudioSampleRate; |
| |
| // Represents the absolute minimum samples per second. Generally speaking, |
| // audio should be captured at the maximum samples per second rate. |
| int min_sample_rate = kDefaultAudioMinSampleRate; |
| }; |
| |
| struct Resolution { |
| bool operator==(const Resolution& other) const; |
| bool operator<(const Resolution& other) const; |
| bool operator<=(const Resolution& other) const; |
| void set_minimum(const Resolution& other); |
| |
| // The effective bit rate is the predicted average bit rate based on the |
| // properties of the Resolution instance, and is currently just the product. |
| constexpr int effective_bit_rate() const { |
| return static_cast<int>(static_cast<double>(width * height) * frame_rate); |
| } |
| |
| int width; |
| int height; |
| double frame_rate; |
| }; |
| |
| // The minimum dimensions are as close as possible to low-definition |
| // television, factoring in the receiver's aspect ratio if provided. |
| constexpr Resolution kDefaultMinResolution{kMinVideoWidth, kMinVideoHeight, |
| kDefaultFrameRate}; |
| |
| // Currently mirroring only supports 1080P. |
| constexpr Resolution kDefaultMaxResolution{1920, 1080, kDefaultFrameRate}; |
| |
| // The mirroring spec suggests 300kbps as the absolute minimum bitrate. |
| constexpr int kDefaultVideoMinBitRate = 300 * 1000; |
| |
| // The theoretical maximum pixels per second is the maximum bit rate |
| // divided by 8 (the max byte rate). In practice it should generally be |
| // less. |
| constexpr int kDefaultVideoMaxPixelsPerSecond = |
| kDefaultMaxResolution.effective_bit_rate() / 8; |
| |
| // Our default limits are merely the product of the minimum and maximum |
| // dimensions, and are only used if the receiver fails to give better |
| // constraint information. |
| constexpr BitRateLimits kDefaultVideoBitRateLimits{ |
| kDefaultVideoMinBitRate, kDefaultMaxResolution.effective_bit_rate()}; |
| |
| // Video capture recommendations. |
| struct Video { |
| bool operator==(const Video& other) const; |
| |
| // Represents the recommended bit rate range. |
| BitRateLimits bit_rate_limits = kDefaultVideoBitRateLimits; |
| |
| // Represents the recommended minimum resolution. |
| Resolution minimum = kDefaultMinResolution; |
| |
| // Represents the recommended maximum resolution. |
| Resolution maximum = kDefaultMaxResolution; |
| |
| // Indicates whether the receiver can scale frames from a different aspect |
| // ratio, or if it needs to be done by the sender. Default is false, meaning |
| // that the sender is responsible for letterboxing. |
| bool supports_scaling = false; |
| |
| // Represents the maximum video delay, in milliseconds. |
| std::chrono::milliseconds max_delay = kDefaultMaxDelayMs; |
| |
| // Represents the maximum pixels per second, not necessarily correlated |
| // to bit rate. |
| int max_pixels_per_second = kDefaultVideoMaxPixelsPerSecond; |
| }; |
| |
| // Outputted recommendations for usage by capture devices. Note that we always |
| // return both audio and video (it is up to the sender to determine what |
| // streams actually get created). If the receiver doesn't give us any |
| // information for making recommendations, the defaults are used. |
| struct Recommendations { |
| bool operator==(const Recommendations& other) const; |
| |
| // Audio specific recommendations. |
| Audio audio; |
| |
| // Video specific recommendations. |
| Video video; |
| }; |
| |
| Recommendations GetRecommendations(const Answer& answer); |
| |
| } // namespace capture_recommendations |
| } // namespace cast |
| } // namespace openscreen |
| |
| #endif // CAST_STREAMING_CAPTURE_RECOMMENDATIONS_H_ |