Home | History | Annotate | Download | only in client
      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 ? "AudioStreamInternalCapture_Service" \
     18                           : "AudioStreamInternalCapture_Client")
     19 //#define LOG_NDEBUG 0
     20 #include <utils/Log.h>
     21 
     22 #include <algorithm>
     23 #include <audio_utils/primitives.h>
     24 #include <aaudio/AAudio.h>
     25 
     26 #include "client/AudioStreamInternalCapture.h"
     27 #include "utility/AudioClock.h"
     28 
     29 #define ATRACE_TAG ATRACE_TAG_AUDIO
     30 #include <utils/Trace.h>
     31 
     32 using android::WrappingBuffer;
     33 
     34 using namespace aaudio;
     35 
     36 AudioStreamInternalCapture::AudioStreamInternalCapture(AAudioServiceInterface  &serviceInterface,
     37                                                  bool inService)
     38     : AudioStreamInternal(serviceInterface, inService) {
     39 
     40 }
     41 
     42 AudioStreamInternalCapture::~AudioStreamInternalCapture() {}
     43 
     44 void AudioStreamInternalCapture::advanceClientToMatchServerPosition() {
     45     int64_t readCounter = mAudioEndpoint.getDataReadCounter();
     46     int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
     47 
     48     // Bump offset so caller does not see the retrograde motion in getFramesRead().
     49     int64_t offset = readCounter - writeCounter;
     50     mFramesOffsetFromService += offset;
     51     ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
     52           (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
     53 
     54     // Force readCounter to match writeCounter.
     55     // This is because we cannot change the write counter in the hardware.
     56     mAudioEndpoint.setDataReadCounter(writeCounter);
     57 }
     58 
     59 // Write the data, block if needed and timeoutMillis > 0
     60 aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames,
     61                                                int64_t timeoutNanoseconds)
     62 {
     63     return processData(buffer, numFrames, timeoutNanoseconds);
     64 }
     65 
     66 // Read as much data as we can without blocking.
     67 aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t numFrames,
     68                                                   int64_t currentNanoTime, int64_t *wakeTimePtr) {
     69     aaudio_result_t result = processCommands();
     70     if (result != AAUDIO_OK) {
     71         return result;
     72     }
     73 
     74     const char *traceName = "aaRdNow";
     75     ATRACE_BEGIN(traceName);
     76 
     77     if (mClockModel.isStarting()) {
     78         // Still haven't got any timestamps from server.
     79         // Keep waiting until we get some valid timestamps then start writing to the
     80         // current buffer position.
     81         ALOGD("processDataNow() wait for valid timestamps");
     82         // Sleep very briefly and hope we get a timestamp soon.
     83         *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
     84         ATRACE_END();
     85         return 0;
     86     }
     87     // If we have gotten this far then we have at least one timestamp from server.
     88 
     89     if (mAudioEndpoint.isFreeRunning()) {
     90         //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
     91         // Update data queue based on the timing model.
     92         int64_t estimatedRemoteCounter = mClockModel.convertTimeToPosition(currentNanoTime);
     93         // TODO refactor, maybe use setRemoteCounter()
     94         mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
     95     }
     96 
     97     // This code assumes that we have already received valid timestamps.
     98     if (mNeedCatchUp.isRequested()) {
     99         // Catch an MMAP pointer that is already advancing.
    100         // This will avoid initial underruns caused by a slow cold start.
    101         advanceClientToMatchServerPosition();
    102         mNeedCatchUp.acknowledge();
    103     }
    104 
    105     // If the write index passed the read index then consider it an overrun.
    106     // For shared streams, the xRunCount is passed up from the service.
    107     if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getEmptyFramesAvailable() < 0) {
    108         mXRunCount++;
    109         if (ATRACE_ENABLED()) {
    110             ATRACE_INT("aaOverRuns", mXRunCount);
    111         }
    112     }
    113 
    114     // Read some data from the buffer.
    115     //ALOGD("AudioStreamInternalCapture::processDataNow() - readNowWithConversion(%d)", numFrames);
    116     int32_t framesProcessed = readNowWithConversion(buffer, numFrames);
    117     //ALOGD("AudioStreamInternalCapture::processDataNow() - tried to read %d frames, read %d",
    118     //    numFrames, framesProcessed);
    119     if (ATRACE_ENABLED()) {
    120         ATRACE_INT("aaRead", framesProcessed);
    121     }
    122 
    123     // Calculate an ideal time to wake up.
    124     if (wakeTimePtr != nullptr && framesProcessed >= 0) {
    125         // By default wake up a few milliseconds from now.  // TODO review
    126         int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
    127         aaudio_stream_state_t state = getState();
    128         //ALOGD("AudioStreamInternalCapture::processDataNow() - wakeTime based on %s",
    129         //      AAudio_convertStreamStateToText(state));
    130         switch (state) {
    131             case AAUDIO_STREAM_STATE_OPEN:
    132             case AAUDIO_STREAM_STATE_STARTING:
    133                 break;
    134             case AAUDIO_STREAM_STATE_STARTED:
    135             {
    136                 // When do we expect the next write burst to occur?
    137 
    138                 // Calculate frame position based off of the readCounter because
    139                 // the writeCounter might have just advanced in the background,
    140                 // causing us to sleep until a later burst.
    141                 int64_t nextPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
    142                 wakeTime = mClockModel.convertPositionToTime(nextPosition);
    143             }
    144                 break;
    145             default:
    146                 break;
    147         }
    148         *wakeTimePtr = wakeTime;
    149 
    150     }
    151 
    152     ATRACE_END();
    153     return framesProcessed;
    154 }
    155 
    156 aaudio_result_t AudioStreamInternalCapture::readNowWithConversion(void *buffer,
    157                                                                 int32_t numFrames) {
    158     // ALOGD("readNowWithConversion(%p, %d)",
    159     //              buffer, numFrames);
    160     WrappingBuffer wrappingBuffer;
    161     uint8_t *destination = (uint8_t *) buffer;
    162     int32_t framesLeft = numFrames;
    163 
    164     mAudioEndpoint.getFullFramesAvailable(&wrappingBuffer);
    165 
    166     // Read data in one or two parts.
    167     for (int partIndex = 0; framesLeft > 0 && partIndex < WrappingBuffer::SIZE; partIndex++) {
    168         int32_t framesToProcess = framesLeft;
    169         const int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
    170         if (framesAvailable <= 0) break;
    171 
    172         if (framesToProcess > framesAvailable) {
    173             framesToProcess = framesAvailable;
    174         }
    175 
    176         const int32_t numBytes = getBytesPerFrame() * framesToProcess;
    177         const int32_t numSamples = framesToProcess * getSamplesPerFrame();
    178 
    179         const audio_format_t sourceFormat = getDeviceFormat();
    180         const audio_format_t destinationFormat = getFormat();
    181         // TODO factor this out into a utility function
    182         if (sourceFormat == destinationFormat) {
    183             memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
    184         } else if (sourceFormat == AUDIO_FORMAT_PCM_16_BIT
    185                    && destinationFormat == AUDIO_FORMAT_PCM_FLOAT) {
    186             memcpy_to_float_from_i16(
    187                     (float *) destination,
    188                     (const int16_t *) wrappingBuffer.data[partIndex],
    189                     numSamples);
    190         } else if (sourceFormat == AUDIO_FORMAT_PCM_FLOAT
    191                    && destinationFormat == AUDIO_FORMAT_PCM_16_BIT) {
    192             memcpy_to_i16_from_float(
    193                     (int16_t *) destination,
    194                     (const float *) wrappingBuffer.data[partIndex],
    195                     numSamples);
    196         } else {
    197             ALOGE("%s() - Format conversion not supported! audio_format_t source = %u, dest = %u",
    198                 __func__, sourceFormat, destinationFormat);
    199             return AAUDIO_ERROR_INVALID_FORMAT;
    200         }
    201         destination += numBytes;
    202         framesLeft -= framesToProcess;
    203     }
    204 
    205     int32_t framesProcessed = numFrames - framesLeft;
    206     mAudioEndpoint.advanceReadIndex(framesProcessed);
    207 
    208     //ALOGD("readNowWithConversion() returns %d", framesProcessed);
    209     return framesProcessed;
    210 }
    211 
    212 int64_t AudioStreamInternalCapture::getFramesWritten() {
    213     const int64_t framesWrittenHardware = isClockModelInControl()
    214             ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
    215             : mAudioEndpoint.getDataWriteCounter();
    216     // Add service offset and prevent retrograde motion.
    217     mLastFramesWritten = std::max(mLastFramesWritten,
    218                                   framesWrittenHardware + mFramesOffsetFromService);
    219     return mLastFramesWritten;
    220 }
    221 
    222 int64_t AudioStreamInternalCapture::getFramesRead() {
    223     int64_t frames = mAudioEndpoint.getDataReadCounter() + mFramesOffsetFromService;
    224     //ALOGD("getFramesRead() returns %lld", (long long)frames);
    225     return frames;
    226 }
    227 
    228 // Read data from the stream and pass it to the callback for processing.
    229 void *AudioStreamInternalCapture::callbackLoop() {
    230     aaudio_result_t result = AAUDIO_OK;
    231     aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
    232     if (!isDataCallbackSet()) return NULL;
    233 
    234     // result might be a frame count
    235     while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
    236 
    237         // Read audio data from stream.
    238         int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
    239 
    240         // This is a BLOCKING READ!
    241         result = read(mCallbackBuffer, mCallbackFrames, timeoutNanos);
    242         if ((result != mCallbackFrames)) {
    243             ALOGE("callbackLoop: read() returned %d", result);
    244             if (result >= 0) {
    245                 // Only read some of the frames requested. Must have timed out.
    246                 result = AAUDIO_ERROR_TIMEOUT;
    247             }
    248             maybeCallErrorCallback(result);
    249             break;
    250         }
    251 
    252         // Call application using the AAudio callback interface.
    253         callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames);
    254 
    255         if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
    256             ALOGD("%s(): callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
    257             result = systemStopFromCallback();
    258             break;
    259         }
    260     }
    261 
    262     ALOGD("callbackLoop() exiting, result = %d, isActive() = %d",
    263           result, (int) isActive());
    264     return NULL;
    265 }
    266