#ifndef SERVICES_AUDIO_LOOPBACK_STREAM_H_
#define SERVICES_AUDIO_LOOPBACK_STREAM_H_
#include <map>
#include <memory>
#include <optional>
#include <utility>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
#include "media/base/audio_parameters.h"
#include "media/mojo/mojom/audio_data_pipe.mojom.h"
#include "media/mojo/mojom/audio_input_stream.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/audio/input_controller.h"
#include "services/audio/input_sync_writer.h"
#include "services/audio/loopback_coordinator.h"
#include "services/audio/loopback_signal_provider.h"
namespace base {
class TickClock;
}
namespace media {
class AudioBus;
}
namespace audio {
class LoopbackStream final : public media::mojom::AudioInputStream {
public:
using CreatedCallback =
base::OnceCallback<void(media::mojom::ReadWriteAudioDataPipePtr)>;
using BindingLostCallback = base::OnceCallback<void(LoopbackStream*)>;
LoopbackStream(
CreatedCallback created_callback,
BindingLostCallback binding_lost_callback,
scoped_refptr<base::SequencedTaskRunner> loopback_task_runner,
mojo::PendingReceiver<media::mojom::AudioInputStream> receiver,
mojo::PendingRemote<media::mojom::AudioInputStreamClient> client,
mojo::PendingRemote<media::mojom::AudioInputStreamObserver> observer,
const media::AudioParameters& params,
uint32_t shared_memory_count,
LoopbackCoordinator* coordinator,
const base::UnguessableToken& group_id);
LoopbackStream(const LoopbackStream&) = delete;
LoopbackStream& operator=(const LoopbackStream&) = delete;
~LoopbackStream() final;
bool is_recording() const {
return loopback_signal_forwarder_ &&
loopback_signal_forwarder_->is_started();
}
void Record() final;
void SetVolume(double volume) final;
void set_clock_for_testing(const base::TickClock* clock) {
loopback_signal_forwarder_->set_clock_for_testing(clock);
}
void set_sync_writer_for_testing(
std::unique_ptr<InputController::SyncWriter> writer) {
loopback_signal_forwarder_->set_writer_for_testing(std::move(writer));
}
static constexpr double kMaxVolume = 2.0;
private:
void AddLoopbackSource(LoopbackSource* source);
void RemoveLoopbackSource(LoopbackSource* source);
class LoopbackSignalForwarder {
public:
LoopbackSignalForwarder(
scoped_refptr<base::SequencedTaskRunner> loopback_task_runner,
const media::AudioParameters& output_params,
std::unique_ptr<InputSyncWriter> writer,
LoopbackSignalProvider* loopback_signal_provider);
LoopbackSignalForwarder(const LoopbackSignalForwarder&) = delete;
LoopbackSignalForwarder& operator=(const LoopbackSignalForwarder&) = delete;
void set_clock_for_testing(const base::TickClock* clock) { clock_ = clock; }
void set_writer_for_testing(
std::unique_ptr<InputController::SyncWriter> writer) {
writer_ = std::move(writer);
}
bool is_started() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
return !!timer_;
}
const media::AudioParameters& output_params() const {
return output_params_;
}
void SetVolume(double volume);
void Start();
void InvalidateLoopbackSignalProvider();
private:
friend class base::DeleteHelper<LoopbackSignalForwarder>;
~LoopbackSignalForwarder();
void GenerateMoreAudio();
raw_ptr<const base::TickClock> clock_;
const scoped_refptr<base::SequencedTaskRunner> loopback_task_runner_;
const media::AudioParameters output_params_;
std::unique_ptr<InputController::SyncWriter> writer_;
base::Lock lock_;
double volume_ GUARDED_BY(lock_) = 1.0;
std::optional<base::DeadlineTimer> timer_;
base::TimeTicks first_generate_time_;
int64_t frames_elapsed_ = 0;
base::TimeTicks next_generate_time_;
const std::unique_ptr<media::AudioBus> mix_bus_;
raw_ptr<LoopbackSignalProvider> loopback_signal_provider_ GUARDED_BY(lock_);
SEQUENCE_CHECKER(control_sequence_);
};
void OnError();
BindingLostCallback binding_lost_callback_;
mojo::Receiver<media::mojom::AudioInputStream> receiver_;
mojo::Remote<media::mojom::AudioInputStreamClient> client_;
mojo::Remote<media::mojom::AudioInputStreamObserver> observer_;
LoopbackSignalProvider loopback_signal_provider_;
std::unique_ptr<LoopbackSignalForwarder, base::OnTaskRunnerDeleter>
loopback_signal_forwarder_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<LoopbackStream> weak_factory_{this};
};
}
#endif