187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk/* 287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * Copyright (C) 2017 The Android Open Source Project 387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * 487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * Licensed under the Apache License, Version 2.0 (the "License"); 587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * you may not use this file except in compliance with the License. 687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * You may obtain a copy of the License at 787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * 887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * http://www.apache.org/licenses/LICENSE-2.0 987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * 1087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * Unless required by applicable law or agreed to in writing, software 1187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * distributed under the License is distributed on an "AS IS" BASIS, 1287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * See the License for the specific language governing permissions and 1487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk * limitations under the License. 1587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk */ 1687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 1787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk#define LOG_TAG "AAudio" 1887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk//#define LOG_NDEBUG 0 1987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk#include <utils/Log.h> 2087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 2187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk#include "client/AudioStreamInternalPlay.h" 2287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk#include "utility/AudioClock.h" 2387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 2487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkusing android::WrappingBuffer; 2587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 2687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkusing namespace aaudio; 2787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 2887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil BurkAudioStreamInternalPlay::AudioStreamInternalPlay(AAudioServiceInterface &serviceInterface, 2987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk bool inService) 3087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk : AudioStreamInternal(serviceInterface, inService) { 3187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 3287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk} 3387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 3487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil BurkAudioStreamInternalPlay::~AudioStreamInternalPlay() {} 3587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 3687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 3787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// Write the data, block if needed and timeoutMillis > 0 3887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkaaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames, 3987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t timeoutNanoseconds) 4087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 4187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk{ 4287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return processData((void *)buffer, numFrames, timeoutNanoseconds); 4387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk} 4487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 4587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// Write as much data as we can without blocking. 4687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkaaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t numFrames, 4787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t currentNanoTime, int64_t *wakeTimePtr) { 4887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk aaudio_result_t result = processCommands(); 4987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (result != AAUDIO_OK) { 5087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return result; 5187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 5287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 5387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (mAudioEndpoint.isFreeRunning()) { 5487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk //ALOGD("AudioStreamInternal::processDataNow() - update read counter"); 5587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Update data queue based on the timing model. 5687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime); 5787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mAudioEndpoint.setDataReadCounter(estimatedReadCounter); 5887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 5987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // TODO else query from endpoint cuz set by actual reader, maybe 6087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 6187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // If the read index passed the write index then consider it an underrun. 6287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (mAudioEndpoint.getFullFramesAvailable() < 0) { 6387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mXRunCount++; 6487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 6587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 6687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Write some data to the buffer. 6787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk //ALOGD("AudioStreamInternal::processDataNow() - writeNowWithConversion(%d)", numFrames); 6887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t framesWritten = writeNowWithConversion(buffer, numFrames); 6987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d", 7087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // numFrames, framesWritten); 7187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 7287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Calculate an ideal time to wake up. 7387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (wakeTimePtr != nullptr && framesWritten >= 0) { 7487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // By default wake up a few milliseconds from now. // TODO review 7587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND); 7687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk aaudio_stream_state_t state = getState(); 7787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk //ALOGD("AudioStreamInternal::processDataNow() - wakeTime based on %s", 7887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // AAudio_convertStreamStateToText(state)); 7987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk switch (state) { 8087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk case AAUDIO_STREAM_STATE_OPEN: 8187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk case AAUDIO_STREAM_STATE_STARTING: 8287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (framesWritten != 0) { 8387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Don't wait to write more data. Just prime the buffer. 8487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk wakeTime = currentNanoTime; 8587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 8687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk break; 8787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk case AAUDIO_STREAM_STATE_STARTED: // When do we expect the next read burst to occur? 8887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk { 8987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk uint32_t burstSize = mFramesPerBurst; 9087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (burstSize < 32) { 9187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk burstSize = 32; // TODO review 9287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 9387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 9487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk uint64_t nextReadPosition = mAudioEndpoint.getDataReadCounter() + burstSize; 9587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk wakeTime = mClockModel.convertPositionToTime(nextReadPosition); 9687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 9787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk break; 9887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk default: 9987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk break; 10087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 10187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk *wakeTimePtr = wakeTime; 10287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 10387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 10487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// ALOGD("AudioStreamInternal::processDataNow finished: now = %llu, read# = %llu, wrote# = %llu", 10587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// (unsigned long long)currentNanoTime, 10687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// (unsigned long long)mAudioEndpoint.getDataReadCounter(), 10787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// (unsigned long long)mAudioEndpoint.getDownDataWriteCounter()); 10887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return framesWritten; 10987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk} 11087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 11187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 11287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkaaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer, 11387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t numFrames) { 11487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)", 11587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // buffer, numFrames); 11687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk WrappingBuffer wrappingBuffer; 11787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk uint8_t *source = (uint8_t *) buffer; 11887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t framesLeft = numFrames; 11987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 12087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer); 12187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 12287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Read data in one or two parts. 12387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int partIndex = 0; 12487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) { 12587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t framesToWrite = framesLeft; 12687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t framesAvailable = wrappingBuffer.numFrames[partIndex]; 12787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (framesAvailable > 0) { 12887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (framesToWrite > framesAvailable) { 12987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk framesToWrite = framesAvailable; 13087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 13187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t numBytes = getBytesPerFrame() * framesToWrite; 13287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t numSamples = framesToWrite * getSamplesPerFrame(); 13387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Data conversion. 13487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk float levelFrom; 13587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk float levelTo; 13687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk bool ramping = mVolumeRamp.nextSegment(framesToWrite * getSamplesPerFrame(), 13787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk &levelFrom, &levelTo); 13887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // The formats are validated when the stream is opened so we do not have to 13987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // check for illegal combinations here. 14087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // TODO factor this out into a utility function 14187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT) { 14287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) { 14387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AAudio_linearRamp( 14487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (const float *) source, 14587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (float *) wrappingBuffer.data[partIndex], 14687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk framesToWrite, 14787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk getSamplesPerFrame(), 14887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelFrom, 14987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelTo); 15087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) { 15187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (ramping) { 15287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AAudioConvert_floatToPcm16( 15387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (const float *) source, 15487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (int16_t *) wrappingBuffer.data[partIndex], 15587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk framesToWrite, 15687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk getSamplesPerFrame(), 15787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelFrom, 15887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelTo); 15987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } else { 16087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AAudioConvert_floatToPcm16( 16187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (const float *) source, 16287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (int16_t *) wrappingBuffer.data[partIndex], 16387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk numSamples, 16487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelTo); 16587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 16687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 16787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } else if (getFormat() == AAUDIO_FORMAT_PCM_I16) { 16887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) { 16987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (ramping) { 17087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AAudioConvert_pcm16ToFloat( 17187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (const int16_t *) source, 17287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (float *) wrappingBuffer.data[partIndex], 17387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk framesToWrite, 17487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk getSamplesPerFrame(), 17587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelFrom, 17687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelTo); 17787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } else { 17887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AAudioConvert_pcm16ToFloat( 17987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (const int16_t *) source, 18087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (float *) wrappingBuffer.data[partIndex], 18187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk numSamples, 18287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelTo); 18387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 18487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) { 18587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AAudio_linearRamp( 18687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (const int16_t *) source, 18787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (int16_t *) wrappingBuffer.data[partIndex], 18887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk framesToWrite, 18987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk getSamplesPerFrame(), 19087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelFrom, 19187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk levelTo); 19287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 19387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 19487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk source += numBytes; 19587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk framesLeft -= framesToWrite; 19687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } else { 19787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk break; 19887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 19987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk partIndex++; 20087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 20187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int32_t framesWritten = numFrames - framesLeft; 20287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mAudioEndpoint.advanceWriteIndex(framesWritten); 20387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 20487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (framesWritten > 0) { 20587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk incrementFramesWritten(framesWritten); 20687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 20787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten); 20887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return framesWritten; 20987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk} 21087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 21187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 21287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkint64_t AudioStreamInternalPlay::getFramesRead() 21387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk{ 21487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t framesRead = 21587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mClockModel.convertTimeToPosition(AudioClock::getNanoseconds()) 21687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk + mFramesOffsetFromService; 21787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Prevent retrograde motion. 21887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (framesRead < mLastFramesRead) { 21987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk framesRead = mLastFramesRead; 22087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } else { 22187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mLastFramesRead = framesRead; 22287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 22387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGD("AudioStreamInternal::getFramesRead() returns %lld", (long long)framesRead); 22487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return framesRead; 22587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk} 22687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 22787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkint64_t AudioStreamInternalPlay::getFramesWritten() 22887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk{ 22987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t getFramesWritten = mAudioEndpoint.getDataWriteCounter() 23087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk + mFramesOffsetFromService; 23187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGD("AudioStreamInternal::getFramesWritten() returns %lld", (long long)getFramesWritten); 23287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return getFramesWritten; 23387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk} 23487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 23587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 23687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk// Render audio in the application callback and then write the data to the stream. 23787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burkvoid *AudioStreamInternalPlay::callbackLoop() { 23887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk aaudio_result_t result = AAUDIO_OK; 23987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE; 24087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AAudioStream_dataCallback appCallback = getDataCallbackProc(); 24187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (appCallback == nullptr) return NULL; 24287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 24387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // result might be a frame count 24487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk while (mCallbackEnabled.load() && isActive() && (result >= 0)) { 24587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Call application using the AAudio callback interface. 24687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk callbackResult = (*appCallback)( 24787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (AAudioStream *) this, 24887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk getDataCallbackUserData(), 24987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mCallbackBuffer, 25087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk mCallbackFrames); 25187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 25287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) { 25387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Write audio data to stream. 25487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames); 25587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 25687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // This is a BLOCKING WRITE! 25787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos); 25887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if ((result != mCallbackFrames)) { 25987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result); 26087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (result >= 0) { 26187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk // Only wrote some of the frames requested. Must have timed out. 26287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk result = AAUDIO_ERROR_TIMEOUT; 26387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 26487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk AAudioStream_errorCallback errorCallback = getErrorCallbackProc(); 26587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk if (errorCallback != nullptr) { 26687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (*errorCallback)( 26787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk (AAudioStream *) this, 26887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk getErrorCallbackUserData(), 26987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk result); 27087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 27187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk break; 27287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 27387c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) { 27487c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGD("AudioStreamInternalPlay(): callback returned AAUDIO_CALLBACK_RESULT_STOP"); 27587c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk break; 27687c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 27787c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk } 27887c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk 27987c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk ALOGD("AudioStreamInternalPlay(): callbackLoop() exiting, result = %d, isActive() = %d", 28087c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk result, (int) isActive()); 28187c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk return NULL; 28287c9f646a94259d7c321c3b3d5947fa1778f5ac2Phil Burk} 283