blob: f7821b05759a6d2548202a947995d769c0c6c5a6 [file] [log] [blame]
// Copyright (c) 2012 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 CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_MIXER_MANAGER_H_
#define CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_MIXER_MANAGER_H_
#include <bitset>
#include <map>
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "content/common/content_export.h"
#include "media/audio/audio_device_description.h"
#include "media/base/audio_latency.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_renderer_mixer_pool.h"
#include "media/base/output_device_info.h"
namespace media {
class AudioRendererMixer;
class AudioRendererMixerInput;
class AudioRendererSink;
}
namespace content {
class AudioRendererSinkCache;
// Manages sharing of an AudioRendererMixer among AudioRendererMixerInputs based
// on their AudioParameters configuration. Inputs with the same AudioParameters
// configuration will share a mixer while a new AudioRendererMixer will be
// lazily created if one with the exact AudioParameters does not exist. When an
// AudioRendererMixer is returned by AudioRendererMixerInput, it will be deleted
// if its only other reference is held by AudioRendererMixerManager.
//
// There should only be one instance of AudioRendererMixerManager per render
// thread.
class CONTENT_EXPORT AudioRendererMixerManager
: public media::AudioRendererMixerPool {
public:
~AudioRendererMixerManager() final;
static std::unique_ptr<AudioRendererMixerManager> Create();
// Creates an AudioRendererMixerInput with the proper callbacks necessary to
// retrieve an AudioRendererMixer instance from AudioRendererMixerManager.
// |source_render_frame_id| refers to the RenderFrame containing the entity
// rendering the audio. Caller must ensure AudioRendererMixerManager outlives
// the returned input. |device_id| and |session_id| identify the output
// device to use. If |device_id| is empty and |session_id| is nonzero,
// output device associated with the opened input device designated by
// |session_id| is used. Otherwise, |session_id| is ignored.
media::AudioRendererMixerInput* CreateInput(
int source_render_frame_id,
int session_id,
const std::string& device_id,
media::AudioLatency::LatencyType latency);
// AudioRendererMixerPool implementation.
media::AudioRendererMixer* GetMixer(
int source_render_frame_id,
const media::AudioParameters& input_params,
media::AudioLatency::LatencyType latency,
const std::string& device_id,
media::OutputDeviceStatus* device_status) final;
void ReturnMixer(media::AudioRendererMixer* mixer) final;
media::OutputDeviceInfo GetOutputDeviceInfo(
int source_render_frame_id,
int session_id,
const std::string& device_id) final;
protected:
explicit AudioRendererMixerManager(
std::unique_ptr<AudioRendererSinkCache> sink_cache);
private:
friend class AudioRendererMixerManagerTest;
// Define a key so that only those AudioRendererMixerInputs from the same
// RenderView, AudioParameters and output device can be mixed together.
struct MixerKey {
MixerKey(int source_render_frame_id,
const media::AudioParameters& params,
media::AudioLatency::LatencyType latency,
const std::string& device_id);
MixerKey(const MixerKey& other);
int source_render_frame_id;
media::AudioParameters params;
media::AudioLatency::LatencyType latency;
std::string device_id;
};
// Custom compare operator for the AudioRendererMixerMap. Allows reuse of
// mixers where only irrelevant keys mismatch.
struct MixerKeyCompare {
bool operator()(const MixerKey& a, const MixerKey& b) const {
if (a.source_render_frame_id != b.source_render_frame_id)
return a.source_render_frame_id < b.source_render_frame_id;
if (a.params.channels() != b.params.channels())
return a.params.channels() < b.params.channels();
if (a.latency != b.latency)
return a.latency < b.latency;
// TODO(olka) add buffer duration comparison for LATENCY_EXACT_MS when
// adding support for it.
DCHECK_NE(media::AudioLatency::LATENCY_EXACT_MS, a.latency);
// Ignore effects(), format(), and frames_per_buffer(), these parameters
// do not affect mixer reuse. All AudioRendererMixer units disable FIFO,
// so frames_per_buffer() can be safely ignored.
if (a.params.channel_layout() != b.params.channel_layout())
return a.params.channel_layout() < b.params.channel_layout();
if (media::AudioDeviceDescription::IsDefaultDevice(a.device_id) &&
media::AudioDeviceDescription::IsDefaultDevice(b.device_id)) {
// Both device IDs represent the same default device => do not compare
// them.
return false;
}
return a.device_id < b.device_id;
}
};
// Map of MixerKey to <AudioRendererMixer, Count>. Count allows
// AudioRendererMixerManager to keep track explicitly (v.s. RefCounted which
// is implicit) of the number of outstanding AudioRendererMixers.
struct AudioRendererMixerReference {
media::AudioRendererMixer* mixer;
int ref_count;
// Mixer sink pointer, to remove a sink from cache upon mixer destruction.
const media::AudioRendererSink* sink_ptr;
};
using AudioRendererMixerMap =
std::map<MixerKey, AudioRendererMixerReference, MixerKeyCompare>;
// Active mixers.
AudioRendererMixerMap mixers_;
base::Lock mixers_lock_;
// Mixer sink cache.
const std::unique_ptr<AudioRendererSinkCache> sink_cache_;
// Map of the output latencies encountered throughout mixer manager lifetime.
// Used for UMA histogram logging.
std::bitset<media::AudioLatency::LATENCY_COUNT> latency_map_;
DISALLOW_COPY_AND_ASSIGN(AudioRendererMixerManager);
};
} // namespace content
#endif // CONTENT_RENDERER_MEDIA_AUDIO_RENDERER_MIXER_MANAGER_H_