AudioStreamInternal.cpp revision c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fb
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 21c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include <stdint.h> 22204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include <assert.h> 23204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 24204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#include <binder/IServiceManager.h> 25204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 265ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk#include <aaudio/AAudio.h> 27e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk#include <utils/String16.h> 28204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 29c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "AudioClock.h" 30c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "AudioEndpointParcelable.h" 31c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "binding/AAudioStreamRequest.h" 32c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "binding/AAudioStreamConfiguration.h" 33c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "binding/IAAudioService.h" 345ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk#include "binding/AAudioServiceMessage.h" 35c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "fifo/FifoBuffer.h" 36204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 373df348fbaca567ca891503213ff8c344a1ea2e05Phil Burk#include "core/AudioStreamBuilder.h" 38c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#include "AudioStreamInternal.h" 39204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 40204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#define LOG_TIMESTAMPS 0 41204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 42204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::String16; 43204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::IServiceManager; 44204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::defaultServiceManager; 45204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkusing android::interface_cast; 46dec33abe3739b2116ef6fbac36f7ca5d26f9d190Phil Burkusing android::Mutex; 47c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkusing android::WrappingBuffer; 48204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 495ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkusing namespace aaudio; 50204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 51e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk#define MIN_TIMEOUT_NANOS (1000 * AAUDIO_NANOS_PER_MILLISECOND) 52e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 53e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk// Wait at least this many times longer than the operation should take. 54e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk#define MIN_TIMEOUT_OPERATIONS 4 55e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 56c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk#define ALOG_CONDITION (mInService == false) 57204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 58c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil BurkAudioStreamInternal::AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService) 59204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk : AudioStream() 60204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk , mClockModel() 61204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk , mAudioEndpoint() 625ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk , mServiceStreamHandle(AAUDIO_HANDLE_INVALID) 63204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk , mFramesPerBurst(16) 64c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk , mServiceInterface(serviceInterface) 65c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk , mInService(inService) 66204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 67204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 68204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 69204a163c86f357a878873fe7d4c4164f3d55c9b6Phil BurkAudioStreamInternal::~AudioStreamInternal() { 70204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 71204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 725ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::open(const AudioStreamBuilder &builder) { 73204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 745ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = AAUDIO_OK; 755ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk AAudioStreamRequest request; 765ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk AAudioStreamConfiguration configuration; 77204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 78204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = AudioStream::open(builder); 79204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (result < 0) { 80204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 81204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 82204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 83c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // We have to do volume scaling. So we prefer FLOAT format. 84c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (getFormat() == AAUDIO_UNSPECIFIED) { 85c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk setFormat(AAUDIO_FORMAT_PCM_FLOAT); 86c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 87c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 88dec33abe3739b2116ef6fbac36f7ca5d26f9d190Phil Burk // Build the request to send to the server. 89204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.setUserId(getuid()); 90204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.setProcessId(getpid()); 91c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk request.setDirection(getDirection()); 92c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 93204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.getConfiguration().setDeviceId(getDeviceId()); 94204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.getConfiguration().setSampleRate(getSampleRate()); 95204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.getConfiguration().setSamplesPerFrame(getSamplesPerFrame()); 96204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk request.getConfiguration().setAudioFormat(getFormat()); 97c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk aaudio_sharing_mode_t sharingMode = getSharingMode(); 98c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGE("AudioStreamInternal.open(): sharingMode %d", sharingMode); 99c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk request.getConfiguration().setSharingMode(sharingMode); 1003df348fbaca567ca891503213ff8c344a1ea2e05Phil Burk request.getConfiguration().setBufferCapacity(builder.getBufferCapacity()); 101204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 102c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceStreamHandle = mServiceInterface.openStream(request, configuration); 103c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.open(): openStream returned mServiceStreamHandle = 0x%08X", 104204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (unsigned int)mServiceStreamHandle); 105204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (mServiceStreamHandle < 0) { 106204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = mServiceStreamHandle; 107c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGE("AudioStreamInternal.open(): openStream() returned %d", result); 108204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } else { 109204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = configuration.validate(); 1105ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (result != AAUDIO_OK) { 111204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk close(); 112204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 113204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 114204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Save results of the open. 115204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk setSampleRate(configuration.getSampleRate()); 116204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk setSamplesPerFrame(configuration.getSamplesPerFrame()); 117c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk setDeviceId(configuration.getDeviceId()); 118204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 119c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // Save device format so we can do format conversion and volume scaling together. 120c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mDeviceFormat = configuration.getAudioFormat(); 121c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 122c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk result = mServiceInterface.getStreamDescription(mServiceStreamHandle, mEndPointParcelable); 123c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.open(): getStreamDescriptor(0x%08X) returns %d", 124c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceStreamHandle, result); 1255ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (result != AAUDIO_OK) { 126204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk ALOGE("AudioStreamInternal.open(): getStreamDescriptor returns %d", result); 127c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(mServiceStreamHandle); 128204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 129204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 130c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 131204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // resolve parcelable into a descriptor 132c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk result = mEndPointParcelable.resolve(&mEndpointDescriptor); 133c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (result != AAUDIO_OK) { 134c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGE("AudioStreamInternal.open(): resolve() returns %d", result); 135c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(mServiceStreamHandle); 136c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return result; 137c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 138204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 139204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Configure endpoint based on descriptor. 140204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mAudioEndpoint.configure(&mEndpointDescriptor); 141204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 142204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mFramesPerBurst = mEndpointDescriptor.downDataQueueDescriptor.framesPerBurst; 143204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk assert(mFramesPerBurst >= 16); 144204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk assert(mEndpointDescriptor.downDataQueueDescriptor.capacityInFrames < 10 * 1024); 145204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 146204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mClockModel.setSampleRate(getSampleRate()); 147204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mClockModel.setFramesPerBurst(mFramesPerBurst); 148204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 149e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (getDataCallbackProc()) { 150e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackFrames = builder.getFramesPerDataCallback(); 151e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (mCallbackFrames > getBufferCapacity() / 2) { 152e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk ALOGE("AudioStreamInternal.open(): framesPerCallback too large"); 153c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(mServiceStreamHandle); 154e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return AAUDIO_ERROR_OUT_OF_RANGE; 155e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 156e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } else if (mCallbackFrames < 0) { 157e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk ALOGE("AudioStreamInternal.open(): framesPerCallback negative"); 158c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(mServiceStreamHandle); 159e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return AAUDIO_ERROR_OUT_OF_RANGE; 160e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 161e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 162e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (mCallbackFrames == AAUDIO_UNSPECIFIED) { 163e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackFrames = mFramesPerBurst; 164e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 165e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 166e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int32_t bytesPerFrame = getSamplesPerFrame() 167e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk * AAudioConvert_formatToSizeInBytes(getFormat()); 168e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int32_t callbackBufferSize = mCallbackFrames * bytesPerFrame; 169e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackBuffer = new uint8_t[callbackBufferSize]; 170e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 171e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 1725ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_OPEN); 173204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 174204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 175204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 176204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 1775ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::close() { 178c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal.close(): mServiceStreamHandle = 0x%08X", mServiceStreamHandle); 1795ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) { 1805ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_handle_t serviceStreamHandle = mServiceStreamHandle; 1815ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk mServiceStreamHandle = AAUDIO_HANDLE_INVALID; 182c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 183c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mServiceInterface.closeStream(serviceStreamHandle); 184e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk delete[] mCallbackBuffer; 185c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mEndPointParcelable.close(); 186204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } else { 1875ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_HANDLE; 188204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 189204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 190204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 191c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 192e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk// Render audio in the application callback and then write the data to the stream. 193e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkvoid *AudioStreamInternal::callbackLoop() { 194e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk aaudio_result_t result = AAUDIO_OK; 195e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; 196e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int32_t framesWritten = 0; 197e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk AAudioStream_dataCallback appCallback = getDataCallbackProc(); 198e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (appCallback == nullptr) return NULL; 199e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 200e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk while (mCallbackEnabled.load() && isPlaying() && (result >= 0)) { // result might be a frame count 201e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk // Call application using the AAudio callback interface. 202e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk callbackResult = (*appCallback)( 203e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk (AAudioStream *) this, 204e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk getDataCallbackUserData(), 205e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackBuffer, 206e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackFrames); 207e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 208e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { 209e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk // Write audio data to stream 210e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); 211e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos); 212e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (result == AAUDIO_ERROR_DISCONNECTED) { 213e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (getErrorCallbackProc() != nullptr) { 214e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk ALOGD("AudioStreamAAudio(): callbackLoop() stream disconnected"); 215e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk (*getErrorCallbackProc())( 216e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk (AAudioStream *) this, 217e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk getErrorCallbackUserData(), 218e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk AAUDIO_OK); 219e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 220e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk break; 221e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } else if (result != mCallbackFrames) { 222e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk ALOGE("AudioStreamAAudio(): callbackLoop() wrote %d / %d", 223e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk framesWritten, mCallbackFrames); 224e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk break; 225e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 226e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { 227e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk ALOGD("AudioStreamAAudio(): callback returned AAUDIO_CALLBACK_RESULT_STOP"); 228e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk break; 229e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 230e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 231e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 232e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk ALOGD("AudioStreamAAudio(): callbackLoop() exiting, result = %d, isPlaying() = %d", 233e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk result, (int) isPlaying()); 234e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return NULL; // TODO review 235e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 236e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 237e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkstatic void *aaudio_callback_thread_proc(void *context) 238e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk{ 239e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk AudioStreamInternal *stream = (AudioStreamInternal *)context; 240e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk //LOGD("AudioStreamAAudio(): oboe_callback_thread, stream = %p", stream); 241e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (stream != NULL) { 242e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return stream->callbackLoop(); 243e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } else { 244e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return NULL; 245e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 246e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 247e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 2485ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::requestStart() 249204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 2503316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t startTime; 251c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): start()"); 2525ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 2535ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 254204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 255c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 2563316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk startTime = AudioClock::getNanoseconds(); 257204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mClockModel.start(startTime); 258204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk processTimestamp(0, startTime); 2595ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_STARTING); 260c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk aaudio_result_t result = mServiceInterface.startStream(mServiceStreamHandle);; 261e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 262e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (result == AAUDIO_OK && getDataCallbackProc() != nullptr) { 263e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk // Launch the callback loop thread. 264e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int64_t periodNanos = mCallbackFrames 265e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk * AAUDIO_NANOS_PER_SECOND 266e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk / getSampleRate(); 267e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackEnabled.store(true); 268e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk result = createThread(periodNanos, aaudio_callback_thread_proc, this); 269e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 270e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return result; 271204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 272204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 273e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkint64_t AudioStreamInternal::calculateReasonableTimeout(int32_t framesPerOperation) { 274e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 275e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk // Wait for at least a second or some number of callbacks to join the thread. 276e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk int64_t timeoutNanoseconds = (MIN_TIMEOUT_OPERATIONS * framesPerOperation * AAUDIO_NANOS_PER_SECOND) 277e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk / getSampleRate(); 278e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (timeoutNanoseconds < MIN_TIMEOUT_NANOS) { // arbitrary number of seconds 279e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk timeoutNanoseconds = MIN_TIMEOUT_NANOS; 280e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 281e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return timeoutNanoseconds; 282e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 283e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 284e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkaaudio_result_t AudioStreamInternal::stopCallback() 285e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk{ 286e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (isDataCallbackActive()) { 287e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk mCallbackEnabled.store(false); 288e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return joinThread(NULL, calculateReasonableTimeout(mCallbackFrames)); 289e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } else { 290e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return AAUDIO_OK; 291e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 292e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 293e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 294e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkaaudio_result_t AudioStreamInternal::requestPauseInternal() 295204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 296204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk ALOGD("AudioStreamInternal(): pause()"); 2975ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 2985ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 299204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 300c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 3013316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk mClockModel.stop(AudioClock::getNanoseconds()); 3025ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_PAUSING); 303c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mServiceInterface.startStream(mServiceStreamHandle); 304204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 305204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 306e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkaaudio_result_t AudioStreamInternal::requestPause() 307e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk{ 308e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk aaudio_result_t result = stopCallback(); 309e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (result != AAUDIO_OK) { 310e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return result; 311e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 312e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return requestPauseInternal(); 313e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk} 314e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk 3155ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::requestFlush() { 316c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): flush()"); 3175ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 3185ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 319204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 320c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 321e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk setState(AAUDIO_STREAM_STATE_FLUSHING); 322c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mServiceInterface.flushStream(mServiceStreamHandle); 323204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 324204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 325204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burkvoid AudioStreamInternal::onFlushFromServer() { 326c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): onFlushFromServer()"); 3273316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t readCounter = mAudioEndpoint.getDownDataReadCounter(); 3283316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t writeCounter = mAudioEndpoint.getDownDataWriteCounter(); 329204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Bump offset so caller does not see the retrograde motion in getFramesRead(). 3303316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t framesFlushed = writeCounter - readCounter; 331204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mFramesOffsetFromService += framesFlushed; 332204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Flush written frames by forcing writeCounter to readCounter. 333204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // This is because we cannot move the read counter in the hardware. 334204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mAudioEndpoint.setDownDataWriteCounter(readCounter); 335204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 336204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 3375ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::requestStop() 338204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 339204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // TODO better implementation of requestStop() 3405ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = requestPause(); 3415ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (result == AAUDIO_OK) { 3425ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_stream_state_t state; 3435ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk result = waitForStateChange(AAUDIO_STREAM_STATE_PAUSING, 344204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk &state, 3455ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk 500 * AAUDIO_NANOS_PER_MILLISECOND);// TODO temporary code 3465ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (result == AAUDIO_OK) { 347204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = requestFlush(); 348204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 349204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 350204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 351204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 352204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 3535ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::registerThread() { 354c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): registerThread()"); 3555ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 3565ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 357204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 358c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mServiceInterface.registerAudioThread(mServiceStreamHandle, 359c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk getpid(), 360c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk gettid(), 361c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk getPeriodNanoseconds()); 362204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 363204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 3645ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::unregisterThread() { 365c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal(): unregisterThread()"); 3665ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) { 3675ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_ERROR_INVALID_STATE; 368204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 369c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return mServiceInterface.unregisterAudioThread(mServiceStreamHandle, getpid(), gettid()); 370204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 371204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 3725ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId, 3733316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t *framePosition, 3743316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t *timeNanoseconds) { 375e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk // TODO implement using real HAL 3763316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t time = AudioClock::getNanoseconds(); 377204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk *framePosition = mClockModel.convertTimeToPosition(time); 3785ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk *timeNanoseconds = time + (10 * AAUDIO_NANOS_PER_MILLISECOND); // Fake hardware delay 3795ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_OK; 380204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 381204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 382e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burkaaudio_result_t AudioStreamInternal::updateStateWhileWaiting() { 383e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk if (isDataCallbackActive()) { 384e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk return AAUDIO_OK; // state is getting updated by the callback thread read/write call 385e4d7bb418df0fdc4c708c334ba3601f5ed8d89b3Phil Burk } 386204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return processCommands(); 387204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 388204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 389204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#if LOG_TIMESTAMPS 3905ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkstatic void AudioStreamInternal_LogTimestamp(AAudioServiceMessage &command) { 391204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk static int64_t oldPosition = 0; 3923316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk static int64_t oldTime = 0; 393204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int64_t framePosition = command.timestamp.position; 3943316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t nanoTime = command.timestamp.timestamp; 395c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() timestamp says framePosition = %08lld at nanoTime %llu", 396204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (long long) framePosition, 397204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (long long) nanoTime); 398204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int64_t nanosDelta = nanoTime - oldTime; 399204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (nanosDelta > 0 && oldTime > 0) { 400204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int64_t framesDelta = framePosition - oldPosition; 4015ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk int64_t rate = (framesDelta * AAUDIO_NANOS_PER_SECOND) / nanosDelta; 402c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - framesDelta = %08lld", (long long) framesDelta); 403c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - nanosDelta = %08lld", (long long) nanosDelta); 404c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal() - measured rate = %llu", (unsigned long long) rate); 405204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 406204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk oldPosition = framePosition; 407204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk oldTime = nanoTime; 408204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 409204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#endif 410204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 4115ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::onTimestampFromServer(AAudioServiceMessage *message) { 4123316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t framePosition = 0; 413204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#if LOG_TIMESTAMPS 414204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk AudioStreamInternal_LogTimestamp(command); 415204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk#endif 416204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk framePosition = message->timestamp.position; 417204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk processTimestamp(framePosition, message->timestamp.timestamp); 4185ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk return AAUDIO_OK; 419204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 420204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 4215ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::onEventFromServer(AAudioServiceMessage *message) { 4225ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = AAUDIO_OK; 423c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "processCommands() got event %d", message->event.event); 424204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk switch (message->event.event) { 4255ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_STARTED: 426c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_STARTED"); 4275ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_STARTED); 428204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 4295ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_PAUSED: 430c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_PAUSED"); 4315ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_PAUSED); 432204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 4335ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_FLUSHED: 434c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_FLUSHED"); 4355ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_FLUSHED); 436204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk onFlushFromServer(); 437204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 4385ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_CLOSED: 439c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "processCommands() got AAUDIO_SERVICE_EVENT_CLOSED"); 4405ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk setState(AAUDIO_STREAM_STATE_CLOSED); 441204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 4425ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_SERVICE_EVENT_DISCONNECTED: 4435ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk result = AAUDIO_ERROR_DISCONNECTED; 444c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk setState(AAUDIO_STREAM_STATE_DISCONNECTED); 4455ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk ALOGW("WARNING - processCommands() AAUDIO_SERVICE_EVENT_DISCONNECTED"); 446204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 447c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk case AAUDIO_SERVICE_EVENT_VOLUME: 448c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mVolume = message->event.dataDouble; 449c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "processCommands() AAUDIO_SERVICE_EVENT_VOLUME %f", mVolume); 450c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk break; 451204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk default: 452204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk ALOGW("WARNING - processCommands() Unrecognized event = %d", 453204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (int) message->event.event); 454204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 455204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 456204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 457204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 458204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 459204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk// Process all the commands coming from the server. 4605ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::processCommands() { 4615ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = AAUDIO_OK; 462204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 4635ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk while (result == AAUDIO_OK) { 464c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::processCommands() - looping, %d", result); 4655ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk AAudioServiceMessage message; 466204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (mAudioEndpoint.readUpCommand(&message) != 1) { 467204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; // no command this time, no problem 468204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 469204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk switch (message.what) { 4705ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAudioServiceMessage::code::TIMESTAMP: 471204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = onTimestampFromServer(&message); 472204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 473204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 4745ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAudioServiceMessage::code::EVENT: 475204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = onEventFromServer(&message); 476204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 477204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 478204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk default: 479204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk ALOGW("WARNING - AudioStreamInternal::processCommands() Unrecognized what = %d", 480204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk (int) message.what); 4815ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk result = AAUDIO_ERROR_UNEXPECTED_VALUE; 482204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 483204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 484204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 485204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 486204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 487204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 488204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk// Write the data, block if needed and timeoutMillis > 0 4895ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::write(const void *buffer, int32_t numFrames, 4903316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t timeoutNanoseconds) 491204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 4925ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = AAUDIO_OK; 493c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t loopCount = 0; 494204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk uint8_t* source = (uint8_t*)buffer; 4953316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t currentTimeNanos = AudioClock::getNanoseconds(); 4963316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t deadlineNanos = currentTimeNanos + timeoutNanoseconds; 497204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int32_t framesLeft = numFrames; 498c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write(%p, %d) at time %08llu , mState = %s", 499c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // buffer, numFrames, (unsigned long long) currentTimeNanos, 500c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // AAudio_convertStreamStateToText(getState())); 501204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 502204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Write until all the data has been written or until a timeout occurs. 503204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk while (framesLeft > 0) { 504c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() loop: framesLeft = %d, loopCount = %d =====", 505c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // framesLeft, loopCount++); 506204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // The call to writeNow() will not block. It will just write as much as it can. 5073316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t wakeTimeNanos = 0; 5085ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t framesWritten = writeNow(source, framesLeft, 509204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk currentTimeNanos, &wakeTimeNanos); 510c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() loop: framesWritten = %d", framesWritten); 511204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (framesWritten < 0) { 512c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGE("AudioStreamInternal::write() loop: writeNow returned %d", framesWritten); 513204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk result = framesWritten; 514204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 515204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 516204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk framesLeft -= (int32_t) framesWritten; 517204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk source += framesWritten * getBytesPerFrame(); 518204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 519204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Should we block? 520204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (timeoutNanoseconds == 0) { 521204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; // don't block 522204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } else if (framesLeft > 0) { 523c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal:: original wakeTimeNanos %lld", (long long) wakeTimeNanos); 524204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // clip the wake time to something reasonable 525204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (wakeTimeNanos < currentTimeNanos) { 526204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk wakeTimeNanos = currentTimeNanos; 527204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 528204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (wakeTimeNanos > deadlineNanos) { 529204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // If we time out, just return the framesWritten so far. 530c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGE("AudioStreamInternal::write(): timed out after %lld nanos", 531c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk (long long) timeoutNanoseconds); 532204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 533204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 534204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 535c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal:: sleep until %lld, dur = %lld", (long long) wakeTimeNanos, 536204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // (long long) (wakeTimeNanos - currentTimeNanos)); 537204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk AudioClock::sleepForNanos(wakeTimeNanos - currentTimeNanos); 538204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk currentTimeNanos = AudioClock::getNanoseconds(); 539204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 540204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 541204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 542204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // return error or framesWritten 543c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::write() result = %d, framesLeft = %d, #%d", 544c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // result, framesLeft, loopCount); 545c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk (void) loopCount; 546204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return (result < 0) ? result : numFrames - framesLeft; 547204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 548204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 549204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk// Write as much data as we can without blocking. 5505ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burkaaudio_result_t AudioStreamInternal::writeNow(const void *buffer, int32_t numFrames, 5513316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t currentNanoTime, int64_t *wakeTimePtr) { 552c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 553c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow(%p) - enter", buffer); 554204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk { 5555ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk aaudio_result_t result = processCommands(); 556c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - processCommands() returned %d", result); 5575ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk if (result != AAUDIO_OK) { 558204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return result; 559204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 560204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 561204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 562204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (mAudioEndpoint.isOutputFreeRunning()) { 563c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - update read counter"); 564204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Update data queue based on the timing model. 565204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime); 566204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mAudioEndpoint.setDownDataReadCounter(estimatedReadCounter); 567204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 568204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // TODO else query from endpoint cuz set by actual reader, maybe 569204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 570c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // If the read index passed the write index then consider it an underrun. 571c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (mAudioEndpoint.getFullFramesAvailable() < 0) { 572c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mXRunCount++; 573204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 574c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 575c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // Write some data to the buffer. 576c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - writeNowWithConversion(%d)", numFrames); 577c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t framesWritten = writeNowWithConversion(buffer, numFrames); 578c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - tried to write %d frames, wrote %d", 579204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // numFrames, framesWritten); 580204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 581204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Calculate an ideal time to wake up. 582204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (wakeTimePtr != nullptr && framesWritten >= 0) { 583204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // By default wake up a few milliseconds from now. // TODO review 584c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND); 585c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk aaudio_stream_state_t state = getState(); 586c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk //ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow() - wakeTime based on %s", 587c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // AAudio_convertStreamStateToText(state)); 588c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk switch (state) { 5895ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_STREAM_STATE_OPEN: 5905ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_STREAM_STATE_STARTING: 591204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (framesWritten != 0) { 592204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Don't wait to write more data. Just prime the buffer. 593204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk wakeTime = currentNanoTime; 594204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 595204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 5965ed503c7a66c90f93759c90237a9b432dbd93f9fPhil Burk case AAUDIO_STREAM_STATE_STARTED: // When do we expect the next read burst to occur? 597204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk { 598204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk uint32_t burstSize = mFramesPerBurst; 599204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (burstSize < 32) { 600204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk burstSize = 32; // TODO review 601204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 602204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 603204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk uint64_t nextReadPosition = mAudioEndpoint.getDownDataReadCounter() + burstSize; 604204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk wakeTime = mClockModel.convertPositionToTime(nextReadPosition); 605204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 606204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 607204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk default: 608204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk break; 609204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 610204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk *wakeTimePtr = wakeTime; 611204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 612204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 613c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk// ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNow finished: now = %llu, read# = %llu, wrote# = %llu", 614204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk// (unsigned long long)currentNanoTime, 615204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk// (unsigned long long)mAudioEndpoint.getDownDataReadCounter(), 616204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk// (unsigned long long)mAudioEndpoint.getDownDataWriteCounter()); 617204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return framesWritten; 618204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 619204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 620c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 621c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk// TODO this function needs a major cleanup. 622c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burkaaudio_result_t AudioStreamInternal::writeNowWithConversion(const void *buffer, 623c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t numFrames) { 624c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNowWithConversion(%p, %d)", buffer, numFrames); 625c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk WrappingBuffer wrappingBuffer; 626c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mAudioEndpoint.getEmptyRoomAvailable(&wrappingBuffer); 627c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk uint8_t *source = (uint8_t *) buffer; 628c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t framesLeft = numFrames; 629c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 630c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mAudioEndpoint.getEmptyRoomAvailable(&wrappingBuffer); 631c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 632c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // Read data in one or two parts. 633c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int partIndex = 0; 634c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 635c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t framesToWrite = framesLeft; 636c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 637c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (framesAvailable > 0) { 638c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (framesToWrite > framesAvailable) { 639c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk framesToWrite = framesAvailable; 640c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 641c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t numBytes = getBytesPerFrame(); 642c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // TODO handle volume scaling 643c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (getFormat() == mDeviceFormat) { 644c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // Copy straight through. 645c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk memcpy(wrappingBuffer.data[partIndex], source, numBytes); 646c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } else if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT 647c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk && mDeviceFormat == AAUDIO_FORMAT_PCM_I16) { 648c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // Data conversion. 649c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk AAudioConvert_floatToPcm16( 650c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk (const float *) source, 651c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk framesToWrite * getSamplesPerFrame(), 652c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk (int16_t *) wrappingBuffer.data[partIndex]); 653c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } else { 654c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // TODO handle more conversions 655c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGE("AudioStreamInternal::writeNowWithConversion() unsupported formats: %d, %d", 656c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk getFormat(), mDeviceFormat); 657c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return AAUDIO_ERROR_UNEXPECTED_VALUE; 658c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 659c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 660c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk source += numBytes; 661c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk framesLeft -= framesToWrite; 662c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 663c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk partIndex++; 664c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 665c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk int32_t framesWritten = numFrames - framesLeft; 666c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk mAudioEndpoint.advanceWriteIndex(framesWritten); 667c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 668c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk if (framesWritten > 0) { 669c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk incrementFramesWritten(framesWritten); 670c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk } 671c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk // ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten); 672c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk return framesWritten; 673c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk} 674c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk 6753316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkvoid AudioStreamInternal::processTimestamp(uint64_t position, int64_t time) { 676204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mClockModel.processTimestamp( position, time); 677204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 678204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 6793316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkaaudio_result_t AudioStreamInternal::setBufferSize(int32_t requestedFrames) { 6803316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int32_t actualFrames = 0; 6813316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk aaudio_result_t result = mAudioEndpoint.setBufferSizeInFrames(requestedFrames, &actualFrames); 6823316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk if (result < 0) { 6833316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk return result; 6843316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk } else { 6853316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk return (aaudio_result_t) actualFrames; 6863316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk } 687204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 688204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 6893316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkint32_t AudioStreamInternal::getBufferSize() const 690204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 691204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return mAudioEndpoint.getBufferSizeInFrames(); 692204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 693204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 6943316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkint32_t AudioStreamInternal::getBufferCapacity() const 695204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 696204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return mAudioEndpoint.getBufferCapacityInFrames(); 697204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 698204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 6993316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkint32_t AudioStreamInternal::getFramesPerBurst() const 700204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 701204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return mEndpointDescriptor.downDataQueueDescriptor.framesPerBurst; 702204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 703204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 7043316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burkint64_t AudioStreamInternal::getFramesRead() 705204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk{ 7063316d5e6d375a4f09c681205e9094d30a0bfc4a2Phil Burk int64_t framesRead = 707204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()) 708204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk + mFramesOffsetFromService; 709204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk // Prevent retrograde motion. 710204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk if (framesRead < mLastFramesRead) { 711204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk framesRead = mLastFramesRead; 712204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } else { 713204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk mLastFramesRead = framesRead; 714204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk } 715c0c70e3c7dd10bc2c0caffcab1f3f5fb406b35fbPhil Burk ALOGD_IF(ALOG_CONDITION, "AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead); 716204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk return framesRead; 717204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk} 718204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk 719204a163c86f357a878873fe7d4c4164f3d55c9b6Phil Burk// TODO implement getTimestamp 720