blob: 93693bdd00a09d8df67c7c4fff614d60b85819c7 [file] [log] [blame]
Phil Burk87c9f642017-05-17 07:22:39 -07001/*
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}