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 ? "AAudioService" : "AAudio") 18 //#define LOG_NDEBUG 0 19 #include <utils/Log.h> 20 21 #define ATRACE_TAG ATRACE_TAG_AUDIO 22 23 #include <utils/Trace.h> 24 25 #include "client/AudioStreamInternalPlay.h" 26 #include "utility/AudioClock.h" 27 28 using android::WrappingBuffer; 29 30 using namespace aaudio; 31 32 AudioStreamInternalPlay::AudioStreamInternalPlay(AAudioServiceInterface &serviceInterface, 33 bool inService) 34 : AudioStreamInternal(serviceInterface, inService) { 35 36 } 37 38 AudioStreamInternalPlay::~AudioStreamInternalPlay() {} 39 40 41 aaudio_result_t AudioStreamInternalPlay::requestPauseInternal() 42 { 43 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 44 ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X", 45 mServiceStreamHandle); 46 return AAUDIO_ERROR_INVALID_STATE; 47 } 48 49 mClockModel.stop(AudioClock::getNanoseconds()); 50 setState(AAUDIO_STREAM_STATE_PAUSING); 51 mAtomicTimestamp.clear(); 52 return mServiceInterface.pauseStream(mServiceStreamHandle); 53 } 54 55 aaudio_result_t AudioStreamInternalPlay::requestPause() 56 { 57 aaudio_result_t result = stopCallback(); 58 if (result != AAUDIO_OK) { 59 return result; 60 } 61 result = requestPauseInternal(); 62 return result; 63 } 64 65 aaudio_result_t AudioStreamInternalPlay::requestFlush() { 66 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 67 ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X", 68 mServiceStreamHandle); 69 return AAUDIO_ERROR_INVALID_STATE; 70 } 71 72 setState(AAUDIO_STREAM_STATE_FLUSHING); 73 return mServiceInterface.flushStream(mServiceStreamHandle); 74 } 75 76 void AudioStreamInternalPlay::advanceClientToMatchServerPosition() { 77 int64_t readCounter = mAudioEndpoint.getDataReadCounter(); 78 int64_t writeCounter = mAudioEndpoint.getDataWriteCounter(); 79 80 // Bump offset so caller does not see the retrograde motion in getFramesRead(). 81 int64_t offset = writeCounter - readCounter; 82 mFramesOffsetFromService += offset; 83 ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld", 84 (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService); 85 86 // Force writeCounter to match readCounter. 87 // This is because we cannot change the read counter in the hardware. 88 mAudioEndpoint.setDataWriteCounter(readCounter); 89 } 90 91 void AudioStreamInternalPlay::onFlushFromServer() { 92 advanceClientToMatchServerPosition(); 93 } 94 95 // Write the data, block if needed and timeoutMillis > 0 96 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames, 97 int64_t timeoutNanoseconds) 98 99 { 100 return processData((void *)buffer, numFrames, timeoutNanoseconds); 101 } 102 103 // Write as much data as we can without blocking. 104 aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t numFrames, 105 int64_t currentNanoTime, int64_t *wakeTimePtr) { 106 aaudio_result_t result = processCommands(); 107 if (result != AAUDIO_OK) { 108 return result; 109 } 110 111 const char *traceName = "aaWrNow"; 112 ATRACE_BEGIN(traceName); 113 114 if (mClockModel.isStarting()) { 115 // Still haven't got any timestamps from server. 116 // Keep waiting until we get some valid timestamps then start writing to the 117 // current buffer position. 118 ALOGD("processDataNow() wait for valid timestamps"); 119 // Sleep very briefly and hope we get a timestamp soon. 120 *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND); 121 ATRACE_END(); 122 return 0; 123 } 124 // If we have gotten this far then we have at least one timestamp from server. 125 126 // If a DMA channel or DSP is reading the other end then we have to update the readCounter. 127 if (mAudioEndpoint.isFreeRunning()) { 128 // Update data queue based on the timing model. 129 int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime); 130 // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter); 131 mAudioEndpoint.setDataReadCounter(estimatedReadCounter); 132 } 133 134 if (mNeedCatchUp.isRequested()) { 135 // Catch an MMAP pointer that is already advancing. 136 // This will avoid initial underruns caused by a slow cold start. 137 advanceClientToMatchServerPosition(); 138 mNeedCatchUp.acknowledge(); 139 } 140 141 // If the read index passed the write index then consider it an underrun. 142 if (mAudioEndpoint.getFullFramesAvailable() < 0) { 143 mXRunCount++; 144 if (ATRACE_ENABLED()) { 145 ATRACE_INT("aaUnderRuns", mXRunCount); 146 } 147 } 148 149 // Write some data to the buffer. 150 //ALOGD("AudioStreamInternal::processDataNow() - writeNowWithConversion(%d)", numFrames); 151 int32_t framesWritten = writeNowWithConversion(buffer, numFrames); 152 //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d", 153 // numFrames, framesWritten); 154 if (ATRACE_ENABLED()) { 155 ATRACE_INT("aaWrote", framesWritten); 156 } 157 158 // Calculate an ideal time to wake up. 159 if (wakeTimePtr != nullptr && framesWritten >= 0) { 160 // By default wake up a few milliseconds from now. // TODO review 161 int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND); 162 aaudio_stream_state_t state = getState(); 163 //ALOGD("AudioStreamInternal::processDataNow() - wakeTime based on %s", 164 // AAudio_convertStreamStateToText(state)); 165 switch (state) { 166 case AAUDIO_STREAM_STATE_OPEN: 167 case AAUDIO_STREAM_STATE_STARTING: 168 if (framesWritten != 0) { 169 // Don't wait to write more data. Just prime the buffer. 170 wakeTime = currentNanoTime; 171 } 172 break; 173 case AAUDIO_STREAM_STATE_STARTED: 174 { 175 // When do we expect the next read burst to occur? 176 177 // Calculate frame position based off of the writeCounter because 178 // the readCounter might have just advanced in the background, 179 // causing us to sleep until a later burst. 180 int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst 181 - mAudioEndpoint.getBufferSizeInFrames(); 182 wakeTime = mClockModel.convertPositionToTime(nextPosition); 183 } 184 break; 185 default: 186 break; 187 } 188 *wakeTimePtr = wakeTime; 189 190 } 191 192 ATRACE_END(); 193 return framesWritten; 194 } 195 196 197 aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer, 198 int32_t numFrames) { 199 // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)", 200 // buffer, numFrames); 201 WrappingBuffer wrappingBuffer; 202 uint8_t *source = (uint8_t *) buffer; 203 int32_t framesLeft = numFrames; 204 205 mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer); 206 207 // Write data in one or two parts. 208 int partIndex = 0; 209 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 210 int32_t framesToWrite = framesLeft; 211 int32_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 212 if (framesAvailable > 0) { 213 if (framesToWrite > framesAvailable) { 214 framesToWrite = framesAvailable; 215 } 216 int32_t numBytes = getBytesPerFrame() * framesToWrite; 217 int32_t numSamples = framesToWrite * getSamplesPerFrame(); 218 // Data conversion. 219 float levelFrom; 220 float levelTo; 221 bool ramping = mVolumeRamp.nextSegment(framesToWrite * getSamplesPerFrame(), 222 &levelFrom, &levelTo); 223 // The formats are validated when the stream is opened so we do not have to 224 // check for illegal combinations here. 225 // TODO factor this out into a utility function 226 if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT) { 227 if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) { 228 AAudio_linearRamp( 229 (const float *) source, 230 (float *) wrappingBuffer.data[partIndex], 231 framesToWrite, 232 getSamplesPerFrame(), 233 levelFrom, 234 levelTo); 235 } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) { 236 if (ramping) { 237 AAudioConvert_floatToPcm16( 238 (const float *) source, 239 (int16_t *) wrappingBuffer.data[partIndex], 240 framesToWrite, 241 getSamplesPerFrame(), 242 levelFrom, 243 levelTo); 244 } else { 245 AAudioConvert_floatToPcm16( 246 (const float *) source, 247 (int16_t *) wrappingBuffer.data[partIndex], 248 numSamples, 249 levelTo); 250 } 251 } 252 } else if (getFormat() == AAUDIO_FORMAT_PCM_I16) { 253 if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) { 254 if (ramping) { 255 AAudioConvert_pcm16ToFloat( 256 (const int16_t *) source, 257 (float *) wrappingBuffer.data[partIndex], 258 framesToWrite, 259 getSamplesPerFrame(), 260 levelFrom, 261 levelTo); 262 } else { 263 AAudioConvert_pcm16ToFloat( 264 (const int16_t *) source, 265 (float *) wrappingBuffer.data[partIndex], 266 numSamples, 267 levelTo); 268 } 269 } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) { 270 AAudio_linearRamp( 271 (const int16_t *) source, 272 (int16_t *) wrappingBuffer.data[partIndex], 273 framesToWrite, 274 getSamplesPerFrame(), 275 levelFrom, 276 levelTo); 277 } 278 } 279 source += numBytes; 280 framesLeft -= framesToWrite; 281 } else { 282 break; 283 } 284 partIndex++; 285 } 286 int32_t framesWritten = numFrames - framesLeft; 287 mAudioEndpoint.advanceWriteIndex(framesWritten); 288 289 // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten); 290 return framesWritten; 291 } 292 293 int64_t AudioStreamInternalPlay::getFramesRead() 294 { 295 int64_t framesReadHardware; 296 if (isActive()) { 297 framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()); 298 } else { 299 framesReadHardware = mAudioEndpoint.getDataReadCounter(); 300 } 301 int64_t framesRead = framesReadHardware + mFramesOffsetFromService; 302 // Prevent retrograde motion. 303 if (framesRead < mLastFramesRead) { 304 framesRead = mLastFramesRead; 305 } else { 306 mLastFramesRead = framesRead; 307 } 308 //ALOGD("AudioStreamInternalPlay::getFramesRead() returns %lld", (long long)framesRead); 309 return framesRead; 310 } 311 312 int64_t AudioStreamInternalPlay::getFramesWritten() 313 { 314 int64_t framesWritten = mAudioEndpoint.getDataWriteCounter() 315 + mFramesOffsetFromService; 316 //ALOGD("AudioStreamInternalPlay::getFramesWritten() returns %lld", (long long)framesWritten); 317 return framesWritten; 318 } 319 320 321 // Render audio in the application callback and then write the data to the stream. 322 void *AudioStreamInternalPlay::callbackLoop() { 323 aaudio_result_t result = AAUDIO_OK; 324 aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; 325 AAudioStream_dataCallback appCallback = getDataCallbackProc(); 326 if (appCallback == nullptr) return NULL; 327 int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); 328 329 // result might be a frame count 330 while (mCallbackEnabled.load() && isActive() && (result >= 0)) { 331 // Call application using the AAudio callback interface. 332 callbackResult = (*appCallback)( 333 (AAudioStream *) this, 334 getDataCallbackUserData(), 335 mCallbackBuffer, 336 mCallbackFrames); 337 338 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { 339 // Write audio data to stream. This is a BLOCKING WRITE! 340 result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos); 341 if ((result != mCallbackFrames)) { 342 ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result); 343 if (result >= 0) { 344 // Only wrote some of the frames requested. Must have timed out. 345 result = AAUDIO_ERROR_TIMEOUT; 346 } 347 AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); 348 if (errorCallback != nullptr) { 349 (*errorCallback)( 350 (AAudioStream *) this, 351 getErrorCallbackUserData(), 352 result); 353 } 354 break; 355 } 356 } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { 357 ALOGD("AudioStreamInternalPlay(): callback returned AAUDIO_CALLBACK_RESULT_STOP"); 358 break; 359 } 360 } 361 362 ALOGD("AudioStreamInternalPlay(): callbackLoop() exiting, result = %d, isActive() = %d", 363 result, (int) isActive()); 364 return NULL; 365 } 366 367 //------------------------------------------------------------------------------ 368 // Implementation of PlayerBase 369 status_t AudioStreamInternalPlay::doSetVolume() { 370 mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume()); 371 return android::NO_ERROR; 372 } 373