// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_
#define CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_
#include <memory>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "chromeos/ash/services/libassistant/public/mojom/audio_output_delegate.mojom-forward.h"
#include "chromeos/assistant/internal/libassistant/shared_headers.h"
#include "media/base/audio_block_fifo.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_sink.h"
#include "media/mojo/mojom/audio_stream_factory.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "services/audio/public/cpp/output_device.h"
#include "services/media_session/public/mojom/media_session.mojom.h"
namespace ash::libassistant {
class AudioDeviceOwner : public media::AudioRendererSink::RenderCallback,
media_session::mojom::MediaSessionObserver {
public:
explicit AudioDeviceOwner(const std::string& device_id);
AudioDeviceOwner(const AudioDeviceOwner&) = delete;
AudioDeviceOwner& operator=(const AudioDeviceOwner&) = delete;
~AudioDeviceOwner() override;
void Start(
mojom::AudioOutputDelegate* audio_output_delegate,
assistant_client::AudioOutput::Delegate* delegate,
mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory,
const assistant_client::OutputStreamFormat& format);
void Stop();
// media_session::mojom::MediaSessionObserver overrides:
void MediaSessionInfoChanged(
media_session::mojom::MediaSessionInfoPtr info) override;
void MediaSessionMetadataChanged(
const std::optional<::media_session::MediaMetadata>& metadata) override {}
void MediaSessionActionsChanged(
const std::vector<media_session::mojom::MediaSessionAction>& action)
override {}
void MediaSessionImagesChanged(
const base::flat_map<media_session::mojom::MediaSessionImageType,
std::vector<::media_session::MediaImage>>& images)
override {}
void MediaSessionPositionChanged(
const std::optional<::media_session::MediaPosition>& position) override {}
// media::AudioRenderSink::RenderCallback overrides:
int Render(base::TimeDelta delay,
base::TimeTicks delay_timestamp,
const media::AudioGlitchInfo& glitch_info,
media::AudioBus* dest) override;
void OnRenderError() override;
void SetDelegate(assistant_client::AudioOutput::Delegate* delegate);
private:
void StartDevice(
mojo::PendingRemote<media::mojom::AudioStreamFactory> stream_factory,
mojom::AudioOutputDelegate* audio_output_delegate);
// Requests assistant to fill buffer with more data.
void ScheduleFillLocked(const base::TimeTicks& time);
// Callback for assistant to notify that it completes the filling.
void BufferFillDone(int num_bytes);
base::Lock lock_;
std::unique_ptr<media::AudioBlockFifo> audio_fifo_ GUARDED_BY(lock_);
// Whether assistant is filling the buffer -- delegate_->FillBuffer is called
// and BufferFillDone() is not called yet.
bool is_filling_ GUARDED_BY(lock_) = false;
media::AudioParameters audio_param_ GUARDED_BY(lock_);
std::vector<uint8_t> audio_data_ GUARDED_BY(lock_);
// Stores audio frames generated by assistant.
assistant_client::OutputStreamFormat format_ GUARDED_BY(lock_);
raw_ptr<assistant_client::AudioOutput::Delegate> delegate_ GUARDED_BY(lock_);
// Audio output device id used for output.
std::string device_id_ GUARDED_BY_CONTEXT(sequence_checker_);
std::unique_ptr<audio::OutputDevice> output_device_
GUARDED_BY_CONTEXT(sequence_checker_);
mojo::Receiver<media_session::mojom::MediaSessionObserver> session_receiver_{
this};
// The callbacks from |RenderCallback| are called on a different sequence,
// so this sequence checker prevents the other methods from being called on
// the render sequence.
SEQUENCE_CHECKER(sequence_checker_);
};
} // namespace ash::libassistant
#endif // CHROMEOS_ASH_SERVICES_LIBASSISTANT_AUDIO_AUDIO_DEVICE_OWNER_H_