aboutsummaryrefslogtreecommitdiff
path: root/cast/streaming/capture_recommendations.h
blob: ccb2475b16753e1e50f838ad59b4898dcbdf19b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// 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(400);

// 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_