NBAIO.cpp revision 2b7b910f4b417ab3930379298f538d0dfc857e88
1010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten/* 2010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * Copyright (C) 2012 The Android Open Source Project 3010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * 4010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * you may not use this file except in compliance with the License. 6010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * You may obtain a copy of the License at 7010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * 8010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * 10010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * Unless required by applicable law or agreed to in writing, software 11010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * See the License for the specific language governing permissions and 14010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten * limitations under the License. 15010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten */ 16010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 17010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten#define LOG_TAG "NBAIO" 18010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten//#define LOG_NDEBUG 0 19010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 20010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten#include <utils/Log.h> 212dd4bdd715f586d4d30cf90cc6fc2bbfbce60fe0Glenn Kasten#include <media/nbaio/NBAIO.h> 22010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 23010662326b9c43c703725f933e95e0897f8a6bddGlenn Kastennamespace android { 24010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 2572e54af9fcdc4754914fe2bf8de699523538b315Glenn Kastensize_t Format_frameSize(const NBAIO_Format& format) 26010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 271ec712f180072a7eb2131be09862921ae62dc2b4Glenn Kasten // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT 28b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten return Format_channelCount(format) * sizeof(short); 29010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 30010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 314d7b3f876b21997680ae32a340d746ed1cae6ab1Glenn Kastenint Format_frameBitShift(const NBAIO_Format& format) 32010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 331ec712f180072a7eb2131be09862921ae62dc2b4Glenn Kasten // FIXME The sample format is hard-coded to AUDIO_FORMAT_PCM_16_BIT 34b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten // sizeof(short) == 2, so frame size == 1 << channels 35b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten return Format_channelCount(format); 364d7b3f876b21997680ae32a340d746ed1cae6ab1Glenn Kasten // FIXME must return -1 for non-power of 2 37010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 38010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 392b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kastenconst NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 }; 4051d53cd993043d9286e12cba884e6ee4d10b5facGlenn Kasten 41b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kastenenum { 42b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_8000, 43b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_11025, 44b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_16000, 45b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_22050, 46b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_24000, 47b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_32000, 48b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_44100, 49b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_48000, 50b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_SR_Mask = 7 51b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten}; 52b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten 53b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kastenenum { 54b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_C_1 = 0x08, 55b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_C_2 = 0x10, 56b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten Format_C_Mask = 0x18 57b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten}; 58b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten 5972e54af9fcdc4754914fe2bf8de699523538b315Glenn Kastenunsigned Format_sampleRate(const NBAIO_Format& format) 60010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 616e0d67d7b496ce17c0970a4ffd3a6f808860949cGlenn Kasten if (!Format_isValid(format)) { 62b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten return 0; 63b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten } 642b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten return format.mSampleRate; 65010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 66010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 6772e54af9fcdc4754914fe2bf8de699523538b315Glenn Kastenunsigned Format_channelCount(const NBAIO_Format& format) 68010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 696e0d67d7b496ce17c0970a4ffd3a6f808860949cGlenn Kasten if (!Format_isValid(format)) { 70b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten return 0; 71b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten } 722b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten return format.mChannelCount; 73010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 74010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 75f95a3c4122d67273d930c7d83c3df99f136603edGlenn KastenNBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, 762b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten audio_format_t format) 77010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 782b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten if (sampleRate == 0 || channelCount == 0 || !audio_is_valid_format(format)) { 79b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten return Format_Invalid; 80b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten } 81c4b8b32dec91a11a83d0a7ab49747606d16d39a5Glenn Kasten NBAIO_Format ret; 822b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten ret.mSampleRate = sampleRate; 832b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten ret.mChannelCount = channelCount; 842b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten ret.mFormat = format; 852b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten ret.mFrameSize = audio_is_linear_pcm(format) ? 862b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten channelCount * audio_bytes_per_sample(format) : sizeof(uint8_t); 87c4b8b32dec91a11a83d0a7ab49747606d16d39a5Glenn Kasten return ret; 88010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 89010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 90010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten// This is a default implementation; it is expected that subclasses will optimize this. 91010662326b9c43c703725f933e95e0897f8a6bddGlenn Kastenssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block) 92010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 93010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (!mNegotiated) { 94010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return (ssize_t) NEGOTIATE; 95010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 96010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten static const size_t maxBlock = 32; 97010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t frameSize = Format_frameSize(mFormat); 98010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT(frameSize > 0 && frameSize <= 8); 99010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten // double guarantees alignment for stack similar to what malloc() gives for heap 100010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (block == 0 || block > maxBlock) { 101010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten block = maxBlock; 102010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 103010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)]; 104010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t accumulator = 0; 105010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten while (accumulator < total) { 106010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t count = total - accumulator; 107010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (count > block) { 108010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten count = block; 109010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 110010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ssize_t ret = via(user, buffer, count); 111010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (ret > 0) { 112010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT((size_t) ret <= count); 113010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t maxRet = ret; 114010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ret = write(buffer, maxRet); 115010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (ret > 0) { 116010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT((size_t) ret <= maxRet); 117010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten accumulator += ret; 118010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten continue; 119010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 120010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 121010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return accumulator > 0 ? accumulator : ret; 122010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 123010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return accumulator; 124010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 125010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 126010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten// This is a default implementation; it is expected that subclasses will optimize this. 1272c3b2da3049627264b7c6b449a1622f002210f03John Grossmanssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, 1282c3b2da3049627264b7c6b449a1622f002210f03John Grossman int64_t readPTS, size_t block) 129010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 130010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (!mNegotiated) { 131010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return (ssize_t) NEGOTIATE; 132010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 133010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten static const size_t maxBlock = 32; 134010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t frameSize = Format_frameSize(mFormat); 135010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT(frameSize > 0 && frameSize <= 8); 136010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten // double guarantees alignment for stack similar to what malloc() gives for heap 137010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (block == 0 || block > maxBlock) { 138010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten block = maxBlock; 139010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 140010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)]; 141010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t accumulator = 0; 142010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten while (accumulator < total) { 143010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t count = total - accumulator; 144010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (count > block) { 145010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten count = block; 146010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 1472c3b2da3049627264b7c6b449a1622f002210f03John Grossman ssize_t ret = read(buffer, count, readPTS); 148010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (ret > 0) { 149010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT((size_t) ret <= count); 150010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t maxRet = ret; 1512c3b2da3049627264b7c6b449a1622f002210f03John Grossman ret = via(user, buffer, maxRet, readPTS); 152010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (ret > 0) { 153010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT((size_t) ret <= maxRet); 154010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten accumulator += ret; 155010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten continue; 156010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 157010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 158010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return accumulator > 0 ? accumulator : ret; 159010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 160010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return accumulator; 161010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 162010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 163010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten// Default implementation that only accepts my mFormat 164010662326b9c43c703725f933e95e0897f8a6bddGlenn Kastenssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers, 165010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten NBAIO_Format counterOffers[], size_t& numCounterOffers) 166010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 167010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u", 168010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten offers, numOffers, counterOffers, numCounterOffers); 1696e0d67d7b496ce17c0970a4ffd3a6f808860949cGlenn Kasten if (Format_isValid(mFormat)) { 170010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten for (size_t i = 0; i < numOffers; ++i) { 1716e0d67d7b496ce17c0970a4ffd3a6f808860949cGlenn Kasten if (Format_isEqual(offers[i], mFormat)) { 172010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten mNegotiated = true; 173010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return i; 174010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 175010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 176010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (numCounterOffers > 0) { 177010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten counterOffers[0] = mFormat; 178010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 179010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten numCounterOffers = 1; 180010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } else { 181010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten numCounterOffers = 0; 182010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 183010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return (ssize_t) NEGOTIATE; 184010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 185010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 186cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kastenbool Format_isValid(const NBAIO_Format& format) 187cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten{ 1882b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten return format.mSampleRate != 0 && format.mChannelCount != 0 && 1892b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten format.mFormat != AUDIO_FORMAT_INVALID && format.mFrameSize != 0; 190cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten} 191cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten 192cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kastenbool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2) 193cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten{ 1942b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten return format1.mSampleRate == format2.mSampleRate && 1952b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten format1.mChannelCount == format2.mChannelCount && format1.mFormat == format2.mFormat && 1962b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten format1.mFrameSize == format2.mFrameSize; 197cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten} 198cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten 199010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} // namespace android 200