Home | History | Annotate | Download | only in client
      1 /*
      2  * Copyright (C) 2016 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 // This file is used in both client and server processes.
     18 // This is needed to make sense of the logs more easily.
     19 #define LOG_TAG (mInService ? "AAudioService" : "AAudio")
     20 //#define LOG_NDEBUG 0
     21 #include <utils/Log.h>
     22 
     23 #define ATRACE_TAG ATRACE_TAG_AUDIO
     24 
     25 #include <stdint.h>
     26 #include <assert.h>
     27 
     28 #include <binder/IServiceManager.h>
     29 
     30 #include <aaudio/AAudio.h>
     31 #include <utils/String16.h>
     32 #include <utils/Trace.h>
     33 
     34 #include "AudioClock.h"
     35 #include "AudioEndpointParcelable.h"
     36 #include "binding/AAudioStreamRequest.h"
     37 #include "binding/AAudioStreamConfiguration.h"
     38 #include "binding/IAAudioService.h"
     39 #include "binding/AAudioServiceMessage.h"
     40 #include "core/AudioStreamBuilder.h"
     41 #include "fifo/FifoBuffer.h"
     42 #include "utility/LinearRamp.h"
     43 
     44 #include "AudioStreamInternal.h"
     45 
     46 using android::String16;
     47 using android::Mutex;
     48 using android::WrappingBuffer;
     49 
     50 using namespace aaudio;
     51 
     52 #define MIN_TIMEOUT_NANOS        (1000 * AAUDIO_NANOS_PER_MILLISECOND)
     53 
     54 // Wait at least this many times longer than the operation should take.
     55 #define MIN_TIMEOUT_OPERATIONS    4
     56 
     57 #define LOG_TIMESTAMPS   0
     58 
     59 AudioStreamInternal::AudioStreamInternal(AAudioServiceInterface  &serviceInterface, bool inService)
     60         : AudioStream()
     61         , mClockModel()
     62         , mAudioEndpoint()
     63         , mServiceStreamHandle(AAUDIO_HANDLE_INVALID)
     64         , mFramesPerBurst(16)
     65         , mServiceInterface(serviceInterface)
     66         , mInService(inService) {
     67 }
     68 
     69 AudioStreamInternal::~AudioStreamInternal() {
     70 }
     71 
     72 aaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) {
     73 
     74     aaudio_result_t result = AAUDIO_OK;
     75     AAudioStreamRequest request;
     76     AAudioStreamConfiguration configuration;
     77 
     78     result = AudioStream::open(builder);
     79     if (result < 0) {
     80         return result;
     81     }
     82 
     83     // We have to do volume scaling. So we prefer FLOAT format.
     84     if (getFormat() == AAUDIO_FORMAT_UNSPECIFIED) {
     85         setFormat(AAUDIO_FORMAT_PCM_FLOAT);
     86     }
     87     // Request FLOAT for the shared mixer.
     88     request.getConfiguration().setAudioFormat(AAUDIO_FORMAT_PCM_FLOAT);
     89 
     90     // Build the request to send to the server.
     91     request.setUserId(getuid());
     92     request.setProcessId(getpid());
     93     request.setDirection(getDirection());
     94     request.setSharingModeMatchRequired(isSharingModeMatchRequired());
     95 
     96     request.getConfiguration().setDeviceId(getDeviceId());
     97     request.getConfiguration().setSampleRate(getSampleRate());
     98     request.getConfiguration().setSamplesPerFrame(getSamplesPerFrame());
     99     request.getConfiguration().setSharingMode(getSharingMode());
    100 
    101     request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
    102 
    103     mServiceStreamHandle = mServiceInterface.openStream(request, configuration);
    104     if (mServiceStreamHandle < 0) {
    105         result = mServiceStreamHandle;
    106         ALOGE("AudioStreamInternal.open(): openStream() returned %d", result);
    107     } else {
    108         result = configuration.validate();
    109         if (result != AAUDIO_OK) {
    110             close();
    111             return result;
    112         }
    113         // Save results of the open.
    114         setSampleRate(configuration.getSampleRate());
    115         setSamplesPerFrame(configuration.getSamplesPerFrame());
    116         setDeviceId(configuration.getDeviceId());
    117 
    118         // Save device format so we can do format conversion and volume scaling together.
    119         mDeviceFormat = configuration.getAudioFormat();
    120 
    121         result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable);
    122         if (result != AAUDIO_OK) {
    123             mServiceInterface.closeStream(mServiceStreamHandle);
    124             return result;
    125         }
    126 
    127         // resolve parcelable into a descriptor
    128         result = mEndPointParcelable.resolve(&mEndpointDescriptor);
    129         if (result != AAUDIO_OK) {
    130             mServiceInterface.closeStream(mServiceStreamHandle);
    131             return result;
    132         }
    133 
    134         // Configure endpoint based on descriptor.
    135         mAudioEndpoint.configure(&mEndpointDescriptor);
    136 
    137         mFramesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
    138         int32_t capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames;
    139 
    140         // Validate result from server.
    141         if (mFramesPerBurst < 16 || mFramesPerBurst > 16 * 1024) {
    142             ALOGE("AudioStream::open(): framesPerBurst out of range = %d", mFramesPerBurst);
    143             return AAUDIO_ERROR_OUT_OF_RANGE;
    144         }
    145         if (capacity < mFramesPerBurst || capacity > 32 * 1024) {
    146             ALOGE("AudioStream::open(): bufferCapacity out of range = %d", capacity);
    147             return AAUDIO_ERROR_OUT_OF_RANGE;
    148         }
    149 
    150         mClockModel.setSampleRate(getSampleRate());
    151         mClockModel.setFramesPerBurst(mFramesPerBurst);
    152 
    153         if (getDataCallbackProc()) {
    154             mCallbackFrames = builder.getFramesPerDataCallback();
    155             if (mCallbackFrames > getBufferCapacity() / 2) {
    156                 ALOGE("AudioStreamInternal.open(): framesPerCallback too large = %d, capacity = %d",
    157                       mCallbackFrames, getBufferCapacity());
    158                 mServiceInterface.closeStream(mServiceStreamHandle);
    159                 return AAUDIO_ERROR_OUT_OF_RANGE;
    160 
    161             } else if (mCallbackFrames < 0) {
    162                 ALOGE("AudioStreamInternal.open(): framesPerCallback negative");
    163                 mServiceInterface.closeStream(mServiceStreamHandle);
    164                 return AAUDIO_ERROR_OUT_OF_RANGE;
    165 
    166             }
    167             if (mCallbackFrames == AAUDIO_UNSPECIFIED) {
    168                 mCallbackFrames = mFramesPerBurst;
    169             }
    170 
    171             int32_t bytesPerFrame = getSamplesPerFrame()
    172                                     * AAudioConvert_formatToSizeInBytes(getFormat());
    173             int32_t callbackBufferSize = mCallbackFrames * bytesPerFrame;
    174             mCallbackBuffer = new uint8_t[callbackBufferSize];
    175         }
    176 
    177         setState(AAUDIO_STREAM_STATE_OPEN);
    178     }
    179     return result;
    180 }
    181 
    182 aaudio_result_t AudioStreamInternal::close() {
    183     ALOGD("AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X",
    184              mServiceStreamHandle);
    185     if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
    186         // Don't close a stream while it is running.
    187         aaudio_stream_state_t currentState = getState();
    188         if (isActive()) {
    189             requestStop();
    190             aaudio_stream_state_t nextState;
    191             int64_t timeoutNanoseconds = MIN_TIMEOUT_NANOS;
    192             aaudio_result_t result = waitForStateChange(currentState, &nextState,
    193                                                        timeoutNanoseconds);
    194             if (result != AAUDIO_OK) {
    195                 ALOGE("AudioStreamInternal::close() waitForStateChange() returned %d %s",
    196                 result, AAudio_convertResultToText(result));
    197             }
    198         }
    199         aaudio_handle_t serviceStreamHandle = mServiceStreamHandle;
    200         mServiceStreamHandle = AAUDIO_HANDLE_INVALID;
    201 
    202         mServiceInterface.closeStream(serviceStreamHandle);
    203         delete[] mCallbackBuffer;
    204         mCallbackBuffer = nullptr;
    205         return mEndPointParcelable.close();
    206     } else {
    207         return AAUDIO_ERROR_INVALID_HANDLE;
    208     }
    209 }
    210 
    211 
    212 static void *aaudio_callback_thread_proc(void *context)
    213 {
    214     AudioStreamInternal *stream = (AudioStreamInternal *)context;
    215     //LOGD("AudioStreamInternal(): oboe_callback_thread, stream = %p", stream);
    216     if (stream != NULL) {
    217         return stream->callbackLoop();
    218     } else {
    219         return NULL;
    220     }
    221 }
    222 
    223 aaudio_result_t AudioStreamInternal::requestStart()
    224 {
    225     int64_t startTime;
    226     ALOGD("AudioStreamInternal(): start()");
    227     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
    228         return AAUDIO_ERROR_INVALID_STATE;
    229     }
    230 
    231     startTime = AudioClock::getNanoseconds();
    232     mClockModel.start(startTime);
    233     setState(AAUDIO_STREAM_STATE_STARTING);
    234     aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);;
    235 
    236     if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) {
    237         // Launch the callback loop thread.
    238         int64_t periodNanos = mCallbackFrames
    239                               * AAUDIO_NANOS_PER_SECOND
    240                               / getSampleRate();
    241         mCallbackEnabled.store(true);
    242         result = createThread(periodNanos, aaudio_callback_thread_proc, this);
    243     }
    244     return result;
    245 }
    246 
    247 int64_t AudioStreamInternal::calculateReasonableTimeout(int32_t framesPerOperation) {
    248 
    249     // Wait for at least a second or some number of callbacks to join the thread.
    250     int64_t timeoutNanoseconds = (MIN_TIMEOUT_OPERATIONS
    251                                   * framesPerOperation
    252                                   * AAUDIO_NANOS_PER_SECOND)
    253                                   / getSampleRate();
    254     if (timeoutNanoseconds < MIN_TIMEOUT_NANOS) { // arbitrary number of seconds
    255         timeoutNanoseconds = MIN_TIMEOUT_NANOS;
    256     }
    257     return timeoutNanoseconds;
    258 }
    259 
    260 int64_t AudioStreamInternal::calculateReasonableTimeout() {
    261     return calculateReasonableTimeout(getFramesPerBurst());
    262 }
    263 
    264 aaudio_result_t AudioStreamInternal::stopCallback()
    265 {
    266     if (isDataCallbackActive()) {
    267         mCallbackEnabled.store(false);
    268         return joinThread(NULL);
    269     } else {
    270         return AAUDIO_OK;
    271     }
    272 }
    273 
    274 aaudio_result_t AudioStreamInternal::requestPauseInternal()
    275 {
    276     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
    277         ALOGE("AudioStreamInternal(): requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
    278               mServiceStreamHandle);
    279         return AAUDIO_ERROR_INVALID_STATE;
    280     }
    281 
    282     mClockModel.stop(AudioClock::getNanoseconds());
    283     setState(AAUDIO_STREAM_STATE_PAUSING);
    284     return mServiceInterface.pauseStream(mServiceStreamHandle);
    285 }
    286 
    287 aaudio_result_t AudioStreamInternal::requestPause()
    288 {
    289     aaudio_result_t result = stopCallback();
    290     if (result != AAUDIO_OK) {
    291         return result;
    292     }
    293     result = requestPauseInternal();
    294     return result;
    295 }
    296 
    297 aaudio_result_t AudioStreamInternal::requestFlush() {
    298     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
    299         ALOGE("AudioStreamInternal(): requestFlush() mServiceStreamHandle invalid = 0x%08X",
    300               mServiceStreamHandle);
    301         return AAUDIO_ERROR_INVALID_STATE;
    302     }
    303 
    304     setState(AAUDIO_STREAM_STATE_FLUSHING);
    305     return mServiceInterface.flushStream(mServiceStreamHandle);
    306 }
    307 
    308 // TODO for Play only
    309 void AudioStreamInternal::onFlushFromServer() {
    310     ALOGD("AudioStreamInternal(): onFlushFromServer()");
    311     int64_t readCounter = mAudioEndpoint.getDataReadCounter();
    312     int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
    313 
    314     // Bump offset so caller does not see the retrograde motion in getFramesRead().
    315     int64_t framesFlushed = writeCounter - readCounter;
    316     mFramesOffsetFromService += framesFlushed;
    317 
    318     // Flush written frames by forcing writeCounter to readCounter.
    319     // This is because we cannot move the read counter in the hardware.
    320     mAudioEndpoint.setDataWriteCounter(readCounter);
    321 }
    322 
    323 aaudio_result_t AudioStreamInternal::requestStopInternal()
    324 {
    325     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
    326         ALOGE("AudioStreamInternal(): requestStopInternal() mServiceStreamHandle invalid = 0x%08X",
    327               mServiceStreamHandle);
    328         return AAUDIO_ERROR_INVALID_STATE;
    329     }
    330 
    331     mClockModel.stop(AudioClock::getNanoseconds());
    332     setState(AAUDIO_STREAM_STATE_STOPPING);
    333     return mServiceInterface.stopStream(mServiceStreamHandle);
    334 }
    335 
    336 aaudio_result_t AudioStreamInternal::requestStop()
    337 {
    338     aaudio_result_t result = stopCallback();
    339     if (result != AAUDIO_OK) {
    340         return result;
    341     }
    342     result = requestStopInternal();
    343     return result;
    344 }
    345 
    346 aaudio_result_t AudioStreamInternal::registerThread() {
    347     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
    348         return AAUDIO_ERROR_INVALID_STATE;
    349     }
    350     return mServiceInterface.registerAudioThread(mServiceStreamHandle,
    351                                               getpid(),
    352                                               gettid(),
    353                                               getPeriodNanoseconds());
    354 }
    355 
    356 aaudio_result_t AudioStreamInternal::unregisterThread() {
    357     if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
    358         return AAUDIO_ERROR_INVALID_STATE;
    359     }
    360     return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, getpid(), gettid());
    361 }
    362 
    363 aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
    364                            int64_t *framePosition,
    365                            int64_t *timeNanoseconds) {
    366     // TODO Generate in server and pass to client. Return latest.
    367     int64_t time = AudioClock::getNanoseconds();
    368     *framePosition = mClockModel.convertTimeToPosition(time);
    369     // TODO Get a more accurate timestamp from the service. This code just adds a fudge factor.
    370     *timeNanoseconds = time + (6 * AAUDIO_NANOS_PER_MILLISECOND);
    371     return AAUDIO_OK;
    372 }
    373 
    374 aaudio_result_t AudioStreamInternal::updateStateWhileWaiting() {
    375     if (isDataCallbackActive()) {
    376         return AAUDIO_OK; // state is getting updated by the callback thread read/write call
    377     }
    378     return processCommands();
    379 }
    380 
    381 #if LOG_TIMESTAMPS
    382 static void AudioStreamInternal_logTimestamp(AAudioServiceMessage &command) {
    383     static int64_t oldPosition = 0;
    384     static int64_t oldTime = 0;
    385     int64_t framePosition = command.timestamp.position;
    386     int64_t nanoTime = command.timestamp.timestamp;
    387     ALOGD("AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %lld",
    388          (long long) framePosition,
    389          (long long) nanoTime);
    390     int64_t nanosDelta = nanoTime - oldTime;
    391     if (nanosDelta > 0 && oldTime > 0) {
    392         int64_t framesDelta = framePosition - oldPosition;
    393         int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta;
    394         ALOGD("AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta);
    395         ALOGD("AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta);
    396         ALOGD("AudioStreamInternal() - measured rate = %lld", (long long) rate);
    397     }
    398     oldPosition = framePosition;
    399     oldTime = nanoTime;
    400 }
    401 #endif
    402 
    403 aaudio_result_t AudioStreamInternal::onTimestampFromServer(AAudioServiceMessage *message) {
    404 #if LOG_TIMESTAMPS
    405     AudioStreamInternal_logTimestamp(*message);
    406 #endif
    407     processTimestamp(message->timestamp.position, message->timestamp.timestamp);
    408     return AAUDIO_OK;
    409 }
    410 
    411 aaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *message) {
    412     aaudio_result_t result = AAUDIO_OK;
    413     switch (message->event.event) {
    414         case AAUDIO_SERVICE_EVENT_STARTED:
    415             ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STARTED");
    416             if (getState() == AAUDIO_STREAM_STATE_STARTING) {
    417                 setState(AAUDIO_STREAM_STATE_STARTED);
    418             }
    419             break;
    420         case AAUDIO_SERVICE_EVENT_PAUSED:
    421             ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_PAUSED");
    422             if (getState() == AAUDIO_STREAM_STATE_PAUSING) {
    423                 setState(AAUDIO_STREAM_STATE_PAUSED);
    424             }
    425             break;
    426         case AAUDIO_SERVICE_EVENT_STOPPED:
    427             ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_STOPPED");
    428             if (getState() == AAUDIO_STREAM_STATE_STOPPING) {
    429                 setState(AAUDIO_STREAM_STATE_STOPPED);
    430             }
    431             break;
    432         case AAUDIO_SERVICE_EVENT_FLUSHED:
    433             ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED");
    434             if (getState() == AAUDIO_STREAM_STATE_FLUSHING) {
    435                 setState(AAUDIO_STREAM_STATE_FLUSHED);
    436                 onFlushFromServer();
    437             }
    438             break;
    439         case AAUDIO_SERVICE_EVENT_CLOSED:
    440             ALOGD("processCommands() got AAUDIO_SERVICE_EVENT_CLOSED");
    441             setState(AAUDIO_STREAM_STATE_CLOSED);
    442             break;
    443         case AAUDIO_SERVICE_EVENT_DISCONNECTED:
    444             result = AAUDIO_ERROR_DISCONNECTED;
    445             setState(AAUDIO_STREAM_STATE_DISCONNECTED);
    446             ALOGW("WARNING - processCommands() AAUDIO_SERVICE_EVENT_DISCONNECTED");
    447             break;
    448         case AAUDIO_SERVICE_EVENT_VOLUME:
    449             mVolumeRamp.setTarget((float) message->event.dataDouble);
    450             ALOGD("processCommands() AAUDIO_SERVICE_EVENT_VOLUME %lf",
    451                      message->event.dataDouble);
    452             break;
    453         default:
    454             ALOGW("WARNING - processCommands() Unrecognized event = %d",
    455                  (int) message->event.event);
    456             break;
    457     }
    458     return result;
    459 }
    460 
    461 // Process all the commands coming from the server.
    462 aaudio_result_t AudioStreamInternal::processCommands() {
    463     aaudio_result_t result = AAUDIO_OK;
    464 
    465     while (result == AAUDIO_OK) {
    466         //ALOGD("AudioStreamInternal::processCommands() - looping, %d", result);
    467         AAudioServiceMessage message;
    468         if (mAudioEndpoint.readUpCommand(&message) != 1) {
    469             break; // no command this time, no problem
    470         }
    471         switch (message.what) {
    472         case AAudioServiceMessage::code::TIMESTAMP:
    473             result = onTimestampFromServer(&message);
    474             break;
    475 
    476         case AAudioServiceMessage::code::EVENT:
    477             result = onEventFromServer(&message);
    478             break;
    479 
    480         default:
    481             ALOGE("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d",
    482                  (int) message.what);
    483             result = AAUDIO_ERROR_INTERNAL;
    484             break;
    485         }
    486     }
    487     return result;
    488 }
    489 
    490 // Read or write the data, block if needed and timeoutMillis > 0
    491 aaudio_result_t AudioStreamInternal::processData(void *buffer, int32_t numFrames,
    492                                                  int64_t timeoutNanoseconds)
    493 {
    494     const char * traceName = (mInService) ? "aaWrtS" : "aaWrtC";
    495     ATRACE_BEGIN(traceName);
    496     aaudio_result_t result = AAUDIO_OK;
    497     int32_t loopCount = 0;
    498     uint8_t* audioData = (uint8_t*)buffer;
    499     int64_t currentTimeNanos = AudioClock::getNanoseconds();
    500     int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds;
    501     int32_t framesLeft = numFrames;
    502 
    503     int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable();
    504     if (ATRACE_ENABLED()) {
    505         const char * traceName = (mInService) ? "aaFullS" : "aaFullC";
    506         ATRACE_INT(traceName, fullFrames);
    507     }
    508 
    509     // Loop until all the data has been processed or until a timeout occurs.
    510     while (framesLeft > 0) {
    511         // The call to processDataNow() will not block. It will just read as much as it can.
    512         int64_t wakeTimeNanos = 0;
    513         aaudio_result_t framesProcessed = processDataNow(audioData, framesLeft,
    514                                                   currentTimeNanos, &wakeTimeNanos);
    515         if (framesProcessed < 0) {
    516             ALOGE("AudioStreamInternal::processData() loop: framesProcessed = %d", framesProcessed);
    517             result = framesProcessed;
    518             break;
    519         }
    520         framesLeft -= (int32_t) framesProcessed;
    521         audioData += framesProcessed * getBytesPerFrame();
    522 
    523         // Should we block?
    524         if (timeoutNanoseconds == 0) {
    525             break; // don't block
    526         } else if (framesLeft > 0) {
    527             // clip the wake time to something reasonable
    528             if (wakeTimeNanos < currentTimeNanos) {
    529                 wakeTimeNanos = currentTimeNanos;
    530             }
    531             if (wakeTimeNanos > deadlineNanos) {
    532                 // If we time out, just return the framesWritten so far.
    533                 // TODO remove after we fix the deadline bug
    534                 ALOGE("AudioStreamInternal::processData(): timed out after %lld nanos",
    535                       (long long) timeoutNanoseconds);
    536                 ALOGE("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos",
    537                       (long long) wakeTimeNanos, (long long) deadlineNanos);
    538                 ALOGE("AudioStreamInternal::processData(): past deadline by %d micros",
    539                       (int)((wakeTimeNanos - deadlineNanos) / AAUDIO_NANOS_PER_MICROSECOND));
    540                 break;
    541             }
    542 
    543             int64_t sleepForNanos = wakeTimeNanos - currentTimeNanos;
    544             AudioClock::sleepForNanos(sleepForNanos);
    545             currentTimeNanos = AudioClock::getNanoseconds();
    546         }
    547     }
    548 
    549     // return error or framesProcessed
    550     (void) loopCount;
    551     ATRACE_END();
    552     return (result < 0) ? result : numFrames - framesLeft;
    553 }
    554 
    555 void AudioStreamInternal::processTimestamp(uint64_t position, int64_t time) {
    556     mClockModel.processTimestamp(position, time);
    557 }
    558 
    559 aaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) {
    560     int32_t actualFrames = 0;
    561     // Round to the next highest burst size.
    562     if (getFramesPerBurst() > 0) {
    563         int32_t numBursts = (requestedFrames + getFramesPerBurst() - 1) / getFramesPerBurst();
    564         requestedFrames = numBursts * getFramesPerBurst();
    565     }
    566 
    567     aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames);
    568     ALOGD("AudioStreamInternal::setBufferSize() req = %d => %d", requestedFrames, actualFrames);
    569     if (result < 0) {
    570         return result;
    571     } else {
    572         return (aaudio_result_t) actualFrames;
    573     }
    574 }
    575 
    576 int32_t AudioStreamInternal::getBufferSize() const {
    577     return mAudioEndpoint.getBufferSizeInFrames();
    578 }
    579 
    580 int32_t AudioStreamInternal::getBufferCapacity() const {
    581     return mAudioEndpoint.getBufferCapacityInFrames();
    582 }
    583 
    584 int32_t AudioStreamInternal::getFramesPerBurst() const {
    585     return mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
    586 }
    587 
    588 aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
    589     return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
    590 }
    591