blob: 51514deefbd073d6918e390de26673a348db2cb2 [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
101NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
102{
Glenn Kastenc4b8b322014-01-31 09:39:01 -0800103 unsigned format;
Glenn Kastenb64497e2012-10-01 09:47:30 -0700104 switch (sampleRate) {
105 case 8000:
106 format = Format_SR_8000;
107 break;
108 case 11025:
109 format = Format_SR_11025;
110 break;
111 case 16000:
112 format = Format_SR_16000;
113 break;
114 case 22050:
115 format = Format_SR_22050;
116 break;
117 case 24000:
118 format = Format_SR_24000;
119 break;
120 case 32000:
121 format = Format_SR_32000;
122 break;
123 case 44100:
124 format = Format_SR_44100;
125 break;
126 case 48000:
127 format = Format_SR_48000;
128 break;
129 default:
130 return Format_Invalid;
131 }
132 switch (channelCount) {
133 case 1:
134 format |= Format_C_1;
135 break;
136 case 2:
137 format |= Format_C_2;
138 break;
139 default:
140 return Format_Invalid;
141 }
Glenn Kastenc4b8b322014-01-31 09:39:01 -0800142 NBAIO_Format ret;
143 ret.mPacked = format;
144 return ret;
Glenn Kasten01066232012-02-27 11:50:44 -0800145}
146
147// This is a default implementation; it is expected that subclasses will optimize this.
148ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
149{
150 if (!mNegotiated) {
151 return (ssize_t) NEGOTIATE;
152 }
153 static const size_t maxBlock = 32;
154 size_t frameSize = Format_frameSize(mFormat);
155 ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
156 // double guarantees alignment for stack similar to what malloc() gives for heap
157 if (block == 0 || block > maxBlock) {
158 block = maxBlock;
159 }
160 double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
161 size_t accumulator = 0;
162 while (accumulator < total) {
163 size_t count = total - accumulator;
164 if (count > block) {
165 count = block;
166 }
167 ssize_t ret = via(user, buffer, count);
168 if (ret > 0) {
169 ALOG_ASSERT((size_t) ret <= count);
170 size_t maxRet = ret;
171 ret = write(buffer, maxRet);
172 if (ret > 0) {
173 ALOG_ASSERT((size_t) ret <= maxRet);
174 accumulator += ret;
175 continue;
176 }
177 }
178 return accumulator > 0 ? accumulator : ret;
179 }
180 return accumulator;
181}
182
183// This is a default implementation; it is expected that subclasses will optimize this.
John Grossman2c3b2da2012-08-02 17:08:54 -0700184ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
185 int64_t readPTS, size_t block)
Glenn Kasten01066232012-02-27 11:50:44 -0800186{
187 if (!mNegotiated) {
188 return (ssize_t) NEGOTIATE;
189 }
190 static const size_t maxBlock = 32;
191 size_t frameSize = Format_frameSize(mFormat);
192 ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
193 // double guarantees alignment for stack similar to what malloc() gives for heap
194 if (block == 0 || block > maxBlock) {
195 block = maxBlock;
196 }
197 double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
198 size_t accumulator = 0;
199 while (accumulator < total) {
200 size_t count = total - accumulator;
201 if (count > block) {
202 count = block;
203 }
John Grossman2c3b2da2012-08-02 17:08:54 -0700204 ssize_t ret = read(buffer, count, readPTS);
Glenn Kasten01066232012-02-27 11:50:44 -0800205 if (ret > 0) {
206 ALOG_ASSERT((size_t) ret <= count);
207 size_t maxRet = ret;
John Grossman2c3b2da2012-08-02 17:08:54 -0700208 ret = via(user, buffer, maxRet, readPTS);
Glenn Kasten01066232012-02-27 11:50:44 -0800209 if (ret > 0) {
210 ALOG_ASSERT((size_t) ret <= maxRet);
211 accumulator += ret;
212 continue;
213 }
214 }
215 return accumulator > 0 ? accumulator : ret;
216 }
217 return accumulator;
218}
219
220// Default implementation that only accepts my mFormat
221ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
222 NBAIO_Format counterOffers[], size_t& numCounterOffers)
223{
224 ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
225 offers, numOffers, counterOffers, numCounterOffers);
Glenn Kasten6e0d67d2014-01-31 09:41:08 -0800226 if (Format_isValid(mFormat)) {
Glenn Kasten01066232012-02-27 11:50:44 -0800227 for (size_t i = 0; i < numOffers; ++i) {
Glenn Kasten6e0d67d2014-01-31 09:41:08 -0800228 if (Format_isEqual(offers[i], mFormat)) {
Glenn Kasten01066232012-02-27 11:50:44 -0800229 mNegotiated = true;
230 return i;
231 }
232 }
233 if (numCounterOffers > 0) {
234 counterOffers[0] = mFormat;
235 }
236 numCounterOffers = 1;
237 } else {
238 numCounterOffers = 0;
239 }
240 return (ssize_t) NEGOTIATE;
241}
242
Glenn Kastencc1e0e82014-01-31 09:48:42 -0800243bool Format_isValid(const NBAIO_Format& format)
244{
Glenn Kastenc4b8b322014-01-31 09:39:01 -0800245 return format.mPacked != Format_Invalid.mPacked;
Glenn Kastencc1e0e82014-01-31 09:48:42 -0800246}
247
248bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
249{
Glenn Kastenc4b8b322014-01-31 09:39:01 -0800250 return format1.mPacked == format2.mPacked;
Glenn Kastencc1e0e82014-01-31 09:48:42 -0800251}
252
Glenn Kasten01066232012-02-27 11:50:44 -0800253} // namespace android