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