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