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

[RTCInsertableStreams] Add underlying source and sink for encoded audio.

This CL introduces underlying source and sink classes for encoded audio.
The source allows sending frames from WebRTC to a ReadableStream.
The sink allows sending frames from a WritableStream to WebRTC.

Unit tests in
https://chromium-review.googlesource.com/c/chromium/src/+/2132258

Bug: 1052765
Change-Id: Ie9083ad92b0bbabc177c284f0bf482b7bc1555b0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2132133Reviewed-by: default avatarMarina Ciocea <marinaciocea@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#755559}
parent b0bf9b92
...@@ -78,6 +78,10 @@ blink_modules_sources("peerconnection") { ...@@ -78,6 +78,10 @@ blink_modules_sources("peerconnection") {
"rtc_dtmf_tone_change_event.h", "rtc_dtmf_tone_change_event.h",
"rtc_encoded_audio_frame.cc", "rtc_encoded_audio_frame.cc",
"rtc_encoded_audio_frame.h", "rtc_encoded_audio_frame.h",
"rtc_encoded_audio_underlying_sink.cc",
"rtc_encoded_audio_underlying_sink.h",
"rtc_encoded_audio_underlying_source.cc",
"rtc_encoded_audio_underlying_source.h",
"rtc_encoded_video_frame.cc", "rtc_encoded_video_frame.cc",
"rtc_encoded_video_frame.h", "rtc_encoded_video_frame.h",
"rtc_encoded_video_underlying_sink.cc", "rtc_encoded_video_underlying_sink.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/modules/peerconnection/rtc_encoded_audio_underlying_sink.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_encoded_audio_frame.h"
#include "third_party/blink/renderer/core/dom/dom_exception.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/peerconnection/rtc_encoded_audio_stream_transformer.h"
#include "third_party/webrtc/api/frame_transformer_interface.h"
namespace blink {
RTCEncodedAudioUnderlyingSink::RTCEncodedAudioUnderlyingSink(
ScriptState* script_state,
TransformerCallback transformer_callback)
: transformer_callback_(std::move(transformer_callback)) {
DCHECK(transformer_callback_);
}
ScriptPromise RTCEncodedAudioUnderlyingSink::start(
ScriptState* script_state,
WritableStreamDefaultController* controller,
ExceptionState&) {
// No extra setup needed.
return ScriptPromise::CastUndefined(script_state);
}
ScriptPromise RTCEncodedAudioUnderlyingSink::write(
ScriptState* script_state,
ScriptValue chunk,
WritableStreamDefaultController* controller,
ExceptionState& exception_state) {
RTCEncodedAudioFrame* encoded_frame =
V8RTCEncodedAudioFrame::ToImplWithTypeCheck(script_state->GetIsolate(),
chunk.V8Value());
if (!encoded_frame) {
exception_state.ThrowDOMException(DOMExceptionCode::kTypeMismatchError,
"Invalid frame");
return ScriptPromise();
}
// Get webrtc frame and send it to the decoder.
if (!transformer_callback_) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Stream closed");
return ScriptPromise();
}
transformer_callback_.Run()->SendFrameToSink(encoded_frame->PassDelegate());
return ScriptPromise::CastUndefined(script_state);
}
ScriptPromise RTCEncodedAudioUnderlyingSink::close(ScriptState* script_state,
ExceptionState&) {
// Disconnect from the transformer if the sink is closed.
if (transformer_callback_)
transformer_callback_.Reset();
return ScriptPromise::CastUndefined(script_state);
}
ScriptPromise RTCEncodedAudioUnderlyingSink::abort(
ScriptState* script_state,
ScriptValue reason,
ExceptionState& exception_state) {
// It is not possible to cancel any frames already sent to the WebRTC sink,
// thus abort() has the same effect as close().
return close(script_state, exception_state);
}
void RTCEncodedAudioUnderlyingSink::Trace(Visitor* visitor) {
UnderlyingSinkBase::Trace(visitor);
}
} // 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_MODULES_PEERCONNECTION_RTC_ENCODED_AUDIO_UNDERLYING_SINK_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ENCODED_AUDIO_UNDERLYING_SINK_H_
#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
#include "third_party/blink/renderer/modules/modules_export.h"
namespace blink {
class ExceptionState;
class RTCEncodedAudioStreamTransformer;
class MODULES_EXPORT RTCEncodedAudioUnderlyingSink final
: public UnderlyingSinkBase {
public:
using TransformerCallback =
base::RepeatingCallback<RTCEncodedAudioStreamTransformer*()>;
RTCEncodedAudioUnderlyingSink(ScriptState*, TransformerCallback);
// UnderlyingSinkBase
ScriptPromise start(ScriptState*,
WritableStreamDefaultController*,
ExceptionState&) override;
ScriptPromise write(ScriptState*,
ScriptValue chunk,
WritableStreamDefaultController*,
ExceptionState&) override;
ScriptPromise close(ScriptState*, ExceptionState&) override;
ScriptPromise abort(ScriptState*,
ScriptValue reason,
ExceptionState&) override;
void Trace(Visitor*) override;
private:
TransformerCallback transformer_callback_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ENCODED_AUDIO_UNDERLYING_SINK_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/modules/peerconnection/rtc_encoded_audio_underlying_source.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_frame.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include "third_party/webrtc/api/frame_transformer_interface.h"
namespace blink {
// Frames should not be queued at all. We allow queuing a few frames to deal
// with transient slowdowns. Specified as a negative number of frames since
// queuing is reported by the stream controller as a negative desired size.
const int RTCEncodedAudioUnderlyingSource::kMinQueueDesiredSize = -60;
RTCEncodedAudioUnderlyingSource::RTCEncodedAudioUnderlyingSource(
ScriptState* script_state,
base::OnceClosure disconnect_callback,
bool is_receiver)
: UnderlyingSourceBase(script_state),
script_state_(script_state),
disconnect_callback_(std::move(disconnect_callback)),
is_receiver_(is_receiver) {
DCHECK(disconnect_callback_);
}
ScriptPromise RTCEncodedAudioUnderlyingSource::pull(ScriptState* script_state) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// WebRTC is a push source without backpressure support, so nothing to do
// here.
return ScriptPromise::CastUndefined(script_state);
}
ScriptPromise RTCEncodedAudioUnderlyingSource::Cancel(ScriptState* script_state,
ScriptValue reason) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (disconnect_callback_)
std::move(disconnect_callback_).Run();
return ScriptPromise::CastUndefined(script_state);
}
void RTCEncodedAudioUnderlyingSource::Trace(Visitor* visitor) {
visitor->Trace(script_state_);
UnderlyingSourceBase::Trace(visitor);
}
void RTCEncodedAudioUnderlyingSource::OnFrameFromSource(
std::unique_ptr<webrtc::TransformableFrameInterface> webrtc_frame) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// If the source is canceled or there are too many queued frames,
// drop the new frame.
if (!disconnect_callback_ || !Controller() ||
Controller()->DesiredSize() <= kMinQueueDesiredSize) {
return;
}
RTCEncodedAudioFrame* encoded_frame = nullptr;
if (is_receiver_) {
// Receivers produce frames as webrtc::TransformableAudioFrameInterface,
// which allows exposing the CSRCs.
std::unique_ptr<webrtc::TransformableAudioFrameInterface> audio_frame =
base::WrapUnique(static_cast<webrtc::TransformableAudioFrameInterface*>(
webrtc_frame.release()));
encoded_frame =
MakeGarbageCollected<RTCEncodedAudioFrame>(std::move(audio_frame));
} else {
encoded_frame =
MakeGarbageCollected<RTCEncodedAudioFrame>(std::move(webrtc_frame));
}
Controller()->Enqueue(encoded_frame);
}
void RTCEncodedAudioUnderlyingSource::Close() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (disconnect_callback_)
std::move(disconnect_callback_).Run();
if (Controller())
Controller()->Close();
}
} // 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_MODULES_PEERCONNECTION_RTC_ENCODED_AUDIO_UNDERLYING_SOURCE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ENCODED_AUDIO_UNDERLYING_SOURCE_H_
#include "base/threading/thread_checker.h"
#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
#include "third_party/blink/renderer/modules/modules_export.h"
namespace webrtc {
class TransformableFrameInterface;
} // namespace webrtc
namespace blink {
class MODULES_EXPORT RTCEncodedAudioUnderlyingSource
: public UnderlyingSourceBase {
public:
explicit RTCEncodedAudioUnderlyingSource(
ScriptState*,
base::OnceClosure disconnect_callback,
bool is_receiver);
// UnderlyingSourceBase
ScriptPromise pull(ScriptState*) override;
ScriptPromise Cancel(ScriptState*, ScriptValue reason) override;
void OnFrameFromSource(std::unique_ptr<webrtc::TransformableFrameInterface>);
void Close();
void Trace(Visitor*) override;
private:
FRIEND_TEST_ALL_PREFIXES(RTCEncodedAudioUnderlyingSourceTest,
QueuedFramesAreDroppedWhenOverflow);
static const int kMinQueueDesiredSize;
const Member<ScriptState> script_state_;
base::OnceClosure disconnect_callback_;
// Indicates if this source is for a receiver. Receiver sources
// expose CSRCs.
const bool is_receiver_;
THREAD_CHECKER(thread_checker_);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ENCODED_AUDIO_UNDERLYING_SOURCE_H_
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