NBAIO.cpp revision cc1e0e807ee9a9f163a4685cbd6efd6ae55849cf
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 == Format_Invalid) {
59        return 0;
60    }
61    switch (format & 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 == Format_Invalid) {
86        return 0;
87    }
88    switch (format & 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    NBAIO_Format 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    return format;
140}
141
142// This is a default implementation; it is expected that subclasses will optimize this.
143ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
144{
145    if (!mNegotiated) {
146        return (ssize_t) NEGOTIATE;
147    }
148    static const size_t maxBlock = 32;
149    size_t frameSize = Format_frameSize(mFormat);
150    ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
151    // double guarantees alignment for stack similar to what malloc() gives for heap
152    if (block == 0 || block > maxBlock) {
153        block = maxBlock;
154    }
155    double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
156    size_t accumulator = 0;
157    while (accumulator < total) {
158        size_t count = total - accumulator;
159        if (count > block) {
160            count = block;
161        }
162        ssize_t ret = via(user, buffer, count);
163        if (ret > 0) {
164            ALOG_ASSERT((size_t) ret <= count);
165            size_t maxRet = ret;
166            ret = write(buffer, maxRet);
167            if (ret > 0) {
168                ALOG_ASSERT((size_t) ret <= maxRet);
169                accumulator += ret;
170                continue;
171            }
172        }
173        return accumulator > 0 ? accumulator : ret;
174    }
175    return accumulator;
176}
177
178// This is a default implementation; it is expected that subclasses will optimize this.
179ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
180                              int64_t readPTS, size_t block)
181{
182    if (!mNegotiated) {
183        return (ssize_t) NEGOTIATE;
184    }
185    static const size_t maxBlock = 32;
186    size_t frameSize = Format_frameSize(mFormat);
187    ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
188    // double guarantees alignment for stack similar to what malloc() gives for heap
189    if (block == 0 || block > maxBlock) {
190        block = maxBlock;
191    }
192    double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
193    size_t accumulator = 0;
194    while (accumulator < total) {
195        size_t count = total - accumulator;
196        if (count > block) {
197            count = block;
198        }
199        ssize_t ret = read(buffer, count, readPTS);
200        if (ret > 0) {
201            ALOG_ASSERT((size_t) ret <= count);
202            size_t maxRet = ret;
203            ret = via(user, buffer, maxRet, readPTS);
204            if (ret > 0) {
205                ALOG_ASSERT((size_t) ret <= maxRet);
206                accumulator += ret;
207                continue;
208            }
209        }
210        return accumulator > 0 ? accumulator : ret;
211    }
212    return accumulator;
213}
214
215// Default implementation that only accepts my mFormat
216ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
217                                  NBAIO_Format counterOffers[], size_t& numCounterOffers)
218{
219    ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
220            offers, numOffers, counterOffers, numCounterOffers);
221    if (mFormat != Format_Invalid) {
222        for (size_t i = 0; i < numOffers; ++i) {
223            if (offers[i] == mFormat) {
224                mNegotiated = true;
225                return i;
226            }
227        }
228        if (numCounterOffers > 0) {
229            counterOffers[0] = mFormat;
230        }
231        numCounterOffers = 1;
232    } else {
233        numCounterOffers = 0;
234    }
235    return (ssize_t) NEGOTIATE;
236}
237
238bool Format_isValid(const NBAIO_Format& format)
239{
240    return format != Format_Invalid;
241}
242
243bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
244{
245    return format1 == format2;
246}
247
248}   // namespace android
249