1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2012 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "NBAIO"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker
20*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <media/nbaio/NBAIO.h>
22*ec779b8eSAndroid Build Coastguard Worker
23*ec779b8eSAndroid Build Coastguard Worker namespace android {
24*ec779b8eSAndroid Build Coastguard Worker
Format_frameSize(const NBAIO_Format & format)25*ec779b8eSAndroid Build Coastguard Worker size_t Format_frameSize(const NBAIO_Format& format)
26*ec779b8eSAndroid Build Coastguard Worker {
27*ec779b8eSAndroid Build Coastguard Worker return format.mFrameSize;
28*ec779b8eSAndroid Build Coastguard Worker }
29*ec779b8eSAndroid Build Coastguard Worker
30*ec779b8eSAndroid Build Coastguard Worker const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 };
31*ec779b8eSAndroid Build Coastguard Worker
Format_sampleRate(const NBAIO_Format & format)32*ec779b8eSAndroid Build Coastguard Worker unsigned Format_sampleRate(const NBAIO_Format& format)
33*ec779b8eSAndroid Build Coastguard Worker {
34*ec779b8eSAndroid Build Coastguard Worker if (!Format_isValid(format)) {
35*ec779b8eSAndroid Build Coastguard Worker return 0;
36*ec779b8eSAndroid Build Coastguard Worker }
37*ec779b8eSAndroid Build Coastguard Worker return format.mSampleRate;
38*ec779b8eSAndroid Build Coastguard Worker }
39*ec779b8eSAndroid Build Coastguard Worker
Format_channelCount(const NBAIO_Format & format)40*ec779b8eSAndroid Build Coastguard Worker unsigned Format_channelCount(const NBAIO_Format& format)
41*ec779b8eSAndroid Build Coastguard Worker {
42*ec779b8eSAndroid Build Coastguard Worker if (!Format_isValid(format)) {
43*ec779b8eSAndroid Build Coastguard Worker return 0;
44*ec779b8eSAndroid Build Coastguard Worker }
45*ec779b8eSAndroid Build Coastguard Worker return format.mChannelCount;
46*ec779b8eSAndroid Build Coastguard Worker }
47*ec779b8eSAndroid Build Coastguard Worker
Format_from_SR_C(unsigned sampleRate,unsigned channelCount,audio_format_t format)48*ec779b8eSAndroid Build Coastguard Worker NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount,
49*ec779b8eSAndroid Build Coastguard Worker audio_format_t format)
50*ec779b8eSAndroid Build Coastguard Worker {
51*ec779b8eSAndroid Build Coastguard Worker if (sampleRate == 0 || channelCount == 0 || !audio_is_valid_format(format)) {
52*ec779b8eSAndroid Build Coastguard Worker return Format_Invalid;
53*ec779b8eSAndroid Build Coastguard Worker }
54*ec779b8eSAndroid Build Coastguard Worker NBAIO_Format ret;
55*ec779b8eSAndroid Build Coastguard Worker ret.mSampleRate = sampleRate;
56*ec779b8eSAndroid Build Coastguard Worker ret.mChannelCount = channelCount;
57*ec779b8eSAndroid Build Coastguard Worker ret.mFormat = format;
58*ec779b8eSAndroid Build Coastguard Worker ret.mFrameSize = audio_bytes_per_frame(channelCount, format);
59*ec779b8eSAndroid Build Coastguard Worker return ret;
60*ec779b8eSAndroid Build Coastguard Worker }
61*ec779b8eSAndroid Build Coastguard Worker
62*ec779b8eSAndroid Build Coastguard Worker // This is a default implementation; it is expected that subclasses will optimize this.
writeVia(writeVia_t via,size_t total,void * user,size_t block)63*ec779b8eSAndroid Build Coastguard Worker ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
64*ec779b8eSAndroid Build Coastguard Worker {
65*ec779b8eSAndroid Build Coastguard Worker if (!mNegotiated) {
66*ec779b8eSAndroid Build Coastguard Worker return (ssize_t) NEGOTIATE;
67*ec779b8eSAndroid Build Coastguard Worker }
68*ec779b8eSAndroid Build Coastguard Worker static const size_t maxBlock = 32;
69*ec779b8eSAndroid Build Coastguard Worker size_t frameSize = Format_frameSize(mFormat);
70*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
71*ec779b8eSAndroid Build Coastguard Worker // double guarantees alignment for stack similar to what malloc() gives for heap
72*ec779b8eSAndroid Build Coastguard Worker if (block == 0 || block > maxBlock) {
73*ec779b8eSAndroid Build Coastguard Worker block = maxBlock;
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
76*ec779b8eSAndroid Build Coastguard Worker size_t accumulator = 0;
77*ec779b8eSAndroid Build Coastguard Worker while (accumulator < total) {
78*ec779b8eSAndroid Build Coastguard Worker size_t count = total - accumulator;
79*ec779b8eSAndroid Build Coastguard Worker if (count > block) {
80*ec779b8eSAndroid Build Coastguard Worker count = block;
81*ec779b8eSAndroid Build Coastguard Worker }
82*ec779b8eSAndroid Build Coastguard Worker ssize_t ret = via(user, buffer, count);
83*ec779b8eSAndroid Build Coastguard Worker if (ret > 0) {
84*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT((size_t) ret <= count);
85*ec779b8eSAndroid Build Coastguard Worker size_t maxRet = ret;
86*ec779b8eSAndroid Build Coastguard Worker ret = write(buffer, maxRet);
87*ec779b8eSAndroid Build Coastguard Worker if (ret > 0) {
88*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT((size_t) ret <= maxRet);
89*ec779b8eSAndroid Build Coastguard Worker accumulator += ret;
90*ec779b8eSAndroid Build Coastguard Worker continue;
91*ec779b8eSAndroid Build Coastguard Worker }
92*ec779b8eSAndroid Build Coastguard Worker }
93*ec779b8eSAndroid Build Coastguard Worker return accumulator > 0 ? accumulator : ret;
94*ec779b8eSAndroid Build Coastguard Worker }
95*ec779b8eSAndroid Build Coastguard Worker return accumulator;
96*ec779b8eSAndroid Build Coastguard Worker }
97*ec779b8eSAndroid Build Coastguard Worker
98*ec779b8eSAndroid Build Coastguard Worker // This is a default implementation; it is expected that subclasses will optimize this.
readVia(readVia_t via,size_t total,void * user,size_t block)99*ec779b8eSAndroid Build Coastguard Worker ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t block)
100*ec779b8eSAndroid Build Coastguard Worker {
101*ec779b8eSAndroid Build Coastguard Worker if (!mNegotiated) {
102*ec779b8eSAndroid Build Coastguard Worker return (ssize_t) NEGOTIATE;
103*ec779b8eSAndroid Build Coastguard Worker }
104*ec779b8eSAndroid Build Coastguard Worker static const size_t maxBlock = 32;
105*ec779b8eSAndroid Build Coastguard Worker size_t frameSize = Format_frameSize(mFormat);
106*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
107*ec779b8eSAndroid Build Coastguard Worker // double guarantees alignment for stack similar to what malloc() gives for heap
108*ec779b8eSAndroid Build Coastguard Worker if (block == 0 || block > maxBlock) {
109*ec779b8eSAndroid Build Coastguard Worker block = maxBlock;
110*ec779b8eSAndroid Build Coastguard Worker }
111*ec779b8eSAndroid Build Coastguard Worker double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
112*ec779b8eSAndroid Build Coastguard Worker size_t accumulator = 0;
113*ec779b8eSAndroid Build Coastguard Worker while (accumulator < total) {
114*ec779b8eSAndroid Build Coastguard Worker size_t count = total - accumulator;
115*ec779b8eSAndroid Build Coastguard Worker if (count > block) {
116*ec779b8eSAndroid Build Coastguard Worker count = block;
117*ec779b8eSAndroid Build Coastguard Worker }
118*ec779b8eSAndroid Build Coastguard Worker ssize_t ret = read(buffer, count);
119*ec779b8eSAndroid Build Coastguard Worker if (ret > 0) {
120*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT((size_t) ret <= count);
121*ec779b8eSAndroid Build Coastguard Worker size_t maxRet = ret;
122*ec779b8eSAndroid Build Coastguard Worker ret = via(user, buffer, maxRet);
123*ec779b8eSAndroid Build Coastguard Worker if (ret > 0) {
124*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT((size_t) ret <= maxRet);
125*ec779b8eSAndroid Build Coastguard Worker accumulator += ret;
126*ec779b8eSAndroid Build Coastguard Worker continue;
127*ec779b8eSAndroid Build Coastguard Worker }
128*ec779b8eSAndroid Build Coastguard Worker }
129*ec779b8eSAndroid Build Coastguard Worker return accumulator > 0 ? accumulator : ret;
130*ec779b8eSAndroid Build Coastguard Worker }
131*ec779b8eSAndroid Build Coastguard Worker return accumulator;
132*ec779b8eSAndroid Build Coastguard Worker }
133*ec779b8eSAndroid Build Coastguard Worker
134*ec779b8eSAndroid Build Coastguard Worker // Default implementation that only accepts my mFormat
negotiate(const NBAIO_Format offers[],size_t numOffers,NBAIO_Format counterOffers[],size_t & numCounterOffers)135*ec779b8eSAndroid Build Coastguard Worker ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
136*ec779b8eSAndroid Build Coastguard Worker NBAIO_Format counterOffers[], size_t& numCounterOffers)
137*ec779b8eSAndroid Build Coastguard Worker {
138*ec779b8eSAndroid Build Coastguard Worker ALOGV("negotiate offers=%p numOffers=%zu countersOffers=%p numCounterOffers=%zu",
139*ec779b8eSAndroid Build Coastguard Worker offers, numOffers, counterOffers, numCounterOffers);
140*ec779b8eSAndroid Build Coastguard Worker if (Format_isValid(mFormat)) {
141*ec779b8eSAndroid Build Coastguard Worker for (size_t i = 0; i < numOffers; ++i) {
142*ec779b8eSAndroid Build Coastguard Worker if (Format_isEqual(offers[i], mFormat)) {
143*ec779b8eSAndroid Build Coastguard Worker mNegotiated = true;
144*ec779b8eSAndroid Build Coastguard Worker return i;
145*ec779b8eSAndroid Build Coastguard Worker }
146*ec779b8eSAndroid Build Coastguard Worker }
147*ec779b8eSAndroid Build Coastguard Worker if (numCounterOffers > 0) {
148*ec779b8eSAndroid Build Coastguard Worker counterOffers[0] = mFormat;
149*ec779b8eSAndroid Build Coastguard Worker }
150*ec779b8eSAndroid Build Coastguard Worker numCounterOffers = 1;
151*ec779b8eSAndroid Build Coastguard Worker } else {
152*ec779b8eSAndroid Build Coastguard Worker numCounterOffers = 0;
153*ec779b8eSAndroid Build Coastguard Worker }
154*ec779b8eSAndroid Build Coastguard Worker return (ssize_t) NEGOTIATE;
155*ec779b8eSAndroid Build Coastguard Worker }
156*ec779b8eSAndroid Build Coastguard Worker
Format_isValid(const NBAIO_Format & format)157*ec779b8eSAndroid Build Coastguard Worker bool Format_isValid(const NBAIO_Format& format)
158*ec779b8eSAndroid Build Coastguard Worker {
159*ec779b8eSAndroid Build Coastguard Worker return format.mSampleRate != 0 && format.mChannelCount != 0 &&
160*ec779b8eSAndroid Build Coastguard Worker format.mFormat != AUDIO_FORMAT_INVALID && format.mFrameSize != 0;
161*ec779b8eSAndroid Build Coastguard Worker }
162*ec779b8eSAndroid Build Coastguard Worker
Format_isEqual(const NBAIO_Format & format1,const NBAIO_Format & format2)163*ec779b8eSAndroid Build Coastguard Worker bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
164*ec779b8eSAndroid Build Coastguard Worker {
165*ec779b8eSAndroid Build Coastguard Worker return format1.mSampleRate == format2.mSampleRate &&
166*ec779b8eSAndroid Build Coastguard Worker format1.mChannelCount == format2.mChannelCount && format1.mFormat == format2.mFormat &&
167*ec779b8eSAndroid Build Coastguard Worker format1.mFrameSize == format2.mFrameSize;
168*ec779b8eSAndroid Build Coastguard Worker }
169*ec779b8eSAndroid Build Coastguard Worker
170*ec779b8eSAndroid Build Coastguard Worker } // namespace android
171