1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "NBAIO"
18 //#define LOG_NDEBUG 0
19
20 #include <utils/Log.h>
21 #include <media/nbaio/NBAIO.h>
22
23 namespace android {
24
Format_frameSize(NBAIO_Format format)25 size_t Format_frameSize(NBAIO_Format format)
26 {
27 return Format_channelCount(format) * sizeof(short);
28 }
29
Format_frameBitShift(NBAIO_Format format)30 size_t Format_frameBitShift(NBAIO_Format format)
31 {
32 // sizeof(short) == 2, so frame size == 1 << channels
33 return Format_channelCount(format);
34 }
35
36 enum {
37 Format_SR_8000,
38 Format_SR_11025,
39 Format_SR_16000,
40 Format_SR_22050,
41 Format_SR_24000,
42 Format_SR_32000,
43 Format_SR_44100,
44 Format_SR_48000,
45 Format_SR_Mask = 7
46 };
47
48 enum {
49 Format_C_1 = 0x08,
50 Format_C_2 = 0x10,
51 Format_C_Mask = 0x18
52 };
53
Format_sampleRate(NBAIO_Format format)54 unsigned Format_sampleRate(NBAIO_Format format)
55 {
56 if (format == Format_Invalid) {
57 return 0;
58 }
59 switch (format & Format_SR_Mask) {
60 case Format_SR_8000:
61 return 8000;
62 case Format_SR_11025:
63 return 11025;
64 case Format_SR_16000:
65 return 16000;
66 case Format_SR_22050:
67 return 22050;
68 case Format_SR_24000:
69 return 24000;
70 case Format_SR_32000:
71 return 32000;
72 case Format_SR_44100:
73 return 44100;
74 case Format_SR_48000:
75 return 48000;
76 default:
77 return 0;
78 }
79 }
80
Format_channelCount(NBAIO_Format format)81 unsigned Format_channelCount(NBAIO_Format format)
82 {
83 if (format == Format_Invalid) {
84 return 0;
85 }
86 switch (format & Format_C_Mask) {
87 case Format_C_1:
88 return 1;
89 case Format_C_2:
90 return 2;
91 default:
92 return 0;
93 }
94 }
95
Format_from_SR_C(unsigned sampleRate,unsigned channelCount)96 NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
97 {
98 NBAIO_Format format;
99 switch (sampleRate) {
100 case 8000:
101 format = Format_SR_8000;
102 break;
103 case 11025:
104 format = Format_SR_11025;
105 break;
106 case 16000:
107 format = Format_SR_16000;
108 break;
109 case 22050:
110 format = Format_SR_22050;
111 break;
112 case 24000:
113 format = Format_SR_24000;
114 break;
115 case 32000:
116 format = Format_SR_32000;
117 break;
118 case 44100:
119 format = Format_SR_44100;
120 break;
121 case 48000:
122 format = Format_SR_48000;
123 break;
124 default:
125 return Format_Invalid;
126 }
127 switch (channelCount) {
128 case 1:
129 format |= Format_C_1;
130 break;
131 case 2:
132 format |= Format_C_2;
133 break;
134 default:
135 return Format_Invalid;
136 }
137 return format;
138 }
139
140 // This is a default implementation; it is expected that subclasses will optimize this.
writeVia(writeVia_t via,size_t total,void * user,size_t block)141 ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
142 {
143 if (!mNegotiated) {
144 return (ssize_t) NEGOTIATE;
145 }
146 static const size_t maxBlock = 32;
147 size_t frameSize = Format_frameSize(mFormat);
148 ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
149 // double guarantees alignment for stack similar to what malloc() gives for heap
150 if (block == 0 || block > maxBlock) {
151 block = maxBlock;
152 }
153 double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
154 size_t accumulator = 0;
155 while (accumulator < total) {
156 size_t count = total - accumulator;
157 if (count > block) {
158 count = block;
159 }
160 ssize_t ret = via(user, buffer, count);
161 if (ret > 0) {
162 ALOG_ASSERT((size_t) ret <= count);
163 size_t maxRet = ret;
164 ret = write(buffer, maxRet);
165 if (ret > 0) {
166 ALOG_ASSERT((size_t) ret <= maxRet);
167 accumulator += ret;
168 continue;
169 }
170 }
171 return accumulator > 0 ? accumulator : ret;
172 }
173 return accumulator;
174 }
175
176 // This is a default implementation; it is expected that subclasses will optimize this.
readVia(readVia_t via,size_t total,void * user,int64_t readPTS,size_t block)177 ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
178 int64_t readPTS, size_t block)
179 {
180 if (!mNegotiated) {
181 return (ssize_t) NEGOTIATE;
182 }
183 static const size_t maxBlock = 32;
184 size_t frameSize = Format_frameSize(mFormat);
185 ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
186 // double guarantees alignment for stack similar to what malloc() gives for heap
187 if (block == 0 || block > maxBlock) {
188 block = maxBlock;
189 }
190 double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
191 size_t accumulator = 0;
192 while (accumulator < total) {
193 size_t count = total - accumulator;
194 if (count > block) {
195 count = block;
196 }
197 ssize_t ret = read(buffer, count, readPTS);
198 if (ret > 0) {
199 ALOG_ASSERT((size_t) ret <= count);
200 size_t maxRet = ret;
201 ret = via(user, buffer, maxRet, readPTS);
202 if (ret > 0) {
203 ALOG_ASSERT((size_t) ret <= maxRet);
204 accumulator += ret;
205 continue;
206 }
207 }
208 return accumulator > 0 ? accumulator : ret;
209 }
210 return accumulator;
211 }
212
213 // Default implementation that only accepts my mFormat
negotiate(const NBAIO_Format offers[],size_t numOffers,NBAIO_Format counterOffers[],size_t & numCounterOffers)214 ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
215 NBAIO_Format counterOffers[], size_t& numCounterOffers)
216 {
217 ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
218 offers, numOffers, counterOffers, numCounterOffers);
219 if (mFormat != Format_Invalid) {
220 for (size_t i = 0; i < numOffers; ++i) {
221 if (offers[i] == mFormat) {
222 mNegotiated = true;
223 return i;
224 }
225 }
226 if (numCounterOffers > 0) {
227 counterOffers[0] = mFormat;
228 }
229 numCounterOffers = 1;
230 } else {
231 numCounterOffers = 0;
232 }
233 return (ssize_t) NEGOTIATE;
234 }
235
236 } // namespace android
237