blob: a15d41c8268bb14129b9c01008d48cbcc9054844 [file] [log] [blame]
Glenn Kasten01066232012-02-27 11:50:44 -08001/*
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>
Glenn Kasten2dd4bdd2012-08-29 11:10:32 -070021#include <media/nbaio/NBAIO.h>
Glenn Kasten01066232012-02-27 11:50:44 -080022
23namespace android {
24
Glenn Kasten72e54af2014-01-31 09:37:35 -080025size_t Format_frameSize(const NBAIO_Format& format)
Glenn Kasten01066232012-02-27 11:50:44 -080026{
Glenn Kasten1ec712f2014-01-31 09:47:15 -080027 // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT
Glenn Kastenb64497e2012-10-01 09:47:30 -070028 return Format_channelCount(format) * sizeof(short);
Glenn Kasten01066232012-02-27 11:50:44 -080029}
30
Glenn Kasten4d7b3f82014-01-31 10:38:16 -080031int Format_frameBitShift(const NBAIO_Format& format)
Glenn Kasten01066232012-02-27 11:50:44 -080032{
Glenn Kasten1ec712f2014-01-31 09:47:15 -080033 // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT
Glenn Kastenb64497e2012-10-01 09:47:30 -070034 // sizeof(short) == 2, so frame size == 1 << channels
35 return Format_channelCount(format);
Glenn Kasten4d7b3f82014-01-31 10:38:16 -080036 // FIXME must return -1 for non-power of 2
Glenn Kasten01066232012-02-27 11:50:44 -080037}
38
Glenn Kasten51d53cd2014-01-31 09:38:33 -080039const NBAIO_Format Format_Invalid = { 0 };
40
Glenn Kastenb64497e2012-10-01 09:47:30 -070041enum {
42 Format_SR_8000,
43 Format_SR_11025,
44 Format_SR_16000,
45 Format_SR_22050,
46 Format_SR_24000,
47 Format_SR_32000,
48 Format_SR_44100,
49 Format_SR_48000,
50 Format_SR_Mask = 7
51};
52
53enum {
54 Format_C_1 = 0x08,
55 Format_C_2 = 0x10,
56 Format_C_Mask = 0x18
57};
58
Glenn Kasten72e54af2014-01-31 09:37:35 -080059unsigned Format_sampleRate(const NBAIO_Format& format)
Glenn Kasten01066232012-02-27 11:50:44 -080060{
Glenn Kasten6e0d67d2014-01-31 09:41:08 -080061 if (!Format_isValid(format)) {
Glenn Kastenb64497e2012-10-01 09:47:30 -070062 return 0;
63 }
Glenn Kastenc4b8b322014-01-31 09:39:01 -080064 switch (format.mPacked & Format_SR_Mask) {
Glenn Kastenb64497e2012-10-01 09:47:30 -070065 case Format_SR_8000:
66 return 8000;
67 case Format_SR_11025:
68 return 11025;
69 case Format_SR_16000:
70 return 16000;
71 case Format_SR_22050:
72 return 22050;
73 case Format_SR_24000:
74 return 24000;
75 case Format_SR_32000:
76 return 32000;
77 case Format_SR_44100:
Glenn Kasten01066232012-02-27 11:50:44 -080078 return 44100;
Glenn Kastenb64497e2012-10-01 09:47:30 -070079 case Format_SR_48000:
Glenn Kasten01066232012-02-27 11:50:44 -080080 return 48000;
Glenn Kasten01066232012-02-27 11:50:44 -080081 default:
82 return 0;
83 }
84}
85
Glenn Kasten72e54af2014-01-31 09:37:35 -080086unsigned Format_channelCount(const NBAIO_Format& format)
Glenn Kasten01066232012-02-27 11:50:44 -080087{
Glenn Kasten6e0d67d2014-01-31 09:41:08 -080088 if (!Format_isValid(format)) {
Glenn Kastenb64497e2012-10-01 09:47:30 -070089 return 0;
90 }
Glenn Kastenc4b8b322014-01-31 09:39:01 -080091 switch (format.mPacked & Format_C_Mask) {
Glenn Kastenb64497e2012-10-01 09:47:30 -070092 case Format_C_1:
Glenn Kasten01066232012-02-27 11:50:44 -080093 return 1;
Glenn Kastenb64497e2012-10-01 09:47:30 -070094 case Format_C_2:
Glenn Kasten01066232012-02-27 11:50:44 -080095 return 2;
Glenn Kasten01066232012-02-27 11:50:44 -080096 default:
97 return 0;
98 }
99}
100
Glenn Kastenf95a3c42014-03-06 07:59:49 -0800101NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount,
102 audio_format_t format_ __unused)
Glenn Kasten01066232012-02-27 11:50:44 -0800103{
Glenn Kastenc4b8b322014-01-31 09:39:01 -0800104 unsigned format;
Glenn Kastenb64497e2012-10-01 09:47:30 -0700105 switch (sampleRate) {
106 case 8000:
107 format = Format_SR_8000;
108 break;
109 case 11025:
110 format = Format_SR_11025;
111 break;
112 case 16000:
113 format = Format_SR_16000;
114 break;
115 case 22050:
116 format = Format_SR_22050;
117 break;
118 case 24000:
119 format = Format_SR_24000;
120 break;
121 case 32000:
122 format = Format_SR_32000;
123 break;
124 case 44100:
125 format = Format_SR_44100;
126 break;
127 case 48000:
128 format = Format_SR_48000;
129 break;
130 default:
131 return Format_Invalid;
132 }
133 switch (channelCount) {
134 case 1:
135 format |= Format_C_1;
136 break;
137 case 2:
138 format |= Format_C_2;
139 break;
140 default:
141 return Format_Invalid;
142 }
Glenn Kastenc4b8b322014-01-31 09:39:01 -0800143 NBAIO_Format ret;
144 ret.mPacked = format;
145 return ret;
Glenn Kasten01066232012-02-27 11:50:44 -0800146}
147
148// This is a default implementation; it is expected that subclasses will optimize this.
149ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
150{
151 if (!mNegotiated) {
152 return (ssize_t) NEGOTIATE;
153 }
154 static const size_t maxBlock = 32;
155 size_t frameSize = Format_frameSize(mFormat);
156 ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
157 // double guarantees alignment for stack similar to what malloc() gives for heap
158 if (block == 0 || block > maxBlock) {
159 block = maxBlock;
160 }
161 double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
162 size_t accumulator = 0;
163 while (accumulator < total) {
164 size_t count = total - accumulator;
165 if (count > block) {
166 count = block;
167 }
168 ssize_t ret = via(user, buffer, count);
169 if (ret > 0) {
170 ALOG_ASSERT((size_t) ret <= count);
171 size_t maxRet = ret;
172 ret = write(buffer, maxRet);
173 if (ret > 0) {
174 ALOG_ASSERT((size_t) ret <= maxRet);
175 accumulator += ret;
176 continue;
177 }
178 }
179 return accumulator > 0 ? accumulator : ret;
180 }
181 return accumulator;
182}
183
184// This is a default implementation; it is expected that subclasses will optimize this.
John Grossman2c3b2da2012-08-02 17:08:54 -0700185ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
186 int64_t readPTS, size_t block)
Glenn Kasten01066232012-02-27 11:50:44 -0800187{
188 if (!mNegotiated) {
189 return (ssize_t) NEGOTIATE;
190 }
191 static const size_t maxBlock = 32;
192 size_t frameSize = Format_frameSize(mFormat);
193 ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
194 // double guarantees alignment for stack similar to what malloc() gives for heap
195 if (block == 0 || block > maxBlock) {
196 block = maxBlock;
197 }
198 double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
199 size_t accumulator = 0;
200 while (accumulator < total) {
201 size_t count = total - accumulator;
202 if (count > block) {
203 count = block;
204 }
John Grossman2c3b2da2012-08-02 17:08:54 -0700205 ssize_t ret = read(buffer, count, readPTS);
Glenn Kasten01066232012-02-27 11:50:44 -0800206 if (ret > 0) {
207 ALOG_ASSERT((size_t) ret <= count);
208 size_t maxRet = ret;
John Grossman2c3b2da2012-08-02 17:08:54 -0700209 ret = via(user, buffer, maxRet, readPTS);
Glenn Kasten01066232012-02-27 11:50:44 -0800210 if (ret > 0) {
211 ALOG_ASSERT((size_t) ret <= maxRet);
212 accumulator += ret;
213 continue;
214 }
215 }
216 return accumulator > 0 ? accumulator : ret;
217 }
218 return accumulator;
219}
220
221// Default implementation that only accepts my mFormat
222ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
223 NBAIO_Format counterOffers[], size_t& numCounterOffers)
224{
225 ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
226 offers, numOffers, counterOffers, numCounterOffers);
Glenn Kasten6e0d67d2014-01-31 09:41:08 -0800227 if (Format_isValid(mFormat)) {
Glenn Kasten01066232012-02-27 11:50:44 -0800228 for (size_t i = 0; i < numOffers; ++i) {
Glenn Kasten6e0d67d2014-01-31 09:41:08 -0800229 if (Format_isEqual(offers[i], mFormat)) {
Glenn Kasten01066232012-02-27 11:50:44 -0800230 mNegotiated = true;
231 return i;
232 }
233 }
234 if (numCounterOffers > 0) {
235 counterOffers[0] = mFormat;
236 }
237 numCounterOffers = 1;
238 } else {
239 numCounterOffers = 0;
240 }
241 return (ssize_t) NEGOTIATE;
242}
243
Glenn Kastencc1e0e82014-01-31 09:48:42 -0800244bool Format_isValid(const NBAIO_Format& format)
245{
Glenn Kastenc4b8b322014-01-31 09:39:01 -0800246 return format.mPacked != Format_Invalid.mPacked;
Glenn Kastencc1e0e82014-01-31 09:48:42 -0800247}
248
249bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
250{
Glenn Kastenc4b8b322014-01-31 09:39:01 -0800251 return format1.mPacked == format2.mPacked;
Glenn Kastencc1e0e82014-01-31 09:48:42 -0800252}
253
Glenn Kasten01066232012-02-27 11:50:44 -0800254} // namespace android