Bump to WebRTC M120 release

Some API deprecation -- ExperimentalAgc and ExperimentalNs are gone.
We're continuing to carry iSAC even though it's gone upstream, but maybe
we'll want to drop that soon.
This commit is contained in:
Arun Raghavan
2023-12-12 10:42:58 -05:00
parent 9a202fb8c2
commit c6abf6cd3f
479 changed files with 20900 additions and 11996 deletions

View File

@ -13,6 +13,7 @@
#include <algorithm>
#include <array>
#include <iterator>
#include <type_traits>
#include "rtc_base/checks.h"
@ -83,7 +84,7 @@ namespace rtc {
// a pointer if fix-sized) and trivially copyable, so it's probably cheaper to
// pass it by value than by const reference.
namespace impl {
namespace array_view_internal {
// Magic constant for indicating that the size of an ArrayView is variable
// instead of fixed.
@ -124,7 +125,7 @@ class ArrayViewBase<T, 0> {
// Specialized base class for ArrayViews of variable size.
template <typename T>
class ArrayViewBase<T, impl::kArrayViewVarSize> {
class ArrayViewBase<T, array_view_internal::kArrayViewVarSize> {
public:
ArrayViewBase(T* data, size_t size)
: data_(size == 0 ? nullptr : data), size_(size) {}
@ -141,18 +142,23 @@ class ArrayViewBase<T, impl::kArrayViewVarSize> {
size_t size_;
};
} // namespace impl
} // namespace array_view_internal
template <typename T, std::ptrdiff_t Size = impl::kArrayViewVarSize>
class ArrayView final : public impl::ArrayViewBase<T, Size> {
template <typename T,
std::ptrdiff_t Size = array_view_internal::kArrayViewVarSize>
class ArrayView final : public array_view_internal::ArrayViewBase<T, Size> {
public:
using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using const_iterator = const T*;
// Construct an ArrayView from a pointer and a length.
template <typename U>
ArrayView(U* data, size_t size)
: impl::ArrayViewBase<T, Size>::ArrayViewBase(data, size) {
: array_view_internal::ArrayViewBase<T, Size>::ArrayViewBase(data, size) {
RTC_DCHECK_EQ(size == 0 ? nullptr : data, this->data());
RTC_DCHECK_EQ(size, this->size());
RTC_DCHECK_EQ(!this->data(),
@ -166,7 +172,8 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
: ArrayView() {}
ArrayView(std::nullptr_t, size_t size)
: ArrayView(static_cast<T*>(nullptr), size) {
static_assert(Size == 0 || Size == impl::kArrayViewVarSize, "");
static_assert(Size == 0 || Size == array_view_internal::kArrayViewVarSize,
"");
RTC_DCHECK_EQ(0, size);
}
@ -174,7 +181,7 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
template <typename U, size_t N>
ArrayView(U (&array)[N]) // NOLINT
: ArrayView(array, N) {
static_assert(Size == N || Size == impl::kArrayViewVarSize,
static_assert(Size == N || Size == array_view_internal::kArrayViewVarSize,
"Array size must match ArrayView size");
}
@ -207,7 +214,7 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
// N> when M != N.
template <
typename U,
typename std::enable_if<Size != impl::kArrayViewVarSize &&
typename std::enable_if<Size != array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(U& u) // NOLINT
: ArrayView(u.data(), u.size()) {
@ -215,7 +222,7 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
}
template <
typename U,
typename std::enable_if<Size != impl::kArrayViewVarSize &&
typename std::enable_if<Size != array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(const U& u) // NOLINT(runtime/explicit)
: ArrayView(u.data(), u.size()) {
@ -235,13 +242,13 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
// const rtc::Buffer to ArrayView<const uint8_t>.
template <
typename U,
typename std::enable_if<Size == impl::kArrayViewVarSize &&
typename std::enable_if<Size == array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(U& u) // NOLINT
: ArrayView(u.data(), u.size()) {}
template <
typename U,
typename std::enable_if<Size == impl::kArrayViewVarSize &&
typename std::enable_if<Size == array_view_internal::kArrayViewVarSize &&
HasDataAndSize<U, T>::value>::type* = nullptr>
ArrayView(const U& u) // NOLINT(runtime/explicit)
: ArrayView(u.data(), u.size()) {}
@ -258,6 +265,18 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> {
T* end() const { return this->data() + this->size(); }
const T* cbegin() const { return this->data(); }
const T* cend() const { return this->data() + this->size(); }
std::reverse_iterator<T*> rbegin() const {
return std::make_reverse_iterator(end());
}
std::reverse_iterator<T*> rend() const {
return std::make_reverse_iterator(begin());
}
std::reverse_iterator<const T*> crbegin() const {
return std::make_reverse_iterator(cend());
}
std::reverse_iterator<const T*> crend() const {
return std::make_reverse_iterator(cbegin());
}
ArrayView<T> subview(size_t offset, size_t size) const {
return offset < this->size()

View File

@ -11,8 +11,6 @@
#include "api/audio/audio_frame.h"
#include <string.h>
#include <algorithm>
#include <utility>
#include "rtc_base/checks.h"
#include "rtc_base/time_utils.h"
@ -24,35 +22,13 @@ AudioFrame::AudioFrame() {
static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes");
}
void swap(AudioFrame& a, AudioFrame& b) {
using std::swap;
swap(a.timestamp_, b.timestamp_);
swap(a.elapsed_time_ms_, b.elapsed_time_ms_);
swap(a.ntp_time_ms_, b.ntp_time_ms_);
swap(a.samples_per_channel_, b.samples_per_channel_);
swap(a.sample_rate_hz_, b.sample_rate_hz_);
swap(a.num_channels_, b.num_channels_);
swap(a.channel_layout_, b.channel_layout_);
swap(a.speech_type_, b.speech_type_);
swap(a.vad_activity_, b.vad_activity_);
swap(a.profile_timestamp_ms_, b.profile_timestamp_ms_);
swap(a.packet_infos_, b.packet_infos_);
const size_t length_a = a.samples_per_channel_ * a.num_channels_;
const size_t length_b = b.samples_per_channel_ * b.num_channels_;
RTC_DCHECK_LE(length_a, AudioFrame::kMaxDataSizeSamples);
RTC_DCHECK_LE(length_b, AudioFrame::kMaxDataSizeSamples);
std::swap_ranges(a.data_, a.data_ + std::max(length_a, length_b), b.data_);
swap(a.muted_, b.muted_);
swap(a.absolute_capture_timestamp_ms_, b.absolute_capture_timestamp_ms_);
}
void AudioFrame::Reset() {
ResetWithoutMuting();
muted_ = true;
}
void AudioFrame::ResetWithoutMuting() {
// TODO(wu): Zero is a valid value for |timestamp_|. We should initialize
// TODO(wu): Zero is a valid value for `timestamp_`. We should initialize
// to an invalid value, or add a new member to indicate invalidity.
timestamp_ = 0;
elapsed_time_ms_ = -1;

View File

@ -14,11 +14,8 @@
#include <stddef.h>
#include <stdint.h>
#include <utility>
#include "api/audio/channel_layout.h"
#include "api/rtp_packet_infos.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
@ -60,7 +57,8 @@ class AudioFrame {
AudioFrame();
friend void swap(AudioFrame& a, AudioFrame& b);
AudioFrame(const AudioFrame&) = delete;
AudioFrame& operator=(const AudioFrame&) = delete;
// Resets all members to their default state.
void Reset();
@ -139,7 +137,7 @@ class AudioFrame {
int64_t profile_timestamp_ms_ = 0;
// Information about packets used to assemble this audio frame. This is needed
// by |SourceTracker| when the frame is delivered to the RTCRtpReceiver's
// by `SourceTracker` when the frame is delivered to the RTCRtpReceiver's
// MediaStreamTrack, in order to implement getContributingSources(). See:
// https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getcontributingsources
//
@ -149,7 +147,7 @@ class AudioFrame {
// sync buffer is the small sample-holding buffer located after the audio
// decoder and before where samples are assembled into output frames.
//
// |RtpPacketInfos| may also be empty if the audio samples did not come from
// `RtpPacketInfos` may also be empty if the audio samples did not come from
// RTP packets. E.g. if the audio were locally generated by packet loss
// concealment, comfort noise generation, etc.
RtpPacketInfos packet_infos_;
@ -165,11 +163,9 @@ class AudioFrame {
// Absolute capture timestamp when this audio frame was originally captured.
// This is only valid for audio frames captured on this machine. The absolute
// capture timestamp of a received frame is found in |packet_infos_|.
// capture timestamp of a received frame is found in `packet_infos_`.
// This timestamp MUST be based on the same clock as rtc::TimeMillis().
absl::optional<int64_t> absolute_capture_timestamp_ms_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioFrame);
};
} // namespace webrtc

View File

@ -275,7 +275,7 @@ const char* ChannelLayoutToString(ChannelLayout layout) {
case CHANNEL_LAYOUT_BITSTREAM:
return "BITSTREAM";
}
RTC_NOTREACHED() << "Invalid channel layout provided: " << layout;
RTC_DCHECK_NOTREACHED() << "Invalid channel layout provided: " << layout;
return "";
}

View File

@ -153,6 +153,7 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
res = res & Limit(&c->filter.config_change_duration_blocks, 0, 100000);
res = res & Limit(&c->filter.initial_state_seconds, 0.f, 100.f);
res = res & Limit(&c->filter.coarse_reset_hangover_blocks, 0, 250000);
res = res & Limit(&c->erle.min, 1.f, 100000.f);
res = res & Limit(&c->erle.max_l, 1.f, 100000.f);
@ -165,6 +166,7 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f);
res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f);
res = res & Limit(&c->ep_strength.nearend_len, -1.0f, 1.0f);
res =
res & Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f);
@ -228,6 +230,12 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
res =
res & Limit(&c->suppressor.nearend_tuning.max_dec_factor_lf, 0.f, 100.f);
res = res & Limit(&c->suppressor.last_permanent_lf_smoothing_band, 0, 64);
res = res & Limit(&c->suppressor.last_lf_smoothing_band, 0, 64);
res = res & Limit(&c->suppressor.last_lf_band, 0, 63);
res = res &
Limit(&c->suppressor.first_hf_band, c->suppressor.last_lf_band + 1, 64);
res = res & Limit(&c->suppressor.dominant_nearend_detection.enr_threshold,
0.f, 1000000.f);
res = res & Limit(&c->suppressor.dominant_nearend_detection.snr_threshold,

View File

@ -43,6 +43,7 @@ struct RTC_EXPORT EchoCanceller3Config {
size_t hysteresis_limit_blocks = 1;
size_t fixed_capture_delay_samples = 0;
float delay_estimate_smoothing = 0.7f;
float delay_estimate_smoothing_delay_found = 0.7f;
float delay_candidate_detection_threshold = 0.2f;
struct DelaySelectionThresholds {
int initial;
@ -58,6 +59,7 @@ struct RTC_EXPORT EchoCanceller3Config {
};
AlignmentMixing render_alignment_mixing = {false, true, 10000.f, true};
AlignmentMixing capture_alignment_mixing = {false, true, 10000.f, false};
bool detect_pre_echo = true;
} delay;
struct Filter {
@ -86,9 +88,11 @@ struct RTC_EXPORT EchoCanceller3Config {
size_t config_change_duration_blocks = 250;
float initial_state_seconds = 2.5f;
int coarse_reset_hangover_blocks = 25;
bool conservative_initial_phase = false;
bool enable_coarse_filter_output_usage = true;
bool use_linear_filter = true;
bool high_pass_filter_echo_reference = false;
bool export_linear_aec_output = false;
} filter;
@ -105,8 +109,11 @@ struct RTC_EXPORT EchoCanceller3Config {
struct EpStrength {
float default_gain = 1.f;
float default_len = 0.83f;
float nearend_len = 0.83f;
bool echo_can_saturate = true;
bool bounded_erl = false;
bool erle_onset_compensation_in_dominant_nearend = false;
bool use_conservative_tail_frequency_response = true;
} ep_strength;
struct EchoAudibility {
@ -190,6 +197,12 @@ struct RTC_EXPORT EchoCanceller3Config {
2.0f,
0.25f);
bool lf_smoothing_during_initial_phase = true;
int last_permanent_lf_smoothing_band = 0;
int last_lf_smoothing_band = 5;
int last_lf_band = 5;
int first_hf_band = 8;
struct DominantNearendDetection {
float enr_threshold = .25f;
float enr_exit_threshold = 10.f;
@ -197,6 +210,7 @@ struct RTC_EXPORT EchoCanceller3Config {
int hold_duration = 50;
int trigger_threshold = 12;
bool use_during_initial_phase = true;
bool use_unbounded_echo_spectrum = true;
} dominant_nearend_detection;
struct SubbandNearendDetection {
@ -221,7 +235,15 @@ struct RTC_EXPORT EchoCanceller3Config {
} high_bands_suppression;
float floor_first_increase = 0.00001f;
bool conservative_hf_suppression = false;
} suppressor;
struct MultiChannel {
bool detect_stereo_content = true;
float stereo_detection_threshold = 0.0f;
int stereo_detection_timeout_threshold_seconds = 300;
float stereo_detection_hysteresis_seconds = 2.0f;
} multi_channel;
};
} // namespace webrtc

View File

@ -48,6 +48,13 @@ class EchoControl {
// Provides an optional external estimate of the audio buffer delay.
virtual void SetAudioBufferDelay(int delay_ms) = 0;
// Specifies whether the capture output will be used. The purpose of this is
// to allow the echo controller to deactivate some of the processing when the
// resulting output is anyway not used, for instance when the endpoint is
// muted.
// TODO(b/177830919): Make pure virtual.
virtual void SetCaptureOutputUsage(bool capture_output_used) {}
// Returns wheter the signal is altered.
virtual bool ActiveProcessing() const = 0;

View File

@ -10,8 +10,6 @@
#include "api/audio_codecs/audio_decoder.h"
#include <assert.h>
#include <memory>
#include <utility>
@ -162,9 +160,10 @@ AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) {
case 2:
return kComfortNoise;
default:
assert(false);
RTC_DCHECK_NOTREACHED();
return kSpeech;
}
}
constexpr int AudioDecoder::kMaxNumberOfChannels;
} // namespace webrtc

View File

@ -20,7 +20,6 @@
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "rtc_base/buffer.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
@ -37,6 +36,9 @@ class AudioDecoder {
AudioDecoder() = default;
virtual ~AudioDecoder() = default;
AudioDecoder(const AudioDecoder&) = delete;
AudioDecoder& operator=(const AudioDecoder&) = delete;
class EncodedAudioFrame {
public:
struct DecodeResult {
@ -53,8 +55,8 @@ class AudioDecoder {
// Returns true if this packet contains DTX.
virtual bool IsDtxPacket() const;
// Decodes this frame of audio and writes the result in |decoded|.
// |decoded| must be large enough to store as many samples as indicated by a
// Decodes this frame of audio and writes the result in `decoded`.
// `decoded` must be large enough to store as many samples as indicated by a
// call to Duration() . On success, returns an absl::optional containing the
// total number of samples across all channels, as well as whether the
// decoder produced comfort noise or speech. On failure, returns an empty
@ -85,8 +87,8 @@ class AudioDecoder {
// Let the decoder parse this payload and prepare zero or more decodable
// frames. Each frame must be between 10 ms and 120 ms long. The caller must
// ensure that the AudioDecoder object outlives any frame objects returned by
// this call. The decoder is free to swap or move the data from the |payload|
// buffer. |timestamp| is the input timestamp, in samples, corresponding to
// this call. The decoder is free to swap or move the data from the `payload`
// buffer. `timestamp` is the input timestamp, in samples, corresponding to
// the start of the payload.
virtual std::vector<ParseResult> ParsePayload(rtc::Buffer&& payload,
uint32_t timestamp);
@ -95,12 +97,12 @@ class AudioDecoder {
// obsolete; callers should call ParsePayload instead. For now, subclasses
// must still implement DecodeInternal.
// Decodes |encode_len| bytes from |encoded| and writes the result in
// |decoded|. The maximum bytes allowed to be written into |decoded| is
// |max_decoded_bytes|. Returns the total number of samples across all
// channels. If the decoder produced comfort noise, |speech_type|
// Decodes `encode_len` bytes from `encoded` and writes the result in
// `decoded`. The maximum bytes allowed to be written into `decoded` is
// `max_decoded_bytes`. Returns the total number of samples across all
// channels. If the decoder produced comfort noise, `speech_type`
// is set to kComfortNoise, otherwise it is kSpeech. The desired output
// sample rate is provided in |sample_rate_hz|, which must be valid for the
// sample rate is provided in `sample_rate_hz`, which must be valid for the
// codec at hand.
int Decode(const uint8_t* encoded,
size_t encoded_len,
@ -123,11 +125,11 @@ class AudioDecoder {
// Calls the packet-loss concealment of the decoder to update the state after
// one or several lost packets. The caller has to make sure that the
// memory allocated in |decoded| should accommodate |num_frames| frames.
// memory allocated in `decoded` should accommodate `num_frames` frames.
virtual size_t DecodePlc(size_t num_frames, int16_t* decoded);
// Asks the decoder to generate packet-loss concealment and append it to the
// end of |concealment_audio|. The concealment audio should be in
// end of `concealment_audio`. The concealment audio should be in
// channel-interleaved format, with as many channels as the last decoded
// packet produced. The implementation must produce at least
// requested_samples_per_channel, or nothing at all. This is a signal to the
@ -136,7 +138,7 @@ class AudioDecoder {
// with the decoded audio on either side of the concealment.
// Note: The default implementation of GeneratePlc will be deleted soon. All
// implementations must provide their own, which can be a simple as a no-op.
// TODO(bugs.webrtc.org/9676): Remove default impementation.
// TODO(bugs.webrtc.org/9676): Remove default implementation.
virtual void GeneratePlc(size_t requested_samples_per_channel,
rtc::BufferT<int16_t>* concealment_audio);
@ -146,19 +148,19 @@ class AudioDecoder {
// Returns the last error code from the decoder.
virtual int ErrorCode();
// Returns the duration in samples-per-channel of the payload in |encoded|
// which is |encoded_len| bytes long. Returns kNotImplemented if no duration
// Returns the duration in samples-per-channel of the payload in `encoded`
// which is `encoded_len` bytes long. Returns kNotImplemented if no duration
// estimate is available, or -1 in case of an error.
virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
// Returns the duration in samples-per-channel of the redandant payload in
// |encoded| which is |encoded_len| bytes long. Returns kNotImplemented if no
// `encoded` which is `encoded_len` bytes long. Returns kNotImplemented if no
// duration estimate is available, or -1 in case of an error.
virtual int PacketDurationRedundant(const uint8_t* encoded,
size_t encoded_len) const;
// Detects whether a packet has forward error correction. The packet is
// comprised of the samples in |encoded| which is |encoded_len| bytes long.
// comprised of the samples in `encoded` which is `encoded_len` bytes long.
// Returns true if the packet has FEC and false otherwise.
virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
@ -170,6 +172,9 @@ class AudioDecoder {
// during the lifetime of the decoder.
virtual size_t Channels() const = 0;
// The maximum number of audio channels supported by WebRTC decoders.
static constexpr int kMaxNumberOfChannels = 24;
protected:
static SpeechType ConvertSpeechType(int16_t type);
@ -184,9 +189,6 @@ class AudioDecoder {
int sample_rate_hz,
int16_t* decoded,
SpeechType* speech_type);
private:
RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoder);
};
} // namespace webrtc

View File

@ -83,7 +83,7 @@ void AudioEncoder::OnReceivedUplinkPacketLossFraction(
void AudioEncoder::OnReceivedUplinkRecoverablePacketLossFraction(
float uplink_recoverable_packet_loss_fraction) {
RTC_NOTREACHED();
RTC_DCHECK_NOTREACHED();
}
void AudioEncoder::OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) {
@ -110,4 +110,5 @@ ANAStats AudioEncoder::GetANAStats() const {
return ANAStats();
}
constexpr int AudioEncoder::kMaxNumberOfChannels;
} // namespace webrtc

View File

@ -16,12 +16,12 @@
#include <utility>
#include <vector>
#include "absl/base/attributes.h"
#include "absl/types/optional.h"
#include "api/array_view.h"
#include "api/call/bitrate_allocation.h"
#include "api/units/time_delta.h"
#include "rtc_base/buffer.h"
#include "rtc_base/deprecation.h"
namespace webrtc {
@ -95,13 +95,13 @@ class AudioEncoder {
// This is the main struct for auxiliary encoding information. Each encoded
// packet should be accompanied by one EncodedInfo struct, containing the
// total number of |encoded_bytes|, the |encoded_timestamp| and the
// |payload_type|. If the packet contains redundant encodings, the |redundant|
// total number of `encoded_bytes`, the `encoded_timestamp` and the
// `payload_type`. If the packet contains redundant encodings, the `redundant`
// vector will be populated with EncodedInfoLeaf structs. Each struct in the
// vector represents one encoding; the order of structs in the vector is the
// same as the order in which the actual payloads are written to the byte
// stream. When EncoderInfoLeaf structs are present in the vector, the main
// struct's |encoded_bytes| will be the sum of all the |encoded_bytes| in the
// struct's `encoded_bytes` will be the sum of all the `encoded_bytes` in the
// vector.
struct EncodedInfo : public EncodedInfoLeaf {
EncodedInfo();
@ -143,7 +143,7 @@ class AudioEncoder {
// Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 *
// NumChannels() samples). Multi-channel audio must be sample-interleaved.
// The encoder appends zero or more bytes of output to |encoded| and returns
// The encoder appends zero or more bytes of output to `encoded` and returns
// additional encoding information. Encode() checks some preconditions, calls
// EncodeImpl() which does the actual work, and then checks some
// postconditions.
@ -182,12 +182,11 @@ class AudioEncoder {
// implementation does nothing.
virtual void SetMaxPlaybackRate(int frequency_hz);
// This is to be deprecated. Please use |OnReceivedTargetAudioBitrate|
// instead.
// Tells the encoder what average bitrate we'd like it to produce. The
// encoder is free to adjust or disregard the given bitrate (the default
// implementation does the latter).
RTC_DEPRECATED virtual void SetTargetBitrate(int target_bps);
ABSL_DEPRECATED("Use OnReceivedTargetAudioBitrate instead")
virtual void SetTargetBitrate(int target_bps);
// Causes this encoder to let go of any other encoders it contains, and
// returns a pointer to an array where they are stored (which is required to
@ -206,11 +205,12 @@ class AudioEncoder {
virtual void DisableAudioNetworkAdaptor();
// Provides uplink packet loss fraction to this encoder to allow it to adapt.
// |uplink_packet_loss_fraction| is in the range [0.0, 1.0].
// `uplink_packet_loss_fraction` is in the range [0.0, 1.0].
virtual void OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction);
RTC_DEPRECATED virtual void OnReceivedUplinkRecoverablePacketLossFraction(
ABSL_DEPRECATED("")
virtual void OnReceivedUplinkRecoverablePacketLossFraction(
float uplink_recoverable_packet_loss_fraction);
// Provides target audio bitrate to this encoder to allow it to adapt.
@ -246,6 +246,9 @@ class AudioEncoder {
virtual absl::optional<std::pair<TimeDelta, TimeDelta>> GetFrameLengthRange()
const = 0;
// The maximum number of audio channels supported by WebRTC encoders.
static constexpr int kMaxNumberOfChannels = 24;
protected:
// Subclasses implement this to perform the actual encoding. Called by
// Encode().

View File

@ -32,7 +32,7 @@ struct BitrateAllocationUpdate {
double packet_loss_ratio = 0;
// Predicted round trip time.
TimeDelta round_trip_time = TimeDelta::PlusInfinity();
// |bwe_period| is deprecated, use |stable_target_bitrate| allocation instead.
// `bwe_period` is deprecated, use `stable_target_bitrate` allocation instead.
TimeDelta bwe_period = TimeDelta::PlusInfinity();
// Congestion window pushback bitrate reduction fraction. Used in
// VideoStreamEncoder to reduce the bitrate by the given fraction

31
webrtc/api/location.h Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright 2023 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_LOCATION_H_
#define API_LOCATION_H_
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// Location provides basic info where of an object was constructed, or was
// significantly brought to life. This is a stripped down version of
// https://source.chromium.org/chromium/chromium/src/+/main:base/location.h
// that only specifies an interface compatible to how base::Location is
// supposed to be used.
// The declaration is overriden inside the Chromium build.
class RTC_EXPORT Location {
public:
static Location Current() { return Location(); }
};
} // namespace webrtc
#endif // API_LOCATION_H_

View File

@ -0,0 +1,120 @@
/*
* Copyright 2022 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_MAKE_REF_COUNTED_H_
#define API_MAKE_REF_COUNTED_H_
#include <type_traits>
#include <utility>
#include "rtc_base/ref_counted_object.h"
namespace rtc {
namespace webrtc_make_ref_counted_internal {
// Determines if the given class has AddRef and Release methods.
template <typename T>
class HasAddRefAndRelease {
private:
template <typename C,
decltype(std::declval<C>().AddRef())* = nullptr,
decltype(std::declval<C>().Release())* = nullptr>
static int Test(int);
template <typename>
static char Test(...);
public:
static constexpr bool value = std::is_same_v<decltype(Test<T>(0)), int>;
};
} // namespace webrtc_make_ref_counted_internal
// General utilities for constructing a reference counted class and the
// appropriate reference count implementation for that class.
//
// These utilities select either the `RefCountedObject` implementation or
// `FinalRefCountedObject` depending on whether the to-be-shared class is
// derived from the RefCountInterface interface or not (respectively).
// `make_ref_counted`:
//
// Use this when you want to construct a reference counted object of type T and
// get a `scoped_refptr<>` back. Example:
//
// auto p = make_ref_counted<Foo>("bar", 123);
//
// For a class that inherits from RefCountInterface, this is equivalent to:
//
// auto p = scoped_refptr<Foo>(new RefCountedObject<Foo>("bar", 123));
//
// If the class does not inherit from RefCountInterface, but does have
// AddRef/Release methods (so a T* is convertible to rtc::scoped_refptr), this
// is equivalent to just
//
// auto p = scoped_refptr<Foo>(new Foo("bar", 123));
//
// Otherwise, the example is equivalent to:
//
// auto p = scoped_refptr<FinalRefCountedObject<Foo>>(
// new FinalRefCountedObject<Foo>("bar", 123));
//
// In these cases, `make_ref_counted` reduces the amount of boilerplate code but
// also helps with the most commonly intended usage of RefCountedObject whereby
// methods for reference counting, are virtual and designed to satisfy the need
// of an interface. When such a need does not exist, it is more efficient to use
// the `FinalRefCountedObject` template, which does not add the vtable overhead.
//
// Note that in some cases, using RefCountedObject directly may still be what's
// needed.
// `make_ref_counted` for abstract classes that are convertible to
// RefCountInterface. The is_abstract requirement rejects classes that inherit
// both RefCountInterface and RefCounted object, which is a a discouraged
// pattern, and would result in double inheritance of RefCountedObject if this
// template was applied.
template <
typename T,
typename... Args,
typename std::enable_if<std::is_convertible_v<T*, RefCountInterface*> &&
std::is_abstract_v<T>,
T>::type* = nullptr>
scoped_refptr<T> make_ref_counted(Args&&... args) {
return scoped_refptr<T>(new RefCountedObject<T>(std::forward<Args>(args)...));
}
// `make_ref_counted` for complete classes that are not convertible to
// RefCountInterface and already carry a ref count.
template <
typename T,
typename... Args,
typename std::enable_if<
!std::is_convertible_v<T*, RefCountInterface*> &&
webrtc_make_ref_counted_internal::HasAddRefAndRelease<T>::value,
T>::type* = nullptr>
scoped_refptr<T> make_ref_counted(Args&&... args) {
return scoped_refptr<T>(new T(std::forward<Args>(args)...));
}
// `make_ref_counted` for complete classes that are not convertible to
// RefCountInterface and have no ref count of their own.
template <
typename T,
typename... Args,
typename std::enable_if<
!std::is_convertible_v<T*, RefCountInterface*> &&
!webrtc_make_ref_counted_internal::HasAddRefAndRelease<T>::value,
T>::type* = nullptr>
scoped_refptr<FinalRefCountedObject<T>> make_ref_counted(Args&&... args) {
return scoped_refptr<FinalRefCountedObject<T>>(
new FinalRefCountedObject<T>(std::forward<Args>(args)...));
}
} // namespace rtc
#endif // API_MAKE_REF_COUNTED_H_

View File

@ -10,8 +10,8 @@
#ifndef API_REF_COUNTED_BASE_H_
#define API_REF_COUNTED_BASE_H_
#include "rtc_base/constructor_magic.h"
#include "rtc_base/ref_count.h"
#include <type_traits>
#include "rtc_base/ref_counter.h"
namespace rtc {
@ -20,6 +20,9 @@ class RefCountedBase {
public:
RefCountedBase() = default;
RefCountedBase(const RefCountedBase&) = delete;
RefCountedBase& operator=(const RefCountedBase&) = delete;
void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const {
const auto status = ref_count_.DecRef();
@ -30,12 +33,64 @@ class RefCountedBase {
}
protected:
// Provided for internal webrtc subclasses for corner cases where it's
// necessary to know whether or not a reference is exclusively held.
bool HasOneRef() const { return ref_count_.HasOneRef(); }
virtual ~RefCountedBase() = default;
private:
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
};
RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
// Template based version of `RefCountedBase` for simple implementations that do
// not need (or want) destruction via virtual destructor or the overhead of a
// vtable.
//
// To use:
// struct MyInt : public rtc::RefCountedNonVirtual<MyInt> {
// int foo_ = 0;
// };
//
// rtc::scoped_refptr<MyInt> my_int(new MyInt());
//
// sizeof(MyInt) on a 32 bit system would then be 8, int + refcount and no
// vtable generated.
template <typename T>
class RefCountedNonVirtual {
public:
RefCountedNonVirtual() = default;
RefCountedNonVirtual(const RefCountedNonVirtual&) = delete;
RefCountedNonVirtual& operator=(const RefCountedNonVirtual&) = delete;
void AddRef() const { ref_count_.IncRef(); }
RefCountReleaseStatus Release() const {
// If you run into this assert, T has virtual methods. There are two
// options:
// 1) The class doesn't actually need virtual methods, the type is complete
// so the virtual attribute(s) can be removed.
// 2) The virtual methods are a part of the design of the class. In this
// case you can consider using `RefCountedBase` instead or alternatively
// use `rtc::RefCountedObject`.
static_assert(!std::is_polymorphic<T>::value,
"T has virtual methods. RefCountedBase is a better fit.");
const auto status = ref_count_.DecRef();
if (status == RefCountReleaseStatus::kDroppedLastRef) {
delete static_cast<const T*>(this);
}
return status;
}
protected:
// Provided for internal webrtc subclasses for corner cases where it's
// necessary to know whether or not a reference is exclusively held.
bool HasOneRef() const { return ref_count_.HasOneRef(); }
~RefCountedNonVirtual() = default;
private:
mutable webrtc::webrtc_impl::RefCounter ref_count_{0};
};
} // namespace rtc

View File

@ -44,7 +44,6 @@ RTPHeader::RTPHeader()
arrOfCSRCs(),
paddingLength(0),
headerLength(0),
payload_type_frequency(0),
extension() {}
RTPHeader::RTPHeader(const RTPHeader& other) = default;

View File

@ -103,15 +103,6 @@ struct RTPHeaderExtension {
(1 << kAbsSendTimeFraction));
}
TimeDelta GetAbsoluteSendTimeDelta(uint32_t previous_sendtime) const {
RTC_DCHECK(hasAbsoluteSendTime);
RTC_DCHECK(absoluteSendTime < (1ul << 24));
RTC_DCHECK(previous_sendtime < (1ul << 24));
int32_t delta =
static_cast<int32_t>((absoluteSendTime - previous_sendtime) << 8) >> 8;
return TimeDelta::Micros((delta * 1000000ll) / (1 << kAbsSendTimeFraction));
}
bool hasTransmissionTimeOffset;
int32_t transmissionTimeOffset;
bool hasAbsoluteSendTime;
@ -144,13 +135,12 @@ struct RTPHeaderExtension {
VideoPlayoutDelay playout_delay;
// For identification of a stream when ssrc is not signaled. See
// https://tools.ietf.org/html/draft-ietf-avtext-rid-09
// TODO(danilchap): Update url from draft to release version.
// https://tools.ietf.org/html/rfc8852
std::string stream_id;
std::string repaired_stream_id;
// For identifying the media section used to interpret this RTP packet. See
// https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-38
// https://tools.ietf.org/html/rfc8843
std::string mid;
absl::optional<ColorSpace> color_space;
@ -158,7 +148,7 @@ struct RTPHeaderExtension {
enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13
struct RTPHeader {
struct RTC_EXPORT RTPHeader {
RTPHeader();
RTPHeader(const RTPHeader& other);
RTPHeader& operator=(const RTPHeader& other);
@ -172,7 +162,6 @@ struct RTPHeader {
uint32_t arrOfCSRCs[kRtpCsrcSize];
size_t paddingLength;
size_t headerLength;
int payload_type_frequency;
RTPHeaderExtension extension;
};

View File

@ -16,27 +16,22 @@
namespace webrtc {
RtpPacketInfo::RtpPacketInfo()
: ssrc_(0), rtp_timestamp_(0), receive_time_ms_(-1) {}
: ssrc_(0), rtp_timestamp_(0), receive_time_(Timestamp::MinusInfinity()) {}
RtpPacketInfo::RtpPacketInfo(
uint32_t ssrc,
std::vector<uint32_t> csrcs,
uint32_t rtp_timestamp,
absl::optional<uint8_t> audio_level,
absl::optional<AbsoluteCaptureTime> absolute_capture_time,
int64_t receive_time_ms)
RtpPacketInfo::RtpPacketInfo(uint32_t ssrc,
std::vector<uint32_t> csrcs,
uint32_t rtp_timestamp,
Timestamp receive_time)
: ssrc_(ssrc),
csrcs_(std::move(csrcs)),
rtp_timestamp_(rtp_timestamp),
audio_level_(audio_level),
absolute_capture_time_(absolute_capture_time),
receive_time_ms_(receive_time_ms) {}
receive_time_(receive_time) {}
RtpPacketInfo::RtpPacketInfo(const RTPHeader& rtp_header,
int64_t receive_time_ms)
Timestamp receive_time)
: ssrc_(rtp_header.ssrc),
rtp_timestamp_(rtp_header.timestamp),
receive_time_ms_(receive_time_ms) {
receive_time_(receive_time) {
const auto& extension = rtp_header.extension;
const auto csrcs_count = std::min<size_t>(rtp_header.numCSRCs, kRtpCsrcSize);
@ -52,9 +47,10 @@ RtpPacketInfo::RtpPacketInfo(const RTPHeader& rtp_header,
bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs) {
return (lhs.ssrc() == rhs.ssrc()) && (lhs.csrcs() == rhs.csrcs()) &&
(lhs.rtp_timestamp() == rhs.rtp_timestamp()) &&
(lhs.receive_time() == rhs.receive_time()) &&
(lhs.audio_level() == rhs.audio_level()) &&
(lhs.absolute_capture_time() == rhs.absolute_capture_time()) &&
(lhs.receive_time_ms() == rhs.receive_time_ms());
(lhs.local_capture_clock_offset() == rhs.local_capture_clock_offset());
}
} // namespace webrtc

View File

@ -17,14 +17,16 @@
#include "absl/types/optional.h"
#include "api/rtp_headers.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
//
// Structure to hold information about a received |RtpPacket|. It is primarily
// Structure to hold information about a received `RtpPacket`. It is primarily
// used to carry per-packet information from when a packet is received until
// the information is passed to |SourceTracker|.
// the information is passed to `SourceTracker`.
//
class RTC_EXPORT RtpPacketInfo {
public:
@ -33,11 +35,9 @@ class RTC_EXPORT RtpPacketInfo {
RtpPacketInfo(uint32_t ssrc,
std::vector<uint32_t> csrcs,
uint32_t rtp_timestamp,
absl::optional<uint8_t> audio_level,
absl::optional<AbsoluteCaptureTime> absolute_capture_time,
int64_t receive_time_ms);
Timestamp receive_time);
RtpPacketInfo(const RTPHeader& rtp_header, int64_t receive_time_ms);
RtpPacketInfo(const RTPHeader& rtp_header, Timestamp receive_time);
RtpPacketInfo(const RtpPacketInfo& other) = default;
RtpPacketInfo(RtpPacketInfo&& other) = default;
@ -53,19 +53,32 @@ class RTC_EXPORT RtpPacketInfo {
uint32_t rtp_timestamp() const { return rtp_timestamp_; }
void set_rtp_timestamp(uint32_t value) { rtp_timestamp_ = value; }
Timestamp receive_time() const { return receive_time_; }
void set_receive_time(Timestamp value) { receive_time_ = value; }
absl::optional<uint8_t> audio_level() const { return audio_level_; }
void set_audio_level(absl::optional<uint8_t> value) { audio_level_ = value; }
RtpPacketInfo& set_audio_level(absl::optional<uint8_t> value) {
audio_level_ = value;
return *this;
}
const absl::optional<AbsoluteCaptureTime>& absolute_capture_time() const {
return absolute_capture_time_;
}
void set_absolute_capture_time(
RtpPacketInfo& set_absolute_capture_time(
const absl::optional<AbsoluteCaptureTime>& value) {
absolute_capture_time_ = value;
return *this;
}
int64_t receive_time_ms() const { return receive_time_ms_; }
void set_receive_time_ms(int64_t value) { receive_time_ms_ = value; }
const absl::optional<TimeDelta>& local_capture_clock_offset() const {
return local_capture_clock_offset_;
}
RtpPacketInfo& set_local_capture_clock_offset(
absl::optional<TimeDelta> value) {
local_capture_clock_offset_ = value;
return *this;
}
private:
// Fields from the RTP header:
@ -74,6 +87,9 @@ class RTC_EXPORT RtpPacketInfo {
std::vector<uint32_t> csrcs_;
uint32_t rtp_timestamp_;
// Local `webrtc::Clock`-based timestamp of when the packet was received.
Timestamp receive_time_;
// Fields from the Audio Level header extension:
// https://tools.ietf.org/html/rfc6464#section-3
absl::optional<uint8_t> audio_level_;
@ -82,8 +98,12 @@ class RTC_EXPORT RtpPacketInfo {
// http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time
absl::optional<AbsoluteCaptureTime> absolute_capture_time_;
// Local |webrtc::Clock|-based timestamp of when the packet was received.
int64_t receive_time_ms_;
// Clock offset between the local clock and the capturer's clock.
// Do not confuse with `AbsoluteCaptureTime::estimated_capture_clock_offset`
// which instead represents the clock offset between a remote sender and the
// capturer. The following holds:
// Capture's NTP Clock = Local NTP Clock + Local-Capture Clock Offset
absl::optional<TimeDelta> local_capture_clock_offset_;
};
bool operator==(const RtpPacketInfo& lhs, const RtpPacketInfo& rhs);

View File

@ -15,6 +15,7 @@
#include <utility>
#include <vector>
#include "api/make_ref_counted.h"
#include "api/ref_counted_base.h"
#include "api/rtp_packet_info.h"
#include "api/scoped_refptr.h"
@ -26,8 +27,8 @@ namespace webrtc {
// an audio or video frame. Uses internal reference counting to make it very
// cheap to copy.
//
// We should ideally just use |std::vector<RtpPacketInfo>| and have it
// |std::move()|-ed as the per-packet information is transferred from one object
// We should ideally just use `std::vector<RtpPacketInfo>` and have it
// `std::move()`-ed as the per-packet information is transferred from one object
// to another. But moving the info, instead of copying it, is not easily done
// for the current video code.
class RTC_EXPORT RtpPacketInfos {
@ -79,7 +80,7 @@ class RTC_EXPORT RtpPacketInfos {
size_type size() const { return entries().size(); }
private:
class Data : public rtc::RefCountedBase {
class Data final : public rtc::RefCountedNonVirtual<Data> {
public:
static rtc::scoped_refptr<Data> Create(const vector_type& entries) {
// Performance optimization for the empty case.
@ -87,7 +88,7 @@ class RTC_EXPORT RtpPacketInfos {
return nullptr;
}
return new Data(entries);
return rtc::make_ref_counted<Data>(entries);
}
static rtc::scoped_refptr<Data> Create(vector_type&& entries) {
@ -96,16 +97,16 @@ class RTC_EXPORT RtpPacketInfos {
return nullptr;
}
return new Data(std::move(entries));
return rtc::make_ref_counted<Data>(std::move(entries));
}
const vector_type& entries() const { return entries_; }
private:
explicit Data(const vector_type& entries) : entries_(entries) {}
explicit Data(vector_type&& entries) : entries_(std::move(entries)) {}
~Data() override {}
~Data() = default;
private:
const vector_type entries_;
};

View File

@ -24,13 +24,13 @@
// void some_function() {
// scoped_refptr<MyFoo> foo = new MyFoo();
// foo->Method(param);
// // |foo| is released when this function returns
// // `foo` is released when this function returns
// }
//
// void some_other_function() {
// scoped_refptr<MyFoo> foo = new MyFoo();
// ...
// foo = nullptr; // explicitly releases |foo|
// foo = nullptr; // explicitly releases `foo`
// ...
// if (foo)
// foo->Method(param);
@ -45,10 +45,10 @@
// scoped_refptr<MyFoo> b;
//
// b.swap(a);
// // now, |b| references the MyFoo object, and |a| references null.
// // now, `b` references the MyFoo object, and `a` references null.
// }
//
// To make both |a| and |b| in the above example reference the same MyFoo
// To make both `a` and `b` in the above example reference the same MyFoo
// object, simply use the assignment operator:
//
// {
@ -56,7 +56,7 @@
// scoped_refptr<MyFoo> b;
//
// b = a;
// // now, |a| and |b| each own a reference to the same MyFoo object.
// // now, `a` and `b` each own a reference to the same MyFoo object.
// }
//
@ -74,8 +74,9 @@ class scoped_refptr {
typedef T element_type;
scoped_refptr() : ptr_(nullptr) {}
scoped_refptr(std::nullptr_t) : ptr_(nullptr) {} // NOLINT(runtime/explicit)
scoped_refptr(T* p) : ptr_(p) { // NOLINT(runtime/explicit)
explicit scoped_refptr(T* p) : ptr_(p) {
if (ptr_)
ptr_->AddRef();
}
@ -103,7 +104,8 @@ class scoped_refptr {
}
T* get() const { return ptr_; }
operator T*() const { return ptr_; }
explicit operator bool() const { return ptr_ != nullptr; }
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
// Returns the (possibly null) raw pointer, and makes the scoped_refptr hold a
@ -159,6 +161,62 @@ class scoped_refptr {
T* ptr_;
};
template <typename T, typename U>
bool operator==(const rtc::scoped_refptr<T>& a,
const rtc::scoped_refptr<U>& b) {
return a.get() == b.get();
}
template <typename T, typename U>
bool operator!=(const rtc::scoped_refptr<T>& a,
const rtc::scoped_refptr<U>& b) {
return !(a == b);
}
template <typename T>
bool operator==(const rtc::scoped_refptr<T>& a, std::nullptr_t) {
return a.get() == nullptr;
}
template <typename T>
bool operator!=(const rtc::scoped_refptr<T>& a, std::nullptr_t) {
return !(a == nullptr);
}
template <typename T>
bool operator==(std::nullptr_t, const rtc::scoped_refptr<T>& a) {
return a.get() == nullptr;
}
template <typename T>
bool operator!=(std::nullptr_t, const rtc::scoped_refptr<T>& a) {
return !(a == nullptr);
}
// Comparison with raw pointer.
template <typename T, typename U>
bool operator==(const rtc::scoped_refptr<T>& a, const U* b) {
return a.get() == b;
}
template <typename T, typename U>
bool operator!=(const rtc::scoped_refptr<T>& a, const U* b) {
return !(a == b);
}
template <typename T, typename U>
bool operator==(const T* a, const rtc::scoped_refptr<U>& b) {
return a == b.get();
}
template <typename T, typename U>
bool operator!=(const T* a, const rtc::scoped_refptr<U>& b) {
return !(a == b);
}
// Ordered comparison, needed for use as a std::map key.
template <typename T, typename U>
bool operator<(const rtc::scoped_refptr<T>& a, const rtc::scoped_refptr<U>& b) {
return a.get() < b.get();
}
} // namespace rtc
#endif // API_SCOPED_REFPTR_H_

View File

@ -0,0 +1,140 @@
/*
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef API_SEQUENCE_CHECKER_H_
#define API_SEQUENCE_CHECKER_H_
#include "rtc_base/checks.h"
#include "rtc_base/synchronization/sequence_checker_internal.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
// SequenceChecker is a helper class used to help verify that some methods
// of a class are called on the same task queue or thread. A
// SequenceChecker is bound to a a task queue if the object is
// created on a task queue, or a thread otherwise.
//
//
// Example:
// class MyClass {
// public:
// void Foo() {
// RTC_DCHECK_RUN_ON(&sequence_checker_);
// ... (do stuff) ...
// }
//
// private:
// SequenceChecker sequence_checker_;
// }
//
// In Release mode, IsCurrent will always return true.
class RTC_LOCKABLE SequenceChecker
#if RTC_DCHECK_IS_ON
: public webrtc_sequence_checker_internal::SequenceCheckerImpl {
using Impl = webrtc_sequence_checker_internal::SequenceCheckerImpl;
#else
: public webrtc_sequence_checker_internal::SequenceCheckerDoNothing {
using Impl = webrtc_sequence_checker_internal::SequenceCheckerDoNothing;
#endif
public:
enum InitialState : bool { kDetached = false, kAttached = true };
// TODO(tommi): We could maybe join these two ctors and have fewer factory
// functions. At the moment they're separate to minimize code changes when
// we added the second ctor as well as avoiding to have unnecessary code at
// the SequenceChecker which much only run for the SequenceCheckerImpl
// implementation.
// In theory we could have something like:
//
// SequenceChecker(InitialState initial_state = kAttached,
// TaskQueueBase* attached_queue = TaskQueueBase::Current());
//
// But the problem with that is having the call to `Current()` exist for
// `SequenceCheckerDoNothing`.
explicit SequenceChecker(InitialState initial_state = kAttached)
: Impl(initial_state) {}
explicit SequenceChecker(TaskQueueBase* attached_queue)
: Impl(attached_queue) {}
// Returns true if sequence checker is attached to the current sequence.
bool IsCurrent() const { return Impl::IsCurrent(); }
// Detaches checker from sequence to which it is attached. Next attempt
// to do a check with this checker will result in attaching this checker
// to the sequence on which check was performed.
void Detach() { Impl::Detach(); }
};
} // namespace webrtc
// RTC_RUN_ON/RTC_GUARDED_BY/RTC_DCHECK_RUN_ON macros allows to annotate
// variables are accessed from same thread/task queue.
// Using tools designed to check mutexes, it checks at compile time everywhere
// variable is access, there is a run-time dcheck thread/task queue is correct.
//
// class SequenceCheckerExample {
// public:
// int CalledFromPacer() RTC_RUN_ON(pacer_sequence_checker_) {
// return var2_;
// }
//
// void CallMeFromPacer() {
// RTC_DCHECK_RUN_ON(&pacer_sequence_checker_)
// << "Should be called from pacer";
// CalledFromPacer();
// }
//
// private:
// int pacer_var_ RTC_GUARDED_BY(pacer_sequence_checker_);
// SequenceChecker pacer_sequence_checker_;
// };
//
// class TaskQueueExample {
// public:
// class Encoder {
// public:
// rtc::TaskQueueBase& Queue() { return encoder_queue_; }
// void Encode() {
// RTC_DCHECK_RUN_ON(&encoder_queue_);
// DoSomething(var_);
// }
//
// private:
// rtc::TaskQueueBase& encoder_queue_;
// Frame var_ RTC_GUARDED_BY(encoder_queue_);
// };
//
// void Encode() {
// // Will fail at runtime when DCHECK is enabled:
// // encoder_->Encode();
// // Will work:
// rtc::scoped_refptr<Encoder> encoder = encoder_;
// encoder_->Queue().PostTask([encoder] { encoder->Encode(); });
// }
//
// private:
// rtc::scoped_refptr<Encoder> encoder_;
// }
// Document if a function expected to be called from same thread/task queue.
#define RTC_RUN_ON(x) \
RTC_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(x))
// Checks current code is running on the desired sequence.
//
// First statement validates it is running on the sequence `x`.
// Second statement annotates for the thread safety analyzer the check was done.
// Such annotation has to be attached to a function, and that function has to be
// called. Thus current implementation creates a noop lambda and calls it.
#define RTC_DCHECK_RUN_ON(x) \
RTC_DCHECK((x)->IsCurrent()) \
<< webrtc::webrtc_sequence_checker_internal::ExpectationToString(x); \
[]() RTC_ASSERT_EXCLUSIVE_LOCK(x) {}()
#endif // API_SEQUENCE_CHECKER_H_

View File

@ -11,6 +11,8 @@
#include "absl/base/attributes.h"
#include "absl/base/config.h"
#include "absl/functional/any_invocable.h"
#include "api/units/time_delta.h"
#include "rtc_base/checks.h"
#if defined(ABSL_HAVE_THREAD_LOCAL)

View File

@ -11,8 +11,11 @@
#define API_TASK_QUEUE_TASK_QUEUE_BASE_H_
#include <memory>
#include <utility>
#include "api/task_queue/queued_task.h"
#include "absl/functional/any_invocable.h"
#include "api/location.h"
#include "api/units/time_delta.h"
#include "rtc_base/system/rtc_export.h"
#include "rtc_base/thread_annotations.h"
@ -24,41 +27,139 @@ namespace webrtc {
// known task queue, use IsCurrent().
class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
public:
enum class DelayPrecision {
// This may include up to a 17 ms leeway in addition to OS timer precision.
// See PostDelayedTask() for more information.
kLow,
// This does not have the additional delay that kLow has, but it is still
// limited by OS timer precision. See PostDelayedHighPrecisionTask() for
// more information.
kHigh,
};
// Starts destruction of the task queue.
// On return ensures no task are running and no new tasks are able to start
// on the task queue.
// Responsible for deallocation. Deallocation may happen syncrhoniously during
// Responsible for deallocation. Deallocation may happen synchronously during
// Delete or asynchronously after Delete returns.
// Code not running on the TaskQueue should not make any assumption when
// TaskQueue is deallocated and thus should not call any methods after Delete.
// Code running on the TaskQueue should not call Delete, but can assume
// TaskQueue still exists and may call other methods, e.g. PostTask.
// Should be called on the same task queue or thread that this task queue
// was created on.
virtual void Delete() = 0;
// Schedules a task to execute. Tasks are executed in FIFO order.
// If |task->Run()| returns true, task is deleted on the task queue
// before next QueuedTask starts executing.
// Schedules a `task` to execute. Tasks are executed in FIFO order.
// When a TaskQueue is deleted, pending tasks will not be executed but they
// will be deleted. The deletion of tasks may happen synchronously on the
// TaskQueue or it may happen asynchronously after TaskQueue is deleted.
// This may vary from one implementation to the next so assumptions about
// lifetimes of pending tasks should not be made.
virtual void PostTask(std::unique_ptr<QueuedTask> task) = 0;
// will be deleted.
//
// As long as tasks are not posted from task destruction, posted tasks are
// guaranteed to be destroyed with Current() pointing to the task queue they
// were posted to, whether they're executed or not. That means SequenceChecker
// works during task destruction, a fact that can be used to guarantee
// thread-compatible object deletion happening on a particular task queue
// which can simplify class design.
// Note that this guarantee does not apply to delayed tasks.
//
// May be called on any thread or task queue, including this task queue.
void PostTask(absl::AnyInvocable<void() &&> task,
const Location& location = Location::Current()) {
PostTaskImpl(std::move(task), PostTaskTraits{}, location);
}
// Schedules a task to execute a specified number of milliseconds from when
// the call is made. The precision should be considered as "best effort"
// and in some cases, such as on Windows when all high precision timers have
// been used up, can be off by as much as 15 millseconds.
virtual void PostDelayedTask(std::unique_ptr<QueuedTask> task,
uint32_t milliseconds) = 0;
// Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
// possible.
//
// Schedules a `task` to execute a specified `delay` from when the call is
// made, using "low" precision. All scheduling is affected by OS-specific
// leeway and current workloads which means that in terms of precision there
// are no hard guarantees, but in addition to the OS induced leeway, "low"
// precision adds up to a 17 ms additional leeway. The purpose of this leeway
// is to achieve more efficient CPU scheduling and reduce Idle Wake Up
// frequency.
//
// The task may execute with [-1, 17 + OS induced leeway) ms additional delay.
//
// Avoid making assumptions about the precision of the OS scheduler. On macOS,
// the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
// precision timers may be used but there are cases, such as when running on
// battery, when the timer precision can be as poor as 15 ms.
//
// "Low" precision is not implemented everywhere yet. Where not yet
// implemented, PostDelayedTask() has "high" precision. See
// https://crbug.com/webrtc/13583 for more information.
//
// May be called on any thread or task queue, including this task queue.
void PostDelayedTask(absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
PostDelayedTaskImpl(std::move(task), delay, PostDelayedTaskTraits{},
location);
}
// Prefer PostDelayedTask() over PostDelayedHighPrecisionTask() whenever
// possible.
//
// Schedules a `task` to execute a specified `delay` from when the call is
// made, using "high" precision. All scheduling is affected by OS-specific
// leeway and current workloads which means that in terms of precision there
// are no hard guarantees.
//
// The task may execute with [-1, OS induced leeway] ms additional delay.
//
// Avoid making assumptions about the precision of the OS scheduler. On macOS,
// the OS induced leeway may be 10% of sleep interval. On Windows, 1 ms
// precision timers may be used but there are cases, such as when running on
// battery, when the timer precision can be as poor as 15 ms.
//
// May be called on any thread or task queue, including this task queue.
void PostDelayedHighPrecisionTask(
absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
PostDelayedTaskTraits traits;
traits.high_precision = true;
PostDelayedTaskImpl(std::move(task), delay, traits, location);
}
// As specified by `precision`, calls either PostDelayedTask() or
// PostDelayedHighPrecisionTask().
void PostDelayedTaskWithPrecision(
DelayPrecision precision,
absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const Location& location = Location::Current()) {
switch (precision) {
case DelayPrecision::kLow:
PostDelayedTask(std::move(task), delay, location);
break;
case DelayPrecision::kHigh:
PostDelayedHighPrecisionTask(std::move(task), delay, location);
break;
}
}
// Returns the task queue that is running the current thread.
// Returns nullptr if this thread is not associated with any task queue.
// May be called on any thread or task queue, including this task queue.
static TaskQueueBase* Current();
bool IsCurrent() const { return Current() == this; }
protected:
class CurrentTaskQueueSetter {
// This is currently only present here to simplify introduction of future
// planned task queue changes.
struct PostTaskTraits {};
struct PostDelayedTaskTraits {
// If `high_precision` is false, tasks may execute within up to a 17 ms
// leeway in addition to OS timer precision. Otherwise the task should be
// limited to OS timer precision. See PostDelayedTask() and
// PostDelayedHighPrecisionTask() for more information.
bool high_precision = false;
};
class RTC_EXPORT CurrentTaskQueueSetter {
public:
explicit CurrentTaskQueueSetter(TaskQueueBase* task_queue);
CurrentTaskQueueSetter(const CurrentTaskQueueSetter&) = delete;
@ -69,6 +170,20 @@ class RTC_LOCKABLE RTC_EXPORT TaskQueueBase {
TaskQueueBase* const previous_;
};
// Subclasses should implement this method to support the behavior defined in
// the PostTask and PostTaskTraits docs above.
virtual void PostTaskImpl(absl::AnyInvocable<void() &&> task,
const PostTaskTraits& traits,
const Location& location) = 0;
// Subclasses should implement this method to support the behavior defined in
// the PostDelayedTask/PostHighPrecisionDelayedTask and PostDelayedTaskTraits
// docs above.
virtual void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task,
TimeDelta delay,
const PostDelayedTaskTraits& traits,
const Location& location) = 0;
// Users of the TaskQueue should call Delete instead of directly deleting
// this object.
virtual ~TaskQueueBase() = default;

View File

@ -11,9 +11,9 @@
#ifndef API_UNITS_DATA_RATE_H_
#define API_UNITS_DATA_RATE_H_
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
#include <limits>
#include <string>
@ -23,7 +23,7 @@
#include "api/units/frequency.h"
#include "api/units/time_delta.h"
#include "rtc_base/checks.h"
#include "rtc_base/units/unit_base.h"
#include "rtc_base/units/unit_base.h" // IWYU pragma: export
namespace webrtc {
// DataRate is a class that represents a given data rate. This can be used to
@ -142,13 +142,13 @@ inline std::string ToLogString(DataRate value) {
return ToString(value);
}
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
DataRate value) {
return stream << ToString(value);
}
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
} // namespace webrtc

View File

@ -11,14 +11,14 @@
#ifndef API_UNITS_DATA_SIZE_H_
#define API_UNITS_DATA_SIZE_H_
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
#include <string>
#include <type_traits>
#include "rtc_base/units/unit_base.h"
#include "rtc_base/units/unit_base.h" // IWYU pragma: export
namespace webrtc {
// DataSize is a class represeting a count of bytes.
@ -53,13 +53,13 @@ inline std::string ToLogString(DataSize value) {
return ToString(value);
}
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
DataSize value) {
return stream << ToString(value);
}
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
} // namespace webrtc

View File

@ -10,9 +10,9 @@
#ifndef API_UNITS_FREQUENCY_H_
#define API_UNITS_FREQUENCY_H_
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
#include <cstdlib>
#include <limits>
@ -20,7 +20,7 @@
#include <type_traits>
#include "api/units/time_delta.h"
#include "rtc_base/units/unit_base.h"
#include "rtc_base/units/unit_base.h" // IWYU pragma: export
namespace webrtc {
@ -89,13 +89,13 @@ inline std::string ToLogString(Frequency value) {
return ToString(value);
}
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
Frequency value) {
return stream << ToString(value);
}
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
} // namespace webrtc
#endif // API_UNITS_FREQUENCY_H_

View File

@ -11,15 +11,15 @@
#ifndef API_UNITS_TIME_DELTA_H_
#define API_UNITS_TIME_DELTA_H_
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
#include <cstdlib>
#include <string>
#include <type_traits>
#include "rtc_base/units/unit_base.h"
#include "rtc_base/units/unit_base.h" // IWYU pragma: export
namespace webrtc {
@ -32,6 +32,11 @@ namespace webrtc {
// microseconds (us).
class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
public:
template <typename T>
static constexpr TimeDelta Minutes(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return Seconds(value * 60);
}
template <typename T>
static constexpr TimeDelta Seconds(T value) {
static_assert(std::is_arithmetic<T>::value, "");
@ -92,13 +97,13 @@ inline std::string ToLogString(TimeDelta value) {
return ToString(value);
}
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
TimeDelta value) {
return stream << ToString(value);
}
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
} // namespace webrtc

View File

@ -11,15 +11,16 @@
#ifndef API_UNITS_TIMESTAMP_H_
#define API_UNITS_TIMESTAMP_H_
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
#include <ostream> // no-presubmit-check TODO(webrtc:8982)
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
#include <string>
#include <type_traits>
#include "api/units/time_delta.h"
#include "rtc_base/checks.h"
#include "rtc_base/units/unit_base.h" // IWYU pragma: export
namespace webrtc {
// Timestamp represents the time that has passed since some unspecified epoch.
@ -125,13 +126,13 @@ inline std::string ToLogString(Timestamp value) {
return ToString(value);
}
#ifdef UNIT_TEST
#ifdef WEBRTC_UNIT_TEST
inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
std::ostream& stream, // no-presubmit-check TODO(webrtc:8982)
Timestamp value) {
return stream << ToString(value);
}
#endif // UNIT_TEST
#endif // WEBRTC_UNIT_TEST
} // namespace webrtc

View File

@ -10,9 +10,11 @@
#include "api/video/color_space.h"
#include "rtc_base/strings/string_builder.h"
namespace webrtc {
namespace {
// Try to convert |enum_value| into the enum class T. |enum_bitmask| is created
// Try to convert `enum_value` into the enum class T. `enum_bitmask` is created
// by the funciton below. Returns true if conversion was successful, false
// otherwise.
template <typename T>
@ -43,7 +45,7 @@ constexpr int MakeMask(const int index, const int length, T (&values)[N]) {
}
// Create a bitmask where each bit corresponds to one potential enum value.
// |values| should be an array listing all possible enum values. The bit is set
// `values` should be an array listing all possible enum values. The bit is set
// to one if the corresponding enum exists. Only works for enums with values
// less than 64.
template <typename T, size_t N>
@ -124,6 +126,80 @@ const HdrMetadata* ColorSpace::hdr_metadata() const {
return hdr_metadata_ ? &*hdr_metadata_ : nullptr;
}
#define PRINT_ENUM_CASE(TYPE, NAME) \
case TYPE::NAME: \
ss << #NAME; \
break;
std::string ColorSpace::AsString() const {
char buf[1024];
rtc::SimpleStringBuilder ss(buf);
ss << "{primaries:";
switch (primaries_) {
PRINT_ENUM_CASE(PrimaryID, kBT709)
PRINT_ENUM_CASE(PrimaryID, kUnspecified)
PRINT_ENUM_CASE(PrimaryID, kBT470M)
PRINT_ENUM_CASE(PrimaryID, kBT470BG)
PRINT_ENUM_CASE(PrimaryID, kSMPTE170M)
PRINT_ENUM_CASE(PrimaryID, kSMPTE240M)
PRINT_ENUM_CASE(PrimaryID, kFILM)
PRINT_ENUM_CASE(PrimaryID, kBT2020)
PRINT_ENUM_CASE(PrimaryID, kSMPTEST428)
PRINT_ENUM_CASE(PrimaryID, kSMPTEST431)
PRINT_ENUM_CASE(PrimaryID, kSMPTEST432)
PRINT_ENUM_CASE(PrimaryID, kJEDECP22)
}
ss << ", transfer:";
switch (transfer_) {
PRINT_ENUM_CASE(TransferID, kBT709)
PRINT_ENUM_CASE(TransferID, kUnspecified)
PRINT_ENUM_CASE(TransferID, kGAMMA22)
PRINT_ENUM_CASE(TransferID, kGAMMA28)
PRINT_ENUM_CASE(TransferID, kSMPTE170M)
PRINT_ENUM_CASE(TransferID, kSMPTE240M)
PRINT_ENUM_CASE(TransferID, kLINEAR)
PRINT_ENUM_CASE(TransferID, kLOG)
PRINT_ENUM_CASE(TransferID, kLOG_SQRT)
PRINT_ENUM_CASE(TransferID, kIEC61966_2_4)
PRINT_ENUM_CASE(TransferID, kBT1361_ECG)
PRINT_ENUM_CASE(TransferID, kIEC61966_2_1)
PRINT_ENUM_CASE(TransferID, kBT2020_10)
PRINT_ENUM_CASE(TransferID, kBT2020_12)
PRINT_ENUM_CASE(TransferID, kSMPTEST2084)
PRINT_ENUM_CASE(TransferID, kSMPTEST428)
PRINT_ENUM_CASE(TransferID, kARIB_STD_B67)
}
ss << ", matrix:";
switch (matrix_) {
PRINT_ENUM_CASE(MatrixID, kRGB)
PRINT_ENUM_CASE(MatrixID, kBT709)
PRINT_ENUM_CASE(MatrixID, kUnspecified)
PRINT_ENUM_CASE(MatrixID, kFCC)
PRINT_ENUM_CASE(MatrixID, kBT470BG)
PRINT_ENUM_CASE(MatrixID, kSMPTE170M)
PRINT_ENUM_CASE(MatrixID, kSMPTE240M)
PRINT_ENUM_CASE(MatrixID, kYCOCG)
PRINT_ENUM_CASE(MatrixID, kBT2020_NCL)
PRINT_ENUM_CASE(MatrixID, kBT2020_CL)
PRINT_ENUM_CASE(MatrixID, kSMPTE2085)
PRINT_ENUM_CASE(MatrixID, kCDNCLS)
PRINT_ENUM_CASE(MatrixID, kCDCLS)
PRINT_ENUM_CASE(MatrixID, kBT2100_ICTCP)
}
ss << ", range:";
switch (range_) {
PRINT_ENUM_CASE(RangeID, kInvalid)
PRINT_ENUM_CASE(RangeID, kLimited)
PRINT_ENUM_CASE(RangeID, kFull)
PRINT_ENUM_CASE(RangeID, kDerived)
}
ss << "}";
return ss.str();
}
#undef PRINT_ENUM_CASE
bool ColorSpace::set_primaries_from_uint8(uint8_t enum_value) {
constexpr PrimaryID kPrimaryIds[] = {
PrimaryID::kBT709, PrimaryID::kUnspecified, PrimaryID::kBT470M,

View File

@ -13,6 +13,8 @@
#include <stdint.h>
#include <string>
#include "absl/types/optional.h"
#include "api/video/hdr_metadata.h"
#include "rtc_base/system/rtc_export.h"
@ -101,7 +103,7 @@ class RTC_EXPORT ColorSpace {
kInvalid = 0,
// Limited Rec. 709 color range with RGB values ranging from 16 to 235.
kLimited = 1,
// Full RGB color range with RGB valees from 0 to 255.
// Full RGB color range with RGB values from 0 to 255.
kFull = 2,
// Range is defined by MatrixCoefficients/TransferCharacteristics.
kDerived = 3,
@ -155,6 +157,7 @@ class RTC_EXPORT ColorSpace {
ChromaSiting chroma_siting_horizontal() const;
ChromaSiting chroma_siting_vertical() const;
const HdrMetadata* hdr_metadata() const;
std::string AsString() const;
bool set_primaries_from_uint8(uint8_t enum_value);
bool set_transfer_from_uint8(uint8_t enum_value);

View File

@ -10,21 +10,7 @@
#include "api/video/video_content_type.h"
// VideoContentType stored as a single byte, which is sent over the network.
// Structure:
//
// 0 1 2 3 4 5 6 7
// +---------------+
// |r r e e e s s c|
//
// where:
// r - reserved bits.
// e - 3-bit number of an experiment group counted from 1. 0 means there's no
// experiment ongoing.
// s - 2-bit simulcast stream id or spatial layer, counted from 1. 0 means that
// no simulcast information is set.
// c - content type. 0 means real-time video, 1 means screenshare.
//
#include "rtc_base/checks.h"
namespace webrtc {
namespace videocontenttypehelpers {
@ -33,57 +19,21 @@ namespace {
static constexpr uint8_t kScreenshareBitsSize = 1;
static constexpr uint8_t kScreenshareBitsMask =
(1u << kScreenshareBitsSize) - 1;
static constexpr uint8_t kSimulcastShift = 1;
static constexpr uint8_t kSimulcastBitsSize = 2;
static constexpr uint8_t kSimulcastBitsMask = ((1u << kSimulcastBitsSize) - 1)
<< kSimulcastShift; // 0b00000110
static constexpr uint8_t kExperimentShift = 3;
static constexpr uint8_t kExperimentBitsSize = 3;
static constexpr uint8_t kExperimentBitsMask =
((1u << kExperimentBitsSize) - 1) << kExperimentShift; // 0b00111000
static constexpr uint8_t kTotalBitsSize =
kScreenshareBitsSize + kSimulcastBitsSize + kExperimentBitsSize;
} // namespace
bool SetExperimentId(VideoContentType* content_type, uint8_t experiment_id) {
// Store in bits 2-4.
if (experiment_id >= (1 << kExperimentBitsSize))
return false;
*content_type = static_cast<VideoContentType>(
(static_cast<uint8_t>(*content_type) & ~kExperimentBitsMask) |
((experiment_id << kExperimentShift) & kExperimentBitsMask));
return true;
}
bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id) {
// Store in bits 5-6.
if (simulcast_id >= (1 << kSimulcastBitsSize))
return false;
*content_type = static_cast<VideoContentType>(
(static_cast<uint8_t>(*content_type) & ~kSimulcastBitsMask) |
((simulcast_id << kSimulcastShift) & kSimulcastBitsMask));
return true;
}
uint8_t GetExperimentId(const VideoContentType& content_type) {
return (static_cast<uint8_t>(content_type) & kExperimentBitsMask) >>
kExperimentShift;
}
uint8_t GetSimulcastId(const VideoContentType& content_type) {
return (static_cast<uint8_t>(content_type) & kSimulcastBitsMask) >>
kSimulcastShift;
}
bool IsScreenshare(const VideoContentType& content_type) {
// Ensure no bits apart from the screenshare bit is set.
// This CHECK is a temporary measure to detect code that introduces
// values according to old versions.
RTC_CHECK((static_cast<uint8_t>(content_type) & !kScreenshareBitsMask) == 0);
return (static_cast<uint8_t>(content_type) & kScreenshareBitsMask) > 0;
}
bool IsValidContentType(uint8_t value) {
// Any 6-bit value is allowed.
return value < (1 << kTotalBitsSize);
// Only the screenshare bit is allowed.
// However, due to previous usage of the next 5 bits, we allow
// the lower 6 bits to be set.
return value < (1 << 6);
}
const char* ToString(const VideoContentType& content_type) {

View File

@ -15,18 +15,15 @@
namespace webrtc {
// VideoContentType stored as a single byte, which is sent over the network
// in the rtp-hdrext/video-content-type extension.
// Only the lowest bit is used, per the enum.
enum class VideoContentType : uint8_t {
UNSPECIFIED = 0,
SCREENSHARE = 1,
};
namespace videocontenttypehelpers {
bool SetExperimentId(VideoContentType* content_type, uint8_t experiment_id);
bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id);
uint8_t GetExperimentId(const VideoContentType& content_type);
uint8_t GetSimulcastId(const VideoContentType& content_type);
bool IsScreenshare(const VideoContentType& content_type);
bool IsValidContentType(uint8_t value);

View File

@ -10,7 +10,10 @@
#include "api/video/video_timing.h"
#include <algorithm>
#include "api/array_view.h"
#include "api/units/time_delta.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/strings/string_builder.h"
@ -25,6 +28,14 @@ uint16_t VideoSendTiming::GetDeltaCappedMs(int64_t base_ms, int64_t time_ms) {
return rtc::saturated_cast<uint16_t>(time_ms - base_ms);
}
uint16_t VideoSendTiming::GetDeltaCappedMs(TimeDelta delta) {
if (delta < TimeDelta::Zero()) {
RTC_DLOG(LS_ERROR) << "Delta " << delta.ms()
<< "ms expected to be positive";
}
return rtc::saturated_cast<uint16_t>(delta.ms());
}
TimingFrameInfo::TimingFrameInfo()
: rtp_timestamp(0),
capture_time_ms(-1),
@ -89,4 +100,23 @@ std::string TimingFrameInfo::ToString() const {
return sb.str();
}
VideoPlayoutDelay::VideoPlayoutDelay(TimeDelta min, TimeDelta max)
: min_(std::clamp(min, TimeDelta::Zero(), kMax)),
max_(std::clamp(max, min_, kMax)) {
if (!(TimeDelta::Zero() <= min && min <= max && max <= kMax)) {
RTC_LOG(LS_ERROR) << "Invalid video playout delay: [" << min << "," << max
<< "]. Clamped to [" << this->min() << "," << this->max()
<< "]";
}
}
bool VideoPlayoutDelay::Set(TimeDelta min, TimeDelta max) {
if (TimeDelta::Zero() <= min && min <= max && max <= kMax) {
min_ = min;
max_ = max;
return true;
}
return false;
}
} // namespace webrtc

View File

@ -16,11 +16,14 @@
#include <limits>
#include <string>
#include "api/units/time_delta.h"
#include "rtc_base/system/rtc_export.h"
namespace webrtc {
// Video timing timestamps in ms counted from capture_time_ms of a frame.
// This structure represents data sent in video-timing RTP header extension.
struct VideoSendTiming {
struct RTC_EXPORT VideoSendTiming {
enum TimingFrameFlags : uint8_t {
kNotTriggered = 0, // Timing info valid, but not to be transmitted.
// Used on send-side only.
@ -34,6 +37,7 @@ struct VideoSendTiming {
// https://webrtc.org/experiments/rtp-hdrext/video-timing/ extension stores
// 16-bit deltas of timestamps from packet capture time.
static uint16_t GetDeltaCappedMs(int64_t base_ms, int64_t time_ms);
static uint16_t GetDeltaCappedMs(TimeDelta delta);
uint16_t encode_start_delta_ms;
uint16_t encode_finish_delta_ms;
@ -41,21 +45,21 @@ struct VideoSendTiming {
uint16_t pacer_exit_delta_ms;
uint16_t network_timestamp_delta_ms;
uint16_t network2_timestamp_delta_ms;
uint8_t flags;
uint8_t flags = TimingFrameFlags::kInvalid;
};
// Used to report precise timings of a 'timing frames'. Contains all important
// timestamps for a lifetime of that specific frame. Reported as a string via
// GetStats(). Only frame which took the longest between two GetStats calls is
// reported.
struct TimingFrameInfo {
struct RTC_EXPORT TimingFrameInfo {
TimingFrameInfo();
// Returns end-to-end delay of a frame, if sender and receiver timestamps are
// synchronized, -1 otherwise.
int64_t EndToEndDelay() const;
// Returns true if current frame took longer to process than |other| frame.
// Returns true if current frame took longer to process than `other` frame.
// If other frame's clocks are not synchronized, current frame is always
// preferred.
bool IsLongerThan(const TimingFrameInfo& other) const;
@ -103,26 +107,43 @@ struct TimingFrameInfo {
// Minimum and maximum playout delay values from capture to render.
// These are best effort values.
//
// A value < 0 indicates no change from previous valid value.
//
// min = max = 0 indicates that the receiver should try and render
// frame as soon as possible.
//
// min = x, max = y indicates that the receiver is free to adapt
// in the range (x, y) based on network jitter.
struct VideoPlayoutDelay {
VideoPlayoutDelay() = default;
VideoPlayoutDelay(int min_ms, int max_ms) : min_ms(min_ms), max_ms(max_ms) {}
int min_ms = -1;
int max_ms = -1;
// This class ensures invariant 0 <= min <= max <= kMax.
class RTC_EXPORT VideoPlayoutDelay {
public:
// Maximum supported value for the delay limit.
static constexpr TimeDelta kMax = TimeDelta::Millis(10) * 0xFFF;
bool operator==(const VideoPlayoutDelay& rhs) const {
return min_ms == rhs.min_ms && max_ms == rhs.max_ms;
// Creates delay limits that indicates receiver should try to render frame
// as soon as possible.
static VideoPlayoutDelay Minimal() {
return VideoPlayoutDelay(TimeDelta::Zero(), TimeDelta::Zero());
}
};
// TODO(bugs.webrtc.org/7660): Old name, delete after downstream use is updated.
using PlayoutDelay = VideoPlayoutDelay;
// Creates valid, but unspecified limits.
VideoPlayoutDelay() = default;
VideoPlayoutDelay(const VideoPlayoutDelay&) = default;
VideoPlayoutDelay& operator=(const VideoPlayoutDelay&) = default;
VideoPlayoutDelay(TimeDelta min, TimeDelta max);
bool Set(TimeDelta min, TimeDelta max);
TimeDelta min() const { return min_; }
TimeDelta max() const { return max_; }
friend bool operator==(const VideoPlayoutDelay& lhs,
const VideoPlayoutDelay& rhs) {
return lhs.min_ == rhs.min_ && lhs.max_ == rhs.max_;
}
private:
TimeDelta min_ = TimeDelta::Zero();
TimeDelta max_ = kMax;
};
} // namespace webrtc