1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
|
// Copyright 2020 The Chromium Authors
// 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 "base/memory/ptr_util.h"
#include "base/unguessable_token.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/modules/peerconnection/rtc_encoded_audio_frame_delegate.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/heap/cross_thread_persistent.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/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,
WTF::CrossThreadOnceClosure disconnect_callback)
: blink::RTCEncodedAudioUnderlyingSource(
script_state,
std::move(disconnect_callback),
/*enable_frame_restrictions=*/false,
base::UnguessableToken::Null(),
/*controller_override=*/nullptr) {}
RTCEncodedAudioUnderlyingSource::RTCEncodedAudioUnderlyingSource(
ScriptState* script_state,
WTF::CrossThreadOnceClosure disconnect_callback,
bool enable_frame_restrictions,
base::UnguessableToken owner_id,
ReadableStreamDefaultControllerWithScriptScope* override_controller)
: UnderlyingSourceBase(script_state),
script_state_(script_state),
disconnect_callback_(std::move(disconnect_callback)),
override_controller_(override_controller),
enable_frame_restrictions_(enable_frame_restrictions),
owner_id_(owner_id) {
DCHECK(disconnect_callback_);
ExecutionContext* context = ExecutionContext::From(script_state);
task_runner_ = context->GetTaskRunner(TaskType::kInternalMediaRealTime);
}
ReadableStreamDefaultControllerWithScriptScope*
RTCEncodedAudioUnderlyingSource::GetController() {
if (override_controller_) {
return override_controller_;
}
return Controller();
}
ScriptPromise<IDLUndefined> RTCEncodedAudioUnderlyingSource::Pull(
ScriptState* script_state,
ExceptionState&) {
DCHECK(task_runner_->BelongsToCurrentThread());
// WebRTC is a push source without backpressure support, so nothing to do
// here.
return ToResolvedUndefinedPromise(script_state);
}
ScriptPromise<IDLUndefined> RTCEncodedAudioUnderlyingSource::Cancel(
ScriptState* script_state,
ScriptValue reason,
ExceptionState&) {
DCHECK(task_runner_->BelongsToCurrentThread());
if (disconnect_callback_)
std::move(disconnect_callback_).Run();
return ToResolvedUndefinedPromise(script_state);
}
void RTCEncodedAudioUnderlyingSource::Trace(Visitor* visitor) const {
visitor->Trace(script_state_);
visitor->Trace(override_controller_);
UnderlyingSourceBase::Trace(visitor);
}
void RTCEncodedAudioUnderlyingSource::OnFrameFromSource(
std::unique_ptr<webrtc::TransformableAudioFrameInterface> webrtc_frame) {
// It can happen that a frame is posted to the task runner of the old
// execution context during a stream transfer to a new context.
// TODO(https://crbug.com/1506631): Make the state updates related to the
// transfer atomic and turn this into a DCHECK.
if (!task_runner_->BelongsToCurrentThread()) {
DVLOG(1) << "Dropped frame posted to incorrect task runner. This can "
"happen during transfer.";
return;
}
// If the source is canceled or there are too many queued frames,
// drop the new frame.
if (!disconnect_callback_ || !GetExecutionContext()) {
return;
}
if (!GetController()) {
// TODO(ricea): Maybe avoid dropping frames during transfer?
DVLOG(1) << "Dropped frame due to null Controller(). This can happen "
"during transfer.";
return;
}
if (GetController()->DesiredSize() <= kMinQueueDesiredSize) {
dropped_frames_++;
VLOG_IF(2, (dropped_frames_ % 20 == 0))
<< "Dropped total of " << dropped_frames_
<< " encoded audio frames due to too many already being queued.";
return;
}
RTCEncodedAudioFrame* encoded_frame;
if (enable_frame_restrictions_) {
encoded_frame = MakeGarbageCollected<RTCEncodedAudioFrame>(
std::move(webrtc_frame), owner_id_, ++last_enqueued_frame_counter_);
} else {
encoded_frame =
MakeGarbageCollected<RTCEncodedAudioFrame>(std::move(webrtc_frame));
}
GetController()->Enqueue(encoded_frame);
}
void RTCEncodedAudioUnderlyingSource::Close() {
DCHECK(task_runner_->BelongsToCurrentThread());
if (disconnect_callback_)
std::move(disconnect_callback_).Run();
if (GetController()) {
GetController()->Close();
}
}
void RTCEncodedAudioUnderlyingSource::OnSourceTransferStartedOnTaskRunner() {
DCHECK(task_runner_->BelongsToCurrentThread());
// This can potentially be called before the stream is constructed and so
// Controller() is still unset.
if (GetController()) {
GetController()->Close();
}
}
void RTCEncodedAudioUnderlyingSource::OnSourceTransferStarted() {
PostCrossThreadTask(
*task_runner_, FROM_HERE,
CrossThreadBindOnce(
&RTCEncodedAudioUnderlyingSource::OnSourceTransferStartedOnTaskRunner,
WrapCrossThreadPersistent(this)));
}
} // namespace blink
|