/* * 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 <utils/Log.h> #include <media/nbaio/NBAIO.h> namespace android { size_t Format_frameSize(const NBAIO_Format& format) { return format.mFrameSize; } const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 }; unsigned Format_sampleRate(const NBAIO_Format& format) { if (!Format_isValid(format)) { return 0; } return format.mSampleRate; } unsigned Format_channelCount(const NBAIO_Format& format) { if (!Format_isValid(format)) { return 0; } return format.mChannelCount; } NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, audio_format_t format) { if (sampleRate == 0 || channelCount == 0 || !audio_is_valid_format(format)) { return Format_Invalid; } NBAIO_Format ret; ret.mSampleRate = sampleRate; ret.mChannelCount = channelCount; ret.mFormat = format; ret.mFrameSize = audio_is_linear_pcm(format) ? channelCount * audio_bytes_per_sample(format) : sizeof(uint8_t); return ret; } // 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, 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); if (ret > 0) { ALOG_ASSERT((size_t) ret <= count); size_t maxRet = ret; ret = via(user, buffer, maxRet); 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=%zu countersOffers=%p numCounterOffers=%zu", offers, numOffers, counterOffers, numCounterOffers); if (Format_isValid(mFormat)) { for (size_t i = 0; i < numOffers; ++i) { if (Format_isEqual(offers[i], mFormat)) { mNegotiated = true; return i; } } if (numCounterOffers > 0) { counterOffers[0] = mFormat; } numCounterOffers = 1; } else { numCounterOffers = 0; } return (ssize_t) NEGOTIATE; } bool Format_isValid(const NBAIO_Format& format) { return format.mSampleRate != 0 && format.mChannelCount != 0 && format.mFormat != AUDIO_FORMAT_INVALID && format.mFrameSize != 0; } bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2) { return format1.mSampleRate == format2.mSampleRate && format1.mChannelCount == format2.mChannelCount && format1.mFormat == format2.mFormat && format1.mFrameSize == format2.mFrameSize; } } // namespace android