Audio codec factories: Pass a codec pair ID to new codecs

Currently ignored by all implementations and callers, but future CLs
will remedy that.

Bug: webrtc:8941
Change-Id: I59a3af78fefcf35af3e5ef37d2adf1165ce5751e
Reviewed-on: https://webrtc-review.googlesource.com/58080
Reviewed-by: Oskar Sundbom <ossu@webrtc.org>
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22248}
This commit is contained in:
Karl Wiberg 2018-03-01 12:03:49 +01:00 committed by Commit Bot
parent f4e99dba41
commit 98900740ad
7 changed files with 259 additions and 4 deletions

View File

@ -15,12 +15,16 @@ if (is_android) {
rtc_source_set("audio_codecs_api") {
visibility = [ "*" ]
sources = [
"audio_codec_pair_id.cc",
"audio_codec_pair_id.h",
"audio_decoder.cc",
"audio_decoder.h",
"audio_decoder_factory.cc",
"audio_decoder_factory.h",
"audio_decoder_factory_template.h",
"audio_encoder.cc",
"audio_encoder.h",
"audio_encoder_factory.cc",
"audio_encoder_factory.h",
"audio_encoder_factory_template.h",
"audio_format.cc",

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2018 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.
*/
#include "api/audio_codecs/audio_codec_pair_id.h"
#include <atomic>
#include "rtc_base/checks.h"
namespace webrtc {
namespace {
// Returns a new value that it has never returned before. You may call it at
// most 2^63 times in the lifetime of the program. Note: The returned values
// may be easily predictable.
uint64_t GetNextId() {
static std::atomic<uint64_t> next_id(0);
// Atomically increment `next_id`, and return the previous value. Relaxed
// memory order is sufficient, since all we care about is that different
// callers return different values.
const uint64_t new_id = next_id.fetch_add(1, std::memory_order_relaxed);
// This check isn't atomic with the increment, so if we start 2^63 + 1
// invocations of GetNextId() in parallel, the last one to do the atomic
// increment could return the ID 0 before any of the others had time to
// trigger this DCHECK. We blithely assume that this won't happen.
RTC_DCHECK_LT(new_id, uint64_t{1} << 63) << "Used up all ID values";
return new_id;
}
// Make an integer ID more unpredictable. This is a 1:1 mapping, so you can
// feed it any value, but the idea is that you can feed it a sequence such as
// 0, 1, 2, ... and get a new sequence that isn't as trivially predictable, so
// that users won't rely on it being consecutive or increasing or anything like
// that.
constexpr uint64_t ObfuscateId(uint64_t id) {
// Any nonzero coefficient that's relatively prime to 2^64 (that is, any odd
// number) and any constant will give a 1:1 mapping. These high-entropy
// values will prevent the sequence from being trivially predictable.
//
// Both the multiplication and the addition going to overflow almost always,
// but that's fine---we *want* arithmetic mod 2^64.
return uint64_t{0x85fdb20e1294309a} + uint64_t{0xc516ef5c37462469} * id;
}
// The first ten values. Verified against the Python function
//
// def f(n):
// return (0x85fdb20e1294309a + 0xc516ef5c37462469 * n) % 2**64
//
// Callers should obviously not depend on these exact values...
//
// (On Visual C++, we have to disable warning C4307 (integral constant
// overflow), even though unsigned integers have perfectly well-defined
// overflow behavior.)
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4307)
#endif
static_assert(ObfuscateId(0) == uint64_t{0x85fdb20e1294309a}, "");
static_assert(ObfuscateId(1) == uint64_t{0x4b14a16a49da5503}, "");
static_assert(ObfuscateId(2) == uint64_t{0x102b90c68120796c}, "");
static_assert(ObfuscateId(3) == uint64_t{0xd5428022b8669dd5}, "");
static_assert(ObfuscateId(4) == uint64_t{0x9a596f7eefacc23e}, "");
static_assert(ObfuscateId(5) == uint64_t{0x5f705edb26f2e6a7}, "");
static_assert(ObfuscateId(6) == uint64_t{0x24874e375e390b10}, "");
static_assert(ObfuscateId(7) == uint64_t{0xe99e3d93957f2f79}, "");
static_assert(ObfuscateId(8) == uint64_t{0xaeb52cefccc553e2}, "");
static_assert(ObfuscateId(9) == uint64_t{0x73cc1c4c040b784b}, "");
#ifdef _MSC_VER
#pragma warning(pop)
#endif
} // namespace
AudioCodecPairId AudioCodecPairId::Create() {
return AudioCodecPairId(ObfuscateId(GetNextId()));
}
} // namespace webrtc

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2018 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_AUDIO_CODECS_AUDIO_CODEC_PAIR_ID_H_
#define API_AUDIO_CODECS_AUDIO_CODEC_PAIR_ID_H_
#include <stdint.h>
#include <utility>
namespace webrtc {
class AudioCodecPairId final {
public:
// Copyable, but not default constructible.
AudioCodecPairId() = delete;
AudioCodecPairId(const AudioCodecPairId&) = default;
AudioCodecPairId(AudioCodecPairId&&) = default;
AudioCodecPairId& operator=(const AudioCodecPairId&) = default;
AudioCodecPairId& operator=(AudioCodecPairId&&) = default;
friend void swap(AudioCodecPairId& a, AudioCodecPairId& b) {
using std::swap;
swap(a.id_, b.id_);
}
// Creates a new ID, unequal to any previously created ID.
static AudioCodecPairId Create();
// IDs can be tested for equality.
friend bool operator==(AudioCodecPairId a, AudioCodecPairId b) {
return a.id_ == b.id_;
}
friend bool operator!=(AudioCodecPairId a, AudioCodecPairId b) {
return a.id_ != b.id_;
}
// Comparisons. The ordering of ID values is completely arbitrary, but
// stable, so it's useful e.g. if you want to use IDs as keys in an ordered
// map.
friend bool operator<(AudioCodecPairId a, AudioCodecPairId b) {
return a.id_ < b.id_;
}
friend bool operator<=(AudioCodecPairId a, AudioCodecPairId b) {
return a.id_ <= b.id_;
}
friend bool operator>=(AudioCodecPairId a, AudioCodecPairId b) {
return a.id_ >= b.id_;
}
friend bool operator>(AudioCodecPairId a, AudioCodecPairId b) {
return a.id_ > b.id_;
}
// Returns a numeric representation of the ID. The numeric values are
// completely arbitrary, but stable, collision-free, and reasonably evenly
// distributed, so they are e.g. useful as hash values in unordered maps.
uint64_t NumericRepresentation() const { return id_; }
private:
explicit AudioCodecPairId(uint64_t id) : id_(id) {}
uint64_t id_;
};
} // namespace webrtc
#endif // API_AUDIO_CODECS_AUDIO_CODEC_PAIR_ID_H_

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018 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.
*/
#include "api/audio_codecs/audio_decoder_factory.h"
namespace webrtc {
std::unique_ptr<AudioDecoder> AudioDecoderFactory::MakeAudioDecoder(
const SdpAudioFormat& format,
rtc::Optional<AudioCodecPairId> codec_pair_id) {
return MakeAudioDecoder(format);
}
std::unique_ptr<AudioDecoder> AudioDecoderFactory::MakeAudioDecoder(
const SdpAudioFormat& format) {
return MakeAudioDecoder(format, rtc::nullopt);
}
} // namespace webrtc

View File

@ -14,8 +14,10 @@
#include <memory>
#include <vector>
#include "api/audio_codecs/audio_codec_pair_id.h"
#include "api/audio_codecs/audio_decoder.h"
#include "api/audio_codecs/audio_format.h"
#include "api/optional.h"
#include "rtc_base/refcount.h"
namespace webrtc {
@ -28,8 +30,22 @@ class AudioDecoderFactory : public rtc::RefCountInterface {
virtual bool IsSupportedDecoder(const SdpAudioFormat& format) = 0;
// Create a new decoder instance. The `codec_pair_id` argument is used to
// link encoders and decoders that talk to the same remote entity; if a
// MakeAudioEncoder() and a MakeAudioDecoder() call receive non-null IDs that
// compare equal, the factory implementations may assume that the encoder and
// decoder form a pair.
//
// Note: Implementations need to be robust against combinations other than
// one encoder, one decoder getting the same ID; such decoders must still
// work.
virtual std::unique_ptr<AudioDecoder> MakeAudioDecoder(
const SdpAudioFormat& format) = 0;
const SdpAudioFormat& format,
rtc::Optional<AudioCodecPairId> codec_pair_id);
// Deprecated version of the above.
virtual std::unique_ptr<AudioDecoder> MakeAudioDecoder(
const SdpAudioFormat& format);
};
} // namespace webrtc

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2018 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.
*/
#include "api/audio_codecs/audio_encoder_factory.h"
namespace webrtc {
std::unique_ptr<AudioEncoder> AudioEncoderFactory::MakeAudioEncoder(
int payload_type,
const SdpAudioFormat& format,
rtc::Optional<AudioCodecPairId> codec_pair_id) {
return MakeAudioEncoder(payload_type, format);
}
std::unique_ptr<AudioEncoder> AudioEncoderFactory::MakeAudioEncoder(
int payload_type,
const SdpAudioFormat& format) {
return MakeAudioEncoder(payload_type, format, rtc::nullopt);
}
} // namespace webrtc

View File

@ -14,8 +14,10 @@
#include <memory>
#include <vector>
#include "api/audio_codecs/audio_codec_pair_id.h"
#include "api/audio_codecs/audio_encoder.h"
#include "api/audio_codecs/audio_format.h"
#include "api/optional.h"
#include "rtc_base/refcount.h"
namespace webrtc {
@ -33,12 +35,27 @@ class AudioEncoderFactory : public rtc::RefCountInterface {
virtual rtc::Optional<AudioCodecInfo> QueryAudioEncoder(
const SdpAudioFormat& format) = 0;
// Creates an AudioEncoder for the specified format. The encoder will tags its
// payloads with the specified payload type.
// Creates an AudioEncoder for the specified format. The encoder will tags
// its payloads with the specified payload type. The `codec_pair_id` argument
// is used to link encoders and decoders that talk to the same remote entity;
// if a MakeAudioEncoder() and a MakeAudioDecoder() call receive non-null IDs
// that compare equal, the factory implementations may assume that the
// encoder and decoder form a pair.
//
// Note: Implementations need to be robust against combinations other than
// one encoder, one decoder getting the same ID; such encoders must still
// work.
//
// TODO(ossu): Try to avoid audio encoders having to know their payload type.
virtual std::unique_ptr<AudioEncoder> MakeAudioEncoder(
int payload_type,
const SdpAudioFormat& format) = 0;
const SdpAudioFormat& format,
rtc::Optional<AudioCodecPairId> codec_pair_id);
// Deprecated version of the above.
virtual std::unique_ptr<AudioEncoder> MakeAudioEncoder(
int payload_type,
const SdpAudioFormat& format);
};
} // namespace webrtc