blob: 4b508080d879df50f14e475a6319d7e76bf9f0e5 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 SRC_MEDIA_AUDIO_AUDIO_CORE_AUDIO_DEVICE_MANAGER_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_AUDIO_DEVICE_MANAGER_H_
#include <fuchsia/media/cpp/fidl.h>
#include <lib/async/cpp/task.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fit/function.h>
#include <lib/syslog/cpp/macros.h>
#include <memory>
#include <unordered_map>
#include <fbl/intrusive_double_list.h>
#include <fbl/ref_ptr.h>
#include "src/media/audio/audio_core/audio_device.h"
#include "src/media/audio/audio_core/audio_driver.h"
#include "src/media/audio/audio_core/audio_input.h"
#include "src/media/audio/audio_core/audio_output.h"
#include "src/media/audio/audio_core/base_renderer.h"
#include "src/media/audio/audio_core/device_registry.h"
#include "src/media/audio/audio_core/plug_detector.h"
#include "src/media/audio/audio_core/route_graph.h"
#include "src/media/audio/audio_core/threading_model.h"
namespace media::audio {
class BaseCapturer;
class SystemGainMuteProvider;
class AudioDeviceManager : public fuchsia::media::AudioDeviceEnumerator, public DeviceRegistry {
public:
AudioDeviceManager(ThreadingModel& threading_model, std::unique_ptr<PlugDetector> plug_detector,
RouteGraph& route_graph, LinkMatrix& link_matrix,
ProcessConfig& process_config);
~AudioDeviceManager();
fidl::InterfaceRequestHandler<fuchsia::media::AudioDeviceEnumerator> GetFidlRequestHandler() {
return bindings_.GetHandler(this);
}
ThreadingModel& threading_model() { return threading_model_; }
// Initialize the input/output manager.
zx_status_t Init();
// Blocking call. Called by the service, once, when it is time to shutdown the service
// implementation. While this function is blocking, it must never block for long. Our process is
// going away; this is our last chance to perform a clean shutdown. If an unclean shutdown must
// be performed in order to implode in a timely fashion, so be it.
//
// Shutdown must be idempotent and safe to call from this object's destructor (although this
// should never be necessary). If a shutdown called from this destructor must do real work,
// something has gone Very Seriously Wrong.
void Shutdown();
// Sends an update message to each effect with the name 'instance_name' across all devices.
// If 'persist' is true, the effect update is persisted and applied to new devices as they are
// plugged. Only the latest update will be persisted for each 'instance_name'.
//
// Returns UpdateEffectError::INVALID_CONFIG if any effect matching 'instance_name' is found, but
// rejects 'message'. Returns UpdateEffectError::NOT_FOUND if no effect is found across any
// device. Returns success if at least one effect named 'instance_name' has accepted 'message'
// without any other effects matching 'effect_name' rejecting the 'message'.
fit::promise<void, fuchsia::media::audio::UpdateEffectError> UpdateEffect(
const std::string& instance_name, const std::string& message, bool persist = false);
// Sends an update message to the effect specified by 'instance_name' for the device specified by
// 'device_id'.
//
// Return values match those of 'UpdateEffect' above, with the addition of an
// UpdateEffectError::NOT_FOUND if the device specified by 'device_id' is not found.
fit::promise<void, fuchsia::media::audio::UpdateEffectError> UpdateDeviceEffect(
const std::string device_id, const std::string& instance_name, const std::string& message);
fit::promise<void, zx_status_t> UpdatePipelineConfig(const std::string device_id,
const PipelineConfig& config,
const VolumeCurve& volume_curve);
// |media::audio::DeviceRegistry|
void AddDevice(const std::shared_ptr<AudioDevice>& device) override;
void ActivateDevice(const std::shared_ptr<AudioDevice>& device) override;
void RemoveDevice(const std::shared_ptr<AudioDevice>& device) override;
void OnPlugStateChanged(const std::shared_ptr<AudioDevice>& device, bool plugged,
zx::time plug_time) override;
std::vector<fuchsia::media::AudioDeviceInfo> GetDeviceInfos() override;
// |fuchsia::media::AudioDeviceEnumerator|
void GetDevices(GetDevicesCallback cbk) final;
void GetDeviceGain(uint64_t device_token, GetDeviceGainCallback cbk) final;
void SetDeviceGain(uint64_t device_token, fuchsia::media::AudioGainInfo gain_info,
fuchsia::media::AudioGainValidFlags) final;
void GetDefaultInputDevice(GetDefaultInputDeviceCallback cbk) final;
void GetDefaultOutputDevice(GetDefaultOutputDeviceCallback cbk) final;
void AddDeviceByChannel(::zx::channel device_channel, std::string device_name,
bool is_input) final;
void AddDeviceByChannel2(
std::string device_name, bool is_input,
fidl::InterfaceHandle<fuchsia::hardware::audio::StreamConfig> channel) final;
void AddDeviceByVersion(zx::channel device_channel, std::string device_name, bool is_input,
AudioDriverVersion version);
private:
// Find the most-recently plugged device (per type: input or output) excluding throttle_output. If
// allow_unplugged, return the most-recently UNplugged device if no plugged devices are found --
// otherwise return nullptr.
std::shared_ptr<AudioDevice> FindLastPlugged(AudioObject::Type type,
bool allow_unplugged = false);
std::shared_ptr<AudioOutput> FindLastPluggedOutput(bool allow_unplugged = false) {
auto dev = FindLastPlugged(AudioObject::Type::Output, allow_unplugged);
FX_DCHECK(!dev || (dev->type() == AudioObject::Type::Output));
return std::static_pointer_cast<AudioOutput>(std::move(dev));
}
std::shared_ptr<AudioInput> FindLastPluggedInput(bool allow_unplugged = false) {
auto dev = FindLastPlugged(AudioObject::Type::Input, allow_unplugged);
FX_DCHECK(!dev || (dev->type() == AudioObject::Type::Input));
return std::static_pointer_cast<AudioInput>(std::move(dev));
}
// Methods to handle routing policy -- when an existing device is unplugged or completely removed,
// or when a new device is plugged or added to the system.
void OnDeviceUnplugged(const std::shared_ptr<AudioDevice>& device, zx::time plug_time);
void OnDevicePlugged(const std::shared_ptr<AudioDevice>& device, zx::time plug_time);
// Send notification to users that this device's gain settings have changed.
void NotifyDeviceGainChanged(const AudioDevice& device);
// Re-evaluate which device is the default. Notify users, if this has changed.
void UpdateDefaultDevice(bool input);
ThreadingModel& threading_model_;
RouteGraph& route_graph_;
std::unique_ptr<PlugDetector> plug_detector_;
LinkMatrix& link_matrix_;
ProcessConfig& process_config_;
// The set of AudioDeviceEnumerator clients we are currently tending to.
fidl::BindingSet<fuchsia::media::AudioDeviceEnumerator> bindings_;
// Our sets of currently active audio devices, AudioCapturers, and AudioRenderers.
//
// These must only be manipulated on main message loop thread. No synchronization should be
// needed.
// These maps are keyed on device token.
std::unordered_map<uint64_t, std::shared_ptr<AudioDevice>> devices_pending_init_;
std::unordered_map<uint64_t, std::shared_ptr<AudioDevice>> devices_;
uint64_t default_output_token_ = ZX_KOID_INVALID;
uint64_t default_input_token_ = ZX_KOID_INVALID;
// Persisted effects updates. Mapping from instant_name to message.
std::unordered_map<std::string, std::string> persisted_effects_updates_;
};
} // namespace media::audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_AUDIO_DEVICE_MANAGER_H_