NBAIO.cpp revision c4b8b32dec91a11a83d0a7ab49747606d16d39a5
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "NBAIO"
18//#define LOG_NDEBUG 0
19
20#include <utils/Log.h>
21#include <media/nbaio/NBAIO.h>
22
23namespace android {
24
25size_t Format_frameSize(const NBAIO_Format& format)
26{
27    return Format_channelCount(format) * sizeof(short);
28}
29
30size_t Format_frameBitShift(const NBAIO_Format& format)
31{
32    // sizeof(short) == 2, so frame size == 1 << channels
33    return Format_channelCount(format);
34}
35
36const NBAIO_Format Format_Invalid = { 0 };
37
38enum {
39    Format_SR_8000,
40    Format_SR_11025,
41    Format_SR_16000,
42    Format_SR_22050,
43    Format_SR_24000,
44    Format_SR_32000,
45    Format_SR_44100,
46    Format_SR_48000,
47    Format_SR_Mask = 7
48};
49
50enum {
51    Format_C_1 = 0x08,
52    Format_C_2 = 0x10,
53    Format_C_Mask = 0x18
54};
55
56unsigned Format_sampleRate(const NBAIO_Format& format)
57{
58    if (!Format_isValid(format)) {
59        return 0;
60    }
61    switch (format.mPacked & Format_SR_Mask) {
62    case Format_SR_8000:
63        return 8000;
64    case Format_SR_11025:
65        return 11025;
66    case Format_SR_16000:
67        return 16000;
68    case Format_SR_22050:
69        return 22050;
70    case Format_SR_24000:
71        return 24000;
72    case Format_SR_32000:
73        return 32000;
74    case Format_SR_44100:
75        return 44100;
76    case Format_SR_48000:
77        return 48000;
78    default:
79        return 0;
80    }
81}
82
83unsigned Format_channelCount(const NBAIO_Format& format)
84{
85    if (!Format_isValid(format)) {
86        return 0;
87    }
88    switch (format.mPacked & Format_C_Mask) {
89    case Format_C_1:
90        return 1;
91    case Format_C_2:
92        return 2;
93    default:
94        return 0;
95    }
96}
97
98NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
99{
100    unsigned format;
101    switch (sampleRate) {
102    case 8000:
103        format = Format_SR_8000;
104        break;
105    case 11025:
106        format = Format_SR_11025;
107        break;
108    case 16000:
109        format = Format_SR_16000;
110        break;
111    case 22050:
112        format = Format_SR_22050;
113        break;
114    case 24000:
115        format = Format_SR_24000;
116        break;
117    case 32000:
118        format = Format_SR_32000;
119        break;
120    case 44100:
121        format = Format_SR_44100;
122        break;
123    case 48000:
124        format = Format_SR_48000;
125        break;
126    default:
127        return Format_Invalid;
128    }
129    switch (channelCount) {
130    case 1:
131        format |= Format_C_1;
132        break;
133    case 2:
134        format |= Format_C_2;
135        break;
136    default:
137        return Format_Invalid;
138    }
139    NBAIO_Format ret;
140    ret.mPacked = format;
141    return ret;
142}
143
144// This is a default implementation; it is expected that subclasses will optimize this.
145ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
146{
147    if (!mNegotiated) {
148        return (ssize_t) NEGOTIATE;
149    }
150    static const size_t maxBlock = 32;
151    size_t frameSize = Format_frameSize(mFormat);
152    ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
153    // double guarantees alignment for stack similar to what malloc() gives for heap
154    if (block == 0 || block > maxBlock) {
155        block = maxBlock;
156    }
157    double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
158    size_t accumulator = 0;
159    while (accumulator < total) {
160        size_t count = total - accumulator;
161        if (count > block) {
162            count = block;
163        }
164        ssize_t ret = via(user, buffer, count);
165        if (ret > 0) {
166            ALOG_ASSERT((size_t) ret <= count);
167            size_t maxRet = ret;
168            ret = write(buffer, maxRet);
169            if (ret > 0) {
170                ALOG_ASSERT((size_t) ret <= maxRet);
171                accumulator += ret;
172                continue;
173            }
174        }
175        return accumulator > 0 ? accumulator : ret;
176    }
177    return accumulator;
178}
179
180// This is a default implementation; it is expected that subclasses will optimize this.
181ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
182                              int64_t readPTS, size_t block)
183{
184    if (!mNegotiated) {
185        return (ssize_t) NEGOTIATE;
186    }
187    static const size_t maxBlock = 32;
188    size_t frameSize = Format_frameSize(mFormat);
189    ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
190    // double guarantees alignment for stack similar to what malloc() gives for heap
191    if (block == 0 || block > maxBlock) {
192        block = maxBlock;
193    }
194    double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
195    size_t accumulator = 0;
196    while (accumulator < total) {
197        size_t count = total - accumulator;
198        if (count > block) {
199            count = block;
200        }
201        ssize_t ret = read(buffer, count, readPTS);
202        if (ret > 0) {
203            ALOG_ASSERT((size_t) ret <= count);
204            size_t maxRet = ret;
205            ret = via(user, buffer, maxRet, readPTS);
206            if (ret > 0) {
207                ALOG_ASSERT((size_t) ret <= maxRet);
208                accumulator += ret;
209                continue;
210            }
211        }
212        return accumulator > 0 ? accumulator : ret;
213    }
214    return accumulator;
215}
216
217// Default implementation that only accepts my mFormat
218ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
219                                  NBAIO_Format counterOffers[], size_t& numCounterOffers)
220{
221    ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
222            offers, numOffers, counterOffers, numCounterOffers);
223    if (Format_isValid(mFormat)) {
224        for (size_t i = 0; i < numOffers; ++i) {
225            if (Format_isEqual(offers[i], mFormat)) {
226                mNegotiated = true;
227                return i;
228            }
229        }
230        if (numCounterOffers > 0) {
231            counterOffers[0] = mFormat;
232        }
233        numCounterOffers = 1;
234    } else {
235        numCounterOffers = 0;
236    }
237    return (ssize_t) NEGOTIATE;
238}
239
240bool Format_isValid(const NBAIO_Format& format)
241{
242    return format.mPacked != Format_Invalid.mPacked;
243}
244
245bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
246{
247    return format1.mPacked == format2.mPacked;
248}
249
250}   // namespace android
251