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 #include <audio-proto-utils/format-utils.h>
6 #include <fbl/algorithm.h>
7 #include <fbl/auto_call.h>
8 
9 #include <utility>
10 
11 #include "debug-logging.h"
12 #include "usb-audio-device.h"
13 #include "usb-audio-path.h"
14 #include "usb-audio-stream-interface.h"
15 
16 namespace audio {
17 namespace usb {
18 
19 // We use our parent's log prefix
log_prefix() const20 const char* UsbAudioStreamInterface::log_prefix() const {
21     return parent_.log_prefix();
22 }
23 
Create(UsbAudioDevice * parent,DescriptorListMemory::Iterator * iter)24 fbl::unique_ptr<UsbAudioStreamInterface> UsbAudioStreamInterface::Create(
25         UsbAudioDevice* parent,
26         DescriptorListMemory::Iterator* iter) {
27     ZX_DEBUG_ASSERT(parent != nullptr);
28     ZX_DEBUG_ASSERT(iter != nullptr);
29 
30     auto ihdr = iter->hdr_as<usb_interface_descriptor_t>();
31     ZX_DEBUG_ASSERT(ihdr);  // The caller should have already verified this.
32     uint8_t iid = ihdr->bInterfaceNumber;
33 
34     fbl::AllocChecker ac;
35     fbl::unique_ptr<UsbAudioStreamInterface> ret(
36             new (&ac) UsbAudioStreamInterface(parent, iter->desc_list(), iid));
37     if (ac.check()) {
38         zx_status_t res = ret->AddInterface(iter);
39         if (res == ZX_OK) {
40             return ret;
41         }
42         LOG_EX(ERROR, *parent,
43               "Failed to add initial interface (id %u) to UsbAudioStreamInterface (res %d)\n",
44               iid, res);
45     } else {
46         iter->Next(); // Success or failure, we are expected to consume this header.
47         LOG_EX(ERROR, *parent,
48                "Out of memory attempting to allocate UsbAudioStreamInterface (id %u)\n", iid);
49     }
50 
51     return nullptr;
52 }
53 
AddInterface(DescriptorListMemory::Iterator * iter)54 zx_status_t UsbAudioStreamInterface::AddInterface(DescriptorListMemory::Iterator* iter) {
55     // All of these checks should have been made by the caller already.
56     ZX_DEBUG_ASSERT(iter != nullptr);
57     ZX_DEBUG_ASSERT(iter->desc_list() == desc_list_);
58 
59     auto ihdr = iter->hdr_as<usb_interface_descriptor_t>();
60     ZX_DEBUG_ASSERT(ihdr != nullptr);
61     ZX_DEBUG_ASSERT(ihdr->bInterfaceNumber == iid());
62 
63     // No matter what, we need to consume the current descriptor header.
64     iter->Next();
65 
66     // Make sure that this header represents a unique alternate setting.
67     auto alt_id = ihdr->bAlternateSetting;
68     auto fmt_iter = formats_.find_if([alt_id](const Format& fmt) -> bool {
69                                         return alt_id == fmt.alt_id();
70                                     });
71     if (fmt_iter.IsValid() || ((idle_hdr_ && (idle_hdr_->bAlternateSetting == alt_id)))) {
72         LOG(WARN,
73             "Skipping duplicate alternate setting ID in streaming interface descriptor.  "
74             "(iid %u, alt_id %u)\n",
75             ihdr->bInterfaceNumber, alt_id);
76         // Don't return an error if we encounter a malformed header.  Just skip
77         // it and do the best we can with what we have.
78         return ZX_OK;
79     }
80 
81     // Examine the next descriptor.  If it is an audio streaming class specific
82     // interface descriptor, then this top level descriptor is part of a
83     // described format.  Otherwise, this is an empty alternate interface which
84     // is probably meant to be selected when this streaming interface is idle
85     // and should not be using any bus resources.
86     auto next_hdr = iter->hdr_as<usb_audio_desc_header>();
87     if ((next_hdr != nullptr) &&
88         (next_hdr->bDescriptorType == USB_AUDIO_CS_INTERFACE) &&
89         (next_hdr->bDescriptorSubtype == USB_AUDIO_AS_GENERAL)) {
90         auto aud_hdr = iter->hdr_as<usb_audio_as_header_desc>();
91         iter->Next();
92 
93         if (aud_hdr == nullptr) {
94             LOG(WARN,
95                 "Skipping badly formed alternate setting ID in streaming interface descriptor "
96                 "(iid %u, alt_id %u).\n",
97                 ihdr->bInterfaceNumber, alt_id);
98             return ZX_OK;
99         }
100 
101         fbl::AllocChecker ac;
102         auto format = fbl::make_unique_checked<Format>(&ac, this, iter->desc_list(), ihdr, aud_hdr);
103         if (!ac.check()) {
104             LOG(ERROR, "Out of memory attempt to add Format to StreamInterface\n");
105             return ZX_ERR_NO_MEMORY;
106         }
107 
108         zx_status_t status = format->Init(iter);
109         if (status != ZX_OK) {
110             LOG(WARN,
111                 "Skipping bad format streaming interface descriptor.  (iid %u, alt_id %u)\n",
112                 ihdr->bInterfaceNumber, alt_id);
113             return ZX_OK;
114         }
115 
116         // Make sure that the endpoint address and terminal link ID of this
117         // format matches all previously encountered formats.
118         //
119         // TODO(johngro) : It is unclear whether or not it makes any sense to
120         // have formats which link to different audio paths or have different
121         // endpoint addresses (implying potentially different directions).  For
122         // now we simply skip these formats if we encounter them.
123         //
124         // If we ever encounter a device which has a mix of these parameters, we
125         // need come back and determine if there is a good generic approach for
126         // dealing with the situation.
127         if (!formats_.is_empty()) {
128             if (format->term_link() != term_link_) {
129                 LOG(WARN,
130                     "Skipping format (iid %u, alt_id %u) with non-uniform terminal ID "
131                     "(expected %u, got %u)\n",
132                     ihdr->bInterfaceNumber, alt_id, term_link_, format->term_link());
133                 return ZX_OK;
134             }
135 
136             if ((format->ep_addr() != ep_addr_) || (format->ep_attr() != ep_attr_)) {
137                 LOG(ERROR,
138                     "Skipping format (iid %u, alt_id %u) with non-uniform endpoint "
139                     "address/attributes (expected 0x%02x/0x%02x, got 0x%02x/0x%02x)\n",
140                     ihdr->bInterfaceNumber, alt_id,
141                     ep_addr_, ep_attr_,
142                     format->ep_addr(), format->ep_attr());
143                 return ZX_OK;
144             }
145         } else {
146             term_link_ = format->term_link();
147             ep_addr_   = format->ep_addr();
148             ep_attr_   = format->ep_attr();
149         }
150 
151         max_req_size_ = fbl::max(max_req_size_, format->max_req_size());
152         formats_.push_back(std::move(format));
153     } else {
154         if (idle_hdr_ == nullptr) {
155             idle_hdr_ = ihdr;
156         } else {
157             LOG(WARN,
158                 "Skipping duplicate \"idle\" interface descriptor in streaming interface "
159                 "descriptor.  (iid %u, alt_id %u)\n",
160                 ihdr->bInterfaceNumber, ihdr->bAlternateSetting);
161         }
162     }
163 
164     return ZX_OK;
165 }
166 
BuildFormatMap()167 zx_status_t UsbAudioStreamInterface::BuildFormatMap() {
168     if (format_map_.size()) {
169         LOG(WARN, "Attempted to re-build format map for streaming interface (iid %u)\n", iid());
170         return ZX_ERR_BAD_STATE;
171     }
172 
173     // Make a pass over our list of formats and figure out how big our format
174     // map vector may need to be.
175     //
176     // Note: this is a rough worst case bound on how big the vector needs to be.
177     // Someday, we could come back here and compute a much tighter bound if we
178     // wanted to.
179     size_t worst_case_map_entries = 0;
180     for (const auto& fmt : formats_) {
181         // A frame rate count of 0 indicates a continuous format range which
182         // requires only one format range entry.
183         worst_case_map_entries += fmt.frame_rate_cnt() ? fmt.frame_rate_cnt() : 1;
184     }
185 
186     // Now reserve our memory.
187     fbl::AllocChecker ac;
188     format_map_.reserve(worst_case_map_entries, &ac);
189     if (!ac.check()) {
190         LOG(ERROR, "Out of memory attempting to reserve %zu format ranges\n",
191             worst_case_map_entries);
192         return ZX_ERR_NO_MEMORY;
193     }
194 
195     // Now iterate over our set and build the map.
196     for (const auto& fmt : formats_) {
197         // Record the min/max number of channels.
198         audio_stream_format_range_t range;
199         range.min_channels = fmt.ch_count();
200         range.max_channels = fmt.ch_count();
201 
202         // Encode the sample container type from the type I format descriptor
203         // as an audio device driver audio_sample_format_t.  If we encounter
204         // anything that we don't know how to encode, log a warning and skip the
205         // format.
206         //
207         auto tag = fmt.format_tag();
208         if (tag == USB_AUDIO_AS_FT_PCM8) {
209             if ((fmt.bit_resolution() != 8) || (fmt.subframe_bytes() != 1)) {
210                 LOG(WARN, "Skipping PCM8 format with invalid bit res/subframe size (%u/%u)\n",
211                     fmt.bit_resolution(), fmt.subframe_bytes());
212                 continue;
213             }
214             range.sample_formats = static_cast<audio_sample_format_t>(
215                     AUDIO_SAMPLE_FORMAT_8BIT | AUDIO_SAMPLE_FORMAT_FLAG_UNSIGNED);
216         } else
217         if (tag == USB_AUDIO_AS_FT_IEEE_FLOAT) {
218             if ((fmt.bit_resolution() != 32) || (fmt.subframe_bytes() != 4)) {
219                 LOG(WARN, "Skipping IEEE_FLOAT format with invalid bit res/subframe size (%u/%u)\n",
220                     fmt.bit_resolution(), fmt.subframe_bytes());
221                 continue;
222             }
223             range.sample_formats = AUDIO_SAMPLE_FORMAT_32BIT_FLOAT;
224         } else
225         if (tag == USB_AUDIO_AS_FT_PCM) {
226             switch (fmt.bit_resolution()) {
227             case 8:
228             case 16:
229             case 32: {
230                 if (fmt.subframe_bytes() != (fmt.bit_resolution() >> 3)) {
231                     LOG(WARN,
232                         "Skipping PCM format.  Subframe size (%u bytes) does not "
233                         "match Bit Res (%u bits)\n",
234                         fmt.bit_resolution(),
235                         fmt.subframe_bytes());
236                     continue;
237                 }
238                 switch (fmt.bit_resolution()) {
239                 case 8:  range.sample_formats = AUDIO_SAMPLE_FORMAT_8BIT; break;
240                 case 16: range.sample_formats = AUDIO_SAMPLE_FORMAT_16BIT; break;
241                 case 32: range.sample_formats = AUDIO_SAMPLE_FORMAT_32BIT; break;
242                 }
243             } break;
244 
245             case 20:
246             case 24: {
247                 if ((fmt.subframe_bytes() != 3) && (fmt.subframe_bytes() != 4)) {
248                     LOG(WARN,
249                         "Skipping PCM format.  %u-bit audio must be packed into a 3 "
250                         "or 4 byte subframe (Subframe size %u)\n",
251                         fmt.bit_resolution(),
252                         fmt.subframe_bytes());
253                     continue;
254                 }
255                 switch (fmt.bit_resolution()) {
256                 case 20:
257                     range.sample_formats = ((fmt.subframe_bytes() == 3)
258                                             ? AUDIO_SAMPLE_FORMAT_20BIT_PACKED
259                                             : AUDIO_SAMPLE_FORMAT_20BIT_IN32);
260                     break;
261                 case 24:
262                     range.sample_formats = ((fmt.subframe_bytes() == 3)
263                                             ? AUDIO_SAMPLE_FORMAT_24BIT_PACKED
264                                             : AUDIO_SAMPLE_FORMAT_24BIT_IN32);
265                     break;
266                 }
267             } break;
268 
269             default:
270                 LOG(WARN, "Skipping PCM format with unsupported bit res (%u bits)\n",
271                     fmt.bit_resolution());
272                 continue;
273             }
274         } else {
275             LOG(WARN, "Skipping unsupported format tag (%u)\n", tag);
276             continue;
277         }
278 
279         // Now pack the supported frame rates.  A format with a frame rate count of
280         // 0 is a continuous range of frame rates.  Otherwise, we pack each discrete
281         // frame rate as an individual entry.
282         //
283         // TODO(johngro) : Discrete frame rates could be encoded more compactly
284         // if wanted to do so by extracting all of the 48k and 44.1k rates into
285         // a bitmask, and then putting together ranges which represented
286         // continuous runs of frame rates in each of the families.
287         if (fmt.frame_rate_cnt()) {
288             for (uint8_t i = 0; i < fmt.frame_rate_cnt(); ++i) {
289                 uint32_t rate = fmt.frame_rate(i);
290                 range.min_frames_per_second = rate;
291                 range.max_frames_per_second = rate;
292 
293                 if (audio::utils::FrameRateIn48kFamily(rate)) {
294                     range.flags = ASF_RANGE_FLAG_FPS_48000_FAMILY;
295                 } else
296                 if (audio::utils::FrameRateIn441kFamily(rate)) {
297                     range.flags = ASF_RANGE_FLAG_FPS_44100_FAMILY;
298                 } else {
299                     range.flags = ASF_RANGE_FLAG_FPS_CONTINUOUS;
300                 }
301 
302                 format_map_.push_back({ range, fmt.alt_id(), fmt.ep_addr(), fmt.max_req_size() });
303             }
304         } else {
305             range.min_frames_per_second = fmt.min_cont_frame_rate();
306             range.max_frames_per_second = fmt.max_cont_frame_rate();
307             range.flags = ASF_RANGE_FLAG_FPS_CONTINUOUS;
308             format_map_.push_back({ range, fmt.alt_id(), fmt.ep_addr(), fmt.max_req_size() });
309         }
310     }
311 
312     // If we failed to encode *any* valid format ranges, log a warning and
313     // return an error.  This stream interface is not going to be useful to us.
314     if (format_map_.is_empty()) {
315         LOG(WARN, "Failed to find any usable formats for streaming interface (iid %u)\n", iid());
316         return ZX_ERR_NOT_SUPPORTED;
317     }
318 
319     return ZX_OK;
320 }
321 
LookupFormat(uint32_t frames_per_second,uint16_t channels,audio_sample_format_t sample_format,size_t * out_format_ndx)322 zx_status_t UsbAudioStreamInterface::LookupFormat(uint32_t frames_per_second,
323                                                   uint16_t channels,
324                                                   audio_sample_format_t sample_format,
325                                                   size_t* out_format_ndx) {
326     if (out_format_ndx == nullptr) {
327         return ZX_ERR_INVALID_ARGS;
328     }
329 
330     *out_format_ndx = format_map_.size();
331 
332     // Search our format map to find the alternate interface setting which
333     // supports the requested format.
334     for (size_t i = 0; i < format_map_.size(); ++i) {
335         if (audio::utils::FormatIsCompatible(frames_per_second,
336                                              channels,
337                                              sample_format,
338                                              format_map_[i].range_)) {
339             *out_format_ndx = i;
340             return ZX_OK;
341         }
342     }
343 
344     return ZX_ERR_NOT_SUPPORTED;
345 }
346 
ActivateFormat(size_t ndx,uint32_t frames_per_second)347 zx_status_t UsbAudioStreamInterface::ActivateFormat(size_t ndx, uint32_t frames_per_second) {
348     if (ndx >= format_map_.size()) {
349         return ZX_ERR_INVALID_ARGS;
350     }
351 
352     // Select the interface used for this format, then configure the endpoint
353     // for the requested frame rate.  user know what the maximum request size is
354     // for this interface.
355     zx_status_t status;
356     const auto& f = format_map_[ndx];
357     status = usb_set_interface(&parent_.usb_proto(), iid(), f.alt_id_);
358     if (status != ZX_OK) {
359         LOG(ERROR,
360             "Failed to select interface (id %u, alt %u, ep %u) "
361             "when configuring format ndx %zu (status %d)\n",
362             iid(), f.alt_id_, f.ep_addr_, ndx, status);
363         return status;
364     }
365 
366     // Do not attempt to set the sample rate if the endpoint supports
367     // only one.  In theory, devices should ignore this request, but in
368     // practice, some devices will refuse the command entirely, and we
369     // will get ZX_ERR_IO_REFUSED back from the bus driver.
370     //
371     // Note: This method of determining whether or not an endpoint
372     // supports only a single rate only works here because we currently
373     // demand that all of our formats share a single endpoint address.
374     // If this changes in the future, this heuristic will need to be
375     // revisited.
376     bool single_rate = (format_map_.size() == 1) &&
377                       !(format_map_[0].range_.flags & ASF_RANGE_FLAG_FPS_CONTINUOUS);
378     if (!single_rate) {
379         // See section 5.2.3.2.3.1 of the USB Audio 1.0 spec.
380         uint8_t buffer[3];
381         buffer[0] = static_cast<uint8_t>(frames_per_second);
382         buffer[1] = static_cast<uint8_t>(frames_per_second >> 8);
383         buffer[2] = static_cast<uint8_t>(frames_per_second >> 16);
384         status = usb_control_out(&parent_.usb_proto(),
385                              USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
386                              USB_AUDIO_SET_CUR,
387                              USB_AUDIO_SAMPLING_FREQ_CONTROL << 8,
388                              f.ep_addr_, ZX_TIME_INFINITE,
389                              &buffer, sizeof(buffer));
390         if (status != ZX_OK) {
391             if (status == ZX_ERR_IO_REFUSED || status == ZX_ERR_IO_INVALID) {
392                 // clear the stall/error
393                 usb_reset_endpoint(&parent_.usb_proto(), f.ep_addr_);
394             }
395 
396             LOG(ERROR, "Failed to set frame rate %u for ep address %u (status %d)\n",
397                 frames_per_second, f.ep_addr_, status);
398 
399             return status;
400         }
401     }
402 
403     return ZX_OK;
404 }
405 
ActivateIdleFormat()406 zx_status_t UsbAudioStreamInterface::ActivateIdleFormat() {
407     if (idle_hdr_ == nullptr) {
408         return ZX_ERR_NOT_SUPPORTED;
409     }
410 
411     ZX_DEBUG_ASSERT(idle_hdr_->bInterfaceNumber == iid());
412     return usb_set_interface(&parent_.usb_proto(), iid(), idle_hdr_->bAlternateSetting);
413 }
414 
LinkPath(fbl::unique_ptr<AudioPath> path)415 void UsbAudioStreamInterface::LinkPath(fbl::unique_ptr<AudioPath> path) {
416     ZX_DEBUG_ASSERT(path != nullptr);
417     ZX_DEBUG_ASSERT(path_ == nullptr);
418     ZX_DEBUG_ASSERT(direction() == path->direction());
419     ZX_DEBUG_ASSERT(term_link() == path->stream_terminal().id());
420     path_ = std::move(path);
421 }
422 
Init(DescriptorListMemory::Iterator * iter)423 zx_status_t UsbAudioStreamInterface::Format::Init(DescriptorListMemory::Iterator* iter) {
424     ZX_DEBUG_ASSERT(iter != nullptr);
425     ZX_DEBUG_ASSERT(iter->desc_list() == desc_list_);
426 
427     // Skip formats tags that we currently do not support or know how to deal
428     // with.  Right now, we only deal with the linear PCM forms of Type I audio
429     // formats.
430     switch (class_hdr_->wFormatTag) {
431     case USB_AUDIO_AS_FT_PCM:
432     case USB_AUDIO_AS_FT_PCM8:
433     case USB_AUDIO_AS_FT_IEEE_FLOAT:
434         break;
435 
436     default:
437         LOG(ERROR,
438             "Unsupported format tag (0x%04hx) in class specific audio stream interface "
439             "(iid %u, alt_id %u)\n",
440             class_hdr_->wFormatTag, interface_hdr_->bInterfaceNumber, alt_id());
441         return ZX_ERR_NOT_SUPPORTED;
442     }
443 
444     // Next go looking for the other headers we will need in order to operate.
445     // In specific, we need to find an audio format descriptor (specifically a
446     // Type I descriptor), a general USB Endpoint descriptor, and a audio class
447     // specific endpoint descriptor.
448     //
449     // If we encounter something which is not one of these things, then we have
450     // run out of headers to parse.
451     //
452     // If we encounter duplicates of these descriptors, or we encounter
453     // something clearly incompatible (such as a type II or type III format
454     // descriptor), then we are confused and this interface should be ignored.
455     // Be sure to skip headers like this if we return from the middle of the
456     // do/while loop below.
457     auto cleanup = fbl::MakeAutoCall([iter]() { iter->Next(); });
458     do {
459         auto hdr = iter->hdr();
460         if (hdr == nullptr) {
461             break;
462         }
463 
464         if (hdr->bDescriptorType == USB_AUDIO_CS_INTERFACE) {
465             // Stop parsing if this is not an audio format type descriptor
466             auto ihdr = iter->hdr_as<usb_audio_desc_header>();
467             if ((ihdr == nullptr) || (ihdr->bDescriptorSubtype != USB_AUDIO_AS_FORMAT_TYPE)) {
468                 break;
469             }
470 
471             auto fmt_hdr = iter->hdr_as<usb_audio_as_format_type_hdr>();
472             if (fmt_hdr == nullptr) {
473                 break;
474             }
475 
476             if (fmt_hdr->bFormatType != USB_AUDIO_FORMAT_TYPE_I) {
477                 LOG(ERROR,
478                     "Unsupported format type (%u) in class specific audio stream format type "
479                     "interface (iid %u, alt_id %u)\n",
480                     fmt_hdr->bFormatType, interface_hdr_->bInterfaceNumber, alt_id());
481                 return ZX_ERR_NOT_SUPPORTED;
482             }
483 
484             auto fmt_desc = iter->hdr_as<usb_audio_as_format_type_i_desc>();
485             if ((fmt_desc_ != nullptr) || (fmt_desc == nullptr)) {
486                 LOG(ERROR,
487                     "Malformed or duplicate type 1 format type descriptor in class specific audio "
488                     "interface (iid %u, alt_id %u)\n",
489                     interface_hdr_->bInterfaceNumber, alt_id());
490                 return ZX_ERR_NOT_SUPPORTED;
491             }
492 
493             // Stash the pointer, we'll sanity check a bit more once we are finished finding
494             // headers.
495             fmt_desc_ = fmt_desc;
496         } else
497         if (hdr->bDescriptorType == USB_DT_ENDPOINT) {
498             auto ep_desc = iter->hdr_as<usb_endpoint_descriptor_t>();
499             if (ep_desc == nullptr) {
500                 LOG(ERROR,
501                     "Malformed standard endpoint descriptor in class specific audio interface "
502                     "(iid %u, alt_id %u)\n",
503                     interface_hdr_->bInterfaceNumber, alt_id());
504                 return ZX_ERR_NOT_SUPPORTED;
505             }
506 
507             // TODO(johngro): Come back and fix this.  There are devices with
508             // multiple isochronous endpoints per format interface.  Device
509             // which use an isochronous output endpoint with an Asynchronous
510             // sync type seem to have an isochronous input endpoint as well
511             // which is probably used for clock recovery.  Instead of
512             // skipping/ignoring this endpoint, we really should be using it to
513             // recover the device clock.
514             if (ep_desc_ != nullptr) {
515                 LOG(WARN,
516                     "Skipping duplicate standard endpoint descriptor in class specific audio "
517                     "interface (iid %u, alt_id %u, ep_addr %u)\n",
518                     interface_hdr_->bInterfaceNumber, alt_id(), ep_desc->bEndpointAddress);
519             } else {
520                 if ((usb_ep_type(ep_desc) != USB_ENDPOINT_ISOCHRONOUS) ||
521                     (usb_ep_sync_type(ep_desc) == USB_ENDPOINT_NO_SYNCHRONIZATION)) {
522                     LOG(WARN,
523                         "Skipping endpoint descriptor with unsupported attributes "
524                         "interface (iid %u, alt_id %u, ep_attr 0x%02x)\n",
525                         interface_hdr_->bInterfaceNumber, alt_id(), ep_desc->bmAttributes);
526                 } else {
527                     ep_desc_ = ep_desc;
528                 }
529             }
530         } else
531         if (hdr->bDescriptorType == USB_AUDIO_CS_ENDPOINT) {
532             // Stop parsing if this is not a class specific AS isochronous endpoint descriptor
533             auto ihdr = iter->hdr_as<usb_audio_desc_header>();
534             if ((ihdr == nullptr) || (ihdr->bDescriptorSubtype != USB_AUDIO_EP_GENERAL)) {
535                 break;
536             }
537 
538             auto class_ep_desc = iter->hdr_as<usb_audio_as_isoch_ep_desc>();
539             if (class_ep_desc == nullptr) {
540                 LOG(ERROR,
541                     "Malformed or class specific endpoint descriptor in class specific audio "
542                     "interface (iid %u, alt_id %u)\n",
543                     interface_hdr_->bInterfaceNumber, alt_id());
544                 return ZX_ERR_NOT_SUPPORTED;
545             }
546 
547             if (class_ep_desc_ != nullptr) {
548                 LOG(WARN,
549                     "Skipping duplicate class specific endpoint descriptor in class specific "
550                     "audio interface (iid %u, alt_id %u\n",
551                     interface_hdr_->bInterfaceNumber, alt_id());
552             } else {
553                 class_ep_desc_ = class_ep_desc;
554             }
555         } else {
556             // We don't recognize this descriptor, so we have run out of
557             // descriptors that we beleive belong to this format.  Move on to
558             // sanity checks.
559             break;
560         }
561     } while (iter->Next());
562     cleanup.cancel();
563 
564     // Sanity check what we have found so far.  Right now, we need to have found...
565     //
566     // 1) A Type I audio format type descriptor (PCM)
567     // 2) A standard Isochronous USB endpoint descriptor.
568     // 3) An audio class specific endpoint descriptor.
569     //
570     // In addition, we need to make sure that the range of frame rates present
571     // in the Type I descriptor makes sense.  If the range is continuous, the
572     // array must contain *exactly* 2 entries.  If the range is discrete, then
573     // the array must contain an integer number of entries, and must contain at
574     // least one entry.
575     if ((fmt_desc_ == nullptr) || (ep_desc_ == nullptr) || (class_ep_desc_ == nullptr)) {
576         LOG(ERROR,
577             "Missing one or more required descriptors in audio interface (iid %u, alt_id %u); "
578             "Missing%s%s%s\n",
579             interface_hdr_->bInterfaceNumber, alt_id(),
580             (fmt_desc_ == nullptr) ? " [Type I Format Type Descriptor]" : "",
581             (ep_desc_ == nullptr) ? " [Standard Endpoint Descriptor]" : "",
582             (class_ep_desc_  == nullptr) ? " [Class Endpoint Descriptor]" : "");
583         return ZX_ERR_NOT_SUPPORTED;
584     }
585 
586     // hdr_as<> should have already verified this for us.
587     ZX_DEBUG_ASSERT(fmt_desc_->bLength >= sizeof(*fmt_desc_));
588 
589     // Sanity check the size of the frame rate table.
590     size_t expected_bytes = (frame_rate_cnt() ? frame_rate_cnt() : 2)
591                           * sizeof(usb_audio_as_samp_freq);
592     size_t extra_bytes = fmt_desc_->bLength - sizeof(*fmt_desc_);
593     if (expected_bytes != extra_bytes) {
594         LOG(ERROR,
595             "Bad frame rate table size in type 1 audio format type descriptor in audio interface "
596             "(iid %u, alt_id %u).  Expected %zu, Got %zu\n",
597             interface_hdr_->bInterfaceNumber, alt_id(), expected_bytes, extra_bytes);
598         return ZX_ERR_INTERNAL;
599     }
600 
601     // If this is a continuous range of frame rates, then the min/max order needs to be correct.
602     if ((frame_rate_cnt() == 0) && (min_cont_frame_rate() > max_cont_frame_rate())) {
603         LOG(ERROR,
604             "Invalid continuous frame rate range [%u, %u] type 1 audio format type descriptor in "
605             "audio interface (iid %u, alt_id %u).\n",
606             min_cont_frame_rate(), max_cont_frame_rate(),
607             interface_hdr_->bInterfaceNumber, alt_id());
608         return ZX_ERR_INTERNAL;
609     }
610 
611     return ZX_OK;
612 }
613 
614 }  // namespace usb
615 }  // namespace audio
616