1 /* 2 * Copyright (C) 2007 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 "AudioTrackShared" 18 //#define LOG_NDEBUG 0 19 20 #include <private/media/AudioTrackShared.h> 21 #include <utils/Log.h> 22 23 namespace android { 24 25 audio_track_cblk_t::audio_track_cblk_t() 26 : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), 27 userBase(0), serverBase(0), frameCount_(0), 28 loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), mVolumeLR(0x10001000), 29 mSampleRate(0), mSendLevel(0), flags(0) 30 { 31 } 32 33 uint32_t audio_track_cblk_t::stepUser(size_t stepCount, size_t frameCount, bool isOut) 34 { 35 ALOGV("stepuser %08x %08x %d", user, server, stepCount); 36 37 uint32_t u = user; 38 u += stepCount; 39 // Ensure that user is never ahead of server for AudioRecord 40 if (isOut) { 41 // If stepServer() has been called once, switch to normal obtainBuffer() timeout period 42 if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) { 43 bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; 44 } 45 } else if (u > server) { 46 ALOGW("stepUser occurred after track reset"); 47 u = server; 48 } 49 50 if (u >= frameCount) { 51 // common case, user didn't just wrap 52 if (u - frameCount >= userBase ) { 53 userBase += frameCount; 54 } 55 } else if (u >= userBase + frameCount) { 56 // user just wrapped 57 userBase += frameCount; 58 } 59 60 user = u; 61 62 // Clear flow control error condition as new data has been written/read to/from buffer. 63 if (flags & CBLK_UNDERRUN) { 64 android_atomic_and(~CBLK_UNDERRUN, &flags); 65 } 66 67 return u; 68 } 69 70 bool audio_track_cblk_t::stepServer(size_t stepCount, size_t frameCount, bool isOut) 71 { 72 ALOGV("stepserver %08x %08x %d", user, server, stepCount); 73 74 if (!tryLock()) { 75 ALOGW("stepServer() could not lock cblk"); 76 return false; 77 } 78 79 uint32_t s = server; 80 bool flushed = (s == user); 81 82 s += stepCount; 83 if (isOut) { 84 // Mark that we have read the first buffer so that next time stepUser() is called 85 // we switch to normal obtainBuffer() timeout period 86 if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS) { 87 bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS - 1; 88 } 89 // It is possible that we receive a flush() 90 // while the mixer is processing a block: in this case, 91 // stepServer() is called After the flush() has reset u & s and 92 // we have s > u 93 if (flushed) { 94 ALOGW("stepServer occurred after track reset"); 95 s = user; 96 } 97 } 98 99 if (s >= loopEnd) { 100 ALOGW_IF(s > loopEnd, "stepServer: s %u > loopEnd %u", s, loopEnd); 101 s = loopStart; 102 if (--loopCount == 0) { 103 loopEnd = UINT_MAX; 104 loopStart = UINT_MAX; 105 } 106 } 107 108 if (s >= frameCount) { 109 // common case, server didn't just wrap 110 if (s - frameCount >= serverBase ) { 111 serverBase += frameCount; 112 } 113 } else if (s >= serverBase + frameCount) { 114 // server just wrapped 115 serverBase += frameCount; 116 } 117 118 server = s; 119 120 if (!(flags & CBLK_INVALID)) { 121 cv.signal(); 122 } 123 lock.unlock(); 124 return true; 125 } 126 127 void* audio_track_cblk_t::buffer(void *buffers, size_t frameSize, uint32_t offset) const 128 { 129 return (int8_t *)buffers + (offset - userBase) * frameSize; 130 } 131 132 uint32_t audio_track_cblk_t::framesAvailable(size_t frameCount, bool isOut) 133 { 134 Mutex::Autolock _l(lock); 135 return framesAvailable_l(frameCount, isOut); 136 } 137 138 uint32_t audio_track_cblk_t::framesAvailable_l(size_t frameCount, bool isOut) 139 { 140 uint32_t u = user; 141 uint32_t s = server; 142 143 if (isOut) { 144 uint32_t limit = (s < loopStart) ? s : loopStart; 145 return limit + frameCount - u; 146 } else { 147 return frameCount + u - s; 148 } 149 } 150 151 uint32_t audio_track_cblk_t::framesReady(bool isOut) 152 { 153 uint32_t u = user; 154 uint32_t s = server; 155 156 if (isOut) { 157 if (u < loopEnd) { 158 return u - s; 159 } else { 160 // do not block on mutex shared with client on AudioFlinger side 161 if (!tryLock()) { 162 ALOGW("framesReady() could not lock cblk"); 163 return 0; 164 } 165 uint32_t frames = UINT_MAX; 166 if (loopCount >= 0) { 167 frames = (loopEnd - loopStart)*loopCount + u - s; 168 } 169 lock.unlock(); 170 return frames; 171 } 172 } else { 173 return s - u; 174 } 175 } 176 177 bool audio_track_cblk_t::tryLock() 178 { 179 // the code below simulates lock-with-timeout 180 // we MUST do this to protect the AudioFlinger server 181 // as this lock is shared with the client. 182 status_t err; 183 184 err = lock.tryLock(); 185 if (err == -EBUSY) { // just wait a bit 186 usleep(1000); 187 err = lock.tryLock(); 188 } 189 if (err != NO_ERROR) { 190 // probably, the client just died. 191 return false; 192 } 193 return true; 194 } 195 196 } // namespace android 197