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 
AudioStreamInternal(AAudioServiceInterface & serviceInterface,bool inService)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 
~AudioStreamInternal()69 AudioStreamInternal::~AudioStreamInternal() {
70 }
71 
open(const AudioStreamBuilder & builder)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 
close()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 
aaudio_callback_thread_proc(void * context)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 
requestStart()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 
calculateReasonableTimeout(int32_t framesPerOperation)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 
calculateReasonableTimeout()260 int64_t AudioStreamInternal::calculateReasonableTimeout() {
261     return calculateReasonableTimeout(getFramesPerBurst());
262 }
263 
stopCallback()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 
requestPauseInternal()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 
requestPause()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 
requestFlush()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
onFlushFromServer()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 
requestStopInternal()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 
requestStop()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 
registerThread()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 
unregisterThread()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 
getTimestamp(clockid_t clockId,int64_t * framePosition,int64_t * timeNanoseconds)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 
updateStateWhileWaiting()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
AudioStreamInternal_logTimestamp(AAudioServiceMessage & command)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 
onTimestampFromServer(AAudioServiceMessage * message)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 
onEventFromServer(AAudioServiceMessage * message)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.
processCommands()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
processData(void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)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 
processTimestamp(uint64_t position,int64_t time)555 void AudioStreamInternal::processTimestamp(uint64_t position, int64_t time) {
556     mClockModel.processTimestamp(position, time);
557 }
558 
setBufferSize(int32_t requestedFrames)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 
getBufferSize() const576 int32_t AudioStreamInternal::getBufferSize() const {
577     return mAudioEndpoint.getBufferSizeInFrames();
578 }
579 
getBufferCapacity() const580 int32_t AudioStreamInternal::getBufferCapacity() const {
581     return mAudioEndpoint.getBufferCapacityInFrames();
582 }
583 
getFramesPerBurst() const584 int32_t AudioStreamInternal::getFramesPerBurst() const {
585     return mEndpointDescriptor.dataQueueDescriptor.framesPerBurst;
586 }
587 
joinThread(void ** returnArg)588 aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
589     return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
590 }
591