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