1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "AAudio"
18//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include <aaudio/AAudio.h>
22
23#include "client/AudioStreamInternalCapture.h"
24#include "utility/AudioClock.h"
25
26using android::WrappingBuffer;
27
28using namespace aaudio;
29
30AudioStreamInternalCapture::AudioStreamInternalCapture(AAudioServiceInterface  &serviceInterface,
31                                                 bool inService)
32    : AudioStreamInternal(serviceInterface, inService) {
33
34}
35
36AudioStreamInternalCapture::~AudioStreamInternalCapture() {}
37
38
39// Write the data, block if needed and timeoutMillis > 0
40aaudio_result_t AudioStreamInternalCapture::read(void *buffer, int32_t numFrames,
41                                               int64_t timeoutNanoseconds)
42{
43    return processData(buffer, numFrames, timeoutNanoseconds);
44}
45
46// Read as much data as we can without blocking.
47aaudio_result_t AudioStreamInternalCapture::processDataNow(void *buffer, int32_t numFrames,
48                                                  int64_t currentNanoTime, int64_t *wakeTimePtr) {
49    aaudio_result_t result = processCommands();
50    if (result != AAUDIO_OK) {
51        return result;
52    }
53
54    if (mAudioEndpoint.isFreeRunning()) {
55        //ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
56        // Update data queue based on the timing model.
57        int64_t estimatedRemoteCounter = mClockModel.convertTimeToPosition(currentNanoTime);
58        // TODO refactor, maybe use setRemoteCounter()
59        mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
60    }
61
62    // If the write index passed the read index then consider it an overrun.
63    if (mAudioEndpoint.getEmptyFramesAvailable() < 0) {
64        mXRunCount++;
65    }
66
67    // Read some data from the buffer.
68    //ALOGD("AudioStreamInternalCapture::processDataNow() - readNowWithConversion(%d)", numFrames);
69    int32_t framesProcessed = readNowWithConversion(buffer, numFrames);
70    //ALOGD("AudioStreamInternalCapture::processDataNow() - tried to read %d frames, read %d",
71    //    numFrames, framesProcessed);
72
73    // Calculate an ideal time to wake up.
74    if (wakeTimePtr != nullptr && framesProcessed >= 0) {
75        // By default wake up a few milliseconds from now.  // TODO review
76        int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
77        aaudio_stream_state_t state = getState();
78        //ALOGD("AudioStreamInternalCapture::processDataNow() - wakeTime based on %s",
79        //      AAudio_convertStreamStateToText(state));
80        switch (state) {
81            case AAUDIO_STREAM_STATE_OPEN:
82            case AAUDIO_STREAM_STATE_STARTING:
83                break;
84            case AAUDIO_STREAM_STATE_STARTED:   // When do we expect the next read burst to occur?
85            {
86                uint32_t burstSize = mFramesPerBurst;
87                if (burstSize < 32) {
88                    burstSize = 32; // TODO review
89                }
90
91                uint64_t nextReadPosition = mAudioEndpoint.getDataWriteCounter() + burstSize;
92                wakeTime = mClockModel.convertPositionToTime(nextReadPosition);
93            }
94                break;
95            default:
96                break;
97        }
98        *wakeTimePtr = wakeTime;
99
100    }
101//    ALOGD("AudioStreamInternalCapture::readNow finished: now = %llu, read# = %llu, wrote# = %llu",
102//         (unsigned long long)currentNanoTime,
103//         (unsigned long long)mAudioEndpoint.getDataReadCounter(),
104//         (unsigned long long)mAudioEndpoint.getDownDataWriteCounter());
105    return framesProcessed;
106}
107
108aaudio_result_t AudioStreamInternalCapture::readNowWithConversion(void *buffer,
109                                                                int32_t numFrames) {
110    // ALOGD("AudioStreamInternalCapture::readNowWithConversion(%p, %d)",
111    //              buffer, numFrames);
112    WrappingBuffer wrappingBuffer;
113    uint8_t *destination = (uint8_t *) buffer;
114    int32_t framesLeft = numFrames;
115
116    mAudioEndpoint.getFullFramesAvailable(&wrappingBuffer);
117
118    // Read data in one or two parts.
119    for (int partIndex = 0; framesLeft > 0 && partIndex < WrappingBuffer::SIZE; partIndex++) {
120        int32_t framesToProcess = framesLeft;
121        int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
122        if (framesAvailable <= 0) break;
123
124        if (framesToProcess > framesAvailable) {
125            framesToProcess = framesAvailable;
126        }
127
128        int32_t numBytes = getBytesPerFrame() * framesToProcess;
129        int32_t numSamples = framesToProcess * getSamplesPerFrame();
130
131        // TODO factor this out into a utility function
132        if (mDeviceFormat == getFormat()) {
133            memcpy(destination, wrappingBuffer.data[partIndex], numBytes);
134        } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16
135                   && getFormat() == AAUDIO_FORMAT_PCM_FLOAT) {
136            AAudioConvert_pcm16ToFloat(
137                    (const int16_t *) wrappingBuffer.data[partIndex],
138                    (float *) destination,
139                    numSamples,
140                    1.0f);
141        } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT
142                   && getFormat() == AAUDIO_FORMAT_PCM_I16) {
143            AAudioConvert_floatToPcm16(
144                    (const float *) wrappingBuffer.data[partIndex],
145                    (int16_t *) destination,
146                    numSamples,
147                    1.0f);
148        } else {
149            ALOGE("Format conversion not supported!");
150            return AAUDIO_ERROR_INVALID_FORMAT;
151        }
152        destination += numBytes;
153        framesLeft -= framesToProcess;
154    }
155
156    int32_t framesProcessed = numFrames - framesLeft;
157    mAudioEndpoint.advanceReadIndex(framesProcessed);
158    incrementFramesRead(framesProcessed);
159
160    //ALOGD("AudioStreamInternalCapture::readNowWithConversion() returns %d", framesProcessed);
161    return framesProcessed;
162}
163
164int64_t AudioStreamInternalCapture::getFramesWritten()
165{
166    int64_t frames =
167            mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
168            + mFramesOffsetFromService;
169    // Prevent retrograde motion.
170    if (frames < mLastFramesWritten) {
171        frames = mLastFramesWritten;
172    } else {
173        mLastFramesWritten = frames;
174    }
175    //ALOGD("AudioStreamInternalCapture::getFramesWritten() returns %lld", (long long)frames);
176    return frames;
177}
178
179int64_t AudioStreamInternalCapture::getFramesRead()
180{
181    int64_t frames = mAudioEndpoint.getDataWriteCounter()
182                               + mFramesOffsetFromService;
183    //ALOGD("AudioStreamInternalCapture::getFramesRead() returns %lld", (long long)frames);
184    return frames;
185}
186
187// Read data from the stream and pass it to the callback for processing.
188void *AudioStreamInternalCapture::callbackLoop() {
189    aaudio_result_t result = AAUDIO_OK;
190    aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
191    AAudioStream_dataCallback appCallback = getDataCallbackProc();
192    if (appCallback == nullptr) return NULL;
193
194    // result might be a frame count
195    while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
196
197        // Read audio data from stream.
198        int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
199
200        // This is a BLOCKING READ!
201        result = read(mCallbackBuffer, mCallbackFrames, timeoutNanos);
202        if ((result != mCallbackFrames)) {
203            ALOGE("AudioStreamInternalCapture(): callbackLoop: read() returned %d", result);
204            if (result >= 0) {
205                // Only read some of the frames requested. Must have timed out.
206                result = AAUDIO_ERROR_TIMEOUT;
207            }
208            AAudioStream_errorCallback errorCallback = getErrorCallbackProc();
209            if (errorCallback != nullptr) {
210                (*errorCallback)(
211                        (AAudioStream *) this,
212                        getErrorCallbackUserData(),
213                        result);
214            }
215            break;
216        }
217
218        // Call application using the AAudio callback interface.
219        callbackResult = (*appCallback)(
220                (AAudioStream *) this,
221                getDataCallbackUserData(),
222                mCallbackBuffer,
223                mCallbackFrames);
224
225        if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
226            ALOGD("AudioStreamInternalCapture(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
227            break;
228        }
229    }
230
231    ALOGD("AudioStreamInternalCapture(): callbackLoop() exiting, result = %d, isActive() = %d",
232          result, (int) isActive());
233    return NULL;
234}
235