NBAIO.cpp revision 0f6a0435713c435e1aaeacbfd9ce7abb6a5b19a9
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{ 27983f0578ccd2928af40c9689f6fe90110d02b92eGlenn Kasten return format.mFrameSize; 28010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 29010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 302b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kastenconst NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 }; 3151d53cd993043d9286e12cba884e6ee4d10b5facGlenn Kasten 3272e54af9fcdc4754914fe2bf8de699523538b315Glenn Kastenunsigned Format_sampleRate(const NBAIO_Format& format) 33010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 346e0d67d7b496ce17c0970a4ffd3a6f808860949cGlenn Kasten if (!Format_isValid(format)) { 35b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten return 0; 36b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten } 372b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten return format.mSampleRate; 38010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 39010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 4072e54af9fcdc4754914fe2bf8de699523538b315Glenn Kastenunsigned Format_channelCount(const NBAIO_Format& format) 41010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 426e0d67d7b496ce17c0970a4ffd3a6f808860949cGlenn Kasten if (!Format_isValid(format)) { 43b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten return 0; 44b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten } 452b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten return format.mChannelCount; 46010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 47010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 48f95a3c4122d67273d930c7d83c3df99f136603edGlenn KastenNBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, 492b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten audio_format_t format) 50010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 512b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten if (sampleRate == 0 || channelCount == 0 || !audio_is_valid_format(format)) { 52b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten return Format_Invalid; 53b64497eb8724c4c372fffdbf3ee30543432953c5Glenn Kasten } 54c4b8b32dec91a11a83d0a7ab49747606d16d39a5Glenn Kasten NBAIO_Format ret; 552b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten ret.mSampleRate = sampleRate; 562b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten ret.mChannelCount = channelCount; 572b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten ret.mFormat = format; 582b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten ret.mFrameSize = audio_is_linear_pcm(format) ? 592b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten channelCount * audio_bytes_per_sample(format) : sizeof(uint8_t); 60c4b8b32dec91a11a83d0a7ab49747606d16d39a5Glenn Kasten return ret; 61010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 62010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 63010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten// This is a default implementation; it is expected that subclasses will optimize this. 64010662326b9c43c703725f933e95e0897f8a6bddGlenn Kastenssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block) 65010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 66010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (!mNegotiated) { 67010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return (ssize_t) NEGOTIATE; 68010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 69010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten static const size_t maxBlock = 32; 70010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t frameSize = Format_frameSize(mFormat); 71010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT(frameSize > 0 && frameSize <= 8); 72010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten // double guarantees alignment for stack similar to what malloc() gives for heap 73010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (block == 0 || block > maxBlock) { 74010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten block = maxBlock; 75010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 76010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)]; 77010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t accumulator = 0; 78010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten while (accumulator < total) { 79010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t count = total - accumulator; 80010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (count > block) { 81010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten count = block; 82010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 83010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ssize_t ret = via(user, buffer, count); 84010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (ret > 0) { 85010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT((size_t) ret <= count); 86010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t maxRet = ret; 87010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ret = write(buffer, maxRet); 88010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (ret > 0) { 89010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT((size_t) ret <= maxRet); 90010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten accumulator += ret; 91010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten continue; 92010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 93010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 94010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return accumulator > 0 ? accumulator : ret; 95010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 96010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return accumulator; 97010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 98010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 99010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten// This is a default implementation; it is expected that subclasses will optimize this. 1002c3b2da3049627264b7c6b449a1622f002210f03John Grossmanssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, 1012c3b2da3049627264b7c6b449a1622f002210f03John Grossman int64_t readPTS, size_t block) 102010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 103010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (!mNegotiated) { 104010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return (ssize_t) NEGOTIATE; 105010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 106010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten static const size_t maxBlock = 32; 107010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t frameSize = Format_frameSize(mFormat); 108010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT(frameSize > 0 && frameSize <= 8); 109010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten // double guarantees alignment for stack similar to what malloc() gives for heap 110010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (block == 0 || block > maxBlock) { 111010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten block = maxBlock; 112010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 113010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)]; 114010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t accumulator = 0; 115010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten while (accumulator < total) { 116010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t count = total - accumulator; 117010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (count > block) { 118010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten count = block; 119010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 1202c3b2da3049627264b7c6b449a1622f002210f03John Grossman ssize_t ret = read(buffer, count, readPTS); 121010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (ret > 0) { 122010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT((size_t) ret <= count); 123010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten size_t maxRet = ret; 1242c3b2da3049627264b7c6b449a1622f002210f03John Grossman ret = via(user, buffer, maxRet, readPTS); 125010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (ret > 0) { 126010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten ALOG_ASSERT((size_t) ret <= maxRet); 127010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten accumulator += ret; 128010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten continue; 129010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 130010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 131010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return accumulator > 0 ? accumulator : ret; 132010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 133010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return accumulator; 134010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 135010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 136010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten// Default implementation that only accepts my mFormat 137010662326b9c43c703725f933e95e0897f8a6bddGlenn Kastenssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers, 138010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten NBAIO_Format counterOffers[], size_t& numCounterOffers) 139010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten{ 1400f6a0435713c435e1aaeacbfd9ce7abb6a5b19a9Mark Salyzyn ALOGV("negotiate offers=%p numOffers=%zu countersOffers=%p numCounterOffers=%zu", 141010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten offers, numOffers, counterOffers, numCounterOffers); 1426e0d67d7b496ce17c0970a4ffd3a6f808860949cGlenn Kasten if (Format_isValid(mFormat)) { 143010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten for (size_t i = 0; i < numOffers; ++i) { 1446e0d67d7b496ce17c0970a4ffd3a6f808860949cGlenn Kasten if (Format_isEqual(offers[i], mFormat)) { 145010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten mNegotiated = true; 146010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return i; 147010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 148010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 149010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten if (numCounterOffers > 0) { 150010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten counterOffers[0] = mFormat; 151010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 152010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten numCounterOffers = 1; 153010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } else { 154010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten numCounterOffers = 0; 155010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten } 156010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten return (ssize_t) NEGOTIATE; 157010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} 158010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten 159cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kastenbool Format_isValid(const NBAIO_Format& format) 160cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten{ 1612b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten return format.mSampleRate != 0 && format.mChannelCount != 0 && 1622b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten format.mFormat != AUDIO_FORMAT_INVALID && format.mFrameSize != 0; 163cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten} 164cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten 165cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kastenbool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2) 166cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten{ 1672b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten return format1.mSampleRate == format2.mSampleRate && 1682b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten format1.mChannelCount == format2.mChannelCount && format1.mFormat == format2.mFormat && 1692b7b910f4b417ab3930379298f538d0dfc857e88Glenn Kasten format1.mFrameSize == format2.mFrameSize; 170cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten} 171cc1e0e807ee9a9f163a4685cbd6efd6ae55849cfGlenn Kasten 172010662326b9c43c703725f933e95e0897f8a6bddGlenn Kasten} // namespace android 173