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 <aaudio/AAudio.h> 22 23 #include "client/AudioStreamInternalCapture.h" 24 #include "utility/AudioClock.h" 25 26 using android::WrappingBuffer; 27 28 using namespace aaudio; 29 30 AudioStreamInternalCapture::AudioStreamInternalCapture(AAudioServiceInterface &serviceInterface, 31 bool inService) 32 : AudioStreamInternal(serviceInterface, inService) { 33 34 } 35 36 AudioStreamInternalCapture::~AudioStreamInternalCapture() {} 37 38 39 // Write the data, block if needed and timeoutMillis > 0 40 aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames, 41 int64_t timeoutNanoseconds) 42 { 43 return processData(buffer, numFrames, timeoutNanoseconds); 44 } 45 46 // Read as much data as we can without blocking. 47 aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t numFrames, 48 int64_t currentNanoTime, int64_t *wakeTimePtr) { 49 aaudio_result_t result = processCommands(); 50 if (result != AAUDIO_OK) { 51 return result; 52 } 53 54 if (mAudioEndpoint.isFreeRunning()) { 55 //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter"); 56 // Update data queue based on the timing model. 57 int64_t estimatedRemoteCounter = mClockModel.convertTimeToPosition(currentNanoTime); 58 // TODO refactor, maybe use setRemoteCounter() 59 mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter); 60 } 61 62 // If the write index passed the read index then consider it an overrun. 63 if (mAudioEndpoint.getEmptyFramesAvailable() < 0) { 64 mXRunCount++; 65 } 66 67 // Read some data from the buffer. 68 //ALOGD("AudioStreamInternalCapture::processDataNow() - readNowWithConversion(%d)", numFrames); 69 int32_t framesProcessed = readNowWithConversion(buffer, numFrames); 70 //ALOGD("AudioStreamInternalCapture::processDataNow() - tried to read %d frames, read %d", 71 // numFrames, framesProcessed); 72 73 // Calculate an ideal time to wake up. 74 if (wakeTimePtr != nullptr && framesProcessed >= 0) { 75 // By default wake up a few milliseconds from now. // TODO review 76 int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND); 77 aaudio_stream_state_t state = getState(); 78 //ALOGD("AudioStreamInternalCapture::processDataNow() - wakeTime based on %s", 79 // AAudio_convertStreamStateToText(state)); 80 switch (state) { 81 case AAUDIO_STREAM_STATE_OPEN: 82 case AAUDIO_STREAM_STATE_STARTING: 83 break; 84 case AAUDIO_STREAM_STATE_STARTED: // When do we expect the next read burst to occur? 85 { 86 uint32_t burstSize = mFramesPerBurst; 87 if (burstSize < 32) { 88 burstSize = 32; // TODO review 89 } 90 91 uint64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + burstSize; 92 wakeTime = mClockModel.convertPositionToTime(nextReadPosition); 93 } 94 break; 95 default: 96 break; 97 } 98 *wakeTimePtr = wakeTime; 99 100 } 101 // ALOGD("AudioStreamInternalCapture::readNow finished: now = %llu, read# = %llu, wrote# = %llu", 102 // (unsigned long long)currentNanoTime, 103 // (unsigned long long)mAudioEndpoint.getDataReadCounter(), 104 // (unsigned long long)mAudioEndpoint.getDownDataWriteCounter()); 105 return framesProcessed; 106 } 107 108 aaudio_result_t AudioStreamInternalCapture::readNowWithConversion(void *buffer, 109 int32_t numFrames) { 110 // ALOGD("AudioStreamInternalCapture::readNowWithConversion(%p, %d)", 111 // buffer, numFrames); 112 WrappingBuffer wrappingBuffer; 113 uint8_t *destination = (uint8_t *) buffer; 114 int32_t framesLeft = numFrames; 115 116 mAudioEndpoint.getFullFramesAvailable(&wrappingBuffer); 117 118 // Read data in one or two parts. 119 for (int partIndex = 0; framesLeft > 0 && partIndex < WrappingBuffer::SIZE; partIndex++) { 120 int32_t framesToProcess = framesLeft; 121 int32_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 122 if (framesAvailable <= 0) break; 123 124 if (framesToProcess > framesAvailable) { 125 framesToProcess = framesAvailable; 126 } 127 128 int32_t numBytes = getBytesPerFrame() * framesToProcess; 129 int32_t numSamples = framesToProcess * getSamplesPerFrame(); 130 131 // TODO factor this out into a utility function 132 if (mDeviceFormat == getFormat()) { 133 memcpy(destination, wrappingBuffer.data[partIndex], numBytes); 134 } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16 135 && getFormat() == AAUDIO_FORMAT_PCM_FLOAT) { 136 AAudioConvert_pcm16ToFloat( 137 (const int16_t *) wrappingBuffer.data[partIndex], 138 (float *) destination, 139 numSamples, 140 1.0f); 141 } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT 142 && getFormat() == AAUDIO_FORMAT_PCM_I16) { 143 AAudioConvert_floatToPcm16( 144 (const float *) wrappingBuffer.data[partIndex], 145 (int16_t *) destination, 146 numSamples, 147 1.0f); 148 } else { 149 ALOGE("Format conversion not supported!"); 150 return AAUDIO_ERROR_INVALID_FORMAT; 151 } 152 destination += numBytes; 153 framesLeft -= framesToProcess; 154 } 155 156 int32_t framesProcessed = numFrames - framesLeft; 157 mAudioEndpoint.advanceReadIndex(framesProcessed); 158 incrementFramesRead(framesProcessed); 159 160 //ALOGD("AudioStreamInternalCapture::readNowWithConversion() returns %d", framesProcessed); 161 return framesProcessed; 162 } 163 164 int64_t AudioStreamInternalCapture::getFramesWritten() 165 { 166 int64_t frames = 167 mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()) 168 + mFramesOffsetFromService; 169 // Prevent retrograde motion. 170 if (frames < mLastFramesWritten) { 171 frames = mLastFramesWritten; 172 } else { 173 mLastFramesWritten = frames; 174 } 175 //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld", (long long)frames); 176 return frames; 177 } 178 179 int64_t AudioStreamInternalCapture::getFramesRead() 180 { 181 int64_t frames = mAudioEndpoint.getDataWriteCounter() 182 + mFramesOffsetFromService; 183 //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames); 184 return frames; 185 } 186 187 // Read data from the stream and pass it to the callback for processing. 188 void *AudioStreamInternalCapture::callbackLoop() { 189 aaudio_result_t result = AAUDIO_OK; 190 aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; 191 AAudioStream_dataCallback appCallback = getDataCallbackProc(); 192 if (appCallback == nullptr) return NULL; 193 194 // result might be a frame count 195 while (mCallbackEnabled.load() && isActive() && (result >= 0)) { 196 197 // Read audio data from stream. 198 int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); 199 200 // This is a BLOCKING READ! 201 result = read(mCallbackBuffer, mCallbackFrames, timeoutNanos); 202 if ((result != mCallbackFrames)) { 203 ALOGE("AudioStreamInternalCapture(): callbackLoop: read() returned %d", result); 204 if (result >= 0) { 205 // Only read some of the frames requested. Must have timed out. 206 result = AAUDIO_ERROR_TIMEOUT; 207 } 208 AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); 209 if (errorCallback != nullptr) { 210 (*errorCallback)( 211 (AAudioStream *) this, 212 getErrorCallbackUserData(), 213 result); 214 } 215 break; 216 } 217 218 // Call application using the AAudio callback interface. 219 callbackResult = (*appCallback)( 220 (AAudioStream *) this, 221 getDataCallbackUserData(), 222 mCallbackBuffer, 223 mCallbackFrames); 224 225 if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { 226 ALOGD("AudioStreamInternalCapture(): callback returned AAUDIO_CALLBACK_RESULT_STOP"); 227 break; 228 } 229 } 230 231 ALOGD("AudioStreamInternalCapture(): callbackLoop() exiting, result = %d, isActive() = %d", 232 result, (int) isActive()); 233 return NULL; 234 } 235