#ifndef SERVICES_AUDIO_MIXING_GRAPH_IMPL_H_
#define SERVICES_AUDIO_MIXING_GRAPH_IMPL_H_
#include <map>
#include "base/gtest_prod_util.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "services/audio/mixing_graph.h"
namespace media {
class LoopbackAudioConverter;
}
namespace audio {
class MixingGraphImpl : public MixingGraph {
public:
using CreateConverterCallback =
base::RepeatingCallback<std::unique_ptr<media::LoopbackAudioConverter>(
const media::AudioParameters& input_params,
const media::AudioParameters& output_params)>;
MixingGraphImpl(const media::AudioParameters& output_params,
OnMoreDataCallback on_more_data_cb,
OnErrorCallback on_error_cb);
MixingGraphImpl(const media::AudioParameters& output_params,
OnMoreDataCallback on_more_data_cb,
OnErrorCallback on_error_cb,
CreateConverterCallback create_converter_cb);
~MixingGraphImpl() override;
std::unique_ptr<Input> CreateInput(
const media::AudioParameters& params) final;
void AddInput(Input* node) final;
void RemoveInput(Input* node) final;
int OnMoreData(base::TimeDelta delay,
base::TimeTicks delay_timestamp,
const media::AudioGlitchInfo& glitch_info,
media::AudioBus* dest) final;
void OnError(ErrorType type) final;
protected:
class OvertimeLogger;
media::LoopbackAudioConverter* FindOrAddConverter(
const media::AudioParameters& input_params,
const media::AudioParameters& output_params,
media::LoopbackAudioConverter* parent_converter);
class AudioConverterKey {
public:
explicit AudioConverterKey(const media::AudioParameters& params)
: sample_rate_(params.sample_rate()),
channel_layout_(params.channel_layout()),
channels_(params.channels()) {}
inline bool operator==(const AudioConverterKey& other) const {
return sample_rate_ == other.sample_rate_ &&
channel_layout_ == other.channel_layout_ &&
channels_ == other.channels_;
}
inline bool operator<(const AudioConverterKey& other) const {
if (sample_rate_ != other.sample_rate_)
return sample_rate_ < other.sample_rate_;
if (channel_layout_ != other.channel_layout_)
return channel_layout_ < other.channel_layout_;
return channels_ < other.channels_;
}
inline bool SameChannelSetup(const media::AudioParameters& params) const {
return channel_layout_ == params.channel_layout() &&
channels_ == params.channels();
}
inline void UpdateChannelSetup(const media::AudioParameters& params) {
channel_layout_ = params.channel_layout();
channels_ = params.channels();
}
inline int sample_rate() const { return sample_rate_; }
inline void set_sample_rate(int sample_rate) { sample_rate_ = sample_rate; }
private:
int sample_rate_;
media::ChannelLayout channel_layout_;
int channels_;
};
FRIEND_TEST_ALL_PREFIXES(MixingGraphImpl, AudioConverterKeySorting);
void Remove(const AudioConverterKey& key,
media::AudioConverter::InputCallback* input);
using AudioConverters =
std::map<AudioConverterKey,
std::unique_ptr<media::LoopbackAudioConverter>>;
SEQUENCE_CHECKER(owning_sequence_);
const media::AudioParameters output_params_;
const OnMoreDataCallback on_more_data_cb_;
const OnErrorCallback on_error_cb_;
const CreateConverterCallback create_converter_cb_;
const std::unique_ptr<OvertimeLogger> overtime_logger_;
base::Lock lock_;
AudioConverters converters_;
media::AudioConverter main_converter_;
};
}
#endif