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:
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 "";
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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().
|
||||
|
@ -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
31
webrtc/api/location.h
Normal 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_
|
120
webrtc/api/make_ref_counted.h
Normal file
120
webrtc/api/make_ref_counted.h
Normal 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_
|
@ -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
|
||||
|
@ -44,7 +44,6 @@ RTPHeader::RTPHeader()
|
||||
arrOfCSRCs(),
|
||||
paddingLength(0),
|
||||
headerLength(0),
|
||||
payload_type_frequency(0),
|
||||
extension() {}
|
||||
|
||||
RTPHeader::RTPHeader(const RTPHeader& other) = default;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
@ -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_
|
||||
|
140
webrtc/api/sequence_checker.h
Normal file
140
webrtc/api/sequence_checker.h
Normal 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_
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user