Commit cec6c171 authored by Sergey Ulanov's avatar Sergey Ulanov Committed by Commit Bot

Fuchsia: Move AudioOutputStreamFuchsia to AudioRenderer2.

Previously AudioOutputStreamFuchsia was using media_client library,
which is deprecated now. Update //media to use AudioRenderer2 FIDL
interface directly.

Bug: 851733
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I356a0ae08798c2eb62d4cb42355aff4c47fbb360
Reviewed-on: https://chromium-review.googlesource.com/1096414
Commit-Queue: Sergey Ulanov <sergeyu@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Reviewed-by: default avatarXiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567376}
parent c6b80124
...@@ -317,7 +317,7 @@ source_set("audio") { ...@@ -317,7 +317,7 @@ source_set("audio") {
"fuchsia/audio_output_stream_fuchsia.cc", "fuchsia/audio_output_stream_fuchsia.cc",
"fuchsia/audio_output_stream_fuchsia.h", "fuchsia/audio_output_stream_fuchsia.h",
] ]
libs += [ "media_client" ] deps += [ "//third_party/fuchsia-sdk:media" ]
} }
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
......
...@@ -53,7 +53,7 @@ class AudioOutputTest : public ::testing::Test { ...@@ -53,7 +53,7 @@ class AudioOutputTest : public ::testing::Test {
} }
protected: protected:
base::MessageLoop message_loop_; base::MessageLoopForIO message_loop_;
std::unique_ptr<AudioManager> audio_manager_; std::unique_ptr<AudioManager> audio_manager_;
std::unique_ptr<AudioDeviceInfoAccessorForTests> audio_manager_device_info_; std::unique_ptr<AudioDeviceInfoAccessorForTests> audio_manager_device_info_;
AudioParameters stream_params_; AudioParameters stream_params_;
......
...@@ -10,10 +10,14 @@ ...@@ -10,10 +10,14 @@
namespace media { namespace media {
AudioThreadImpl::AudioThreadImpl() : thread_("AudioThread") { AudioThreadImpl::AudioThreadImpl() : thread_("AudioThread") {
base::Thread::Options thread_options;
#if defined(OS_WIN) #if defined(OS_WIN)
thread_.init_com_with_mta(true); thread_.init_com_with_mta(true);
#elif defined(OS_FUCHSIA)
// FIDL-based APIs require async_t, which is initialized on IO thread.
thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
#endif #endif
CHECK(thread_.Start()); CHECK(thread_.StartWithOptions(thread_options));
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// On Mac, the audio task runner must belong to the main thread. // On Mac, the audio task runner must belong to the main thread.
......
...@@ -15,16 +15,14 @@ namespace media { ...@@ -15,16 +15,14 @@ namespace media {
AudioManagerFuchsia::AudioManagerFuchsia( AudioManagerFuchsia::AudioManagerFuchsia(
std::unique_ptr<AudioThread> audio_thread, std::unique_ptr<AudioThread> audio_thread,
AudioLogFactory* audio_log_factory) AudioLogFactory* audio_log_factory)
: AudioManagerBase(std::move(audio_thread), audio_log_factory), : AudioManagerBase(std::move(audio_thread), audio_log_factory) {}
fuchsia_audio_manager_(fuchsia_audio_manager_create()) {}
AudioManagerFuchsia::~AudioManagerFuchsia() { AudioManagerFuchsia::~AudioManagerFuchsia() = default;
fuchsia_audio_manager_free(fuchsia_audio_manager_);
}
bool AudioManagerFuchsia::HasAudioOutputDevices() { bool AudioManagerFuchsia::HasAudioOutputDevices() {
return fuchsia_audio_manager_get_output_devices(fuchsia_audio_manager_, // TODO(crbug.com/852834): Fuchsia currently doesn't provide an API for device
nullptr, 0) > 0; // enumeration. Update this method when that functionality is implemented.
return true;
} }
bool AudioManagerFuchsia::HasAudioInputDevices() { bool AudioManagerFuchsia::HasAudioInputDevices() {
...@@ -40,33 +38,9 @@ void AudioManagerFuchsia::GetAudioInputDeviceNames( ...@@ -40,33 +38,9 @@ void AudioManagerFuchsia::GetAudioInputDeviceNames(
void AudioManagerFuchsia::GetAudioOutputDeviceNames( void AudioManagerFuchsia::GetAudioOutputDeviceNames(
AudioDeviceNames* device_names) { AudioDeviceNames* device_names) {
device_names->clear(); // TODO(crbug.com/852834): Fuchsia currently doesn't provide an API for device
// enumeration. Update this method when that functionality is implemented.
std::vector<fuchsia_audio_device_description> descriptions; *device_names = {AudioDeviceName::CreateDefault()};
descriptions.resize(16);
bool try_again = true;
while (try_again) {
int result = fuchsia_audio_manager_get_output_devices(
fuchsia_audio_manager_, descriptions.data(), descriptions.size());
if (result < 0) {
LOG(ERROR) << "fuchsia_audio_manager_get_output_devices() returned "
<< result;
device_names->clear();
return;
}
// Try again if the buffer was too small.
try_again = static_cast<size_t>(result) > descriptions.size();
descriptions.resize(result);
}
// Create default device if we have any output devices present.
if (!descriptions.empty())
device_names->push_back(AudioDeviceName::CreateDefault());
for (auto& desc : descriptions) {
device_names->push_back(AudioDeviceName(desc.name, desc.id));
}
} }
AudioParameters AudioManagerFuchsia::GetInputStreamParameters( AudioParameters AudioManagerFuchsia::GetInputStreamParameters(
...@@ -78,32 +52,11 @@ AudioParameters AudioManagerFuchsia::GetInputStreamParameters( ...@@ -78,32 +52,11 @@ AudioParameters AudioManagerFuchsia::GetInputStreamParameters(
AudioParameters AudioManagerFuchsia::GetPreferredOutputStreamParameters( AudioParameters AudioManagerFuchsia::GetPreferredOutputStreamParameters(
const std::string& output_device_id, const std::string& output_device_id,
const AudioParameters& input_params) { const AudioParameters& input_params) {
fuchsia_audio_parameters device_params; // TODO(crbug.com/852834): Fuchsia currently doesn't provide an API to get
int result = fuchsia_audio_manager_get_output_device_default_parameters( // device configuration. Update this method when that functionality is
fuchsia_audio_manager_, // implemented.
output_device_id == AudioDeviceDescription::kDefaultDeviceId
? nullptr
: const_cast<char*>(output_device_id.c_str()),
&device_params);
if (result < 0) {
LOG(ERROR) << "fuchsia_audio_manager_get_default_output_device_parameters()"
" returned "
<< result;
return AudioParameters();
}
int user_buffer_size = GetUserBufferSize();
if (user_buffer_size > 0)
device_params.buffer_size = user_buffer_size;
int sample_rate = input_params.sample_rate();
if (sample_rate < 8000 || sample_rate > 96000)
sample_rate = device_params.sample_rate;
return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
GuessChannelLayout(device_params.num_channels), CHANNEL_LAYOUT_STEREO, 48000, 480);
sample_rate, device_params.buffer_size);
} }
const char* AudioManagerFuchsia::GetName() { const char* AudioManagerFuchsia::GetName() {
...@@ -122,7 +75,13 @@ AudioOutputStream* AudioManagerFuchsia::MakeLowLatencyOutputStream( ...@@ -122,7 +75,13 @@ AudioOutputStream* AudioManagerFuchsia::MakeLowLatencyOutputStream(
const std::string& device_id, const std::string& device_id,
const LogCallback& log_callback) { const LogCallback& log_callback) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
return new AudioOutputStreamFuchsia(this, device_id, params);
if (!device_id.empty() &&
device_id != AudioDeviceDescription::kDefaultDeviceId) {
return nullptr;
}
return new AudioOutputStreamFuchsia(this, params);
} }
AudioInputStream* AudioManagerFuchsia::MakeLinearInputStream( AudioInputStream* AudioManagerFuchsia::MakeLinearInputStream(
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
#ifndef MEDIA_AUDIO_FUCHSIA_AUDIO_MANAGER_FUCHSIA_H_ #ifndef MEDIA_AUDIO_FUCHSIA_AUDIO_MANAGER_FUCHSIA_H_
#define MEDIA_AUDIO_FUCHSIA_AUDIO_MANAGER_FUCHSIA_H_ #define MEDIA_AUDIO_FUCHSIA_AUDIO_MANAGER_FUCHSIA_H_
#include <media/audio.h>
#include "media/audio/audio_manager_base.h" #include "media/audio/audio_manager_base.h"
namespace media { namespace media {
...@@ -43,18 +41,12 @@ class AudioManagerFuchsia : public AudioManagerBase { ...@@ -43,18 +41,12 @@ class AudioManagerFuchsia : public AudioManagerBase {
const std::string& device_id, const std::string& device_id,
const LogCallback& log_callback) override; const LogCallback& log_callback) override;
fuchsia_audio_manager* GetFuchsiaAudioManager() const {
return fuchsia_audio_manager_;
}
protected: protected:
AudioParameters GetPreferredOutputStreamParameters( AudioParameters GetPreferredOutputStreamParameters(
const std::string& output_device_id, const std::string& output_device_id,
const AudioParameters& input_params) override; const AudioParameters& input_params) override;
private: private:
fuchsia_audio_manager* fuchsia_audio_manager_;
DISALLOW_COPY_AND_ASSIGN(AudioManagerFuchsia); DISALLOW_COPY_AND_ASSIGN(AudioManagerFuchsia);
}; };
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
#include "media/audio/fuchsia/audio_output_stream_fuchsia.h" #include "media/audio/fuchsia/audio_output_stream_fuchsia.h"
#include <media/audio.h>
#include <zircon/syscalls.h> #include <zircon/syscalls.h>
#include "base/fuchsia/component_context.h"
#include "media/audio/fuchsia/audio_manager_fuchsia.h" #include "media/audio/fuchsia/audio_manager_fuchsia.h"
#include "media/base/audio_sample_types.h" #include "media/base/audio_sample_types.h"
#include "media/base/audio_timestamp_helper.h" #include "media/base/audio_timestamp_helper.h"
...@@ -15,43 +15,53 @@ namespace media { ...@@ -15,43 +15,53 @@ namespace media {
AudioOutputStreamFuchsia::AudioOutputStreamFuchsia( AudioOutputStreamFuchsia::AudioOutputStreamFuchsia(
AudioManagerFuchsia* manager, AudioManagerFuchsia* manager,
const std::string& device_id,
const AudioParameters& parameters) const AudioParameters& parameters)
: manager_(manager), : manager_(manager),
device_id_(device_id),
parameters_(parameters), parameters_(parameters),
audio_bus_(AudioBus::Create(parameters)), audio_bus_(AudioBus::Create(parameters)) {}
buffer_(parameters_.frames_per_buffer() * parameters_.channels()) {}
AudioOutputStreamFuchsia::~AudioOutputStreamFuchsia() { AudioOutputStreamFuchsia::~AudioOutputStreamFuchsia() {
// Close() must be called first. // Close() must be called first.
DCHECK(!stream_); DCHECK(!audio_renderer_);
} }
bool AudioOutputStreamFuchsia::Open() { bool AudioOutputStreamFuchsia::Open() {
DCHECK(!stream_); DCHECK(!audio_renderer_);
fuchsia_audio_parameters fuchsia_params; // Connect |audio_renderer_| to the audio service.
fuchsia_params.sample_rate = parameters_.sample_rate(); fuchsia::media::AudioPtr audio_server =
fuchsia_params.num_channels = parameters_.channels(); base::fuchsia::ComponentContext::GetDefault()
fuchsia_params.buffer_size = parameters_.frames_per_buffer(); ->ConnectToService<fuchsia::media::Audio>();
audio_server->CreateRendererV2(audio_renderer_.NewRequest());
int result = fuchsia_audio_manager_create_output_stream( audio_renderer_.set_error_handler(
manager_->GetFuchsiaAudioManager(), const_cast<char*>(device_id_.c_str()), fit::bind_member(this, &AudioOutputStreamFuchsia::OnRendererError));
&fuchsia_params, &stream_);
if (result < 0) { // Inform the |audio_renderer_| of the format required by the caller.
DLOG(ERROR) << "Failed to open audio output " << device_id_ fuchsia::media::AudioPcmFormat format;
<< " error code: " << result; format.sample_format = fuchsia::media::AudioSampleFormat::FLOAT;
DCHECK(!stream_); format.channels = parameters_.channels();
return false; format.frames_per_second = parameters_.sample_rate();
} audio_renderer_->SetPcmFormat(std::move(format));
// Use number of samples to specify media position.
audio_renderer_->SetPtsUnits(parameters_.sample_rate(), 1);
// Setup OnMinLeadTimeChanged event listener. This event is used to get
// |min_lead_time_|, which indicates how far ahead audio samples need to be
// sent to the renderer.
audio_renderer_.events().OnMinLeadTimeChanged =
fit::bind_member(this, &AudioOutputStreamFuchsia::OnMinLeadTimeChanged);
audio_renderer_->EnableMinLeadTimeEvents(true);
// The renderer may fail initialization asynchronously, which is handled in
// OnRendererError().
return true; return true;
} }
void AudioOutputStreamFuchsia::Start(AudioSourceCallback* callback) { void AudioOutputStreamFuchsia::Start(AudioSourceCallback* callback) {
DCHECK(!callback_); DCHECK(!callback_);
DCHECK(started_time_.is_null()); DCHECK(reference_time_.is_null());
DCHECK(!timer_.IsRunning());
callback_ = callback; callback_ = callback;
PumpSamples(); PumpSamples();
...@@ -59,7 +69,8 @@ void AudioOutputStreamFuchsia::Start(AudioSourceCallback* callback) { ...@@ -59,7 +69,8 @@ void AudioOutputStreamFuchsia::Start(AudioSourceCallback* callback) {
void AudioOutputStreamFuchsia::Stop() { void AudioOutputStreamFuchsia::Stop() {
callback_ = nullptr; callback_ = nullptr;
started_time_ = base::TimeTicks(); reference_time_ = base::TimeTicks();
audio_renderer_->FlushNoReply();
timer_.Stop(); timer_.Stop();
} }
...@@ -74,95 +85,140 @@ void AudioOutputStreamFuchsia::GetVolume(double* volume) { ...@@ -74,95 +85,140 @@ void AudioOutputStreamFuchsia::GetVolume(double* volume) {
void AudioOutputStreamFuchsia::Close() { void AudioOutputStreamFuchsia::Close() {
Stop(); Stop();
audio_renderer_.Unbind();
if (stream_) {
fuchsia_audio_output_stream_free(stream_);
stream_ = nullptr;
}
// Signal to the manager that we're closed and can be removed. This should be // Signal to the manager that we're closed and can be removed. This should be
// the last call in the function as it deletes "this". // the last call in the function as it deletes |this|.
manager_->ReleaseOutputStream(this); manager_->ReleaseOutputStream(this);
} }
base::TimeTicks AudioOutputStreamFuchsia::GetCurrentStreamTime() { base::TimeTicks AudioOutputStreamFuchsia::GetCurrentStreamTime() {
DCHECK(!started_time_.is_null()); DCHECK(!reference_time_.is_null());
return started_time_ + return reference_time_ +
AudioTimestampHelper::FramesToTime(stream_position_samples_, AudioTimestampHelper::FramesToTime(stream_position_samples_,
parameters_.sample_rate()); parameters_.sample_rate());
} }
bool AudioOutputStreamFuchsia::UpdatePresentationDelay() { size_t AudioOutputStreamFuchsia::GetMinBufferSize() {
int result = fuchsia_audio_output_stream_get_min_delay( // Ensure that |payload_buffer_| fits enough packets to cover min_lead_time_
stream_, &presentation_delay_ns_); // plus one extra packet.
if (result != ZX_OK) { int min_packets = (AudioTimestampHelper::TimeToFrames(
DLOG(ERROR) << "fuchsia_audio_output_stream_get_min_delay() failed: " min_lead_time_, parameters_.sample_rate()) +
<< result; parameters_.frames_per_buffer() - 1) /
callback_->OnError(); parameters_.frames_per_buffer() +
1;
return parameters_.GetBytesPerBuffer(kSampleFormatF32) * min_packets;
}
bool AudioOutputStreamFuchsia::InitializePayloadBuffer() {
size_t buffer_size = GetMinBufferSize();
if (!payload_buffer_.CreateAndMapAnonymous(buffer_size)) {
LOG(WARNING) << "Failed to allocate VMO of size " << buffer_size;
return false; return false;
} }
payload_buffer_pos_ = 0;
audio_renderer_->SetPayloadBuffer(
zx::vmo(payload_buffer_.handle().Duplicate().GetHandle()));
return true; return true;
} }
void AudioOutputStreamFuchsia::OnMinLeadTimeChanged(int64_t min_lead_time) {
min_lead_time_ = base::TimeDelta::FromNanoseconds(min_lead_time);
// When min_lead_time_ increases we may need to reallocate |payload_buffer_|.
// Code below just unmaps the current buffer. The new buffer will be allocated
// lated in PumpSamples(). This is necessary because VMO allocation may fail
// and it's not possible to report that error here - OnMinLeadTimeChanged()
// may be invoked before Start().
if (payload_buffer_.mapped_size() > 0 &&
GetMinBufferSize() > payload_buffer_.mapped_size()) {
payload_buffer_.Unmap();
}
}
void AudioOutputStreamFuchsia::OnRendererError() {
LOG(WARNING) << "AudioRenderer has failed.";
Stop();
callback_->OnError();
}
void AudioOutputStreamFuchsia::PumpSamples() { void AudioOutputStreamFuchsia::PumpSamples() {
DCHECK(stream_); DCHECK(audio_renderer_);
// Allocate payload buffer if necessary.
if (!payload_buffer_.mapped_size() && !InitializePayloadBuffer()) {
Stop();
callback_->OnError();
return;
}
base::TimeTicks now = base::TimeTicks::Now(); base::TimeTicks now = base::TimeTicks::Now();
// Reset stream position if: base::TimeDelta delay;
// 1. The stream wasn't previously running. if (reference_time_.is_null()) {
// 2. We missed timer deadline, e.g. after the system was suspended. delay = min_lead_time_;
if (started_time_.is_null() || now > GetCurrentStreamTime()) { } else {
if (!UpdatePresentationDelay()) auto stream_time = GetCurrentStreamTime();
return;
started_time_ = base::TimeTicks(); // Adjust stream position if we missed timer deadline.
} if (now + min_lead_time_ > stream_time) {
stream_position_samples_ += AudioTimestampHelper::TimeToFrames(
now + min_lead_time_ - stream_time, parameters_.sample_rate());
}
base::TimeDelta delay = delay = stream_time - now;
base::TimeDelta::FromMicroseconds(presentation_delay_ns_ / 1000); }
if (!started_time_.is_null())
delay += GetCurrentStreamTime() - now;
int frames_filled = callback_->OnMoreData(delay, now, 0, audio_bus_.get()); int frames_filled = callback_->OnMoreData(delay, now, 0, audio_bus_.get());
DCHECK_EQ(frames_filled, audio_bus_->frames()); DCHECK_EQ(frames_filled, audio_bus_->frames());
audio_bus_->Scale(volume_); audio_bus_->Scale(volume_);
size_t packet_size = parameters_.GetBytesPerBuffer(kSampleFormatF32);
DCHECK_LE(payload_buffer_pos_ + packet_size, payload_buffer_.mapped_size());
audio_bus_->ToInterleaved<media::Float32SampleTypeTraits>( audio_bus_->ToInterleaved<media::Float32SampleTypeTraits>(
audio_bus_->frames(), buffer_.data()); audio_bus_->frames(),
reinterpret_cast<float*>(
do { reinterpret_cast<uint8_t*>(payload_buffer_.memory()) +
zx_time_t presentation_time = FUCHSIA_AUDIO_NO_TIMESTAMP; payload_buffer_pos_));
if (started_time_.is_null()) {
// Presentation time (PTS) needs to be specified only for the first frame fuchsia::media::AudioPacket packet;
// after stream is started or restarted. Mixer will calculate PTS for all packet.timestamp = stream_position_samples_;
// following frames. 1us is added to account for the time passed between packet.payload_offset = payload_buffer_pos_;
// zx_clock_get() and fuchsia_audio_output_stream_write(). packet.payload_size = packet_size;
zx_time_t zx_now = zx_clock_get(ZX_CLOCK_MONOTONIC); packet.flags = 0;
presentation_time = zx_now + presentation_delay_ns_ + ZX_USEC(1);
started_time_ = base::TimeTicks::FromZxTime(zx_now); audio_renderer_->SendPacketNoReply(std::move(packet));
stream_position_samples_ = 0;
}
int result = fuchsia_audio_output_stream_write(
stream_, buffer_.data(), buffer_.size(), presentation_time);
if (result == ZX_ERR_IO_MISSED_DEADLINE) {
DLOG(ERROR) << "AudioOutputStreamFuchsia::PumpSamples() missed deadline, "
"resetting PTS.";
if (!UpdatePresentationDelay())
return;
started_time_ = base::TimeTicks();
} else if (result != ZX_OK) {
DLOG(ERROR) << "fuchsia_audio_output_stream_write() returned " << result;
callback_->OnError();
}
} while (started_time_.is_null());
stream_position_samples_ += frames_filled; stream_position_samples_ += frames_filled;
payload_buffer_pos_ =
(payload_buffer_pos_ + packet_size) % payload_buffer_.mapped_size();
if (reference_time_.is_null()) {
audio_renderer_->Play(
fuchsia::media::kNoTimestamp, stream_position_samples_ - frames_filled,
[this](int64_t reference_time, int64_t media_time) {
if (!callback_)
return;
reference_time_ = base::TimeTicks::FromZxTime(reference_time);
stream_position_samples_ = media_time;
SchedulePumpSamples(base::TimeTicks::Now());
});
} else {
SchedulePumpSamples(now);
}
}
timer_.Start(FROM_HERE, void AudioOutputStreamFuchsia::SchedulePumpSamples(base::TimeTicks now) {
GetCurrentStreamTime() - base::TimeTicks::Now() - base::TimeTicks next_pump_time = GetCurrentStreamTime() - min_lead_time_ -
parameters_.GetBufferDuration() / 2, parameters_.GetBufferDuration() / 2;
timer_.Start(FROM_HERE, next_pump_time - now,
base::Bind(&AudioOutputStreamFuchsia::PumpSamples, base::Bind(&AudioOutputStreamFuchsia::PumpSamples,
base::Unretained(this))); base::Unretained(this)));
} }
......
...@@ -5,8 +5,9 @@ ...@@ -5,8 +5,9 @@
#ifndef MEDIA_AUDIO_FUCHSIA_AUDIO_OUTPUT_STREAM_FUCHSIA_H_ #ifndef MEDIA_AUDIO_FUCHSIA_AUDIO_OUTPUT_STREAM_FUCHSIA_H_
#define MEDIA_AUDIO_FUCHSIA_AUDIO_OUTPUT_STREAM_FUCHSIA_H_ #define MEDIA_AUDIO_FUCHSIA_AUDIO_OUTPUT_STREAM_FUCHSIA_H_
#include <media/audio.h> #include <fuchsia/media/cpp/fidl.h>
#include "base/memory/shared_memory.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "media/audio/audio_io.h" #include "media/audio/audio_io.h"
#include "media/base/audio_parameters.h" #include "media/base/audio_parameters.h"
...@@ -19,7 +20,6 @@ class AudioOutputStreamFuchsia : public AudioOutputStream { ...@@ -19,7 +20,6 @@ class AudioOutputStreamFuchsia : public AudioOutputStream {
public: public:
// Caller must ensure that manager outlives the stream. // Caller must ensure that manager outlives the stream.
AudioOutputStreamFuchsia(AudioManagerFuchsia* manager, AudioOutputStreamFuchsia(AudioManagerFuchsia* manager,
const std::string& device_id,
const AudioParameters& parameters); const AudioParameters& parameters);
// AudioOutputStream interface. // AudioOutputStream interface.
...@@ -33,35 +33,53 @@ class AudioOutputStreamFuchsia : public AudioOutputStream { ...@@ -33,35 +33,53 @@ class AudioOutputStreamFuchsia : public AudioOutputStream {
private: private:
~AudioOutputStreamFuchsia() override; ~AudioOutputStreamFuchsia() override;
// Returns minimum |payload_buffer_| size for the current |min_lead_time_|.
size_t GetMinBufferSize();
// Allocates and maps |payload_buffer_|.
bool InitializePayloadBuffer();
base::TimeTicks GetCurrentStreamTime(); base::TimeTicks GetCurrentStreamTime();
// Updates |presentation_delay_ns_|. // Event handler for |audio_renderer_|.
bool UpdatePresentationDelay(); void OnMinLeadTimeChanged(int64_t min_lead_time);
// Error handler for |audio_renderer_|.
void OnRendererError();
// Requests data from AudioSourceCallback, passes it to the mixer and // Requests data from AudioSourceCallback, passes it to the mixer and
// schedules |timer_| for the next call. // schedules |timer_| for the next call.
void PumpSamples(); void PumpSamples();
// Schedules |timer_| to call PumpSamples() when appropriate for the next
// packet.
void SchedulePumpSamples(base::TimeTicks now);
AudioManagerFuchsia* manager_; AudioManagerFuchsia* manager_;
std::string device_id_;
AudioParameters parameters_; AudioParameters parameters_;
// These are used only in PumpSamples(). They are kept here to avoid // Audio renderer connection.
fuchsia::media::AudioRenderer2Ptr audio_renderer_;
// |audio_bus_| is used only in PumpSamples(). It is kept here to avoid
// reallocating the memory every time. // reallocating the memory every time.
std::unique_ptr<AudioBus> audio_bus_; std::unique_ptr<AudioBus> audio_bus_;
std::vector<float> buffer_;
fuchsia_audio_output_stream* stream_ = nullptr; base::SharedMemory payload_buffer_;
size_t payload_buffer_pos_ = 0;
AudioSourceCallback* callback_ = nullptr; AudioSourceCallback* callback_ = nullptr;
double volume_ = 1.0; double volume_ = 1.0;
base::TimeTicks started_time_; base::TimeTicks reference_time_;
int64_t stream_position_samples_ = 0;
int64_t stream_position_samples_;
// Total presentation delay for the stream. This value is returned by // Current min lead time for the stream. This value is updated by
// fuchsia_audio_output_stream_get_min_delay() // AudioRenderer::OnMinLeadTimeChanged event. Assume 50ms until we get the
zx_duration_t presentation_delay_ns_ = 0; // first OnMinLeadTimeChanged event.
base::TimeDelta min_lead_time_ = base::TimeDelta::FromMilliseconds(50);
// Timer that's scheduled to call PumpSamples(). // Timer that's scheduled to call PumpSamples().
base::OneShotTimer timer_; base::OneShotTimer timer_;
......
...@@ -206,6 +206,7 @@ fuchsia_sdk_fidl_pkg("media") { ...@@ -206,6 +206,7 @@ fuchsia_sdk_fidl_pkg("media") {
namespace_path = "fuchsia" namespace_path = "fuchsia"
sources = [ sources = [
"audio.fidl",
"audio_capturer.fidl", "audio_capturer.fidl",
"audio_renderer.fidl", "audio_renderer.fidl",
"media_renderer.fidl", "media_renderer.fidl",
......
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