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