Transform encoded frames in ChannelSend.

This change is part of the implementation of the Insertable Streams Web
API: https://github.com/alvestrand/webrtc-media-streams/blob/master/explainer.md

Design doc for WebRTC library changes:
http://doc/1eiLkjNUkRy2FssCPLUp6eH08BZuXXoHfbbBP1ZN7EVk

Bug: webrtc:11380
Change-Id: I75444283ddb7f8db742687b497bf532c6dda47be
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/171871
Commit-Queue: Marina Ciocea <marinaciocea@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30952}
diff --git a/audio/BUILD.gn b/audio/BUILD.gn
index 7da3c79..cc52664 100644
--- a/audio/BUILD.gn
+++ b/audio/BUILD.gn
@@ -28,6 +28,8 @@
     "channel_receive.h",
     "channel_send.cc",
     "channel_send.h",
+    "channel_send_frame_transformer_delegate.cc",
+    "channel_send_frame_transformer_delegate.h",
     "conversion.h",
     "null_audio_poller.cc",
     "null_audio_poller.h",
diff --git a/audio/channel_send.cc b/audio/channel_send.cc
index d8ac39c..21f36aa 100644
--- a/audio/channel_send.cc
+++ b/audio/channel_send.cc
@@ -21,6 +21,7 @@
 #include "api/call/transport.h"
 #include "api/crypto/frame_encryptor_interface.h"
 #include "api/rtc_event_log/rtc_event_log.h"
+#include "audio/channel_send_frame_transformer_delegate.h"
 #include "audio/utility/audio_frame_operations.h"
 #include "call/rtp_transport_controller_send_interface.h"
 #include "logging/rtc_event_log/events/rtc_event_audio_playout.h"
@@ -170,6 +171,9 @@
 
   void OnReceivedRtt(int64_t rtt_ms);
 
+  void InitFrameTransformerDelegate(
+      rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer);
+
   // Thread checkers document and lock usage of some methods on voe::Channel to
   // specific threads we know about. The goal is to eventually split up
   // voe::Channel into parts with single-threaded semantics, and thereby reduce
@@ -224,9 +228,11 @@
   // E2EE Frame Encryption Options
   const webrtc::CryptoOptions crypto_options_;
 
-  // Frame transformer used by insertable streams to transform encoded frames.
-  rtc::scoped_refptr<FrameTransformerInterface> frame_transformer_
-      RTC_GUARDED_BY(encoder_queue_);
+  // Delegates calls to a frame transformer to transform audio, and
+  // receives callbacks with the transformed frames; delegates calls to
+  // ChannelSend::SendRtpAudio to send the transformed audio.
+  rtc::scoped_refptr<ChannelSendFrameTransformerDelegate>
+      frame_transformer_delegate_ RTC_GUARDED_BY(encoder_queue_);
 
   rtc::CriticalSection bitrate_crit_section_;
   int configured_bitrate_bps_ RTC_GUARDED_BY(bitrate_crit_section_) = 0;
@@ -379,6 +385,14 @@
                               int64_t absolute_capture_timestamp_ms) {
   RTC_DCHECK_RUN_ON(&encoder_queue_);
   rtc::ArrayView<const uint8_t> payload(payloadData, payloadSize);
+  if (frame_transformer_delegate_) {
+    // Asynchronously transform the payload before sending it. After the payload
+    // is transformed, the delegate will call SendRtpAudio to send it.
+    frame_transformer_delegate_->Transform(
+        frameType, payloadType, rtp_timestamp, payloadData, payloadSize,
+        absolute_capture_timestamp_ms, _rtpRtcpModule->SSRC());
+    return 0;
+  }
   return SendRtpAudio(frameType, payloadType, rtp_timestamp, payload,
                       absolute_capture_timestamp_ms);
 }
@@ -491,7 +505,6 @@
           new RateLimiter(clock, kMaxRetransmissionWindowMs)),
       frame_encryptor_(frame_encryptor),
       crypto_options_(crypto_options),
-      frame_transformer_(std::move(frame_transformer)),
       encoder_queue_(task_queue_factory->CreateTaskQueue(
           "AudioEncoder",
           TaskQueueFactory::Priority::NORMAL)) {
@@ -532,11 +545,17 @@
 
   int error = audio_coding_->RegisterTransportCallback(this);
   RTC_DCHECK_EQ(0, error);
+  if (frame_transformer)
+    InitFrameTransformerDelegate(std::move(frame_transformer));
 }
 
 ChannelSend::~ChannelSend() {
   RTC_DCHECK(construction_thread_.IsCurrent());
 
+  // Resets the delegate's callback to ChannelSend::SendRtpAudio.
+  if (frame_transformer_delegate_)
+    frame_transformer_delegate_->Reset();
+
   StopSend();
   int error = audio_coding_->RegisterTransportCallback(NULL);
   RTC_DCHECK_EQ(0, error);
@@ -915,10 +934,13 @@
 void ChannelSend::SetEncoderToPacketizerFrameTransformer(
     rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer) {
   RTC_DCHECK_RUN_ON(&worker_thread_checker_);
+  if (!frame_transformer)
+    return;
+
   encoder_queue_.PostTask(
       [this, frame_transformer = std::move(frame_transformer)]() mutable {
         RTC_DCHECK_RUN_ON(&encoder_queue_);
-        frame_transformer_ = std::move(frame_transformer);
+        InitFrameTransformerDelegate(std::move(frame_transformer));
       });
 }
 
@@ -928,6 +950,29 @@
       [rtt_ms](AudioEncoder* encoder) { encoder->OnReceivedRtt(rtt_ms); });
 }
 
+void ChannelSend::InitFrameTransformerDelegate(
+    rtc::scoped_refptr<webrtc::FrameTransformerInterface> frame_transformer) {
+  RTC_DCHECK_RUN_ON(&encoder_queue_);
+  RTC_DCHECK(frame_transformer);
+  RTC_DCHECK(!frame_transformer_delegate_);
+
+  // Pass a callback to ChannelSend::SendRtpAudio, to be called by the delegate
+  // to send the transformed audio.
+  ChannelSendFrameTransformerDelegate::SendFrameCallback send_audio_callback =
+      [this](AudioFrameType frameType, uint8_t payloadType,
+             uint32_t rtp_timestamp, rtc::ArrayView<const uint8_t> payload,
+             int64_t absolute_capture_timestamp_ms) {
+        RTC_DCHECK_RUN_ON(&encoder_queue_);
+        return SendRtpAudio(frameType, payloadType, rtp_timestamp, payload,
+                            absolute_capture_timestamp_ms);
+      };
+  frame_transformer_delegate_ =
+      new rtc::RefCountedObject<ChannelSendFrameTransformerDelegate>(
+          std::move(send_audio_callback), std::move(frame_transformer),
+          &encoder_queue_);
+  frame_transformer_delegate_->Init();
+}
+
 }  // namespace
 
 std::unique_ptr<ChannelSendInterface> CreateChannelSend(
diff --git a/audio/channel_send_frame_transformer_delegate.cc b/audio/channel_send_frame_transformer_delegate.cc
new file mode 100644
index 0000000..53df6b0
--- /dev/null
+++ b/audio/channel_send_frame_transformer_delegate.cc
@@ -0,0 +1,116 @@
+/*
+ *  Copyright (c) 2020 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 "audio/channel_send_frame_transformer_delegate.h"
+
+#include <utility>
+
+namespace webrtc {
+namespace {
+
+class TransformableAudioFrame : public TransformableFrameInterface {
+ public:
+  TransformableAudioFrame(AudioFrameType frame_type,
+                          uint8_t payload_type,
+                          uint32_t rtp_timestamp,
+                          const uint8_t* payload_data,
+                          size_t payload_size,
+                          int64_t absolute_capture_timestamp_ms,
+                          uint32_t ssrc)
+      : frame_type_(frame_type),
+        payload_type_(payload_type),
+        rtp_timestamp_(rtp_timestamp),
+        payload_(payload_data, payload_size),
+        absolute_capture_timestamp_ms_(absolute_capture_timestamp_ms),
+        ssrc_(ssrc) {}
+  ~TransformableAudioFrame() override = default;
+  rtc::ArrayView<const uint8_t> GetData() const override { return payload_; }
+  void SetData(rtc::ArrayView<const uint8_t> data) override {
+    payload_.SetData(data.data(), data.size());
+  }
+  uint32_t GetTimestamp() const override { return rtp_timestamp_; }
+  uint32_t GetSsrc() const override { return ssrc_; }
+
+  AudioFrameType GetFrameType() const { return frame_type_; }
+  uint8_t GetPayloadType() const { return payload_type_; }
+  int64_t GetAbsoluteCaptureTimestampMs() const {
+    return absolute_capture_timestamp_ms_;
+  }
+
+ private:
+  AudioFrameType frame_type_;
+  uint8_t payload_type_;
+  uint32_t rtp_timestamp_;
+  rtc::Buffer payload_;
+  int64_t absolute_capture_timestamp_ms_;
+  uint32_t ssrc_;
+};
+}  // namespace
+
+ChannelSendFrameTransformerDelegate::ChannelSendFrameTransformerDelegate(
+    SendFrameCallback send_frame_callback,
+    rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
+    rtc::TaskQueue* encoder_queue)
+    : send_frame_callback_(send_frame_callback),
+      frame_transformer_(std::move(frame_transformer)),
+      encoder_queue_(encoder_queue) {}
+
+void ChannelSendFrameTransformerDelegate::Init() {
+  frame_transformer_->RegisterTransformedFrameCallback(
+      rtc::scoped_refptr<TransformedFrameCallback>(this));
+}
+
+void ChannelSendFrameTransformerDelegate::Reset() {
+  frame_transformer_->UnregisterTransformedFrameCallback();
+  frame_transformer_ = nullptr;
+
+  rtc::CritScope lock(&send_lock_);
+  send_frame_callback_ = SendFrameCallback();
+}
+
+void ChannelSendFrameTransformerDelegate::Transform(
+    AudioFrameType frame_type,
+    uint8_t payload_type,
+    uint32_t rtp_timestamp,
+    const uint8_t* payload_data,
+    size_t payload_size,
+    int64_t absolute_capture_timestamp_ms,
+    uint32_t ssrc) {
+  frame_transformer_->Transform(std::make_unique<TransformableAudioFrame>(
+      frame_type, payload_type, rtp_timestamp, payload_data, payload_size,
+      absolute_capture_timestamp_ms, ssrc));
+}
+
+void ChannelSendFrameTransformerDelegate::OnTransformedFrame(
+    std::unique_ptr<TransformableFrameInterface> frame) {
+  rtc::CritScope lock(&send_lock_);
+  if (!send_frame_callback_)
+    return;
+  rtc::scoped_refptr<ChannelSendFrameTransformerDelegate> delegate = this;
+  encoder_queue_->PostTask(
+      [delegate = std::move(delegate), frame = std::move(frame)]() mutable {
+        delegate->SendFrame(std::move(frame));
+      });
+}
+
+void ChannelSendFrameTransformerDelegate::SendFrame(
+    std::unique_ptr<TransformableFrameInterface> frame) const {
+  rtc::CritScope lock(&send_lock_);
+  RTC_DCHECK_RUN_ON(encoder_queue_);
+  if (!send_frame_callback_)
+    return;
+  auto* transformed_frame = static_cast<TransformableAudioFrame*>(frame.get());
+  send_frame_callback_(
+      transformed_frame->GetFrameType(), transformed_frame->GetPayloadType(),
+      transformed_frame->GetTimestamp(), transformed_frame->GetData(),
+      transformed_frame->GetAbsoluteCaptureTimestampMs());
+}
+
+}  // namespace webrtc
diff --git a/audio/channel_send_frame_transformer_delegate.h b/audio/channel_send_frame_transformer_delegate.h
new file mode 100644
index 0000000..f2655e7
--- /dev/null
+++ b/audio/channel_send_frame_transformer_delegate.h
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (c) 2020 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 AUDIO_CHANNEL_SEND_FRAME_TRANSFORMER_DELEGATE_H_
+#define AUDIO_CHANNEL_SEND_FRAME_TRANSFORMER_DELEGATE_H_
+
+#include <memory>
+
+#include "api/frame_transformer_interface.h"
+#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
+#include "rtc_base/buffer.h"
+#include "rtc_base/critical_section.h"
+#include "rtc_base/synchronization/sequence_checker.h"
+#include "rtc_base/task_queue.h"
+
+namespace webrtc {
+
+// Delegates calls to FrameTransformerInterface to transform frames, and to
+// ChannelSend to send the transformed frames using |send_frame_callback_| on
+// the |encoder_queue_|.
+// OnTransformedFrame() can be called from any thread, the delegate ensures
+// thread-safe access to the ChannelSend callback.
+class ChannelSendFrameTransformerDelegate : public TransformedFrameCallback {
+ public:
+  using SendFrameCallback =
+      std::function<int32_t(AudioFrameType frameType,
+                            uint8_t payloadType,
+                            uint32_t rtp_timestamp,
+                            rtc::ArrayView<const uint8_t> payload,
+                            int64_t absolute_capture_timestamp_ms)>;
+  ChannelSendFrameTransformerDelegate(
+      SendFrameCallback send_frame_callback,
+      rtc::scoped_refptr<FrameTransformerInterface> frame_transformer,
+      rtc::TaskQueue* encoder_queue);
+
+  // Registers |this| as callback for |frame_transformer_|, to get the
+  // transformed frames.
+  void Init();
+
+  // Unregisters and releases the |frame_transformer_| reference, and resets
+  // |send_frame_callback_| under lock. Called from ChannelSend destructor to
+  // prevent running the callback on a dangling channel.
+  void Reset();
+
+  // Delegates the call to FrameTransformerInterface::TransformFrame, to
+  // transform the frame asynchronously.
+  void Transform(AudioFrameType frame_type,
+                 uint8_t payload_type,
+                 uint32_t rtp_timestamp,
+                 const uint8_t* payload_data,
+                 size_t payload_size,
+                 int64_t absolute_capture_timestamp_ms,
+                 uint32_t ssrc);
+
+  // Implements TransformedFrameCallback. Can be called on any thread.
+  void OnTransformedFrame(
+      std::unique_ptr<TransformableFrameInterface> frame) override;
+
+  // Delegates the call to ChannelSend::SendRtpAudio on the |encoder_queue_|,
+  // by calling |send_audio_callback_|.
+  void SendFrame(std::unique_ptr<TransformableFrameInterface> frame) const;
+
+ protected:
+  ~ChannelSendFrameTransformerDelegate() override = default;
+
+ private:
+  rtc::CriticalSection send_lock_;
+  SendFrameCallback send_frame_callback_ RTC_GUARDED_BY(send_lock_);
+  rtc::scoped_refptr<FrameTransformerInterface> frame_transformer_;
+  rtc::TaskQueue* encoder_queue_ RTC_GUARDED_BY(send_lock_);
+};
+}  // namespace webrtc
+#endif  // AUDIO_CHANNEL_SEND_FRAME_TRANSFORMER_DELEGATE_H_