NBAIO.cpp revision 72e54af9fcdc4754914fe2bf8de699523538b315
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
36enum {
37    Format_SR_8000,
38    Format_SR_11025,
39    Format_SR_16000,
40    Format_SR_22050,
41    Format_SR_24000,
42    Format_SR_32000,
43    Format_SR_44100,
44    Format_SR_48000,
45    Format_SR_Mask = 7
46};
47
48enum {
49    Format_C_1 = 0x08,
50    Format_C_2 = 0x10,
51    Format_C_Mask = 0x18
52};
53
54unsigned Format_sampleRate(const NBAIO_Format& format)
55{
56    if (format == Format_Invalid) {
57        return 0;
58    }
59    switch (format & Format_SR_Mask) {
60    case Format_SR_8000:
61        return 8000;
62    case Format_SR_11025:
63        return 11025;
64    case Format_SR_16000:
65        return 16000;
66    case Format_SR_22050:
67        return 22050;
68    case Format_SR_24000:
69        return 24000;
70    case Format_SR_32000:
71        return 32000;
72    case Format_SR_44100:
73        return 44100;
74    case Format_SR_48000:
75        return 48000;
76    default:
77        return 0;
78    }
79}
80
81unsigned Format_channelCount(const NBAIO_Format& format)
82{
83    if (format == Format_Invalid) {
84        return 0;
85    }
86    switch (format & Format_C_Mask) {
87    case Format_C_1:
88        return 1;
89    case Format_C_2:
90        return 2;
91    default:
92        return 0;
93    }
94}
95
96NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
97{
98    NBAIO_Format format;
99    switch (sampleRate) {
100    case 8000:
101        format = Format_SR_8000;
102        break;
103    case 11025:
104        format = Format_SR_11025;
105        break;
106    case 16000:
107        format = Format_SR_16000;
108        break;
109    case 22050:
110        format = Format_SR_22050;
111        break;
112    case 24000:
113        format = Format_SR_24000;
114        break;
115    case 32000:
116        format = Format_SR_32000;
117        break;
118    case 44100:
119        format = Format_SR_44100;
120        break;
121    case 48000:
122        format = Format_SR_48000;
123        break;
124    default:
125        return Format_Invalid;
126    }
127    switch (channelCount) {
128    case 1:
129        format |= Format_C_1;
130        break;
131    case 2:
132        format |= Format_C_2;
133        break;
134    default:
135        return Format_Invalid;
136    }
137    return format;
138}
139
140// This is a default implementation; it is expected that subclasses will optimize this.
141ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
142{
143    if (!mNegotiated) {
144        return (ssize_t) NEGOTIATE;
145    }
146    static const size_t maxBlock = 32;
147    size_t frameSize = Format_frameSize(mFormat);
148    ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
149    // double guarantees alignment for stack similar to what malloc() gives for heap
150    if (block == 0 || block > maxBlock) {
151        block = maxBlock;
152    }
153    double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
154    size_t accumulator = 0;
155    while (accumulator < total) {
156        size_t count = total - accumulator;
157        if (count > block) {
158            count = block;
159        }
160        ssize_t ret = via(user, buffer, count);
161        if (ret > 0) {
162            ALOG_ASSERT((size_t) ret <= count);
163            size_t maxRet = ret;
164            ret = write(buffer, maxRet);
165            if (ret > 0) {
166                ALOG_ASSERT((size_t) ret <= maxRet);
167                accumulator += ret;
168                continue;
169            }
170        }
171        return accumulator > 0 ? accumulator : ret;
172    }
173    return accumulator;
174}
175
176// This is a default implementation; it is expected that subclasses will optimize this.
177ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
178                              int64_t readPTS, size_t block)
179{
180    if (!mNegotiated) {
181        return (ssize_t) NEGOTIATE;
182    }
183    static const size_t maxBlock = 32;
184    size_t frameSize = Format_frameSize(mFormat);
185    ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
186    // double guarantees alignment for stack similar to what malloc() gives for heap
187    if (block == 0 || block > maxBlock) {
188        block = maxBlock;
189    }
190    double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
191    size_t accumulator = 0;
192    while (accumulator < total) {
193        size_t count = total - accumulator;
194        if (count > block) {
195            count = block;
196        }
197        ssize_t ret = read(buffer, count, readPTS);
198        if (ret > 0) {
199            ALOG_ASSERT((size_t) ret <= count);
200            size_t maxRet = ret;
201            ret = via(user, buffer, maxRet, readPTS);
202            if (ret > 0) {
203                ALOG_ASSERT((size_t) ret <= maxRet);
204                accumulator += ret;
205                continue;
206            }
207        }
208        return accumulator > 0 ? accumulator : ret;
209    }
210    return accumulator;
211}
212
213// Default implementation that only accepts my mFormat
214ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
215                                  NBAIO_Format counterOffers[], size_t& numCounterOffers)
216{
217    ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
218            offers, numOffers, counterOffers, numCounterOffers);
219    if (mFormat != Format_Invalid) {
220        for (size_t i = 0; i < numOffers; ++i) {
221            if (offers[i] == mFormat) {
222                mNegotiated = true;
223                return i;
224            }
225        }
226        if (numCounterOffers > 0) {
227            counterOffers[0] = mFormat;
228        }
229        numCounterOffers = 1;
230    } else {
231        numCounterOffers = 0;
232    }
233    return (ssize_t) NEGOTIATE;
234}
235
236}   // namespace android
237