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}
diff --git a/api/audio_codecs/BUILD.gn b/api/audio_codecs/BUILD.gn
index f730260..fb033f2 100644
--- a/api/audio_codecs/BUILD.gn
+++ b/api/audio_codecs/BUILD.gn
@@ -15,12 +15,16 @@
 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",
diff --git a/api/audio_codecs/audio_codec_pair_id.cc b/api/audio_codecs/audio_codec_pair_id.cc
new file mode 100644
index 0000000..ac84107
--- /dev/null
+++ b/api/audio_codecs/audio_codec_pair_id.cc
@@ -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
diff --git a/api/audio_codecs/audio_codec_pair_id.h b/api/audio_codecs/audio_codec_pair_id.h
new file mode 100644
index 0000000..b10f14e
--- /dev/null
+++ b/api/audio_codecs/audio_codec_pair_id.h
@@ -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_
diff --git a/api/audio_codecs/audio_decoder_factory.cc b/api/audio_codecs/audio_decoder_factory.cc
new file mode 100644
index 0000000..08dbe78
--- /dev/null
+++ b/api/audio_codecs/audio_decoder_factory.cc
@@ -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
diff --git a/api/audio_codecs/audio_decoder_factory.h b/api/audio_codecs/audio_decoder_factory.h
index ac0f451..9954f31 100644
--- a/api/audio_codecs/audio_decoder_factory.h
+++ b/api/audio_codecs/audio_decoder_factory.h
@@ -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 @@
 
   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
diff --git a/api/audio_codecs/audio_encoder_factory.cc b/api/audio_codecs/audio_encoder_factory.cc
new file mode 100644
index 0000000..b5c7110
--- /dev/null
+++ b/api/audio_codecs/audio_encoder_factory.cc
@@ -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
diff --git a/api/audio_codecs/audio_encoder_factory.h b/api/audio_codecs/audio_encoder_factory.h
index 43461f6..02bdfd9 100644
--- a/api/audio_codecs/audio_encoder_factory.h
+++ b/api/audio_codecs/audio_encoder_factory.h
@@ -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 @@
   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