// 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 #include #include #include #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 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 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 fbl::unique_ptr; using UnitMap = fbl::WAVLTree>; 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 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 commited 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 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> paths_; }; } // namespace usb } // namespace audio