Commit be9f8beb authored by Guido Urdaneta's avatar Guido Urdaneta Committed by Commit Bot

[RTCInsertableStreams] Add encoded audio transformer

This class implements the WebRTC interface for encoded audio insertable
streams.
It allows receiving encoded frames from WebRTC (e.g., from the encoder
or depacketizer) and writing encoded frames back to WebRTC (e.g., to the
packetizer or decoder).

Bug: 1052765
Change-Id: I548defd3b6abc020a11add797ef7708d9d81f054
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2132208Reviewed-by: default avatarPhilip Jägenstedt <foolip@chromium.org>
Reviewed-by: default avatarMarina Ciocea <marinaciocea@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#755552}
parent ef69c0d9
...@@ -1270,6 +1270,8 @@ jumbo_component("platform") { ...@@ -1270,6 +1270,8 @@ jumbo_component("platform") {
"peerconnection/rtc_api_name.h", "peerconnection/rtc_api_name.h",
"peerconnection/rtc_dtmf_sender_handler.cc", "peerconnection/rtc_dtmf_sender_handler.cc",
"peerconnection/rtc_dtmf_sender_handler.h", "peerconnection/rtc_dtmf_sender_handler.h",
"peerconnection/rtc_encoded_audio_stream_transformer.cc",
"peerconnection/rtc_encoded_audio_stream_transformer.h",
"peerconnection/rtc_encoded_video_stream_transformer.cc", "peerconnection/rtc_encoded_video_stream_transformer.cc",
"peerconnection/rtc_encoded_video_stream_transformer.h", "peerconnection/rtc_encoded_video_stream_transformer.h",
"peerconnection/rtc_event_log_output_sink.h", "peerconnection/rtc_event_log_output_sink.h",
...@@ -1894,6 +1896,7 @@ jumbo_source_set("blink_platform_unittests_sources") { ...@@ -1894,6 +1896,7 @@ jumbo_source_set("blink_platform_unittests_sources") {
"mojo/string16_mojom_traits_test.cc", "mojo/string16_mojom_traits_test.cc",
"p2p/filtering_network_manager_test.cc", "p2p/filtering_network_manager_test.cc",
"p2p/ipc_network_manager_test.cc", "p2p/ipc_network_manager_test.cc",
"peerconnection/rtc_encoded_audio_stream_transformer_test.cc",
"peerconnection/rtc_encoded_video_stream_transformer_test.cc", "peerconnection/rtc_encoded_video_stream_transformer_test.cc",
"peerconnection/rtc_stats_test.cc", "peerconnection/rtc_stats_test.cc",
"peerconnection/rtc_video_decoder_adapter_test.cc", "peerconnection/rtc_video_decoder_adapter_test.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_audio_stream_transformer.h"
#include <utility>
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_scoped_refptr_cross_thread_copier.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/webrtc/api/frame_transformer_interface.h"
#include "third_party/webrtc/rtc_base/ref_counted_object.h"
namespace blink {
namespace {
// This delegate class exists to work around the fact that
// RTCEncodedAudioStreamTransformer cannot derive from rtc::RefCountedObject
// and post tasks referencing itself as an rtc::scoped_refptr. Instead,
// RTCEncodedAudioStreamTransformer creates a delegate using
// rtc::RefCountedObject and posts tasks referencing the delegate, which invokes
// the RTCEncodedAudioStreamTransformer via callbacks.
class RTCEncodedAudioStreamTransformerDelegate
: public webrtc::FrameTransformerInterface {
public:
RTCEncodedAudioStreamTransformerDelegate(
const base::WeakPtr<RTCEncodedAudioStreamTransformer>& transformer,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
: transformer_(transformer),
main_task_runner_(std::move(main_task_runner)) {
DCHECK(main_task_runner_->BelongsToCurrentThread());
}
// webrtc::FrameTransformerInterface
void RegisterTransformedFrameCallback(
rtc::scoped_refptr<webrtc::TransformedFrameCallback>
send_frame_to_sink_callback) override {
PostCrossThreadTask(
*main_task_runner_, FROM_HERE,
CrossThreadBindOnce(
&RTCEncodedAudioStreamTransformer::RegisterTransformedFrameCallback,
transformer_, std::move(send_frame_to_sink_callback)));
}
void UnregisterTransformedFrameCallback() override {
PostCrossThreadTask(
*main_task_runner_, FROM_HERE,
CrossThreadBindOnce(&RTCEncodedAudioStreamTransformer::
UnregisterTransformedFrameCallback,
transformer_));
}
void Transform(
std::unique_ptr<webrtc::TransformableFrameInterface> frame) override {
auto audio_frame = base::WrapUnique(
static_cast<webrtc::TransformableFrameInterface*>(frame.release()));
PostCrossThreadTask(
*main_task_runner_, FROM_HERE,
CrossThreadBindOnce(&RTCEncodedAudioStreamTransformer::TransformFrame,
transformer_, std::move(audio_frame)));
}
private:
base::WeakPtr<RTCEncodedAudioStreamTransformer> transformer_;
const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
};
} // namespace
RTCEncodedAudioStreamTransformer::RTCEncodedAudioStreamTransformer(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
DCHECK(main_task_runner->BelongsToCurrentThread());
delegate_ =
new rtc::RefCountedObject<RTCEncodedAudioStreamTransformerDelegate>(
weak_factory_.GetWeakPtr(), std::move(main_task_runner));
}
void RTCEncodedAudioStreamTransformer::RegisterTransformedFrameCallback(
rtc::scoped_refptr<webrtc::TransformedFrameCallback> callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
send_frame_to_sink_cb_ = callback;
}
void RTCEncodedAudioStreamTransformer::UnregisterTransformedFrameCallback() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
send_frame_to_sink_cb_ = nullptr;
}
void RTCEncodedAudioStreamTransformer::TransformFrame(
std::unique_ptr<webrtc::TransformableFrameInterface> frame) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// If no transformer callback has been set, drop the frame.
if (!transformer_callback_)
return;
transformer_callback_.Run(std::move(frame));
}
void RTCEncodedAudioStreamTransformer::SendFrameToSink(
std::unique_ptr<webrtc::TransformableFrameInterface> frame) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (send_frame_to_sink_cb_)
send_frame_to_sink_cb_->OnTransformedFrame(std::move(frame));
}
void RTCEncodedAudioStreamTransformer::SetTransformerCallback(
TransformerCallback callback) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
transformer_callback_ = std::move(callback);
}
void RTCEncodedAudioStreamTransformer::ResetTransformerCallback() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
transformer_callback_.Reset();
}
bool RTCEncodedAudioStreamTransformer::HasTransformerCallback() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return !transformer_callback_.is_null();
}
bool RTCEncodedAudioStreamTransformer::HasTransformedFrameCallback() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return !!send_frame_to_sink_cb_;
}
rtc::scoped_refptr<webrtc::FrameTransformerInterface>
RTCEncodedAudioStreamTransformer::Delegate() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return delegate_;
}
} // namespace blink
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_ENCODED_AUDIO_STREAM_TRANSFORMER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_ENCODED_AUDIO_STREAM_TRANSFORMER_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/webrtc/api/scoped_refptr.h"
namespace base {
class SingleThreadTaskRunner;
} // namespace base
namespace webrtc {
class FrameTransformerInterface;
class TransformedFrameCallback;
class TransformableFrameInterface;
} // namespace webrtc
namespace blink {
class PLATFORM_EXPORT RTCEncodedAudioStreamTransformer {
public:
using TransformerCallback = base::RepeatingCallback<void(
std::unique_ptr<webrtc::TransformableFrameInterface>)>;
explicit RTCEncodedAudioStreamTransformer(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
// Called by WebRTC to let us know about a callback object to send transformed
// frames to the WebRTC decoder. Runs on an internal WebRTC thread.
// The callback can run on any thread.
void RegisterTransformedFrameCallback(
rtc::scoped_refptr<webrtc::TransformedFrameCallback>);
// Called by WebRTC to let us know that any reference to the callback object
// reported by RegisterTransformedFrameCallback() should be released since
// the callback is no longer useful and is intended for destruction.
void UnregisterTransformedFrameCallback();
// Called by WebRTC to notify of new untransformed frames from the WebRTC
// stack. Runs on an internal WebRTC thread.
void TransformFrame(std::unique_ptr<webrtc::TransformableFrameInterface>);
// Send a transformed frame to the WebRTC sink. Must run on the main
// thread.
void SendFrameToSink(
std::unique_ptr<webrtc::TransformableFrameInterface> frame);
// Set a callback to be invoked on every untransformed frame. Must run on the
// main thread.
void SetTransformerCallback(TransformerCallback);
// Removes the callback
void ResetTransformerCallback();
// Returns true if a callback has been set with SetTransformerCallback(),
// false otherwise. Must run on the main thread.
bool HasTransformerCallback() const;
// Returns true if a webrtc::TransformedFrameCallback is registered.
bool HasTransformedFrameCallback() const;
rtc::scoped_refptr<webrtc::FrameTransformerInterface> Delegate();
private:
THREAD_CHECKER(thread_checker_);
rtc::scoped_refptr<webrtc::FrameTransformerInterface> delegate_;
rtc::scoped_refptr<webrtc::TransformedFrameCallback> send_frame_to_sink_cb_;
TransformerCallback transformer_callback_;
base::WeakPtrFactory<RTCEncodedAudioStreamTransformer> weak_factory_{this};
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_ENCODED_AUDIO_STREAM_TRANSFORMER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_audio_stream_transformer.h"
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/memory/scoped_refptr.h"
#include "base/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_scoped_refptr_cross_thread_copier.h"
#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/webrtc/api/frame_transformer_interface.h"
#include "third_party/webrtc/rtc_base/ref_counted_object.h"
namespace blink {
namespace {
class MockWebRtcTransformedFrameCallback
: public webrtc::TransformedFrameCallback {
public:
MOCK_METHOD1(OnTransformedFrame,
void(std::unique_ptr<webrtc::TransformableFrameInterface>));
};
class MockTransformerCallbackHolder {
public:
MOCK_METHOD1(OnEncodedFrame,
void(std::unique_ptr<webrtc::TransformableFrameInterface>));
};
} // namespace
class RTCEncodedAudioStreamTransformerTest : public ::testing::Test {
public:
RTCEncodedAudioStreamTransformerTest()
: main_task_runner_(
blink::scheduler::GetSingleThreadTaskRunnerForTesting()),
webrtc_task_runner_(base::ThreadPool::CreateSingleThreadTaskRunner({})),
webrtc_callback_(
new rtc::RefCountedObject<MockWebRtcTransformedFrameCallback>()),
encoded_audio_stream_transformer_(main_task_runner_) {}
void SetUp() override {
EXPECT_FALSE(
encoded_audio_stream_transformer_.HasTransformedFrameCallback());
encoded_audio_stream_transformer_.RegisterTransformedFrameCallback(
webrtc_callback_);
EXPECT_TRUE(
encoded_audio_stream_transformer_.HasTransformedFrameCallback());
}
void TearDown() override {
encoded_audio_stream_transformer_.UnregisterTransformedFrameCallback();
EXPECT_FALSE(
encoded_audio_stream_transformer_.HasTransformedFrameCallback());
}
protected:
base::test::TaskEnvironment task_environment_;
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> webrtc_task_runner_;
rtc::scoped_refptr<MockWebRtcTransformedFrameCallback> webrtc_callback_;
MockTransformerCallbackHolder mock_transformer_callback_holder_;
RTCEncodedAudioStreamTransformer encoded_audio_stream_transformer_;
};
TEST_F(RTCEncodedAudioStreamTransformerTest,
TransformerForwardsFrameToTransformerCallback) {
EXPECT_FALSE(encoded_audio_stream_transformer_.HasTransformerCallback());
encoded_audio_stream_transformer_.SetTransformerCallback(
WTF::BindRepeating(&MockTransformerCallbackHolder::OnEncodedFrame,
WTF::Unretained(&mock_transformer_callback_holder_)));
EXPECT_TRUE(encoded_audio_stream_transformer_.HasTransformerCallback());
EXPECT_CALL(mock_transformer_callback_holder_, OnEncodedFrame);
// Frames are pushed to the RTCEncodedAudioStreamTransformer via its delegate,
// which would normally be registered with a WebRTC sender or receiver.
// In this test, manually send the frame to the transformer on the simulated
// WebRTC thread.
PostCrossThreadTask(
*webrtc_task_runner_, FROM_HERE,
CrossThreadBindOnce(&webrtc::FrameTransformerInterface::Transform,
encoded_audio_stream_transformer_.Delegate(),
nullptr));
task_environment_.RunUntilIdle();
}
TEST_F(RTCEncodedAudioStreamTransformerTest, TransformerForwardsFrameToWebRTC) {
EXPECT_CALL(*webrtc_callback_, OnTransformedFrame);
encoded_audio_stream_transformer_.SendFrameToSink(nullptr);
task_environment_.RunUntilIdle();
}
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment