blob: d3357b22b1b32f68013824a4d8bf03bb48f834a0 [file] [log] [blame]
// Copyright 2018 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.
#pragma once
#include <fbl/macros.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/unique_ptr.h>
#include <utility>
#include "usb-audio.h"
#include "usb-audio-units.h"
namespace audio {
namespace usb {
class UsbAudioControlInterface;
// A small container class used by the audio control interface for describing a
// path through the unit/terminal graph from host to pin (or vice-versa)
class AudioPath : public fbl::DoublyLinkedListable<fbl::unique_ptr<AudioPath>> {
public:
Direction direction() const { return direction_; }
const Terminal& stream_terminal() const {
// If we do not have a stashed pointer to our terminal yet, then someone
// is calling this accessor before Setup completed successfully. This
// should never happen.
ZX_DEBUG_ASSERT(stream_terminal_ != nullptr);
return *stream_terminal_;
}
bool has_gain() const { return feature_unit_ && feature_unit_->has_vol(); }
bool has_agc() const { return feature_unit_ && feature_unit_->has_agc(); }
bool has_mute() const { return feature_unit_ && feature_unit_->has_mute(); }
float cur_gain() const { return feature_unit_ ? feature_unit_->vol_cur_db() : 0.0f; }
float min_gain() const { return feature_unit_ ? feature_unit_->vol_min_db() : 0.0f; }
float max_gain() const { return feature_unit_ ? feature_unit_->vol_max_db() : 0.0f; }
float gain_res() const { return feature_unit_ ? feature_unit_->vol_res_db() : 0.0f; }
bool cur_agc() const { return feature_unit_ ? feature_unit_->agc_cur() : false; }
bool cur_mute() const { return feature_unit_ ? feature_unit_->mute_cur() : false; }
float SetGain(const usb_protocol_t& proto, float db) {
return feature_unit_ ? feature_unit_->SetVol(proto, db) : 0.0f;
}
bool SetMute(const usb_protocol_t& proto, bool mute) {
return feature_unit_ ? feature_unit_->SetMute(proto, mute) : false;
}
bool SetAgc(const usb_protocol_t& proto, bool enabled) {
return feature_unit_ ? feature_unit_->SetAgc(proto, enabled) : false;
}
private:
friend class fbl::unique_ptr<AudioPath>;
friend class UsbAudioControlInterface;
// Methods use by the audio control interface class to build audio paths
// during its walk of the unit/terminal graph. Basically, the control
// interface class calls...
//
// 1) 'Create' when it finds what looks like a valid path during its recursive
// walk of the graph.
// 2) 'AddUnit' as it unwinds from the walk in order to store references
// which form the path in the proper order inside of the path.
// 3) 'Setup' when it is finished in order to sanity check the path and to
// stash pointers to important elements, such as the stream terminal
// node and the feature unit node (if found).
//
static fbl::unique_ptr<AudioPath> Create(uint32_t unit_count);
void AddUnit(uint32_t ndx, fbl::RefPtr<AudioUnit> unit);
zx_status_t Setup(const usb_protocol_t& proto);
AudioPath(fbl::unique_ptr<fbl::RefPtr<AudioUnit>[]> units, uint32_t unit_count)
: units_(std::move(units)), unit_count_(unit_count) {}
~AudioPath() {}
DISALLOW_COPY_ASSIGN_AND_MOVE(AudioPath);
const fbl::unique_ptr<fbl::RefPtr<AudioUnit>[]> units_;
const uint32_t unit_count_;
Direction direction_ = Direction::Unknown;
// Note: Strictly speaking, these cached references do not have to be
// RefPtrs. In theory, the members of units_ should always outlive these
// cache references. This said, the cost of holding an extra reference on
// the objects is basically zero, and storing the pointers internally as
// RefPtr<>s makes it easy to know that this is safe from a lifecycle
// perspective, if perhaps a tiny bit paranoid.
fbl::RefPtr<const Terminal> stream_terminal_;
fbl::RefPtr<FeatureUnit> feature_unit_;
};
} // namespace usb
} // namespace audio