Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
[Windows] Implementation of 'AudioDestinationNode.devicePosition' att…
Browse files Browse the repository at this point in the history
…ribute

The newly added 'AudioDestinationNode.devicePosition' attribute
helps to bind audio context time and performance time values.

Please see for more details:
WebAudio/web-audio-api#754
WebAudio/web-audio-api#12
  • Loading branch information
Mikhail Pozdnyakov authored and Mrunal Kapade committed Jun 10, 2016
1 parent 2755f6e commit 5e2427c
Show file tree
Hide file tree
Showing 30 changed files with 264 additions and 33 deletions.
4 changes: 3 additions & 1 deletion content/browser/renderer_host/media/audio_sync_reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ AudioSyncReader::~AudioSyncReader() {

// media::AudioOutputController::SyncReader implementations.
void AudioSyncReader::UpdatePendingBytes(uint32_t bytes,
uint32_t frames_skipped) {
uint32_t frames_skipped,
const media::StreamPosition& device_position) {
// Increase the number of skipped frames stored in shared memory. We don't
// send it over the socket since sending more than 4 bytes might lead to being
// descheduled. The reading side will zero it when consumed.
Expand All @@ -120,6 +121,7 @@ void AudioSyncReader::UpdatePendingBytes(uint32_t bytes,
output_bus_->Zero();

socket_->Send(&bytes, sizeof(bytes));
socket_->Send(&device_position, sizeof(device_position));
++buffer_index_;
}

Expand Down
5 changes: 4 additions & 1 deletion content/browser/renderer_host/media/audio_sync_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ class AudioSyncReader : public media::AudioOutputController::SyncReader {
~AudioSyncReader() override;

// media::AudioOutputController::SyncReader implementations.
void UpdatePendingBytes(uint32_t bytes, uint32_t frames_skipped) override;
void UpdatePendingBytes(
uint32_t bytes,
uint32_t frames_skipped,
const media::StreamPosition& position) override;
void Read(media::AudioBus* dest) override;
void Close() override;

Expand Down
11 changes: 9 additions & 2 deletions content/renderer/media/renderer_webaudiodevice_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ double RendererWebAudioDeviceImpl::sampleRate() {

int RendererWebAudioDeviceImpl::Render(media::AudioBus* dest,
uint32_t frames_delayed,
uint32_t frames_skipped) {
uint32_t frames_skipped,
const media::StreamPosition& position) {
#if defined(OS_ANDROID)
if (is_first_buffer_after_silence_) {
DCHECK(!is_using_null_audio_sink_);
Expand All @@ -120,9 +121,15 @@ int RendererWebAudioDeviceImpl::Render(media::AudioBus* dest,
// TODO(xians): Remove the following |web_audio_source_data| after
// changing the blink interface.
WebVector<float*> web_audio_source_data(static_cast<size_t>(0));

double seconds = position.ticks
/ static_cast<double>(base::Time::kMicrosecondsPerSecond);
StreamPosition device_position(static_cast<size_t>(position.frames),
seconds);
client_callback_->render(web_audio_source_data,
web_audio_dest_data,
dest->frames());
dest->frames(),
device_position);

#if defined(OS_ANDROID)
const bool is_zero = dest->AreFramesZero();
Expand Down
6 changes: 5 additions & 1 deletion content/renderer/media/renderer_webaudiodevice_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
#include "media/base/audio_renderer_sink.h"
#include "third_party/WebKit/public/platform/WebAudioDevice.h"
Expand Down Expand Up @@ -45,7 +46,8 @@ class RendererWebAudioDeviceImpl
// AudioRendererSink::RenderCallback implementation.
int Render(media::AudioBus* dest,
uint32_t frames_delayed,
uint32_t frames_skipped) override;
uint32_t frames_skipped,
const media::StreamPosition& position) override;

void OnRenderError() override;

Expand Down Expand Up @@ -89,6 +91,8 @@ class RendererWebAudioDeviceImpl
// period of silence. We do this on android to save battery consumption.
base::CancelableClosure start_null_audio_sink_callback_;

media::StreamPosition device_position_;

// Security origin, used to check permissions for |output_device_|.
url::Origin security_origin_;

Expand Down
1 change: 1 addition & 0 deletions media/audio/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ source_set("audio") {
"audio_input_device.h",
"audio_input_ipc.cc",
"audio_input_ipc.h",
"audio_io.cc",
"audio_io.h",
"audio_manager.cc",
"audio_manager.h",
Expand Down
7 changes: 6 additions & 1 deletion media/audio/audio_device_thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ void AudioDeviceThread::Thread::Run() {
if (bytes_read != sizeof(pending_data))
break;

StreamPosition device_position = { 0, 0 };
bytes_read = socket_.Receive(&device_position, sizeof(device_position));
if (bytes_read != sizeof(device_position))
break;

// std::numeric_limits<uint32_t>::max() is a special signal which is
// returned after the browser stops the output device in response to a
// renderer side request.
Expand All @@ -186,7 +191,7 @@ void AudioDeviceThread::Thread::Run() {
if (pending_data != std::numeric_limits<uint32_t>::max()) {
base::AutoLock auto_lock(callback_lock_);
if (callback_)
callback_->Process(pending_data);
callback_->Process(pending_data, device_position);
}

// The usage of |synchronized_buffers_| differs between input and output
Expand Down
6 changes: 5 additions & 1 deletion media/audio/audio_device_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "base/memory/shared_memory.h"
#include "base/sync_socket.h"
#include "base/synchronization/lock.h"
#include "media/audio/audio_io.h"
#include "media/audio/audio_parameters.h"
#include "media/base/media_export.h"

Expand All @@ -22,6 +23,7 @@ class MessageLoop;

namespace media {
class AudioBus;
struct StreamPosition;

// Data transfer between browser and render process uses a combination
// of sync sockets and shared memory. To read from the socket and render
Expand Down Expand Up @@ -53,7 +55,9 @@ class MEDIA_EXPORT AudioDeviceThread {
virtual void MapSharedMemory() = 0;

// Called whenever we receive notifications about pending input data.
virtual void Process(uint32_t pending_data) = 0;
virtual void Process(
uint32_t pending_data,
const StreamPosition& position) = 0;

protected:
// Protected so that derived classes can access directly.
Expand Down
6 changes: 4 additions & 2 deletions media/audio/audio_input_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class AudioInputDevice::AudioThreadCallback
void MapSharedMemory() override;

// Called whenever we receive notifications about pending data.
void Process(uint32_t pending_data) override;
void Process(uint32_t pending_data, const StreamPosition& position) override;

private:
int current_segment_id_;
Expand Down Expand Up @@ -302,7 +302,9 @@ void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
}
}

void AudioInputDevice::AudioThreadCallback::Process(uint32_t pending_data) {
void AudioInputDevice::AudioThreadCallback::Process(
uint32_t pending_data,
const StreamPosition& position) {
// The shared memory represents parameters, size of the data buffer and the
// actual data buffer containing audio data. Map the memory into this
// structure and parse out parameters and the data area.
Expand Down
24 changes: 24 additions & 0 deletions media/audio/audio_io.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2016 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 "media/audio/audio_io.h"

namespace media {

int AudioOutputStream::AudioSourceCallback::OnMoreData(
AudioBus* dest,
uint32_t total_bytes_delay,
uint32_t frames_skipped) {
return 0;
}

int AudioOutputStream::AudioSourceCallback::OnMoreData(
AudioBus* dest,
uint32_t total_bytes_delay,
uint32_t frames_skipped,
const StreamPosition& device_position) {
return OnMoreData(dest, total_bytes_delay, frames_skipped);
}

} // namespace media
13 changes: 12 additions & 1 deletion media/audio/audio_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@

namespace media {

struct MEDIA_EXPORT StreamPosition {
int64_t frames;
int64_t ticks; // Obtained from base::TimeTicks::ToInternalValue().
};

class MEDIA_EXPORT AudioOutputStream {
public:
// Audio sources must implement AudioSourceCallback. This interface will be
Expand All @@ -65,7 +70,13 @@ class MEDIA_EXPORT AudioOutputStream {
// |frames_skipped| contains the number of frames skipped by the consumer.
virtual int OnMoreData(AudioBus* dest,
uint32_t total_bytes_delay,
uint32_t frames_skipped) = 0;
uint32_t frames_skipped);
// An alternate version which provides also device stream position,
// by default it just invokes the above method.
virtual int OnMoreData(AudioBus* dest,
uint32_t total_bytes_delay,
uint32_t frames_skipped,
const StreamPosition& device_position);

// There was an error while playing a buffer. Audio source cannot be
// destroyed yet. No direct action needed by the AudioStream, but it is
Expand Down
6 changes: 4 additions & 2 deletions media/audio/audio_output_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ void AudioOutputController::DoReportError() {

int AudioOutputController::OnMoreData(AudioBus* dest,
uint32_t total_bytes_delay,
uint32_t frames_skipped) {
uint32_t frames_skipped,
const StreamPosition& device_position) {
TRACE_EVENT0("audio", "AudioOutputController::OnMoreData");

// Indicate that we haven't wedged (at least not indefinitely, WedgeCheck()
Expand All @@ -299,7 +300,8 @@ int AudioOutputController::OnMoreData(AudioBus* dest,

const int frames = dest->frames();
sync_reader_->UpdatePendingBytes(
total_bytes_delay + frames * params_.GetBytesPerFrame(), frames_skipped);
total_bytes_delay + frames * params_.GetBytesPerFrame(), frames_skipped,
device_position);

if (will_monitor_audio_levels())
power_monitor_.Scan(*dest, frames);
Expand Down
9 changes: 6 additions & 3 deletions media/audio/audio_output_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,10 @@ class MEDIA_EXPORT AudioOutputController
// frames has been skipped by the renderer (typically the OS). The renderer
// source can handle this appropriately depending on the type of source. An
// ordinary file playout would ignore this.
virtual void UpdatePendingBytes(uint32_t bytes,
uint32_t frames_skipped) = 0;
virtual void UpdatePendingBytes(
uint32_t bytes,
uint32_t frames_skipped,
const StreamPosition& position = StreamPosition()) = 0;

// Attempts to completely fill |dest|, zeroing |dest| if the request can not
// be fulfilled (due to timeout).
Expand Down Expand Up @@ -163,7 +165,8 @@ class MEDIA_EXPORT AudioOutputController
// AudioSourceCallback implementation.
int OnMoreData(AudioBus* dest,
uint32_t total_bytes_delay,
uint32_t frames_skipped) override;
uint32_t frames_skipped,
const StreamPosition& device_position) override;
void OnError(AudioOutputStream* stream) override;

// AudioDeviceListener implementation. When called AudioOutputController will
Expand Down
8 changes: 5 additions & 3 deletions media/audio/audio_output_device.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class AudioOutputDevice::AudioThreadCallback
void MapSharedMemory() override;

// Called whenever we receive notifications about pending data.
void Process(uint32_t pending_data) override;
void Process(uint32_t pending_data, const StreamPosition& position) override;

private:
AudioRendererSink::RenderCallback* render_callback_;
Expand Down Expand Up @@ -397,7 +397,9 @@ void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() {
}

// Called whenever we receive notifications about pending data.
void AudioOutputDevice::AudioThreadCallback::Process(uint32_t pending_data) {
void AudioOutputDevice::AudioThreadCallback::Process(
uint32_t pending_data,
const StreamPosition& position) {
// Convert the number of pending bytes in the render buffer into frames.
double frames_delayed = static_cast<double>(pending_data) / bytes_per_frame_;

Expand Down Expand Up @@ -427,7 +429,7 @@ void AudioOutputDevice::AudioThreadCallback::Process(uint32_t pending_data) {
// the shared memory the Render() call is writing directly into the shared
// memory.
render_callback_->Render(output_bus_.get(), std::round(frames_delayed),
frames_skipped);
frames_skipped, position);
}

} // namespace media
19 changes: 14 additions & 5 deletions media/audio/audio_output_resampler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class OnMoreDataConverter
// AudioSourceCallback interface.
int OnMoreData(AudioBus* dest,
uint32_t total_bytes_delay,
uint32_t frames_skipped) override;
uint32_t frames_skipped,
const StreamPosition& position) override;
void OnError(AudioOutputStream* stream) override;

// Sets |source_callback_|. If this is not a new object, then Stop() must be
Expand Down Expand Up @@ -73,6 +74,9 @@ class OnMoreDataConverter
// stream has been stopped.
bool error_occurred_;

// Information about last recodred stream output position.
StreamPosition device_position_;

DISALLOW_COPY_AND_ASSIGN(OnMoreDataConverter);
};

Expand Down Expand Up @@ -349,7 +353,8 @@ OnMoreDataConverter::OnMoreDataConverter(const AudioParameters& input_params,
source_callback_(nullptr),
input_bytes_per_second_(input_params.GetBytesPerSecond()),
audio_converter_(input_params, output_params, false),
error_occurred_(false) {}
error_occurred_(false),
device_position_() {}

OnMoreDataConverter::~OnMoreDataConverter() {
// Ensure Stop() has been called so we don't end up with an AudioOutputStream
Expand All @@ -376,7 +381,9 @@ void OnMoreDataConverter::Stop() {

int OnMoreDataConverter::OnMoreData(AudioBus* dest,
uint32_t total_bytes_delay,
uint32_t frames_skipped) {
uint32_t frames_skipped,
const StreamPosition& position) {
device_position_ = position;
current_total_bytes_delay_ = total_bytes_delay;
audio_converter_.Convert(dest);

Expand All @@ -395,8 +402,10 @@ double OnMoreDataConverter::ProvideInput(AudioBus* dest,
buffer_delay.InSecondsF() * input_bytes_per_second_));

// Retrieve data from the original callback.
const int frames =
source_callback_->OnMoreData(dest, new_total_bytes_delay, 0);
const int frames = source_callback_->OnMoreData(dest,
new_total_bytes_delay,
0,
device_position_);

// Zero any unfilled frames if anything was filled, otherwise we'll just
// return a volume of zero and let AudioConverter drop the output.
Expand Down
25 changes: 23 additions & 2 deletions media/audio/win/audio_low_latency_output_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
share_mode_(GetShareMode()),
num_written_frames_(0),
source_(NULL),
hns_units_to_perf_count_(0.0),
audio_bus_(AudioBus::Create(params)) {
DCHECK(manager_);

Expand Down Expand Up @@ -126,6 +127,14 @@ WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
// Create the event which will be set in Stop() when capturing shall stop.
stop_render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
DCHECK(stop_render_event_.IsValid());

LARGE_INTEGER performance_frequency;
if (QueryPerformanceFrequency(&performance_frequency)) {
hns_units_to_perf_count_ =
(static_cast<double>(performance_frequency.QuadPart) / 10000000.0);
} else {
DLOG(ERROR) << "High-resolution performance counters are not supported.";
}
}

WASAPIAudioOutputStream::~WASAPIAudioOutputStream() {
Expand Down Expand Up @@ -510,8 +519,11 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) {
// can typically be utilized by an acoustic echo-control (AEC)
// unit at the render side.
UINT64 position = 0;
UINT64 qpc_position = 0;
uint32_t audio_delay_bytes = 0;
hr = audio_clock_->GetPosition(&position, NULL);
StreamPosition device_position = { 0, 0 };

hr = audio_clock_->GetPosition(&position, &qpc_position);
if (SUCCEEDED(hr)) {
// Stream position of the sample that is currently playing
// through the speaker.
Expand All @@ -528,13 +540,22 @@ bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) {
// render client using the OnMoreData() callback.
audio_delay_bytes = (pos_last_sample_written_frames -
pos_sample_playing_frames) * format_.Format.nBlockAlign;
if (hns_units_to_perf_count_) {
device_position.frames = pos_sample_playing_frames;
device_position.ticks =
base::TimeTicks::FromQPCValue(
qpc_position * hns_units_to_perf_count_).ToInternalValue();
}
}

// Read a data packet from the registered client source and
// deliver a delay estimate in the same callback to the client.

int frames_filled =
source_->OnMoreData(audio_bus_.get(), audio_delay_bytes, 0);
source_->OnMoreData(audio_bus_.get(),
audio_delay_bytes,
0,
device_position);
uint32_t num_filled_bytes = frames_filled * format_.Format.nBlockAlign;
DCHECK_LE(num_filled_bytes, packet_size_bytes_);

Expand Down
Loading

0 comments on commit 5e2427c

Please sign in to comment.