1 /* 2 * Copyright (C) 2017 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 (mInService ? "AudioStreamInternalPlay_Service" \ 18 : "AudioStreamInternalPlay_Client") 19 //#define LOG_NDEBUG 0 20 #include <utils/Log.h> 21 22 #define ATRACE_TAG ATRACE_TAG_AUDIO 23 24 #include <utils/Trace.h> 25 26 #include "client/AudioStreamInternalPlay.h" 27 #include "utility/AudioClock.h" 28 29 using android::WrappingBuffer; 30 31 using namespace aaudio; 32 33 AudioStreamInternalPlay::AudioStreamInternalPlay(AAudioServiceInterface &serviceInterface, 34 bool inService) 35 : AudioStreamInternal(serviceInterface, inService) { 36 37 } 38 39 AudioStreamInternalPlay::~AudioStreamInternalPlay() {} 40 41 constexpr int kRampMSec = 10; // time to apply a change in volume 42 43 aaudio_result_t AudioStreamInternalPlay::open(const AudioStreamBuilder &builder) { 44 aaudio_result_t result = AudioStreamInternal::open(builder); 45 if (result == AAUDIO_OK) { 46 result = mFlowGraph.configure(getFormat(), 47 getSamplesPerFrame(), 48 getDeviceFormat(), 49 getDeviceChannelCount()); 50 51 if (result != AAUDIO_OK) { 52 close(); 53 } 54 // Sample rate is constrained to common values by now and should not overflow. 55 int32_t numFrames = kRampMSec * getSampleRate() / AAUDIO_MILLIS_PER_SECOND; 56 mFlowGraph.setRampLengthInFrames(numFrames); 57 } 58 return result; 59 } 60 61 // This must be called under mStreamLock. 62 aaudio_result_t AudioStreamInternalPlay::requestPause() 63 { 64 aaudio_result_t result = stopCallback(); 65 if (result != AAUDIO_OK) { 66 return result; 67 } 68 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 69 ALOGW("%s() mServiceStreamHandle invalid", __func__); 70 return AAUDIO_ERROR_INVALID_STATE; 71 } 72 73 mClockModel.stop(AudioClock::getNanoseconds()); 74 setState(AAUDIO_STREAM_STATE_PAUSING); 75 mAtomicInternalTimestamp.clear(); 76 return mServiceInterface.pauseStream(mServiceStreamHandle); 77 } 78 79 aaudio_result_t AudioStreamInternalPlay::requestFlush() { 80 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 81 ALOGW("%s() mServiceStreamHandle invalid", __func__); 82 return AAUDIO_ERROR_INVALID_STATE; 83 } 84 85 setState(AAUDIO_STREAM_STATE_FLUSHING); 86 return mServiceInterface.flushStream(mServiceStreamHandle); 87 } 88 89 void AudioStreamInternalPlay::advanceClientToMatchServerPosition() { 90 int64_t readCounter = mAudioEndpoint.getDataReadCounter(); 91 int64_t writeCounter = mAudioEndpoint.getDataWriteCounter(); 92 93 // Bump offset so caller does not see the retrograde motion in getFramesRead(). 94 int64_t offset = writeCounter - readCounter; 95 mFramesOffsetFromService += offset; 96 ALOGV("%s() readN = %lld, writeN = %lld, offset = %lld", __func__, 97 (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService); 98 99 // Force writeCounter to match readCounter. 100 // This is because we cannot change the read counter in the hardware. 101 mAudioEndpoint.setDataWriteCounter(readCounter); 102 } 103 104 void AudioStreamInternalPlay::onFlushFromServer() { 105 advanceClientToMatchServerPosition(); 106 } 107 108 // Write the data, block if needed and timeoutMillis > 0 109 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames, 110 int64_t timeoutNanoseconds) { 111 return processData((void *)buffer, numFrames, timeoutNanoseconds); 112 } 113 114 // Write as much data as we can without blocking. 115 aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t numFrames, 116 int64_t currentNanoTime, int64_t *wakeTimePtr) { 117 aaudio_result_t result = processCommands(); 118 if (result != AAUDIO_OK) { 119 return result; 120 } 121 122 const char *traceName = "aaWrNow"; 123 ATRACE_BEGIN(traceName); 124 125 if (mClockModel.isStarting()) { 126 // Still haven't got any timestamps from server. 127 // Keep waiting until we get some valid timestamps then start writing to the 128 // current buffer position. 129 ALOGV("%s() wait for valid timestamps", __func__); 130 // Sleep very briefly and hope we get a timestamp soon. 131 *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND); 132 ATRACE_END(); 133 return 0; 134 } 135 // If we have gotten this far then we have at least one timestamp from server. 136 137 // If a DMA channel or DSP is reading the other end then we have to update the readCounter. 138 if (mAudioEndpoint.isFreeRunning()) { 139 // Update data queue based on the timing model. 140 int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime); 141 // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter); 142 mAudioEndpoint.setDataReadCounter(estimatedReadCounter); 143 } 144 145 if (mNeedCatchUp.isRequested()) { 146 // Catch an MMAP pointer that is already advancing. 147 // This will avoid initial underruns caused by a slow cold start. 148 advanceClientToMatchServerPosition(); 149 mNeedCatchUp.acknowledge(); 150 } 151 152 // If the read index passed the write index then consider it an underrun. 153 // For shared streams, the xRunCount is passed up from the service. 154 if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getFullFramesAvailable() < 0) { 155 mXRunCount++; 156 if (ATRACE_ENABLED()) { 157 ATRACE_INT("aaUnderRuns", mXRunCount); 158 } 159 } 160 161 // Write some data to the buffer. 162 //ALOGD("AudioStreamInternal::processDataNow() - writeNowWithConversion(%d)", numFrames); 163 int32_t framesWritten = writeNowWithConversion(buffer, numFrames); 164 //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d", 165 // numFrames, framesWritten); 166 if (ATRACE_ENABLED()) { 167 ATRACE_INT("aaWrote", framesWritten); 168 } 169 170 // Calculate an ideal time to wake up. 171 if (wakeTimePtr != nullptr && framesWritten >= 0) { 172 // By default wake up a few milliseconds from now. // TODO review 173 int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND); 174 aaudio_stream_state_t state = getState(); 175 //ALOGD("AudioStreamInternal::processDataNow() - wakeTime based on %s", 176 // AAudio_convertStreamStateToText(state)); 177 switch (state) { 178 case AAUDIO_STREAM_STATE_OPEN: 179 case AAUDIO_STREAM_STATE_STARTING: 180 if (framesWritten != 0) { 181 // Don't wait to write more data. Just prime the buffer. 182 wakeTime = currentNanoTime; 183 } 184 break; 185 case AAUDIO_STREAM_STATE_STARTED: 186 { 187 // When do we expect the next read burst to occur? 188 189 // Calculate frame position based off of the writeCounter because 190 // the readCounter might have just advanced in the background, 191 // causing us to sleep until a later burst. 192 int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst 193 - mAudioEndpoint.getBufferSizeInFrames(); 194 wakeTime = mClockModel.convertPositionToTime(nextPosition); 195 } 196 break; 197 default: 198 break; 199 } 200 *wakeTimePtr = wakeTime; 201 202 } 203 204 ATRACE_END(); 205 return framesWritten; 206 } 207 208 209 aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer, 210 int32_t numFrames) { 211 WrappingBuffer wrappingBuffer; 212 uint8_t *byteBuffer = (uint8_t *) buffer; 213 int32_t framesLeft = numFrames; 214 215 mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer); 216 217 // Write data in one or two parts. 218 int partIndex = 0; 219 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 220 int32_t framesToWrite = framesLeft; 221 int32_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 222 if (framesAvailable > 0) { 223 if (framesToWrite > framesAvailable) { 224 framesToWrite = framesAvailable; 225 } 226 227 int32_t numBytes = getBytesPerFrame() * framesToWrite; 228 229 mFlowGraph.process((void *)byteBuffer, 230 wrappingBuffer.data[partIndex], 231 framesToWrite); 232 233 byteBuffer += numBytes; 234 framesLeft -= framesToWrite; 235 } else { 236 break; 237 } 238 partIndex++; 239 } 240 int32_t framesWritten = numFrames - framesLeft; 241 mAudioEndpoint.advanceWriteIndex(framesWritten); 242 243 return framesWritten; 244 } 245 246 int64_t AudioStreamInternalPlay::getFramesRead() { 247 const int64_t framesReadHardware = isClockModelInControl() 248 ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()) 249 : mAudioEndpoint.getDataReadCounter(); 250 // Add service offset and prevent retrograde motion. 251 mLastFramesRead = std::max(mLastFramesRead, framesReadHardware + mFramesOffsetFromService); 252 return mLastFramesRead; 253 } 254 255 int64_t AudioStreamInternalPlay::getFramesWritten() { 256 const int64_t framesWritten = mAudioEndpoint.getDataWriteCounter() 257 + mFramesOffsetFromService; 258 return framesWritten; 259 } 260 261 262 // Render audio in the application callback and then write the data to the stream. 263 void *AudioStreamInternalPlay::callbackLoop() { 264 ALOGD("%s() entering >>>>>>>>>>>>>>>", __func__); 265 aaudio_result_t result = AAUDIO_OK; 266 aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; 267 if (!isDataCallbackSet()) return NULL; 268 int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); 269 270 // result might be a frame count 271 while (mCallbackEnabled.load() && isActive() && (result >= 0)) { 272 // Call application using the AAudio callback interface. 273 callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames); 274 275 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { 276 // Write audio data to stream. This is a BLOCKING WRITE! 277 result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos); 278 if ((result != mCallbackFrames)) { 279 if (result >= 0) { 280 // Only wrote some of the frames requested. Must have timed out. 281 result = AAUDIO_ERROR_TIMEOUT; 282 } 283 maybeCallErrorCallback(result); 284 break; 285 } 286 } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { 287 ALOGD("%s(): callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__); 288 result = systemStopFromCallback(); 289 break; 290 } 291 } 292 293 ALOGD("%s() exiting, result = %d, isActive() = %d <<<<<<<<<<<<<<", 294 __func__, result, (int) isActive()); 295 return NULL; 296 } 297 298 //------------------------------------------------------------------------------ 299 // Implementation of PlayerBase 300 status_t AudioStreamInternalPlay::doSetVolume() { 301 float combinedVolume = mStreamVolume * getDuckAndMuteVolume(); 302 ALOGD("%s() mStreamVolume * duckAndMuteVolume = %f * %f = %f", 303 __func__, mStreamVolume, getDuckAndMuteVolume(), combinedVolume); 304 mFlowGraph.setTargetVolume(combinedVolume); 305 return android::NO_ERROR; 306 } 307