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 "AudioBufferProviderSource"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker
20*ec779b8eSAndroid Build Coastguard Worker #include <cutils/compiler.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <media/nbaio/AudioBufferProviderSource.h>
23*ec779b8eSAndroid Build Coastguard Worker
24*ec779b8eSAndroid Build Coastguard Worker namespace android {
25*ec779b8eSAndroid Build Coastguard Worker
AudioBufferProviderSource(AudioBufferProvider * provider,const NBAIO_Format & format)26*ec779b8eSAndroid Build Coastguard Worker AudioBufferProviderSource::AudioBufferProviderSource(AudioBufferProvider *provider,
27*ec779b8eSAndroid Build Coastguard Worker const NBAIO_Format& format) :
28*ec779b8eSAndroid Build Coastguard Worker NBAIO_Source(format), mProvider(provider), mConsumed(0)
29*ec779b8eSAndroid Build Coastguard Worker {
30*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(provider != NULL);
31*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(Format_isValid(format));
32*ec779b8eSAndroid Build Coastguard Worker }
33*ec779b8eSAndroid Build Coastguard Worker
~AudioBufferProviderSource()34*ec779b8eSAndroid Build Coastguard Worker AudioBufferProviderSource::~AudioBufferProviderSource()
35*ec779b8eSAndroid Build Coastguard Worker {
36*ec779b8eSAndroid Build Coastguard Worker if (mBuffer.raw != NULL) {
37*ec779b8eSAndroid Build Coastguard Worker mProvider->releaseBuffer(&mBuffer);
38*ec779b8eSAndroid Build Coastguard Worker }
39*ec779b8eSAndroid Build Coastguard Worker }
40*ec779b8eSAndroid Build Coastguard Worker
availableToRead()41*ec779b8eSAndroid Build Coastguard Worker ssize_t AudioBufferProviderSource::availableToRead()
42*ec779b8eSAndroid Build Coastguard Worker {
43*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(!mNegotiated)) {
44*ec779b8eSAndroid Build Coastguard Worker return NEGOTIATE;
45*ec779b8eSAndroid Build Coastguard Worker }
46*ec779b8eSAndroid Build Coastguard Worker return mBuffer.raw != NULL ? mBuffer.frameCount - mConsumed : 0;
47*ec779b8eSAndroid Build Coastguard Worker }
48*ec779b8eSAndroid Build Coastguard Worker
read(void * buffer,size_t count)49*ec779b8eSAndroid Build Coastguard Worker ssize_t AudioBufferProviderSource::read(void *buffer, size_t count)
50*ec779b8eSAndroid Build Coastguard Worker {
51*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(!mNegotiated)) {
52*ec779b8eSAndroid Build Coastguard Worker return NEGOTIATE;
53*ec779b8eSAndroid Build Coastguard Worker }
54*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(mBuffer.raw == NULL)) {
55*ec779b8eSAndroid Build Coastguard Worker mBuffer.frameCount = count;
56*ec779b8eSAndroid Build Coastguard Worker status_t status = mProvider->getNextBuffer(&mBuffer);
57*ec779b8eSAndroid Build Coastguard Worker if (status != OK) {
58*ec779b8eSAndroid Build Coastguard Worker return status == NOT_ENOUGH_DATA ? (ssize_t) WOULD_BLOCK : (ssize_t) status;
59*ec779b8eSAndroid Build Coastguard Worker }
60*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(mBuffer.raw != NULL);
61*ec779b8eSAndroid Build Coastguard Worker // mConsumed is 0 either from constructor or after releaseBuffer()
62*ec779b8eSAndroid Build Coastguard Worker }
63*ec779b8eSAndroid Build Coastguard Worker size_t available = mBuffer.frameCount - mConsumed;
64*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(count > available)) {
65*ec779b8eSAndroid Build Coastguard Worker count = available;
66*ec779b8eSAndroid Build Coastguard Worker }
67*ec779b8eSAndroid Build Coastguard Worker // count could be zero, either because count was zero on entry or
68*ec779b8eSAndroid Build Coastguard Worker // available is zero, but both are unlikely so don't check for that
69*ec779b8eSAndroid Build Coastguard Worker memcpy(buffer, (char *) mBuffer.raw + (mConsumed * mFrameSize), count * mFrameSize);
70*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY((mConsumed += count) >= mBuffer.frameCount)) {
71*ec779b8eSAndroid Build Coastguard Worker mProvider->releaseBuffer(&mBuffer);
72*ec779b8eSAndroid Build Coastguard Worker mBuffer.raw = NULL;
73*ec779b8eSAndroid Build Coastguard Worker mConsumed = 0;
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker mFramesRead += count;
76*ec779b8eSAndroid Build Coastguard Worker // For better responsiveness with large values of count,
77*ec779b8eSAndroid Build Coastguard Worker // return a short count rather than continuing with next buffer.
78*ec779b8eSAndroid Build Coastguard Worker // This gives the caller a chance to interpolate other actions.
79*ec779b8eSAndroid Build Coastguard Worker return count;
80*ec779b8eSAndroid Build Coastguard Worker }
81*ec779b8eSAndroid Build Coastguard Worker
readVia(readVia_t via,size_t total,void * user,size_t block)82*ec779b8eSAndroid Build Coastguard Worker ssize_t AudioBufferProviderSource::readVia(readVia_t via, size_t total, void *user, size_t block)
83*ec779b8eSAndroid Build Coastguard Worker {
84*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(!mNegotiated)) {
85*ec779b8eSAndroid Build Coastguard Worker return NEGOTIATE;
86*ec779b8eSAndroid Build Coastguard Worker }
87*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(block == 0)) {
88*ec779b8eSAndroid Build Coastguard Worker block = ~0;
89*ec779b8eSAndroid Build Coastguard Worker }
90*ec779b8eSAndroid Build Coastguard Worker for (size_t accumulator = 0; ; ) {
91*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(accumulator <= total);
92*ec779b8eSAndroid Build Coastguard Worker size_t count = total - accumulator;
93*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(count == 0)) {
94*ec779b8eSAndroid Build Coastguard Worker return accumulator;
95*ec779b8eSAndroid Build Coastguard Worker }
96*ec779b8eSAndroid Build Coastguard Worker if (CC_LIKELY(count > block)) {
97*ec779b8eSAndroid Build Coastguard Worker count = block;
98*ec779b8eSAndroid Build Coastguard Worker }
99*ec779b8eSAndroid Build Coastguard Worker // 1 <= count <= block
100*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(mBuffer.raw == NULL)) {
101*ec779b8eSAndroid Build Coastguard Worker mBuffer.frameCount = count;
102*ec779b8eSAndroid Build Coastguard Worker status_t status = mProvider->getNextBuffer(&mBuffer);
103*ec779b8eSAndroid Build Coastguard Worker if (CC_LIKELY(status == OK)) {
104*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(mBuffer.raw != NULL && mBuffer.frameCount <= count);
105*ec779b8eSAndroid Build Coastguard Worker // mConsumed is 0 either from constructor or after releaseBuffer()
106*ec779b8eSAndroid Build Coastguard Worker continue;
107*ec779b8eSAndroid Build Coastguard Worker }
108*ec779b8eSAndroid Build Coastguard Worker // FIXME simplify logic - does the initial count and block checks again for no reason;
109*ec779b8eSAndroid Build Coastguard Worker // don't you just want to fall through to the size_t available line?
110*ec779b8eSAndroid Build Coastguard Worker if (CC_LIKELY(status == NOT_ENOUGH_DATA)) {
111*ec779b8eSAndroid Build Coastguard Worker status = WOULD_BLOCK;
112*ec779b8eSAndroid Build Coastguard Worker }
113*ec779b8eSAndroid Build Coastguard Worker return accumulator > 0 ? accumulator : (ssize_t) status;
114*ec779b8eSAndroid Build Coastguard Worker }
115*ec779b8eSAndroid Build Coastguard Worker size_t available = mBuffer.frameCount - mConsumed;
116*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(count > available)) {
117*ec779b8eSAndroid Build Coastguard Worker count = available;
118*ec779b8eSAndroid Build Coastguard Worker }
119*ec779b8eSAndroid Build Coastguard Worker if (CC_LIKELY(count > 0)) {
120*ec779b8eSAndroid Build Coastguard Worker ssize_t ret = via(user, (char *) mBuffer.raw + (mConsumed * mFrameSize), count);
121*ec779b8eSAndroid Build Coastguard Worker
122*ec779b8eSAndroid Build Coastguard Worker if (CC_UNLIKELY(ret <= 0)) {
123*ec779b8eSAndroid Build Coastguard Worker if (CC_LIKELY(accumulator > 0)) {
124*ec779b8eSAndroid Build Coastguard Worker return accumulator;
125*ec779b8eSAndroid Build Coastguard Worker }
126*ec779b8eSAndroid Build Coastguard Worker return ret;
127*ec779b8eSAndroid Build Coastguard Worker }
128*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT((size_t) ret <= count);
129*ec779b8eSAndroid Build Coastguard Worker mFramesRead += ret;
130*ec779b8eSAndroid Build Coastguard Worker accumulator += ret;
131*ec779b8eSAndroid Build Coastguard Worker if (CC_LIKELY((mConsumed += ret) < mBuffer.frameCount)) {
132*ec779b8eSAndroid Build Coastguard Worker continue;
133*ec779b8eSAndroid Build Coastguard Worker }
134*ec779b8eSAndroid Build Coastguard Worker }
135*ec779b8eSAndroid Build Coastguard Worker mProvider->releaseBuffer(&mBuffer);
136*ec779b8eSAndroid Build Coastguard Worker mBuffer.raw = NULL;
137*ec779b8eSAndroid Build Coastguard Worker mConsumed = 0;
138*ec779b8eSAndroid Build Coastguard Worker // don't get next buffer until we really need it
139*ec779b8eSAndroid Build Coastguard Worker }
140*ec779b8eSAndroid Build Coastguard Worker }
141*ec779b8eSAndroid Build Coastguard Worker
142*ec779b8eSAndroid Build Coastguard Worker } // namespace android
143