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 "AAudio" 18 //#define LOG_NDEBUG 0 19 #include <utils/Log.h> 20 21 #include "client/AudioStreamInternalPlay.h" 22 #include "utility/AudioClock.h" 23 24 using android::WrappingBuffer; 25 26 using namespace aaudio; 27 28 AudioStreamInternalPlay::AudioStreamInternalPlay(AAudioServiceInterface &serviceInterface, 29 bool inService) 30 : AudioStreamInternal(serviceInterface, inService) { 31 32 } 33 34 AudioStreamInternalPlay::~AudioStreamInternalPlay() {} 35 36 37 // Write the data, block if needed and timeoutMillis > 0 38 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames, 39 int64_t timeoutNanoseconds) 40 41 { 42 return processData((void *)buffer, numFrames, timeoutNanoseconds); 43 } 44 45 // Write as much data as we can without blocking. 46 aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t numFrames, 47 int64_t currentNanoTime, int64_t *wakeTimePtr) { 48 aaudio_result_t result = processCommands(); 49 if (result != AAUDIO_OK) { 50 return result; 51 } 52 53 if (mAudioEndpoint.isFreeRunning()) { 54 //ALOGD("AudioStreamInternal::processDataNow() - update read counter"); 55 // Update data queue based on the timing model. 56 int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime); 57 mAudioEndpoint.setDataReadCounter(estimatedReadCounter); 58 } 59 // TODO else query from endpoint cuz set by actual reader, maybe 60 61 // If the read index passed the write index then consider it an underrun. 62 if (mAudioEndpoint.getFullFramesAvailable() < 0) { 63 mXRunCount++; 64 } 65 66 // Write some data to the buffer. 67 //ALOGD("AudioStreamInternal::processDataNow() - writeNowWithConversion(%d)", numFrames); 68 int32_t framesWritten = writeNowWithConversion(buffer, numFrames); 69 //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d", 70 // numFrames, framesWritten); 71 72 // Calculate an ideal time to wake up. 73 if (wakeTimePtr != nullptr && framesWritten >= 0) { 74 // By default wake up a few milliseconds from now. // TODO review 75 int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND); 76 aaudio_stream_state_t state = getState(); 77 //ALOGD("AudioStreamInternal::processDataNow() - wakeTime based on %s", 78 // AAudio_convertStreamStateToText(state)); 79 switch (state) { 80 case AAUDIO_STREAM_STATE_OPEN: 81 case AAUDIO_STREAM_STATE_STARTING: 82 if (framesWritten != 0) { 83 // Don't wait to write more data. Just prime the buffer. 84 wakeTime = currentNanoTime; 85 } 86 break; 87 case AAUDIO_STREAM_STATE_STARTED: // When do we expect the next read burst to occur? 88 { 89 uint32_t burstSize = mFramesPerBurst; 90 if (burstSize < 32) { 91 burstSize = 32; // TODO review 92 } 93 94 uint64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + burstSize; 95 wakeTime = mClockModel.convertPositionToTime(nextReadPosition); 96 } 97 break; 98 default: 99 break; 100 } 101 *wakeTimePtr = wakeTime; 102 103 } 104 // ALOGD("AudioStreamInternal::processDataNow finished: now = %llu, read# = %llu, wrote# = %llu", 105 // (unsigned long long)currentNanoTime, 106 // (unsigned long long)mAudioEndpoint.getDataReadCounter(), 107 // (unsigned long long)mAudioEndpoint.getDownDataWriteCounter()); 108 return framesWritten; 109 } 110 111 112 aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer, 113 int32_t numFrames) { 114 // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)", 115 // buffer, numFrames); 116 WrappingBuffer wrappingBuffer; 117 uint8_t *source = (uint8_t *) buffer; 118 int32_t framesLeft = numFrames; 119 120 mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer); 121 122 // Read data in one or two parts. 123 int partIndex = 0; 124 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 125 int32_t framesToWrite = framesLeft; 126 int32_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 127 if (framesAvailable > 0) { 128 if (framesToWrite > framesAvailable) { 129 framesToWrite = framesAvailable; 130 } 131 int32_t numBytes = getBytesPerFrame() * framesToWrite; 132 int32_t numSamples = framesToWrite * getSamplesPerFrame(); 133 // Data conversion. 134 float levelFrom; 135 float levelTo; 136 bool ramping = mVolumeRamp.nextSegment(framesToWrite * getSamplesPerFrame(), 137 &levelFrom, &levelTo); 138 // The formats are validated when the stream is opened so we do not have to 139 // check for illegal combinations here. 140 // TODO factor this out into a utility function 141 if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT) { 142 if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) { 143 AAudio_linearRamp( 144 (const float *) source, 145 (float *) wrappingBuffer.data[partIndex], 146 framesToWrite, 147 getSamplesPerFrame(), 148 levelFrom, 149 levelTo); 150 } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) { 151 if (ramping) { 152 AAudioConvert_floatToPcm16( 153 (const float *) source, 154 (int16_t *) wrappingBuffer.data[partIndex], 155 framesToWrite, 156 getSamplesPerFrame(), 157 levelFrom, 158 levelTo); 159 } else { 160 AAudioConvert_floatToPcm16( 161 (const float *) source, 162 (int16_t *) wrappingBuffer.data[partIndex], 163 numSamples, 164 levelTo); 165 } 166 } 167 } else if (getFormat() == AAUDIO_FORMAT_PCM_I16) { 168 if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) { 169 if (ramping) { 170 AAudioConvert_pcm16ToFloat( 171 (const int16_t *) source, 172 (float *) wrappingBuffer.data[partIndex], 173 framesToWrite, 174 getSamplesPerFrame(), 175 levelFrom, 176 levelTo); 177 } else { 178 AAudioConvert_pcm16ToFloat( 179 (const int16_t *) source, 180 (float *) wrappingBuffer.data[partIndex], 181 numSamples, 182 levelTo); 183 } 184 } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) { 185 AAudio_linearRamp( 186 (const int16_t *) source, 187 (int16_t *) wrappingBuffer.data[partIndex], 188 framesToWrite, 189 getSamplesPerFrame(), 190 levelFrom, 191 levelTo); 192 } 193 } 194 source += numBytes; 195 framesLeft -= framesToWrite; 196 } else { 197 break; 198 } 199 partIndex++; 200 } 201 int32_t framesWritten = numFrames - framesLeft; 202 mAudioEndpoint.advanceWriteIndex(framesWritten); 203 204 if (framesWritten > 0) { 205 incrementFramesWritten(framesWritten); 206 } 207 // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten); 208 return framesWritten; 209 } 210 211 212 int64_t AudioStreamInternalPlay::getFramesRead() 213 { 214 int64_t framesRead = 215 mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()) 216 + mFramesOffsetFromService; 217 // Prevent retrograde motion. 218 if (framesRead < mLastFramesRead) { 219 framesRead = mLastFramesRead; 220 } else { 221 mLastFramesRead = framesRead; 222 } 223 ALOGD("AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead); 224 return framesRead; 225 } 226 227 int64_t AudioStreamInternalPlay::getFramesWritten() 228 { 229 int64_t getFramesWritten = mAudioEndpoint.getDataWriteCounter() 230 + mFramesOffsetFromService; 231 ALOGD("AudioStreamInternal::getFramesWritten() returns %lld", (long long)getFramesWritten); 232 return getFramesWritten; 233 } 234 235 236 // Render audio in the application callback and then write the data to the stream. 237 void *AudioStreamInternalPlay::callbackLoop() { 238 aaudio_result_t result = AAUDIO_OK; 239 aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; 240 AAudioStream_dataCallback appCallback = getDataCallbackProc(); 241 if (appCallback == nullptr) return NULL; 242 243 // result might be a frame count 244 while (mCallbackEnabled.load() && isActive() && (result >= 0)) { 245 // Call application using the AAudio callback interface. 246 callbackResult = (*appCallback)( 247 (AAudioStream *) this, 248 getDataCallbackUserData(), 249 mCallbackBuffer, 250 mCallbackFrames); 251 252 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { 253 // Write audio data to stream. 254 int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); 255 256 // This is a BLOCKING WRITE! 257 result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos); 258 if ((result != mCallbackFrames)) { 259 ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result); 260 if (result >= 0) { 261 // Only wrote some of the frames requested. Must have timed out. 262 result = AAUDIO_ERROR_TIMEOUT; 263 } 264 AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); 265 if (errorCallback != nullptr) { 266 (*errorCallback)( 267 (AAudioStream *) this, 268 getErrorCallbackUserData(), 269 result); 270 } 271 break; 272 } 273 } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { 274 ALOGD("AudioStreamInternalPlay(): callback returned AAUDIO_CALLBACK_RESULT_STOP"); 275 break; 276 } 277 } 278 279 ALOGD("AudioStreamInternalPlay(): callbackLoop() exiting, result = %d, isActive() = %d", 280 result, (int) isActive()); 281 return NULL; 282 } 283