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