1// Copyright 2017 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 <string.h> 8 9namespace audio { 10namespace utils { 11 12// Note: these sets must be kept in monotonically increasing order. 13static const uint32_t RATES_48000_FAMILY[] = { 8000,16000,32000,48000,96000,192000,384000,768000 }; 14static const uint32_t RATES_44100_FAMILY[] = { 11025,22050,44100,88200,176400 }; 15static const uint32_t* RATES_48000_FAMILY_LAST = RATES_48000_FAMILY + fbl::count_of(RATES_48000_FAMILY); 16static const uint32_t* RATES_44100_FAMILY_LAST = RATES_44100_FAMILY + fbl::count_of(RATES_44100_FAMILY); 17static constexpr auto DISCRETE_FLAGS = ASF_RANGE_FLAG_FPS_48000_FAMILY 18 | ASF_RANGE_FLAG_FPS_44100_FAMILY; 19 20bool FrameRateIn48kFamily(uint32_t rate) { 21 const uint32_t* found = fbl::lower_bound(RATES_48000_FAMILY, RATES_48000_FAMILY_LAST, rate); 22 return ((found < RATES_48000_FAMILY_LAST) && (*found == rate)); 23} 24 25bool FrameRateIn441kFamily(uint32_t rate) { 26 const uint32_t* found = fbl::lower_bound(RATES_44100_FAMILY, RATES_44100_FAMILY_LAST, rate); 27 return ((found < RATES_44100_FAMILY_LAST) && (*found == rate)); 28} 29 30// Figure out the size of an audio frame based on the sample format. Returns 0 31// in the case of an error (bad channel count, bad sample format) 32uint32_t ComputeFrameSize(uint16_t channels, audio_sample_format_t sample_format) { 33 uint32_t fmt_noflags = sample_format & ~AUDIO_SAMPLE_FORMAT_FLAG_MASK; 34 35 switch (fmt_noflags) { 36 case AUDIO_SAMPLE_FORMAT_8BIT: return 1u * channels; 37 case AUDIO_SAMPLE_FORMAT_16BIT: return 2u * channels; 38 case AUDIO_SAMPLE_FORMAT_24BIT_PACKED: return 3u * channels; 39 case AUDIO_SAMPLE_FORMAT_20BIT_IN32: 40 case AUDIO_SAMPLE_FORMAT_24BIT_IN32: 41 case AUDIO_SAMPLE_FORMAT_32BIT: 42 case AUDIO_SAMPLE_FORMAT_32BIT_FLOAT: return 4u * channels; 43 44 // See ZX-1003 45 // We currently don't really know how 20 bit audio should be packed. For 46 // now, treat it as an error. 47 case AUDIO_SAMPLE_FORMAT_20BIT_PACKED: 48 default: 49 return 0; 50 } 51} 52 53bool FormatIsCompatible(uint32_t frame_rate, 54 uint16_t channels, 55 audio_sample_format_t sample_format, 56 const audio_stream_format_range_t& format_range) { 57 // Are the requested number of channels in range? 58 if ((channels < format_range.min_channels) || (channels > format_range.max_channels)) 59 return false; 60 61 // Is the requested sample format compatible with the range's supported 62 // formats? If so... 63 // 64 // 1) The flags for each (requested and supported) must match exactly. 65 // 2) The requested format must be unique, and a PCM format (we don't know 66 // how to test compatibility for compressed bitstream formats right now) 67 // 3) The requested format must intersect the set of supported formats. 68 // 69 // Start by testing requirement #1. 70 uint32_t requested_flags = sample_format & AUDIO_SAMPLE_FORMAT_FLAG_MASK; 71 uint32_t supported_flags = format_range.sample_formats & AUDIO_SAMPLE_FORMAT_FLAG_MASK; 72 if (requested_flags != supported_flags) 73 return false; 74 75 // Requirement #2. If this format is unique and PCM, then there is exactly 76 // 1 bit set in it and that bit is not AUDIO_SAMPLE_FORMAT_BITSTREAM. We 77 // can use fbl::is_pow2 to check if there is exactly 1 bit set. (note, 78 // fbl::is_pow2 does not consider 0 to be a power of 2, so it's perfect for 79 // this) 80 uint32_t requested_noflags = sample_format & ~AUDIO_SAMPLE_FORMAT_FLAG_MASK; 81 if ((requested_noflags == AUDIO_SAMPLE_FORMAT_BITSTREAM) || 82 (!fbl::is_pow2(requested_noflags))) 83 return false; 84 85 // Requirement #3. Testing intersection is easy, just and the two. No need 86 // to strip the flags from the supported format bitmask, we have already 87 // stripped them from the request when checking requirement #2. 88 if (!(format_range.sample_formats & requested_noflags)) 89 return false; 90 91 // Check the requested frame rate. If it is not in the range expressed by 92 // the format_range, then we know this is not a match. 93 if ((frame_rate < format_range.min_frames_per_second) || 94 (frame_rate > format_range.max_frames_per_second)) 95 return false; 96 97 // The frame rate is in range, if this format_range supports continuous 98 // frame rates, then this is a match. 99 if (format_range.flags & ASF_RANGE_FLAG_FPS_CONTINUOUS) 100 return true; 101 102 // Check the 48k family. 103 if ((format_range.flags & ASF_RANGE_FLAG_FPS_48000_FAMILY) && FrameRateIn48kFamily(frame_rate)) 104 return true; 105 106 // Check the 44.1k family. 107 if ((format_range.flags & ASF_RANGE_FLAG_FPS_44100_FAMILY) && FrameRateIn441kFamily(frame_rate)) 108 return true; 109 110 // No supported frame rates found. Declare no-match. 111 return false; 112} 113 114FrameRateEnumerator::iterator::iterator(const FrameRateEnumerator* enumerator) 115 : enumerator_(enumerator) { 116 // If we have no enumerator, then we cannot advance to the first valid frame 117 // rate. Just get out. 118 if (!enumerator_) 119 return; 120 121 // Sanity check our range first. If it is continuous, or invalid in any 122 // way, then we are not going to enumerate any valid frame rates. Just set 123 // our enumerator to nullptr and get out. 124 const auto& range = enumerator_->range(); 125 if ((range.flags & ASF_RANGE_FLAG_FPS_CONTINUOUS) || 126 !(range.flags & DISCRETE_FLAGS) || 127 (range.min_frames_per_second > range.max_frames_per_second)) { 128 enumerator_ = nullptr; 129 return; 130 } 131 132 // Reset our current iterator state, then advance to the first valid 133 // frame rate (if any) 134 cur_flag_ = ASF_RANGE_FLAG_FPS_48000_FAMILY; 135 fmt_ndx_ = static_cast<uint16_t>(-1); 136 Advance(); 137} 138 139void FrameRateEnumerator::iterator::Advance() { 140 if (enumerator_ == nullptr) { 141 ZX_DEBUG_ASSERT(!cur_rate_ && !cur_flag_ && !fmt_ndx_); 142 return; 143 } 144 145 const auto& range = enumerator_->range(); 146 147 while (cur_flag_ & DISCRETE_FLAGS) { 148 const uint32_t* rates; 149 uint16_t rates_count; 150 151 if (cur_flag_ == ASF_RANGE_FLAG_FPS_48000_FAMILY) { 152 rates = RATES_48000_FAMILY; 153 rates_count = sizeof(RATES_48000_FAMILY); 154 } else { 155 ZX_DEBUG_ASSERT(cur_flag_ == ASF_RANGE_FLAG_FPS_44100_FAMILY); 156 rates = RATES_44100_FAMILY; 157 rates_count = sizeof(RATES_44100_FAMILY); 158 } 159 160 if (range.flags & cur_flag_) { 161 for (++fmt_ndx_; fmt_ndx_ < rates_count; ++fmt_ndx_) { 162 uint32_t rate = rates[fmt_ndx_]; 163 164 // If the rate in the table is less than the minimum 165 // frames_per_second, keep advancing the index. 166 if (rate < range.min_frames_per_second) 167 continue; 168 169 // If the rate in the table is greater than the maximum 170 // frames_per_second, then we are done with this table. There are 171 // no more matches to be found in it. 172 if (rate > range.max_frames_per_second) 173 break; 174 175 // The rate in this table is between the min and the max rates 176 // supported by this range. Record it and get out. 177 cur_rate_ = rate; 178 return; 179 } 180 } 181 182 // We are done with this table. If we were searching the 48KHz family, 183 // move on to the 44.1KHz family. Otherwise, we are finished. 184 if (cur_flag_ == ASF_RANGE_FLAG_FPS_48000_FAMILY) { 185 cur_flag_ = ASF_RANGE_FLAG_FPS_44100_FAMILY; 186 fmt_ndx_ = static_cast<uint16_t>(-1); 187 } else { 188 break; 189 } 190 } 191 192 memset(this, 0, sizeof(*this)); 193} 194 195} // namespace utils 196} // namespace audio 197