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 25 size_t Format_frameSize(NBAIO_Format format) 26 { 27 return Format_channelCount(format) * sizeof(short); 28 } 29 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 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 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 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. 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. 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 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