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 
9 namespace audio {
10 namespace utils {
11 
12 // Note: these sets must be kept in monotonically increasing order.
13 static const uint32_t RATES_48000_FAMILY[] = { 8000,16000,32000,48000,96000,192000,384000,768000 };
14 static const uint32_t RATES_44100_FAMILY[] = { 11025,22050,44100,88200,176400 };
15 static const uint32_t* RATES_48000_FAMILY_LAST = RATES_48000_FAMILY + fbl::count_of(RATES_48000_FAMILY);
16 static const uint32_t* RATES_44100_FAMILY_LAST = RATES_44100_FAMILY + fbl::count_of(RATES_44100_FAMILY);
17 static constexpr auto DISCRETE_FLAGS = ASF_RANGE_FLAG_FPS_48000_FAMILY
18                                      | ASF_RANGE_FLAG_FPS_44100_FAMILY;
19 
FrameRateIn48kFamily(uint32_t rate)20 bool 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 
FrameRateIn441kFamily(uint32_t rate)25 bool 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)
ComputeFrameSize(uint16_t channels,audio_sample_format_t sample_format)32 uint32_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 
FormatIsCompatible(uint32_t frame_rate,uint16_t channels,audio_sample_format_t sample_format,const audio_stream_format_range_t & format_range)53 bool 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 
iterator(const FrameRateEnumerator * enumerator)114 FrameRateEnumerator::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 
Advance()139 void 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