/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "NBAIO" //#define LOG_NDEBUG 0 #include #include namespace android { size_t Format_frameSize(NBAIO_Format format) { return Format_channelCount(format) * sizeof(short); } size_t Format_frameBitShift(NBAIO_Format format) { // sizeof(short) == 2, so frame size == 1 << channels return Format_channelCount(format); } enum { Format_SR_8000, Format_SR_11025, Format_SR_16000, Format_SR_22050, Format_SR_24000, Format_SR_32000, Format_SR_44100, Format_SR_48000, Format_SR_Mask = 7 }; enum { Format_C_1 = 0x08, Format_C_2 = 0x10, Format_C_Mask = 0x18 }; unsigned Format_sampleRate(NBAIO_Format format) { if (format == Format_Invalid) { return 0; } switch (format & Format_SR_Mask) { case Format_SR_8000: return 8000; case Format_SR_11025: return 11025; case Format_SR_16000: return 16000; case Format_SR_22050: return 22050; case Format_SR_24000: return 24000; case Format_SR_32000: return 32000; case Format_SR_44100: return 44100; case Format_SR_48000: return 48000; default: return 0; } } unsigned Format_channelCount(NBAIO_Format format) { if (format == Format_Invalid) { return 0; } switch (format & Format_C_Mask) { case Format_C_1: return 1; case Format_C_2: return 2; default: return 0; } } NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount) { NBAIO_Format format; switch (sampleRate) { case 8000: format = Format_SR_8000; break; case 11025: format = Format_SR_11025; break; case 16000: format = Format_SR_16000; break; case 22050: format = Format_SR_22050; break; case 24000: format = Format_SR_24000; break; case 32000: format = Format_SR_32000; break; case 44100: format = Format_SR_44100; break; case 48000: format = Format_SR_48000; break; default: return Format_Invalid; } switch (channelCount) { case 1: format |= Format_C_1; break; case 2: format |= Format_C_2; break; default: return Format_Invalid; } return format; } // This is a default implementation; it is expected that subclasses will optimize this. ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block) { if (!mNegotiated) { return (ssize_t) NEGOTIATE; } static const size_t maxBlock = 32; size_t frameSize = Format_frameSize(mFormat); ALOG_ASSERT(frameSize > 0 && frameSize <= 8); // double guarantees alignment for stack similar to what malloc() gives for heap if (block == 0 || block > maxBlock) { block = maxBlock; } double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)]; size_t accumulator = 0; while (accumulator < total) { size_t count = total - accumulator; if (count > block) { count = block; } ssize_t ret = via(user, buffer, count); if (ret > 0) { ALOG_ASSERT((size_t) ret <= count); size_t maxRet = ret; ret = write(buffer, maxRet); if (ret > 0) { ALOG_ASSERT((size_t) ret <= maxRet); accumulator += ret; continue; } } return accumulator > 0 ? accumulator : ret; } return accumulator; } // This is a default implementation; it is expected that subclasses will optimize this. ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, int64_t readPTS, size_t block) { if (!mNegotiated) { return (ssize_t) NEGOTIATE; } static const size_t maxBlock = 32; size_t frameSize = Format_frameSize(mFormat); ALOG_ASSERT(frameSize > 0 && frameSize <= 8); // double guarantees alignment for stack similar to what malloc() gives for heap if (block == 0 || block > maxBlock) { block = maxBlock; } double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)]; size_t accumulator = 0; while (accumulator < total) { size_t count = total - accumulator; if (count > block) { count = block; } ssize_t ret = read(buffer, count, readPTS); if (ret > 0) { ALOG_ASSERT((size_t) ret <= count); size_t maxRet = ret; ret = via(user, buffer, maxRet, readPTS); if (ret > 0) { ALOG_ASSERT((size_t) ret <= maxRet); accumulator += ret; continue; } } return accumulator > 0 ? accumulator : ret; } return accumulator; } // Default implementation that only accepts my mFormat ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers, NBAIO_Format counterOffers[], size_t& numCounterOffers) { ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u", offers, numOffers, counterOffers, numCounterOffers); if (mFormat != Format_Invalid) { for (size_t i = 0; i < numOffers; ++i) { if (offers[i] == mFormat) { mNegotiated = true; return i; } } if (numCounterOffers > 0) { counterOffers[0] = mFormat; } numCounterOffers = 1; } else { numCounterOffers = 0; } return (ssize_t) NEGOTIATE; } } // namespace android