xref: /aosp_15_r20/frameworks/av/media/libnbaio/AudioBufferProviderSource.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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