From b7a9ec9ac994fefc3ef476533f6b76eef1f0a947 Mon Sep 17 00:00:00 2001 From: wutao Date: Thu, 30 Aug 2018 05:13:14 +0000 Subject: [PATCH] Assistant: Decodes streaming data This patch implements the decoding service for streaming data. The underlining decoding method has been changed, therefore the decoded output are in interleaved data format, not as AudioBuffer. Bug: b/113131759, b/80315134 Test: manual. Change-Id: I5b382caa33a1bd60a8b262847b76498280c3ed90 Reviewed-on: https://chromium-review.googlesource.com/1192685 Reviewed-by: Sam McNally Reviewed-by: Xiaohui Chen Commit-Queue: Tao Wu Cr-Commit-Position: refs/heads/master@{#587447} --- .../services/assistant/audio_decoder/BUILD.gn | 2 + .../assistant/audio_decoder/README.md | 3 + .../audio_decoder/assistant_audio_decoder.cc | 167 +++++++++--------- .../audio_decoder/assistant_audio_decoder.h | 52 +++--- .../assistant_audio_decoder_factory.cc | 10 +- .../assistant_audio_decoder_factory.h | 3 +- .../assistant_audio_decoder_service.cc | 3 +- .../audio_decoder/ipc_data_source.cc | 86 +++++++++ .../assistant/audio_decoder/ipc_data_source.h | 63 +++++++ .../services/assistant/public/mojom/BUILD.gn | 1 - .../mojom/assistant_audio_decoder.mojom | 40 ++--- 11 files changed, 293 insertions(+), 137 deletions(-) create mode 100644 chromeos/services/assistant/audio_decoder/README.md create mode 100644 chromeos/services/assistant/audio_decoder/ipc_data_source.cc create mode 100644 chromeos/services/assistant/audio_decoder/ipc_data_source.h diff --git a/chromeos/services/assistant/audio_decoder/BUILD.gn b/chromeos/services/assistant/audio_decoder/BUILD.gn index 0dd692d4412b80..6c6a3bf7f2373d 100644 --- a/chromeos/services/assistant/audio_decoder/BUILD.gn +++ b/chromeos/services/assistant/audio_decoder/BUILD.gn @@ -16,6 +16,8 @@ source_set("lib") { "assistant_audio_decoder_factory.h", "assistant_audio_decoder_service.cc", "assistant_audio_decoder_service.h", + "ipc_data_source.cc", + "ipc_data_source.h", ] deps = [ diff --git a/chromeos/services/assistant/audio_decoder/README.md b/chromeos/services/assistant/audio_decoder/README.md new file mode 100644 index 00000000000000..3a4b3370f7ecfb --- /dev/null +++ b/chromeos/services/assistant/audio_decoder/README.md @@ -0,0 +1,3 @@ +This directory contains audio decoder service for the Chrome OS native Assistant +to decode the audio output by Libassistant, before connecting to AudioService. +We cannot use the standard media service, which does not have the demuxer. diff --git a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.cc b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.cc index 30d6b9c7bb64e0..2d9da813aa8d01 100644 --- a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.cc +++ b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.cc @@ -4,115 +4,118 @@ #include "chromeos/services/assistant/audio_decoder/assistant_audio_decoder.h" -#include "base/bind_helpers.h" -#include "media/base/audio_buffer.h" -#include "media/base/media_log.h" -#include "media/base/media_tracks.h" -#include "media/base/stream_parser_buffer.h" -#include "media/base/text_track_config.h" -#include "media/filters/ffmpeg_audio_decoder.h" -#include "media/formats/mpeg/mpeg1_audio_stream_parser.h" -#include "media/mojo/common/media_type_converters.h" -#include "media/mojo/interfaces/media_types.mojom.h" +#include "base/threading/thread.h" +#include "chromeos/services/assistant/audio_decoder/ipc_data_source.h" +#include "media/base/audio_bus.h" +#include "media/base/data_source.h" +#include "media/filters/audio_file_reader.h" +#include "media/filters/blocking_url_protocol.h" #include "services/service_manager/public/cpp/service_context_ref.h" namespace chromeos { namespace assistant { +namespace { + +// Preferred bytes per sample when get interleaved data from AudioBus. +constexpr int kBytesPerSample = 2; + +void OnError(bool* succeeded) { + *succeeded = false; +} + +} // namespace + AssistantAudioDecoder::AssistantAudioDecoder( std::unique_ptr service_ref, - mojom::AssistantAudioDecoderClientPtr client) + mojom::AssistantAudioDecoderClientPtr client, + mojom::AssistantMediaDataSourcePtr data_source) : service_ref_(std::move(service_ref)), client_(std::move(client)), task_runner_(base::ThreadTaskRunnerHandle::Get()), - media_log_(std::make_unique()), - parser_(std::make_unique()), - decoder_(std::make_unique(task_runner_, - media_log_.get())) { - parser_->Init( - /*init_cb=*/base::DoNothing(), - base::BindRepeating(&AssistantAudioDecoder::OnNewConfigs, - base::Unretained(this)), - base::BindRepeating(&AssistantAudioDecoder::OnNewBuffers, - base::Unretained(this)), - /*ignore_text_tracks=*/true, - /*encrypted_media_init_data_cb=*/base::DoNothing(), - /*new_segment_cb=*/base::DoNothing(), - /*end_of_segment_cb=*/base::DoNothing(), media_log_.get()); + media_thread_(std::make_unique("media_thread")), + data_source_(std::make_unique(std::move(data_source))) { + CHECK(media_thread_->Start()); } AssistantAudioDecoder::~AssistantAudioDecoder() = default; -void AssistantAudioDecoder::Decode(const std::vector& data) { - if (!parser_->Parse(data.data(), data.size())) - client_->OnDecoderError(); +void AssistantAudioDecoder::Decode() { + media_thread_->task_runner()->PostTask( + FROM_HERE, base::BindOnce(&AssistantAudioDecoder::DecodeOnMediaThread, + base::Unretained(this))); } -bool AssistantAudioDecoder::OnNewConfigs( - std::unique_ptr tracks, - const media::StreamParser::TextTrackConfigMap& text_configs) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - const media::StreamParser::TrackId track_id = - tracks->tracks().back()->bytestream_track_id(); - - // Initialize decoder. - const media::AudioDecoderConfig& config = tracks->getAudioConfig(track_id); - decoder_->Initialize( - config, /*cdm_context=*/nullptr, - base::BindRepeating(&AssistantAudioDecoder::OnDecoderInitialized, - base::Unretained(this), config), - base::BindRepeating(&AssistantAudioDecoder::OnDecodeOutput, - base::Unretained(this)), - /*waiting_for_decryption_key_cb=*/base::NullCallback()); - return true; +void AssistantAudioDecoder::OpenDecoder(OpenDecoderCallback callback) { + media_thread_->task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&AssistantAudioDecoder::OpenDecoderOnMediaThread, + base::Unretained(this), std::move(callback))); } -bool AssistantAudioDecoder::OnNewBuffers( - const media::StreamParser::BufferQueueMap& buffer_queue_map) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - int new_buffer_size = 0; - for (const auto& queue_map : buffer_queue_map) { - new_buffer_size += queue_map.second.size(); - for (const auto& buffer : queue_map.second) - parsed_buffers_.push_back(buffer); +void AssistantAudioDecoder::OpenDecoderOnMediaThread( + OpenDecoderCallback callback) { + bool read_ok = true; + protocol_ = std::make_unique( + data_source_.get(), base::BindRepeating(&OnError, &read_ok)); + decoder_ = std::make_unique(protocol_.get()); + + if (!decoder_->Open() || !read_ok) { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&AssistantAudioDecoder::OnDecoderErrorOnThread, + base::Unretained(this), std::move(callback))); + return; } - client_->OnNewBuffers(new_buffer_size); - DecodeNow(); - return true; -} -void AssistantAudioDecoder::OnDecoderInitialized( - media::AudioDecoderConfig config, - bool success) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - client_->OnDecoderInitialized(success, config.samples_per_second(), - config.channels()); + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&AssistantAudioDecoder::OnDecoderInitializedOnThread, + base::Unretained(this), std::move(callback), + decoder_->sample_rate(), decoder_->channels())); } -void AssistantAudioDecoder::OnDecodeOutput( - const scoped_refptr& decoded) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - client_->OnBufferDecoded(media::mojom::AudioBuffer::From(decoded)); - DecodeNow(); -} +void AssistantAudioDecoder::DecodeOnMediaThread() { + std::vector> decoded_audio_packets; + // Experimental number of decoded packets before sending to |client_|. + constexpr int kPacketsToRead = 128; + decoder_->Read(&decoded_audio_packets, kPacketsToRead); -void AssistantAudioDecoder::OnDecodeStatus(media::DecodeStatus status) { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - if (status != media::DecodeStatus::OK) - client_->OnDecoderError(); + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&AssistantAudioDecoder::OnBufferDecodedOnThread, + base::Unretained(this), std::move(decoded_audio_packets))); } -void AssistantAudioDecoder::DecodeNow() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - if (!parsed_buffers_.empty()) { - const auto& data = parsed_buffers_.front(); - DCHECK_NE(data->timestamp(), media::kNoTimestamp); +void AssistantAudioDecoder::OnDecoderInitializedOnThread( + OpenDecoderCallback callback, + int sample_rate, + int channels) { + std::move(callback).Run(/*success=*/true, kBytesPerSample, sample_rate, + channels); +} - decoder_->Decode(data, - base::BindRepeating(&AssistantAudioDecoder::OnDecodeStatus, - base::Unretained(this))); - parsed_buffers_.pop_front(); +void AssistantAudioDecoder::OnBufferDecodedOnThread( + const std::vector>& + decoded_audio_packets) { + std::vector> buffers; + for (const auto& audio_bus : decoded_audio_packets) { + const int bytes_to_alloc = + audio_bus->frames() * kBytesPerSample * audio_bus->channels(); + std::vector buffer(bytes_to_alloc); + audio_bus->ToInterleaved(audio_bus->frames(), kBytesPerSample, + buffer.data()); + buffers.emplace_back(buffer); } + client_->OnNewBuffers(buffers); +} + +void AssistantAudioDecoder::OnDecoderErrorOnThread( + OpenDecoderCallback callback) { + std::move(callback).Run(/*success=*/false, + /*bytes_per_sample=*/0, + /*samples_per_second=*/0, + /*channels=*/0); } } // namespace assistant diff --git a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.h b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.h index e875a8c312bb62..cbb45376da3f35 100644 --- a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.h +++ b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder.h @@ -7,18 +7,14 @@ #include -#include "base/containers/circular_deque.h" #include "base/macros.h" +#include "base/synchronization/lock.h" #include "chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom.h" -#include "media/base/stream_parser.h" namespace media { -class AudioBuffer; -class MediaLog; -class MediaTracks; -class MPEG1AudioStreamParser; -class FFmpegAudioDecoder; -class StreamParserBuffer; +class AudioFileReader; +class AudioBus; +class DataSource; } // namespace media namespace service_manager { @@ -32,36 +28,36 @@ class AssistantAudioDecoder : public mojom::AssistantAudioDecoder { public: AssistantAudioDecoder( std::unique_ptr service_ref, - mojom::AssistantAudioDecoderClientPtr client); + mojom::AssistantAudioDecoderClientPtr client, + mojom::AssistantMediaDataSourcePtr data_source); ~AssistantAudioDecoder() override; // Called by |client_| on main thread. - void Decode(const std::vector& data) override; + void OpenDecoder(OpenDecoderCallback callback) override; + void Decode() override; private: - // Called by |parser_| on main thread. - bool OnNewConfigs( - std::unique_ptr tracks, - const media::StreamParser::TextTrackConfigMap& text_configs); - bool OnNewBuffers( - const media::StreamParser::BufferQueueMap& buffer_queue_map); + // Calls |decoder_| to decode on media thread. + void OpenDecoderOnMediaThread(OpenDecoderCallback callback); + void DecodeOnMediaThread(); - // Called by |decoder_| on main thread. - void OnDecoderInitialized(media::AudioDecoderConfig config, bool success); - void OnDecodeOutput(const scoped_refptr& decoded); - void OnDecodeStatus(media::DecodeStatus status); - - // Called by |OnNewBuffers()| and |OnDecodeOutput()| on main thread. - void DecodeNow(); + // Calls |client_| methods on main thread. + void OnDecoderInitializedOnThread(OpenDecoderCallback callback, + int sample_rate, + int channels); + void OnDecoderErrorOnThread(OpenDecoderCallback callback); + void OnBufferDecodedOnThread( + const std::vector>& + decoded_audio_buffers); const std::unique_ptr service_ref_; mojom::AssistantAudioDecoderClientPtr client_; scoped_refptr task_runner_; - std::unique_ptr media_log_; - std::unique_ptr parser_; - std::unique_ptr decoder_; - base::circular_deque> - parsed_buffers_; + + std::unique_ptr data_source_; + std::unique_ptr protocol_; + std::unique_ptr decoder_; + std::unique_ptr media_thread_; DISALLOW_COPY_AND_ASSIGN(AssistantAudioDecoder); }; diff --git a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_factory.cc b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_factory.cc index f6c624c3b6a12c..856eaedf9d45cd 100644 --- a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_factory.cc +++ b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_factory.cc @@ -18,10 +18,12 @@ AssistantAudioDecoderFactory::~AssistantAudioDecoderFactory() = default; void AssistantAudioDecoderFactory::CreateAssistantAudioDecoder( mojom::AssistantAudioDecoderRequest request, - mojom::AssistantAudioDecoderClientPtr client) { - mojo::MakeStrongBinding(std::make_unique( - service_ref_->Clone(), std::move(client)), - std::move(request)); + mojom::AssistantAudioDecoderClientPtr client, + mojom::AssistantMediaDataSourcePtr data_source) { + mojo::MakeStrongBinding( + std::make_unique( + service_ref_->Clone(), std::move(client), std::move(data_source)), + std::move(request)); } } // namespace assistant diff --git a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_factory.h b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_factory.h index 38717662a0caa8..de6b815096e50e 100644 --- a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_factory.h +++ b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_factory.h @@ -24,7 +24,8 @@ class AssistantAudioDecoderFactory // mojom::AssistantAudioDecoderFactory: void CreateAssistantAudioDecoder( mojom::AssistantAudioDecoderRequest request, - mojom::AssistantAudioDecoderClientPtr client) override; + mojom::AssistantAudioDecoderClientPtr client, + mojom::AssistantMediaDataSourcePtr data_source) override; const std::unique_ptr service_ref_; diff --git a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_service.cc b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_service.cc index 7f82229bbad6d3..c3d4a947af17da 100644 --- a/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_service.cc +++ b/chromeos/services/assistant/audio_decoder/assistant_audio_decoder_service.cc @@ -36,7 +36,8 @@ void AssistantAudioDecoderService::OnStart() { ref_factory_ = std::make_unique( context()->CreateQuitClosure()); registry_.AddInterface( - base::BindRepeating(&OnAudioDecoderFactoryRequest, ref_factory_.get())); + base::BindRepeating(&OnAudioDecoderFactoryRequest, ref_factory_.get()), + base::ThreadTaskRunnerHandle::Get()); } void AssistantAudioDecoderService::OnBindInterface( diff --git a/chromeos/services/assistant/audio_decoder/ipc_data_source.cc b/chromeos/services/assistant/audio_decoder/ipc_data_source.cc new file mode 100644 index 00000000000000..f314fc9be86cc7 --- /dev/null +++ b/chromeos/services/assistant/audio_decoder/ipc_data_source.cc @@ -0,0 +1,86 @@ +// Copyright 2018 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 "chromeos/services/assistant/audio_decoder/ipc_data_source.h" + +#include "base/threading/thread_task_runner_handle.h" +#include "mojo/public/cpp/bindings/message.h" + +namespace chromeos { +namespace assistant { + +IPCDataSource::IPCDataSource( + mojom::AssistantMediaDataSourcePtr media_data_source) + : media_data_source_(std::move(media_data_source)), + utility_task_runner_(base::ThreadTaskRunnerHandle::Get()) { + DETACH_FROM_THREAD(data_source_thread_checker_); +} + +IPCDataSource::~IPCDataSource() { + DCHECK_CALLED_ON_VALID_THREAD(utility_thread_checker_); +} + +void IPCDataSource::Stop() { + DCHECK_CALLED_ON_VALID_THREAD(data_source_thread_checker_); +} + +void IPCDataSource::Abort() { + DCHECK_CALLED_ON_VALID_THREAD(data_source_thread_checker_); +} + +void IPCDataSource::Read(int64_t position, + int size, + uint8_t* destination, + const DataSource::ReadCB& callback) { + DCHECK_CALLED_ON_VALID_THREAD(data_source_thread_checker_); + + utility_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&IPCDataSource::ReadMediaData, base::Unretained(this), + destination, callback, size)); +} + +bool IPCDataSource::GetSize(int64_t* size_out) { + DCHECK_CALLED_ON_VALID_THREAD(data_source_thread_checker_); + *size_out = 0; + return false; +} + +bool IPCDataSource::IsStreaming() { + DCHECK_CALLED_ON_VALID_THREAD(data_source_thread_checker_); + return true; +} + +void IPCDataSource::SetBitrate(int bitrate) { + DCHECK_CALLED_ON_VALID_THREAD(data_source_thread_checker_); +} + +void IPCDataSource::ReadMediaData(uint8_t* destination, + const DataSource::ReadCB& callback, + int size) { + DCHECK_CALLED_ON_VALID_THREAD(utility_thread_checker_); + CHECK_GE(size, 0); + + media_data_source_->Read( + size, base::BindOnce(&IPCDataSource::ReadDone, base::Unretained(this), + destination, callback, size)); +} + +void IPCDataSource::ReadDone(uint8_t* destination, + const DataSource::ReadCB& callback, + int requested_size, + const std::vector& data) { + DCHECK_CALLED_ON_VALID_THREAD(utility_thread_checker_); + if (data.size() > requested_size) { + mojo::ReportBadMessage("IPCDataSource::ReadDone: Unexpected data size."); + callback.Run(0); + return; + } + + std::copy(data.begin(), data.end(), destination); + callback.Run(data.size()); +} + +} // namespace assistant +} // namespace chromeos diff --git a/chromeos/services/assistant/audio_decoder/ipc_data_source.h b/chromeos/services/assistant/audio_decoder/ipc_data_source.h new file mode 100644 index 00000000000000..f3995234f81074 --- /dev/null +++ b/chromeos/services/assistant/audio_decoder/ipc_data_source.h @@ -0,0 +1,63 @@ +// Copyright 2018 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. + +#ifndef CHROMEOS_SERVICES_ASSISTANT_AUDIO_DECODER_IPC_DATA_SOURCE_H_ +#define CHROMEOS_SERVICES_ASSISTANT_AUDIO_DECODER_IPC_DATA_SOURCE_H_ + +#include + +#include "base/threading/thread_checker.h" +#include "chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom.h" +#include "media/base/data_source.h" + +namespace base { +class TaskRunner; +} + +namespace chromeos { +namespace assistant { + +// Provides data source to the audio stream decoder. Class must be created and +// destroyed on a same thread. The thread must not be blocked for read +// operations to succeed. +class IPCDataSource : public media::DataSource { + public: + // May only be called on the utility thread. + explicit IPCDataSource(mojom::AssistantMediaDataSourcePtr media_data_source); + ~IPCDataSource() override; + + // media::DataSource implementation. The methods may be called on any single + // thread. First usage of these methods attaches a thread checker. + void Stop() override; + void Abort() override; + void Read(int64_t position, + int size, + uint8_t* destination, + const ReadCB& callback) override; + bool GetSize(int64_t* size_out) override; + bool IsStreaming() override; + void SetBitrate(int bitrate) override; + + private: + // Media data read helpers: must be run on the utility thread. + void ReadMediaData(uint8_t* destination, const ReadCB& callback, int size); + void ReadDone(uint8_t* destination, + const ReadCB& callback, + int requested_size, + const std::vector& data); + + mojom::AssistantMediaDataSourcePtr media_data_source_; + + scoped_refptr utility_task_runner_; + + THREAD_CHECKER(utility_thread_checker_); + + // Enforces that the DataSource methods are called on one other thread only. + THREAD_CHECKER(data_source_thread_checker_); +}; + +} // namespace assistant +} // namespace chromeos + +#endif // CHROMEOS_SERVICES_ASSISTANT_AUDIO_DECODER_IPC_DATA_SOURCE_H_ diff --git a/chromeos/services/assistant/public/mojom/BUILD.gn b/chromeos/services/assistant/public/mojom/BUILD.gn index baf378c38a737f..a01ba59c3a4994 100644 --- a/chromeos/services/assistant/public/mojom/BUILD.gn +++ b/chromeos/services/assistant/public/mojom/BUILD.gn @@ -13,7 +13,6 @@ mojom("mojom") { ] public_deps = [ - "//media/mojo/interfaces", "//mojo/public/mojom/base", "//services/identity/public/mojom", "//ui/accessibility/mojom", diff --git a/chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom b/chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom index 5c09f56a84c08e..009bb5b8edccfe 100644 --- a/chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom +++ b/chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom @@ -4,36 +4,36 @@ module chromeos.assistant.mojom; -import "media/mojo/interfaces/media_types.mojom"; - // A factory for creating an assistant audio decoder. interface AssistantAudioDecoderFactory { - // Creates an AssistantAudioDecoder. |client|'s methods will be called when - // certain events happen. + // Creates an AssistantAudioDecoder to decode audio stream data from + // |data_source|. + // |client|'s methods will be called when certain events happen. CreateAssistantAudioDecoder(AssistantAudioDecoder& audio_decoder, - AssistantAudioDecoderClient client); + AssistantAudioDecoderClient client, + AssistantMediaDataSource data_source); }; // Interface to communicate with assistant audio decoder service. interface AssistantAudioDecoder { - // Starts to parse and decode |data|. - Decode(array data); + // Reads the audio data format. + OpenDecoder() => (bool success, + int32 bytes_per_sample, + int32 samples_per_second, + int32 channels); + + // Reads the audio data and decodes. + Decode(); }; // Interface for assistant audio decoder service to call into client. interface AssistantAudioDecoderClient { - // Called when the decoder has been initialized. - OnDecoderInitialized(bool success, - int32 samples_per_second, - int32 channels); - - // Called when new buffers have been parsed. - // |total_frames| is the total number of new buffers. - OnNewBuffers(int32 total_frames); - - // Called when an audio buffer has been decoded. - OnBufferDecoded(media.mojom.AudioBuffer buffer); + // Called when new audio buffers have been decoded. + // |buffers| are in interleaved format. + OnNewBuffers(array> buffers); +}; - // Called when there is error. - OnDecoderError(); +// Interface used to read data from the calling process. +interface AssistantMediaDataSource { + Read(int32 size) => (array data); };