Commit 83fec715 authored by Raymond Toy's avatar Raymond Toy Committed by Commit Bot

Move audibility detection to BaseAudioContext

Have the BaseAudioContext do the audibility detection instead of the
AudioDestination.  And also post a task to the main thread when
audible audio starts or stops.  This is in preparation for reporting
this information to the browser.

Bug: 855069
Test: 
Change-Id: I8abd9be664697e8cc02998daec06f9ca0d34a98d
Reviewed-on: https://chromium-review.googlesource.com/1165947Reviewed-by: default avatarHongchan Choi <hongchan@chromium.org>
Commit-Queue: Raymond Toy <rtoy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582029}
parent 439c480b
......@@ -69,16 +69,21 @@
#include "third_party/blink/renderer/modules/webaudio/script_processor_node.h"
#include "third_party/blink/renderer/modules/webaudio/stereo_panner_node.h"
#include "third_party/blink/renderer/modules/webaudio/wave_shaper_node.h"
#include "third_party/blink/renderer/platform/uuid.h"
#include "third_party/blink/renderer/platform/audio/iir_filter.h"
#include "third_party/blink/renderer/platform/audio/vector_math.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/uuid.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
// Recording of audio audibility stops after the context has been running for
// this long. We don't need this information for the lifetime of the context.
const double kStopRecordingAudibilityTime = 10;
BaseAudioContext* BaseAudioContext::Create(
Document& document,
const AudioContextOptions& context_options,
......@@ -695,7 +700,24 @@ void BaseAudioContext::HandlePreRenderTasks(
}
}
void BaseAudioContext::HandlePostRenderTasks() {
// Determine if the rendered data is audible.
static bool IsAudible(const AudioBus* rendered_data) {
// Compute the energy in each channel and sum up the energy in each channel
// for the total energy.
float energy = 0;
unsigned data_size = rendered_data->length();
for (unsigned k = 0; k < rendered_data->NumberOfChannels(); ++k) {
const float* data = rendered_data->Channel(k)->Data();
float channel_energy;
VectorMath::Vsvesq(data, 1, &channel_energy, data_size);
energy += channel_energy;
}
return energy > 0;
}
void BaseAudioContext::HandlePostRenderTasks(const AudioBus* destination_bus) {
DCHECK(IsAudioThread());
// Must use a tryLock() here too. Don't worry, the lock will very rarely be
......@@ -712,6 +734,37 @@ void BaseAudioContext::HandlePostRenderTasks() {
unlock();
}
// Notify browser if audible audio has started or stopped.
if (HasRealtimeConstraint()) {
// Detect silence (or not) for MEI
bool is_audible = IsAudible(destination_bus);
// We want to keep track of the total audible audio, but we don't need to
// record the start and stop of audible audio after
// |kStopRecordingAudibilityTime|.
if (is_audible) {
++total_audible_renders_;
}
if (currentTime() <= kStopRecordingAudibilityTime) {
if (was_audible_ != is_audible) {
// Audibility changed in this render, so report the change.
was_audible_ = is_audible;
if (is_audible) {
PostCrossThreadTask(
*Platform::Current()->MainThread()->GetTaskRunner(), FROM_HERE,
CrossThreadBind(&BaseAudioContext::NotifyAudibleAudioStarted,
WrapCrossThreadPersistent(this)));
} else {
PostCrossThreadTask(
*Platform::Current()->MainThread()->GetTaskRunner(), FROM_HERE,
CrossThreadBind(&BaseAudioContext::NotifyAudibleAudioStopped,
WrapCrossThreadPersistent(this)));
}
}
}
}
}
void BaseAudioContext::PerformCleanupOnMainThread() {
......@@ -941,4 +994,18 @@ bool BaseAudioContext::WouldTaintOrigin(const KURL& url) const {
return true;
}
void BaseAudioContext::NotifyAudibleAudioStarted() {
DCHECK(IsMainThread());
// TODO(crbug.com/855069): Actually notify the browser that audible audio has
// started.
VLOG(1) << this << ": Audible audio started @" << currentTime();
}
void BaseAudioContext::NotifyAudibleAudioStopped() {
DCHECK(IsMainThread());
// TODO(crbug.com/855069): Actually notify the browser that audible audio has
// started.
VLOG(1) << this << ": Audible audio stopped @" << currentTime();
}
} // namespace blink
......@@ -245,7 +245,7 @@ class MODULES_EXPORT BaseAudioContext
void HandlePreRenderTasks(const AudioIOPosition& output_position);
// Called at the end of each render quantum.
void HandlePostRenderTasks();
void HandlePostRenderTasks(const AudioBus* destination_bus);
DeferredTaskHandler& GetDeferredTaskHandler() const {
return *deferred_task_handler_;
......@@ -452,6 +452,19 @@ class MODULES_EXPORT BaseAudioContext
// This cannot be nullptr once it is assigned from AudioWorkletThread until
// the BaseAudioContext goes away.
WorkerThread* audio_worklet_thread_ = nullptr;
// Notifies browser when audible audio started or stopped.
void NotifyAudibleAudioStarted();
void NotifyAudibleAudioStopped();
// Keeps track if the output of this destination was audible, before the
// current rendering quantum. Used for recording "playback" time.
bool was_audible_ = false;
// Counts the number of render quanta where audible sound was played. We
// determine audibility on render quantum boundaries, so counting quanta is
// all that's needed.
size_t total_audible_renders_ = 0;
};
} // namespace blink
......
......@@ -197,7 +197,7 @@ void DefaultAudioDestinationHandler::Render(
Context()->GetDeferredTaskHandler().ProcessAutomaticPullNodes(
number_of_frames);
Context()->HandlePostRenderTasks();
Context()->HandlePostRenderTasks(destination_bus);
// Advances the current sample-frame.
size_t new_sample_frame = current_sample_frame_ + number_of_frames;
......
......@@ -150,22 +150,6 @@ void AudioDestination::Render(const WebVector<float*>& destination_data,
delay_timestamp, "delay (s)", delay);
}
// Determine if the rendered data is audible.
static bool IsAudible(const AudioBus* rendered_data) {
// Compute the energy in each channel and sum up the energy in each channel
// for the total energy.
float energy = 0;
unsigned data_size = rendered_data->length();
for (unsigned k = 0; k < rendered_data->NumberOfChannels(); ++k) {
const float* data = rendered_data->Channel(k)->Data();
float channel_energy;
VectorMath::Vsvesq(data, 1, &channel_energy, data_size);
energy += channel_energy;
}
return energy > 0;
}
void AudioDestination::RequestRender(size_t frames_requested,
size_t frames_to_render,
......@@ -204,23 +188,6 @@ void AudioDestination::RequestRender(size_t frames_requested,
callback_.Render(render_bus_.get(),
AudioUtilities::kRenderQuantumFrames, output_position);
// Detect silence (or not) for MEI
bool is_audible = IsAudible(render_bus_.get());
if (is_audible) {
++total_audible_renders_;
}
if (was_audible_) {
if (!is_audible) {
was_audible_ = false;
}
} else {
if (is_audible) {
was_audible_ = true;
}
}
fifo_->Push(render_bus_.get());
}
......
......@@ -138,15 +138,6 @@ class PLATFORM_EXPORT AudioDestination
// graph into the FIFO.
scoped_refptr<AudioBus> render_bus_;
// Keeps track if the output of this destination was audible, before the
// current rendering quantum. Used for recording "playback" time.
bool was_audible_ = false;
// Counts the number of render quanta where audible sound was played. We
// determine audibility on render quantum boundaries, so counting quanta is
// all that's needed.
size_t total_audible_renders_ = 0;
// Accessed by rendering thread: the render callback function of WebAudio
// engine. (i.e. DestinationNode)
AudioIOCallback& callback_;
......
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