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 (mInService ? "AAudioService" : "AAudio")
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #define ATRACE_TAG ATRACE_TAG_AUDIO
22
23 #include <utils/Trace.h>
24
25 #include "client/AudioStreamInternalPlay.h"
26 #include "utility/AudioClock.h"
27
28 using android::WrappingBuffer;
29
30 using namespace aaudio;
31
AudioStreamInternalPlay(AAudioServiceInterface & serviceInterface,bool inService)32 AudioStreamInternalPlay::AudioStreamInternalPlay(AAudioServiceInterface &serviceInterface,
33 bool inService)
34 : AudioStreamInternal(serviceInterface, inService) {
35
36 }
37
~AudioStreamInternalPlay()38 AudioStreamInternalPlay::~AudioStreamInternalPlay() {}
39
40
requestPauseInternal()41 aaudio_result_t AudioStreamInternalPlay::requestPauseInternal()
42 {
43 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
44 ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
45 mServiceStreamHandle);
46 return AAUDIO_ERROR_INVALID_STATE;
47 }
48
49 mClockModel.stop(AudioClock::getNanoseconds());
50 setState(AAUDIO_STREAM_STATE_PAUSING);
51 mAtomicTimestamp.clear();
52 return mServiceInterface.pauseStream(mServiceStreamHandle);
53 }
54
requestPause()55 aaudio_result_t AudioStreamInternalPlay::requestPause()
56 {
57 aaudio_result_t result = stopCallback();
58 if (result != AAUDIO_OK) {
59 return result;
60 }
61 result = requestPauseInternal();
62 return result;
63 }
64
requestFlush()65 aaudio_result_t AudioStreamInternalPlay::requestFlush() {
66 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
67 ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
68 mServiceStreamHandle);
69 return AAUDIO_ERROR_INVALID_STATE;
70 }
71
72 setState(AAUDIO_STREAM_STATE_FLUSHING);
73 return mServiceInterface.flushStream(mServiceStreamHandle);
74 }
75
advanceClientToMatchServerPosition()76 void AudioStreamInternalPlay::advanceClientToMatchServerPosition() {
77 int64_t readCounter = mAudioEndpoint.getDataReadCounter();
78 int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
79
80 // Bump offset so caller does not see the retrograde motion in getFramesRead().
81 int64_t offset = writeCounter - readCounter;
82 mFramesOffsetFromService += offset;
83 ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
84 (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
85
86 // Force writeCounter to match readCounter.
87 // This is because we cannot change the read counter in the hardware.
88 mAudioEndpoint.setDataWriteCounter(readCounter);
89 }
90
onFlushFromServer()91 void AudioStreamInternalPlay::onFlushFromServer() {
92 advanceClientToMatchServerPosition();
93 }
94
95 // Write the data, block if needed and timeoutMillis > 0
write(const void * buffer,int32_t numFrames,int64_t timeoutNanoseconds)96 aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
97 int64_t timeoutNanoseconds)
98
99 {
100 return processData((void *)buffer, numFrames, timeoutNanoseconds);
101 }
102
103 // Write as much data as we can without blocking.
processDataNow(void * buffer,int32_t numFrames,int64_t currentNanoTime,int64_t * wakeTimePtr)104 aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t numFrames,
105 int64_t currentNanoTime, int64_t *wakeTimePtr) {
106 aaudio_result_t result = processCommands();
107 if (result != AAUDIO_OK) {
108 return result;
109 }
110
111 const char *traceName = "aaWrNow";
112 ATRACE_BEGIN(traceName);
113
114 if (mClockModel.isStarting()) {
115 // Still haven't got any timestamps from server.
116 // Keep waiting until we get some valid timestamps then start writing to the
117 // current buffer position.
118 ALOGD("processDataNow() wait for valid timestamps");
119 // Sleep very briefly and hope we get a timestamp soon.
120 *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
121 ATRACE_END();
122 return 0;
123 }
124 // If we have gotten this far then we have at least one timestamp from server.
125
126 // If a DMA channel or DSP is reading the other end then we have to update the readCounter.
127 if (mAudioEndpoint.isFreeRunning()) {
128 // Update data queue based on the timing model.
129 int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
130 // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter);
131 mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
132 }
133
134 if (mNeedCatchUp.isRequested()) {
135 // Catch an MMAP pointer that is already advancing.
136 // This will avoid initial underruns caused by a slow cold start.
137 advanceClientToMatchServerPosition();
138 mNeedCatchUp.acknowledge();
139 }
140
141 // If the read index passed the write index then consider it an underrun.
142 if (mAudioEndpoint.getFullFramesAvailable() < 0) {
143 mXRunCount++;
144 if (ATRACE_ENABLED()) {
145 ATRACE_INT("aaUnderRuns", mXRunCount);
146 }
147 }
148
149 // Write some data to the buffer.
150 //ALOGD("AudioStreamInternal::processDataNow() - writeNowWithConversion(%d)", numFrames);
151 int32_t framesWritten = writeNowWithConversion(buffer, numFrames);
152 //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d",
153 // numFrames, framesWritten);
154 if (ATRACE_ENABLED()) {
155 ATRACE_INT("aaWrote", framesWritten);
156 }
157
158 // Calculate an ideal time to wake up.
159 if (wakeTimePtr != nullptr && framesWritten >= 0) {
160 // By default wake up a few milliseconds from now. // TODO review
161 int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
162 aaudio_stream_state_t state = getState();
163 //ALOGD("AudioStreamInternal::processDataNow() - wakeTime based on %s",
164 // AAudio_convertStreamStateToText(state));
165 switch (state) {
166 case AAUDIO_STREAM_STATE_OPEN:
167 case AAUDIO_STREAM_STATE_STARTING:
168 if (framesWritten != 0) {
169 // Don't wait to write more data. Just prime the buffer.
170 wakeTime = currentNanoTime;
171 }
172 break;
173 case AAUDIO_STREAM_STATE_STARTED:
174 {
175 // When do we expect the next read burst to occur?
176
177 // Calculate frame position based off of the writeCounter because
178 // the readCounter might have just advanced in the background,
179 // causing us to sleep until a later burst.
180 int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
181 - mAudioEndpoint.getBufferSizeInFrames();
182 wakeTime = mClockModel.convertPositionToTime(nextPosition);
183 }
184 break;
185 default:
186 break;
187 }
188 *wakeTimePtr = wakeTime;
189
190 }
191
192 ATRACE_END();
193 return framesWritten;
194 }
195
196
writeNowWithConversion(const void * buffer,int32_t numFrames)197 aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer,
198 int32_t numFrames) {
199 // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)",
200 // buffer, numFrames);
201 WrappingBuffer wrappingBuffer;
202 uint8_t *source = (uint8_t *) buffer;
203 int32_t framesLeft = numFrames;
204
205 mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer);
206
207 // Write data in one or two parts.
208 int partIndex = 0;
209 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
210 int32_t framesToWrite = framesLeft;
211 int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
212 if (framesAvailable > 0) {
213 if (framesToWrite > framesAvailable) {
214 framesToWrite = framesAvailable;
215 }
216 int32_t numBytes = getBytesPerFrame() * framesToWrite;
217 int32_t numSamples = framesToWrite * getSamplesPerFrame();
218 // Data conversion.
219 float levelFrom;
220 float levelTo;
221 bool ramping = mVolumeRamp.nextSegment(framesToWrite * getSamplesPerFrame(),
222 &levelFrom, &levelTo);
223 // The formats are validated when the stream is opened so we do not have to
224 // check for illegal combinations here.
225 // TODO factor this out into a utility function
226 if (getFormat() == AAUDIO_FORMAT_PCM_FLOAT) {
227 if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) {
228 AAudio_linearRamp(
229 (const float *) source,
230 (float *) wrappingBuffer.data[partIndex],
231 framesToWrite,
232 getSamplesPerFrame(),
233 levelFrom,
234 levelTo);
235 } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) {
236 if (ramping) {
237 AAudioConvert_floatToPcm16(
238 (const float *) source,
239 (int16_t *) wrappingBuffer.data[partIndex],
240 framesToWrite,
241 getSamplesPerFrame(),
242 levelFrom,
243 levelTo);
244 } else {
245 AAudioConvert_floatToPcm16(
246 (const float *) source,
247 (int16_t *) wrappingBuffer.data[partIndex],
248 numSamples,
249 levelTo);
250 }
251 }
252 } else if (getFormat() == AAUDIO_FORMAT_PCM_I16) {
253 if (mDeviceFormat == AAUDIO_FORMAT_PCM_FLOAT) {
254 if (ramping) {
255 AAudioConvert_pcm16ToFloat(
256 (const int16_t *) source,
257 (float *) wrappingBuffer.data[partIndex],
258 framesToWrite,
259 getSamplesPerFrame(),
260 levelFrom,
261 levelTo);
262 } else {
263 AAudioConvert_pcm16ToFloat(
264 (const int16_t *) source,
265 (float *) wrappingBuffer.data[partIndex],
266 numSamples,
267 levelTo);
268 }
269 } else if (mDeviceFormat == AAUDIO_FORMAT_PCM_I16) {
270 AAudio_linearRamp(
271 (const int16_t *) source,
272 (int16_t *) wrappingBuffer.data[partIndex],
273 framesToWrite,
274 getSamplesPerFrame(),
275 levelFrom,
276 levelTo);
277 }
278 }
279 source += numBytes;
280 framesLeft -= framesToWrite;
281 } else {
282 break;
283 }
284 partIndex++;
285 }
286 int32_t framesWritten = numFrames - framesLeft;
287 mAudioEndpoint.advanceWriteIndex(framesWritten);
288
289 // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
290 return framesWritten;
291 }
292
getFramesRead()293 int64_t AudioStreamInternalPlay::getFramesRead()
294 {
295 int64_t framesReadHardware;
296 if (isActive()) {
297 framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
298 } else {
299 framesReadHardware = mAudioEndpoint.getDataReadCounter();
300 }
301 int64_t framesRead = framesReadHardware + mFramesOffsetFromService;
302 // Prevent retrograde motion.
303 if (framesRead < mLastFramesRead) {
304 framesRead = mLastFramesRead;
305 } else {
306 mLastFramesRead = framesRead;
307 }
308 //ALOGD("AudioStreamInternalPlay::getFramesRead() returns %lld", (long long)framesRead);
309 return framesRead;
310 }
311
getFramesWritten()312 int64_t AudioStreamInternalPlay::getFramesWritten()
313 {
314 int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
315 + mFramesOffsetFromService;
316 //ALOGD("AudioStreamInternalPlay::getFramesWritten() returns %lld", (long long)framesWritten);
317 return framesWritten;
318 }
319
320
321 // Render audio in the application callback and then write the data to the stream.
callbackLoop()322 void *AudioStreamInternalPlay::callbackLoop() {
323 aaudio_result_t result = AAUDIO_OK;
324 aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
325 AAudioStream_dataCallback appCallback = getDataCallbackProc();
326 if (appCallback == nullptr) return NULL;
327 int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
328
329 // result might be a frame count
330 while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
331 // Call application using the AAudio callback interface.
332 callbackResult = (*appCallback)(
333 (AAudioStream *) this,
334 getDataCallbackUserData(),
335 mCallbackBuffer,
336 mCallbackFrames);
337
338 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
339 // Write audio data to stream. This is a BLOCKING WRITE!
340 result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos);
341 if ((result != mCallbackFrames)) {
342 ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result);
343 if (result >= 0) {
344 // Only wrote some of the frames requested. Must have timed out.
345 result = AAUDIO_ERROR_TIMEOUT;
346 }
347 AAudioStream_errorCallback errorCallback = getErrorCallbackProc();
348 if (errorCallback != nullptr) {
349 (*errorCallback)(
350 (AAudioStream *) this,
351 getErrorCallbackUserData(),
352 result);
353 }
354 break;
355 }
356 } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
357 ALOGD("AudioStreamInternalPlay(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
358 break;
359 }
360 }
361
362 ALOGD("AudioStreamInternalPlay(): callbackLoop() exiting, result = %d, isActive() = %d",
363 result, (int) isActive());
364 return NULL;
365 }
366
367 //------------------------------------------------------------------------------
368 // Implementation of PlayerBase
doSetVolume()369 status_t AudioStreamInternalPlay::doSetVolume() {
370 mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
371 return android::NO_ERROR;
372 }
373