| // 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/intrusive_double_list.h> |
| #include <fbl/intrusive_wavl_tree.h> |
| #include <fbl/unique_ptr.h> |
| #include <zircon/hw/usb/audio.h> |
| |
| #include "usb-audio-descriptors.h" |
| #include "usb-audio-path.h" |
| #include "usb-audio-units.h" |
| |
| namespace audio { |
| namespace usb { |
| |
| class UsbAudioDevice; |
| |
| class UsbAudioControlInterface { |
| public: |
| // Note that UsbAudioControlInterfaces are entirely owned by UsbAudioDevice |
| // instances. The control interface needs to hold a pointer to its parent, |
| // so it is critically important that the owning parent is certain that the |
| // control interface (and all of its children) have been properly shut down |
| // before exiting. At all times, the lifetime of the control interface |
| // needs to be a subset of the lifetime of the device parent. |
| static fbl::unique_ptr<UsbAudioControlInterface> Create(UsbAudioDevice* parent); |
| zx_status_t Initialize(DescriptorListMemory::Iterator* iter); |
| |
| const char* log_prefix() const; |
| |
| // Extract the AudioPath whose streaming terminal interface link ID matches |
| // the users request, if any. Otherwise, simply return nullptr. |
| fbl::unique_ptr<AudioPath> ExtractPath(uint8_t term_link, Direction direction) { |
| return paths_.erase_if([term_link, direction](const AudioPath& path) -> bool { |
| return (path.stream_terminal().id() == term_link) && (path.direction() == direction); |
| }); |
| } |
| |
| private: |
| friend class std::default_delete<UsbAudioControlInterface>; |
| using UnitMap = fbl::WAVLTree<uint32_t, fbl::RefPtr<AudioUnit>>; |
| |
| UsbAudioControlInterface(UsbAudioDevice* parent); |
| ~UsbAudioControlInterface(); |
| |
| // A recursive method used to find interesting audio paths in the |
| // unit/terminal graph. See the comment at the end of the Init |
| // implementation for details about the algorithm used to find these paths. |
| fbl::unique_ptr<AudioPath> TracePath(const OutputTerminal& out_term, |
| const UnitMap::iterator& current, uint32_t level = 0); |
| |
| // The reference to our parent. Note, because of this unmanaged reference, |
| // it is critically important that the surrounding code ensure that we never |
| // outlive our parent device. |
| UsbAudioDevice& parent_; |
| |
| // Cached, unmanaged pointers to our interface and class descriptors. The |
| // memory which backs these descriptors is kept alive by the top level |
| // desc_list_ reference. |
| // |
| // TODO(johngro) : this desc_list_ memory is contained in our parent |
| // UsbAudioDevice. Since we have already committed to having a lifetime |
| // which is strictly <= the lifetime of our parent, we should probably just |
| // access the descriptor memory using our parent instead of holding our own |
| // reference to it. |
| fbl::RefPtr<DescriptorListMemory> desc_list_; |
| const usb_interface_descriptor_t* interface_hdr_ = nullptr; |
| const usb_audio_ac_header_desc* class_hdr_ = nullptr; |
| |
| // All unit/terminal IDs for a given Audio Control Interface |
| // |
| // TODO(johngro): Strictly speaking, we don't really need to hold onto this. |
| // If we wanted, we could just keep this as a local variable used during |
| // Init and discard it afterwards. |
| UnitMap units_; |
| |
| // The complete set of valid paths we have discovered. |
| fbl::DoublyLinkedList<fbl::unique_ptr<AudioPath>> paths_; |
| }; |
| |
| } // namespace usb |
| } // namespace audio |