1// Copyright 2018 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#pragma once 6 7#include <fbl/macros.h> 8#include <fbl/intrusive_double_list.h> 9#include <fbl/unique_ptr.h> 10 11#include "usb-audio.h" 12#include "usb-audio-units.h" 13 14namespace audio { 15namespace usb { 16 17class UsbAudioControlInterface; 18 19// A small container class used by the audio control interface for describing a 20// path through the unit/terminal graph from host to pin (or vice-versa) 21class AudioPath : public fbl::DoublyLinkedListable<fbl::unique_ptr<AudioPath>> { 22 public: 23 Direction direction() const { return direction_; } 24 const Terminal& stream_terminal() const { 25 // If we do not have a stashed pointer to our terminal yet, then someone 26 // is calling this accessor before Setup completed successfully. This 27 // should never happen. 28 ZX_DEBUG_ASSERT(stream_terminal_ != nullptr); 29 return *stream_terminal_; 30 } 31 32 bool has_gain() const { return feature_unit_ && feature_unit_->has_vol(); } 33 bool has_agc() const { return feature_unit_ && feature_unit_->has_agc(); } 34 bool has_mute() const { return feature_unit_ && feature_unit_->has_mute(); } 35 float cur_gain() const { return feature_unit_ ? feature_unit_->vol_cur_db() : 0.0f; } 36 float min_gain() const { return feature_unit_ ? feature_unit_->vol_min_db() : 0.0f; } 37 float max_gain() const { return feature_unit_ ? feature_unit_->vol_max_db() : 0.0f; } 38 float gain_res() const { return feature_unit_ ? feature_unit_->vol_res_db() : 0.0f; } 39 bool cur_agc() const { return feature_unit_ ? feature_unit_->agc_cur() : false; } 40 bool cur_mute() const { return feature_unit_ ? feature_unit_->mute_cur() : false; } 41 42 float SetGain(const usb_protocol_t& proto, float db) { 43 return feature_unit_ ? feature_unit_->SetVol(proto, db) : 0.0f; 44 } 45 46 bool SetMute(const usb_protocol_t& proto, bool mute) { 47 return feature_unit_ ? feature_unit_->SetMute(proto, mute) : false; 48 } 49 50 bool SetAgc(const usb_protocol_t& proto, bool enabled) { 51 return feature_unit_ ? feature_unit_->SetAgc(proto, enabled) : false; 52 } 53 54 private: 55 friend class fbl::unique_ptr<AudioPath>; 56 friend class UsbAudioControlInterface; 57 58 // Methods use by the audio control interface class to build audio paths 59 // during its walk of the unit/terminal graph. Basically, the control 60 // interface class calls... 61 // 62 // 1) 'Create' when it finds what looks like a valid path during its recursive 63 // walk of the graph. 64 // 2) 'AddUnit' as it unwinds from the walk in order to store references 65 // which form the path in the proper order inside of the path. 66 // 3) 'Setup' when it is finished in order to sanity check the path and to 67 // stash pointers to important elements, such as the stream terminal 68 // node and the feature unit node (if found). 69 // 70 static fbl::unique_ptr<AudioPath> Create(uint32_t unit_count); 71 void AddUnit(uint32_t ndx, fbl::RefPtr<AudioUnit> unit); 72 zx_status_t Setup(const usb_protocol_t& proto); 73 74 AudioPath(fbl::unique_ptr<fbl::RefPtr<AudioUnit>[]> units, uint32_t unit_count) 75 : units_(fbl::move(units)), unit_count_(unit_count) {} 76 ~AudioPath() {} 77 78 DISALLOW_COPY_ASSIGN_AND_MOVE(AudioPath); 79 80 const fbl::unique_ptr<fbl::RefPtr<AudioUnit>[]> units_; 81 const uint32_t unit_count_; 82 Direction direction_ = Direction::Unknown; 83 84 // Note: Strictly speaking, these cached references do not have to be 85 // RefPtrs. In theory, the members of units_ should always outlive these 86 // cache references. This said, the cost of holding an extra reference on 87 // the objects is basically zero, and storing the pointers internally as 88 // RefPtr<>s makes it easy to know that this is safe from a lifecycle 89 // perspective, if perhaps a tiny bit parinoid. 90 fbl::RefPtr<const Terminal> stream_terminal_; 91 fbl::RefPtr<FeatureUnit> feature_unit_; 92}; 93 94} // namespace usb 95} // namespace audio 96 97