AudioStreamInternal.cpp revision 17fff38dd9d467bc5fb6cd5b9a6b183951c7750d
1204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk/* 2204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * Copyright (C) 2016 The Android Open Source Project 3204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * 4204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * Licensed under the Apache License, Version 2.0 (the "License"); 5204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * you may not use this file except in compliance with the License. 6204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * You may obtain a copy of the License at 7204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * 8204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * http://www.apache.org/licenses/LICENSE-2.0 9204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * 10204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * Unless required by applicable law or agreed to in writing, software 11204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * distributed under the License is distributed on an "AS IS" BASIS, 12204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * See the License for the specific language governing permissions and 14204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk * limitations under the License. 15204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk */ 16204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 175ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk#define LOG_TAG "AAudio" 18204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk//#define LOG_NDEBUG 0 19204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include <utils/Log.h> 20204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 214485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk#define ATRACE_TAG ATRACE_TAG_AUDIO 224485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk 23c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <stdint.h> 24204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include <assert.h> 25204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 26204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include <binder/IServiceManager.h> 27204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 285ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk#include <aaudio/AAudio.h> 29e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk#include <utils/String16.h> 304485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk#include <utils/Trace.h> 31204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 32c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "AudioClock.h" 33c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "AudioEndpointParcelable.h" 34c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "binding/AAudioStreamRequest.h" 35c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "binding/AAudioStreamConfiguration.h" 36c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "binding/IAAudioService.h" 375ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk#include "binding/AAudioServiceMessage.h" 38e572f469de5dca1078a79d3d80e5b04f96ae7505Phil Burk#include "core/AudioStreamBuilder.h" 39c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "fifo/FifoBuffer.h" 40e572f469de5dca1078a79d3d80e5b04f96ae7505Phil Burk#include "utility/LinearRamp.h" 41204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 42c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "AudioStreamInternal.h" 43204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 44204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::String16; 45dec33abe3739b2116ef6fbac36f7ca5d26f9d190Phil Burkusing android::Mutex; 46c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::WrappingBuffer; 47204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 485ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkusing namespace aaudio; 49204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 50e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk#define MIN_TIMEOUT_NANOS (1000 * AAUDIO_NANOS_PER_MILLISECOND) 51e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 52e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk// Wait at least this many times longer than the operation should take. 53e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk#define MIN_TIMEOUT_OPERATIONS 4 54e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 5571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk//static int64_t s_logCounter = 0; 5671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk//#define MYLOG_CONDITION (mInService == true && s_logCounter++ < 500) 5771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk//#define MYLOG_CONDITION (s_logCounter++ < 500000) 5871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk#define MYLOG_CONDITION (1) 59204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 6087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk#define LOG_TIMESTAMPS 0 6187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 62c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil BurkAudioStreamInternal::AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService) 63204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk : AudioStream() 64204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk , mClockModel() 65204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk , mAudioEndpoint() 665ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk , mServiceStreamHandle(AAUDIO_HANDLE_INVALID) 67204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk , mFramesPerBurst(16) 68c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk , mServiceInterface(serviceInterface) 6971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk , mInService(inService) { 70204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 71204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 72204a163c86f357a878873fe7d4c4164f3d55c9b6Phil BurkAudioStreamInternal::~AudioStreamInternal() { 73204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 74204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 755ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { 76204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 775ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = AAUDIO_OK; 785ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk AAudioStreamRequest request; 795ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk AAudioStreamConfiguration configuration; 80204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 81204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = AudioStream::open(builder); 82204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (result < 0) { 83204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 84204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 85204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 86c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // We have to do volume scaling. So we prefer FLOAT format. 87c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (getFormat() == AAUDIO_UNSPECIFIED) { 88c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk setFormat(AAUDIO_FORMAT_PCM_FLOAT); 89c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 9071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk // Request FLOAT for the shared mixer. 9171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk request.getConfiguration().setAudioFormat(AAUDIO_FORMAT_PCM_FLOAT); 92c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 93dec33abe3739b2116ef6fbac36f7ca5d26f9d190Phil Burk // Build the request to send to the server. 94204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.setUserId(getuid()); 95204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.setProcessId(getpid()); 96c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk request.setDirection(getDirection()); 9771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk request.setSharingModeMatchRequired(isSharingModeMatchRequired()); 98c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 99204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.getConfiguration().setDeviceId(getDeviceId()); 100204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.getConfiguration().setSampleRate(getSampleRate()); 101204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.getConfiguration().setSamplesPerFrame(getSamplesPerFrame()); 10271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk request.getConfiguration().setSharingMode(getSharingMode()); 10371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk 1043df348fbaca567ca891503213ff8c344a1ea2e05Phil Burk request.getConfiguration().setBufferCapacity(builder.getBufferCapacity()); 105204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 106c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceStreamHandle = mServiceInterface.openStream(request, configuration); 107204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (mServiceStreamHandle < 0) { 108204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = mServiceStreamHandle; 10971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("AudioStreamInternal.open(): %s openStream() returned %d", getLocationName(), result); 110204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } else { 111204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = configuration.validate(); 1125ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (result != AAUDIO_OK) { 113204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk close(); 114204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 115204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 116204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Save results of the open. 117204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk setSampleRate(configuration.getSampleRate()); 118204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk setSamplesPerFrame(configuration.getSamplesPerFrame()); 119c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk setDeviceId(configuration.getDeviceId()); 120204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 121c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // Save device format so we can do format conversion and volume scaling together. 122c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mDeviceFormat = configuration.getAudioFormat(); 123c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 124c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable); 1255ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (result != AAUDIO_OK) { 12671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("AudioStreamInternal.open(): %s getStreamDescriptor returns %d", 12771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk getLocationName(), result); 128c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(mServiceStreamHandle); 129204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 130204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 131c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 132204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // resolve parcelable into a descriptor 133c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk result = mEndPointParcelable.resolve(&mEndpointDescriptor); 134c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (result != AAUDIO_OK) { 135c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGE("AudioStreamInternal.open(): resolve() returns %d", result); 136c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(mServiceStreamHandle); 137c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return result; 138c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 139204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 140204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Configure endpoint based on descriptor. 141204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mAudioEndpoint.configure(&mEndpointDescriptor); 142204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 14387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mFramesPerBurst = mEndpointDescriptor.dataQueueDescriptor.framesPerBurst; 14487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t capacity = mEndpointDescriptor.dataQueueDescriptor.capacityInFrames; 14571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk 14671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal.open() %s framesPerBurst = %d, capacity = %d", 14771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk getLocationName(), mFramesPerBurst, capacity); 14871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk // Validate result from server. 14971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk if (mFramesPerBurst < 16 || mFramesPerBurst > 16 * 1024) { 15071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("AudioStream::open(): framesPerBurst out of range = %d", mFramesPerBurst); 15171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk return AAUDIO_ERROR_OUT_OF_RANGE; 15271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk } 15371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk if (capacity < mFramesPerBurst || capacity > 32 * 1024) { 15471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("AudioStream::open(): bufferCapacity out of range = %d", capacity); 15571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk return AAUDIO_ERROR_OUT_OF_RANGE; 15671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk } 157204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 158204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mClockModel.setSampleRate(getSampleRate()); 159204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mClockModel.setFramesPerBurst(mFramesPerBurst); 160204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 161e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (getDataCallbackProc()) { 162e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackFrames = builder.getFramesPerDataCallback(); 163e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (mCallbackFrames > getBufferCapacity() / 2) { 16471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("AudioStreamInternal.open(): framesPerCallback too large = %d, capacity = %d", 16571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk mCallbackFrames, getBufferCapacity()); 166c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(mServiceStreamHandle); 167e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return AAUDIO_ERROR_OUT_OF_RANGE; 168e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 169e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } else if (mCallbackFrames < 0) { 170e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk ALOGE("AudioStreamInternal.open(): framesPerCallback negative"); 171c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(mServiceStreamHandle); 172e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return AAUDIO_ERROR_OUT_OF_RANGE; 173e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 174e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 175e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (mCallbackFrames == AAUDIO_UNSPECIFIED) { 176e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackFrames = mFramesPerBurst; 177e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 178e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 179e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int32_t bytesPerFrame = getSamplesPerFrame() 180e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk * AAudioConvert_formatToSizeInBytes(getFormat()); 181e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int32_t callbackBufferSize = mCallbackFrames * bytesPerFrame; 182e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackBuffer = new uint8_t[callbackBufferSize]; 183e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 184e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 1855ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_OPEN); 186204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 187204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 188204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 189204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 1905ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::close() { 19171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", 19271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk mServiceStreamHandle); 1935ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) { 1944485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk // Don't close a stream while it is running. 1954485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk aaudio_stream_state_t currentState = getState(); 19687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (isActive()) { 1974485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk requestStop(); 1984485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk aaudio_stream_state_t nextState; 1994485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk int64_t timeoutNanoseconds = MIN_TIMEOUT_NANOS; 2004485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk aaudio_result_t result = waitForStateChange(currentState, &nextState, 2014485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk timeoutNanoseconds); 2024485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk if (result != AAUDIO_OK) { 2034485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk ALOGE("AudioStreamInternal::close() waitForStateChange() returned %d %s", 2044485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk result, AAudio_convertResultToText(result)); 2054485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk } 2064485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk } 2075ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_handle_t serviceStreamHandle = mServiceStreamHandle; 2085ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk mServiceStreamHandle = AAUDIO_HANDLE_INVALID; 209c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 210c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(serviceStreamHandle); 211e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk delete[] mCallbackBuffer; 2124485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk mCallbackBuffer = nullptr; 213c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mEndPointParcelable.close(); 214204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } else { 2155ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_HANDLE; 216204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 217204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 218204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 219c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 220e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkstatic void *aaudio_callback_thread_proc(void *context) 221e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk{ 222e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk AudioStreamInternal *stream = (AudioStreamInternal *)context; 223677d7916c0fa6f0955aae8f3ef921383e285beb2Phil Burk //LOGD("AudioStreamInternal(): oboe_callback_thread, stream = %p", stream); 224e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (stream != NULL) { 225e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return stream->callbackLoop(); 226e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } else { 227e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return NULL; 228e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 229e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 230e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 2315ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::requestStart() 232204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 2333316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t startTime; 23471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): start()"); 2355ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 2365ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 237204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 238c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 2393316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk startTime = AudioClock::getNanoseconds(); 240204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mClockModel.start(startTime); 2415ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_STARTING); 242c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);; 243e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 244e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) { 245e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk // Launch the callback loop thread. 246e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int64_t periodNanos = mCallbackFrames 247e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk * AAUDIO_NANOS_PER_SECOND 248e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk / getSampleRate(); 249e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackEnabled.store(true); 250e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk result = createThread(periodNanos, aaudio_callback_thread_proc, this); 251e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 252e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return result; 253204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 254204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 255e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkint64_t AudioStreamInternal::calculateReasonableTimeout(int32_t framesPerOperation) { 256e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 257e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk // Wait for at least a second or some number of callbacks to join the thread. 25871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk int64_t timeoutNanoseconds = (MIN_TIMEOUT_OPERATIONS 25971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk * framesPerOperation 26071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk * AAUDIO_NANOS_PER_SECOND) 26171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk / getSampleRate(); 262e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (timeoutNanoseconds < MIN_TIMEOUT_NANOS) { // arbitrary number of seconds 263e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk timeoutNanoseconds = MIN_TIMEOUT_NANOS; 264e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 265e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return timeoutNanoseconds; 266e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 267e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 26887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkint64_t AudioStreamInternal::calculateReasonableTimeout() { 26987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return calculateReasonableTimeout(getFramesPerBurst()); 27087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk} 27187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 272e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkaaudio_result_t AudioStreamInternal::stopCallback() 273e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk{ 274e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (isDataCallbackActive()) { 275e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackEnabled.store(false); 27687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return joinThread(NULL); 277e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } else { 278e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return AAUDIO_OK; 279e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 280e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 281e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 282e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkaaudio_result_t AudioStreamInternal::requestPauseInternal() 283204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 2845ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 28571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("AudioStreamInternal(): requestPauseInternal() mServiceStreamHandle invalid = 0x%08X", 28671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk mServiceStreamHandle); 2875ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 288204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 289c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 2903316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk mClockModel.stop(AudioClock::getNanoseconds()); 2915ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_PAUSING); 29271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk return mServiceInterface.pauseStream(mServiceStreamHandle); 293204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 294204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 295e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkaaudio_result_t AudioStreamInternal::requestPause() 296e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk{ 29771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): %s requestPause()", getLocationName()); 298e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk aaudio_result_t result = stopCallback(); 299e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (result != AAUDIO_OK) { 300e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return result; 301e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 30271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk result = requestPauseInternal(); 30371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD("AudioStreamInternal(): requestPause() returns %d", result); 30471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk return result; 305e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 306e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 3075ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::requestFlush() { 30871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): requestFlush()"); 3095ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 31071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("AudioStreamInternal(): requestFlush() mServiceStreamHandle invalid = 0x%08X", 31171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk mServiceStreamHandle); 3125ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 313204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 314c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 315e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk setState(AAUDIO_STREAM_STATE_FLUSHING); 316c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mServiceInterface.flushStream(mServiceStreamHandle); 317204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 318204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 31987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// TODO for Play only 320204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkvoid AudioStreamInternal::onFlushFromServer() { 32171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): onFlushFromServer()"); 32287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t readCounter = mAudioEndpoint.getDataReadCounter(); 32387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t writeCounter = mAudioEndpoint.getDataWriteCounter(); 32471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk 325204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Bump offset so caller does not see the retrograde motion in getFramesRead(). 3263316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t framesFlushed = writeCounter - readCounter; 327204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mFramesOffsetFromService += framesFlushed; 32871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk 329204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Flush written frames by forcing writeCounter to readCounter. 330204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // This is because we cannot move the read counter in the hardware. 33187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mAudioEndpoint.setDataWriteCounter(readCounter); 332204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 333204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 33471f35bb687476694882a617ba4a810a0bb56fe23Phil Burkaaudio_result_t AudioStreamInternal::requestStopInternal() 33571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk{ 33671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 33771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("AudioStreamInternal(): requestStopInternal() mServiceStreamHandle invalid = 0x%08X", 33871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk mServiceStreamHandle); 33971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk return AAUDIO_ERROR_INVALID_STATE; 34071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk } 34171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk 34271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk mClockModel.stop(AudioClock::getNanoseconds()); 34371f35bb687476694882a617ba4a810a0bb56fe23Phil Burk setState(AAUDIO_STREAM_STATE_STOPPING); 34471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk return mServiceInterface.stopStream(mServiceStreamHandle); 34571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk} 34671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk 3475ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::requestStop() 348204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 34971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal(): %s requestStop()", getLocationName()); 35071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk aaudio_result_t result = stopCallback(); 35171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk if (result != AAUDIO_OK) { 35271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk return result; 353204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 35471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk result = requestStopInternal(); 35571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD("AudioStreamInternal(): requestStop() returns %d", result); 356204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 357204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 358204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 3595ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::registerThread() { 3605ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 3615ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 362204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 363c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mServiceInterface.registerAudioThread(mServiceStreamHandle, 364c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk getpid(), 365c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk gettid(), 366c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk getPeriodNanoseconds()); 367204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 368204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 3695ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::unregisterThread() { 3705ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 3715ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 372204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 373c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, getpid(), gettid()); 374204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 375204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 3765ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId, 3773316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t *framePosition, 3783316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t *timeNanoseconds) { 3795204d315c6c6f53188f8d1414dd1b55b6c90142bPhil Burk // TODO Generate in server and pass to client. Return latest. 3803316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t time = AudioClock::getNanoseconds(); 381204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk *framePosition = mClockModel.convertTimeToPosition(time); 38287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // TODO Get a more accurate timestamp from the service. This code just adds a fudge factor. 38387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk *timeNanoseconds = time + (6 * AAUDIO_NANOS_PER_MILLISECOND); 3845ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_OK; 385204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 386204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 387e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkaaudio_result_t AudioStreamInternal::updateStateWhileWaiting() { 388e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (isDataCallbackActive()) { 389e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return AAUDIO_OK; // state is getting updated by the callback thread read/write call 390e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 391204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return processCommands(); 392204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 393204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 394204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#if LOG_TIMESTAMPS 39587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkstatic void AudioStreamInternal_logTimestamp(AAudioServiceMessage &command) { 396204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk static int64_t oldPosition = 0; 3973316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk static int64_t oldTime = 0; 398204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int64_t framePosition = command.timestamp.position; 3993316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t nanoTime = command.timestamp.timestamp; 40071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %llu", 401204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (long long) framePosition, 402204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (long long) nanoTime); 403204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int64_t nanosDelta = nanoTime - oldTime; 404204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (nanosDelta > 0 && oldTime > 0) { 405204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int64_t framesDelta = framePosition - oldPosition; 4065ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta; 40771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta); 40871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta); 40971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal() - measured rate = %llu", (unsigned long long) rate); 410204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 411204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk oldPosition = framePosition; 412204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk oldTime = nanoTime; 413204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 414204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#endif 415204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 4165ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::onTimestampFromServer(AAudioServiceMessage *message) { 417204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#if LOG_TIMESTAMPS 41887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AudioStreamInternal_logTimestamp(*message); 419204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#endif 42087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk processTimestamp(message->timestamp.position, message->timestamp.timestamp); 4215ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_OK; 422204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 423204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 4245ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *message) { 4255ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = AAUDIO_OK; 42671f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "processCommands() got event %d", message->event.event); 427204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk switch (message->event.event) { 4285ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_STARTED: 42971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_STARTED"); 43087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (getState() == AAUDIO_STREAM_STATE_STARTING) { 43187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk setState(AAUDIO_STREAM_STATE_STARTED); 43287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 433204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 4345ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_PAUSED: 43571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_PAUSED"); 43687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (getState() == AAUDIO_STREAM_STATE_PAUSING) { 43787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk setState(AAUDIO_STREAM_STATE_PAUSED); 43887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 439204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 44071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk case AAUDIO_SERVICE_EVENT_STOPPED: 44171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_STOPPED"); 44287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (getState() == AAUDIO_STREAM_STATE_STOPPING) { 44387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk setState(AAUDIO_STREAM_STATE_STOPPED); 44487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 44571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk break; 4465ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_FLUSHED: 44771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED"); 44887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (getState() == AAUDIO_STREAM_STATE_FLUSHING) { 44987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk setState(AAUDIO_STREAM_STATE_FLUSHED); 45087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk onFlushFromServer(); 45187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 452204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 4535ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_CLOSED: 45471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_CLOSED"); 4555ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_CLOSED); 456204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 4575ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_DISCONNECTED: 4585ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk result = AAUDIO_ERROR_DISCONNECTED; 459c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk setState(AAUDIO_STREAM_STATE_DISCONNECTED); 4605ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk ALOGW("WARNING - processCommands() AAUDIO_SERVICE_EVENT_DISCONNECTED"); 461204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 462c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk case AAUDIO_SERVICE_EVENT_VOLUME: 463e572f469de5dca1078a79d3d80e5b04f96ae7505Phil Burk mVolumeRamp.setTarget((float) message->event.dataDouble); 464e572f469de5dca1078a79d3d80e5b04f96ae7505Phil Burk ALOGD_IF(MYLOG_CONDITION, "processCommands() AAUDIO_SERVICE_EVENT_VOLUME %f", 465e572f469de5dca1078a79d3d80e5b04f96ae7505Phil Burk message->event.dataDouble); 466c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk break; 467204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk default: 468204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk ALOGW("WARNING - processCommands() Unrecognized event = %d", 469204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (int) message->event.event); 470204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 471204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 472204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 473204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 474204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 475204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk// Process all the commands coming from the server. 4765ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::processCommands() { 4775ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = AAUDIO_OK; 478204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 4795ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk while (result == AAUDIO_OK) { 48071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk //ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::processCommands() - looping, %d", result); 4815ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk AAudioServiceMessage message; 482204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (mAudioEndpoint.readUpCommand(&message) != 1) { 483204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; // no command this time, no problem 484204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 485204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk switch (message.what) { 4865ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAudioServiceMessage::code::TIMESTAMP: 487204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = onTimestampFromServer(&message); 488204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 489204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 4905ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAudioServiceMessage::code::EVENT: 491204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = onEventFromServer(&message); 492204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 493204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 494204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk default: 49571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGE("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d", 496204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (int) message.what); 49717fff38dd9d467bc5fb6cd5b9a6b183951c7750dPhil Burk result = AAUDIO_ERROR_INTERNAL; 498204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 499204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 500204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 501204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 502204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 503204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 50487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// Read or write the data, block if needed and timeoutMillis > 0 50587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkaaudio_result_t AudioStreamInternal::processData(void *buffer, int32_t numFrames, 50687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t timeoutNanoseconds) 507204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 5084485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk const char * traceName = (mInService) ? "aaWrtS" : "aaWrtC"; 5094485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk ATRACE_BEGIN(traceName); 5105ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = AAUDIO_OK; 511c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t loopCount = 0; 51287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk uint8_t* audioData = (uint8_t*)buffer; 5133316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t currentTimeNanos = AudioClock::getNanoseconds(); 5143316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds; 515204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int32_t framesLeft = numFrames; 516204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 5174485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk int32_t fullFrames = mAudioEndpoint.getFullFramesAvailable(); 5184485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk if (ATRACE_ENABLED()) { 5194485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk const char * traceName = (mInService) ? "aaFullS" : "aaFullC"; 5204485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk ATRACE_INT(traceName, fullFrames); 5214485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk } 5224485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk 52387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Loop until all the data has been processed or until a timeout occurs. 524204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk while (framesLeft > 0) { 52587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // The call to processDataNow() will not block. It will just read as much as it can. 5263316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t wakeTimeNanos = 0; 52787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk aaudio_result_t framesProcessed = processDataNow(audioData, framesLeft, 52887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk currentTimeNanos, &wakeTimeNanos); 52987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (framesProcessed < 0) { 53087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGE("AudioStreamInternal::processData() loop: framesProcessed = %d", framesProcessed); 53187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk result = framesProcessed; 532204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 533204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 53487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk framesLeft -= (int32_t) framesProcessed; 53587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk audioData += framesProcessed * getBytesPerFrame(); 536204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 537204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Should we block? 538204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (timeoutNanoseconds == 0) { 539204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; // don't block 540204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } else if (framesLeft > 0) { 541204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // clip the wake time to something reasonable 542204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (wakeTimeNanos < currentTimeNanos) { 543204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk wakeTimeNanos = currentTimeNanos; 544204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 545204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (wakeTimeNanos > deadlineNanos) { 546204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // If we time out, just return the framesWritten so far. 54787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGE("AudioStreamInternal::processData(): timed out after %lld nanos", 548c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk (long long) timeoutNanoseconds); 54987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGE("AudioStreamInternal::processData(): wakeTime = %lld, deadline = %lld nanos", 55087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (long long) wakeTimeNanos, (long long) deadlineNanos); 55187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGE("AudioStreamInternal::processData(): past deadline by %d micros", 55287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (int)((wakeTimeNanos - deadlineNanos) / AAUDIO_NANOS_PER_MICROSECOND)); 55387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 554204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 555204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 556204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 55771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk int64_t sleepForNanos = wakeTimeNanos - currentTimeNanos; 55887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk //ALOGE("AudioStreamInternal::processData(): sleep for %d micros", 55987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // (int)(sleepForNanos / AAUDIO_NANOS_PER_MICROSECOND)); 56071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk AudioClock::sleepForNanos(sleepForNanos); 561204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk currentTimeNanos = AudioClock::getNanoseconds(); 562204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 563204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 564204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 56587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // return error or framesProcessed 566c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk (void) loopCount; 5674485d41bcded0eceec7ec97d50aa2b0e702397a0Phil Burk ATRACE_END(); 568204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return (result < 0) ? result : numFrames - framesLeft; 569204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 570204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 5713316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkvoid AudioStreamInternal::processTimestamp(uint64_t position, int64_t time) { 57287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mClockModel.processTimestamp(position, time); 573204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 574204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 5753316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkaaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) { 5763316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int32_t actualFrames = 0; 57771f35bb687476694882a617ba4a810a0bb56fe23Phil Burk // Round to the next highest burst size. 57871f35bb687476694882a617ba4a810a0bb56fe23Phil Burk if (getFramesPerBurst() > 0) { 57971f35bb687476694882a617ba4a810a0bb56fe23Phil Burk int32_t numBursts = (requestedFrames + getFramesPerBurst() - 1) / getFramesPerBurst(); 58071f35bb687476694882a617ba4a810a0bb56fe23Phil Burk requestedFrames = numBursts * getFramesPerBurst(); 58171f35bb687476694882a617ba4a810a0bb56fe23Phil Burk } 58271f35bb687476694882a617ba4a810a0bb56fe23Phil Burk 5833316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames); 58471f35bb687476694882a617ba4a810a0bb56fe23Phil Burk ALOGD_IF(MYLOG_CONDITION, "AudioStreamInternal::setBufferSize() %s req = %d => %d", 58571f35bb687476694882a617ba4a810a0bb56fe23Phil Burk getLocationName(), requestedFrames, actualFrames); 5863316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk if (result < 0) { 5873316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk return result; 5883316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk } else { 5893316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk return (aaudio_result_t) actualFrames; 5903316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk } 591204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 592204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 59387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkint32_t AudioStreamInternal::getBufferSize() const { 594204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return mAudioEndpoint.getBufferSizeInFrames(); 595204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 596204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 59787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkint32_t AudioStreamInternal::getBufferCapacity() const { 598204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return mAudioEndpoint.getBufferCapacityInFrames(); 599204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 600204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 60187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkint32_t AudioStreamInternal::getFramesPerBurst() const { 60287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return mEndpointDescriptor.dataQueueDescriptor.framesPerBurst; 603204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 604204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 60587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkaaudio_result_t AudioStreamInternal::joinThread(void** returnArg) { 60687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst())); 6074c5129b410884ec0400cbe65fce56d0ade12d11bPhil Burk} 608