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

Commit

Permalink
Merge pull request #332 from pozdnyakov/web_audio
Browse files Browse the repository at this point in the history
[Windows] Implementation of 'AudioDestinationNode.devicePosition' att…
  • Loading branch information
Raphael Kubo da Costa committed Apr 1, 2016
2 parents 4ff4032 + 4a0b6c0 commit 96132b6
Show file tree
Hide file tree
Showing 31 changed files with 264 additions and 34 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 @@ -88,7 +88,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 @@ -101,6 +102,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 @@ -99,7 +99,8 @@ double RendererWebAudioDeviceImpl::sampleRate() {

int RendererWebAudioDeviceImpl::Render(media::AudioBus* dest,
uint32_t audio_delay_milliseconds,
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 @@ -117,9 +118,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 @@ -44,7 +45,8 @@ class RendererWebAudioDeviceImpl
// AudioRendererSink::RenderCallback implementation.
int Render(media::AudioBus* dest,
uint32_t audio_delay_milliseconds,
uint32_t frames_skipped) override;
uint32_t frames_skipped,
const media::StreamPosition& position) override;

void OnRenderError() override;

Expand Down Expand Up @@ -88,6 +90,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_;

DISALLOW_COPY_AND_ASSIGN(RendererWebAudioDeviceImpl);
};

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 @@ -34,7 +34,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 @@ -412,7 +412,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 milliseconds.
uint32_t audio_delay_milliseconds = pending_data / bytes_per_ms_;

Expand All @@ -438,7 +440,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(), audio_delay_milliseconds,
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 96132b6

Please sign in to comment.