blob: 7695dfa084762ed3acb6d55c600197cc7d752b75 [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
Phil Burkfbf031e2017-10-12 15:58:31 -070017#define LOG_TAG (mInService ? "AudioStreamInternalPlay_Service" \
18 : "AudioStreamInternalPlay_Client")
Phil Burk87c9f642017-05-17 07:22:39 -070019//#define LOG_NDEBUG 0
20#include <utils/Log.h>
21
Phil Burkfd34a932017-07-19 07:03:52 -070022#define ATRACE_TAG ATRACE_TAG_AUDIO
23
24#include <utils/Trace.h>
25
Phil Burk87c9f642017-05-17 07:22:39 -070026#include "client/AudioStreamInternalPlay.h"
27#include "utility/AudioClock.h"
28
29using android::WrappingBuffer;
30
31using namespace aaudio;
32
33AudioStreamInternalPlay::AudioStreamInternalPlay(AAudioServiceInterface &serviceInterface,
34 bool inService)
35 : AudioStreamInternal(serviceInterface, inService) {
36
37}
38
39AudioStreamInternalPlay::~AudioStreamInternalPlay() {}
40
Phil Burk5cc83c32017-11-28 15:43:18 -080041aaudio_result_t AudioStreamInternalPlay::requestPause()
Phil Burkb336e892017-07-05 15:35:43 -070042{
Phil Burk5cc83c32017-11-28 15:43:18 -080043 aaudio_result_t result = stopCallback();
44 if (result != AAUDIO_OK) {
45 return result;
46 }
Phil Burkb336e892017-07-05 15:35:43 -070047 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
48 ALOGE("AudioStreamInternal::requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
49 mServiceStreamHandle);
50 return AAUDIO_ERROR_INVALID_STATE;
51 }
52
53 mClockModel.stop(AudioClock::getNanoseconds());
54 setState(AAUDIO_STREAM_STATE_PAUSING);
Phil Burkbcc36742017-08-31 17:24:51 -070055 mAtomicTimestamp.clear();
Phil Burk965650e2017-09-07 21:00:09 -070056 return mServiceInterface.pauseStream(mServiceStreamHandle);
Phil Burkb336e892017-07-05 15:35:43 -070057}
58
Phil Burkb336e892017-07-05 15:35:43 -070059aaudio_result_t AudioStreamInternalPlay::requestFlush() {
60 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
61 ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
62 mServiceStreamHandle);
63 return AAUDIO_ERROR_INVALID_STATE;
64 }
65
66 setState(AAUDIO_STREAM_STATE_FLUSHING);
67 return mServiceInterface.flushStream(mServiceStreamHandle);
68}
69
Phil Burkbcc36742017-08-31 17:24:51 -070070void AudioStreamInternalPlay::advanceClientToMatchServerPosition() {
Phil Burkb336e892017-07-05 15:35:43 -070071 int64_t readCounter = mAudioEndpoint.getDataReadCounter();
72 int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
73
74 // Bump offset so caller does not see the retrograde motion in getFramesRead().
Phil Burkbcc36742017-08-31 17:24:51 -070075 int64_t offset = writeCounter - readCounter;
76 mFramesOffsetFromService += offset;
77 ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
Phil Burkb336e892017-07-05 15:35:43 -070078 (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
79
Phil Burkbcc36742017-08-31 17:24:51 -070080 // Force writeCounter to match readCounter.
81 // This is because we cannot change the read counter in the hardware.
Phil Burkb336e892017-07-05 15:35:43 -070082 mAudioEndpoint.setDataWriteCounter(readCounter);
83}
84
Phil Burkbcc36742017-08-31 17:24:51 -070085void AudioStreamInternalPlay::onFlushFromServer() {
86 advanceClientToMatchServerPosition();
87}
88
Phil Burk87c9f642017-05-17 07:22:39 -070089// Write the data, block if needed and timeoutMillis > 0
90aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
91 int64_t timeoutNanoseconds)
92
93{
94 return processData((void *)buffer, numFrames, timeoutNanoseconds);
95}
96
97// Write as much data as we can without blocking.
98aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t numFrames,
99 int64_t currentNanoTime, int64_t *wakeTimePtr) {
100 aaudio_result_t result = processCommands();
101 if (result != AAUDIO_OK) {
102 return result;
103 }
104
Phil Burkfd34a932017-07-19 07:03:52 -0700105 const char *traceName = "aaWrNow";
106 ATRACE_BEGIN(traceName);
107
Phil Burkbcc36742017-08-31 17:24:51 -0700108 if (mClockModel.isStarting()) {
109 // Still haven't got any timestamps from server.
110 // Keep waiting until we get some valid timestamps then start writing to the
111 // current buffer position.
112 ALOGD("processDataNow() wait for valid timestamps");
113 // Sleep very briefly and hope we get a timestamp soon.
114 *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
115 ATRACE_END();
116 return 0;
117 }
118 // If we have gotten this far then we have at least one timestamp from server.
119
Phil Burkfd34a932017-07-19 07:03:52 -0700120 // If a DMA channel or DSP is reading the other end then we have to update the readCounter.
Phil Burk87c9f642017-05-17 07:22:39 -0700121 if (mAudioEndpoint.isFreeRunning()) {
Phil Burk87c9f642017-05-17 07:22:39 -0700122 // Update data queue based on the timing model.
123 int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
Phil Burkec89b2e2017-06-20 15:05:06 -0700124 // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter);
Phil Burk87c9f642017-05-17 07:22:39 -0700125 mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
126 }
Phil Burk87c9f642017-05-17 07:22:39 -0700127
Phil Burkbcc36742017-08-31 17:24:51 -0700128 if (mNeedCatchUp.isRequested()) {
129 // Catch an MMAP pointer that is already advancing.
130 // This will avoid initial underruns caused by a slow cold start.
131 advanceClientToMatchServerPosition();
132 mNeedCatchUp.acknowledge();
133 }
134
Phil Burk87c9f642017-05-17 07:22:39 -0700135 // If the read index passed the write index then consider it an underrun.
Phil Burk23296382017-11-20 15:45:11 -0800136 // For shared streams, the xRunCount is passed up from the service.
137 if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getFullFramesAvailable() < 0) {
Phil Burk87c9f642017-05-17 07:22:39 -0700138 mXRunCount++;
Phil Burkfd34a932017-07-19 07:03:52 -0700139 if (ATRACE_ENABLED()) {
140 ATRACE_INT("aaUnderRuns", mXRunCount);
141 }
Phil Burk87c9f642017-05-17 07:22:39 -0700142 }
143
144 // Write some data to the buffer.
145 //ALOGD("AudioStreamInternal::processDataNow() - writeNowWithConversion(%d)", numFrames);
146 int32_t framesWritten = writeNowWithConversion(buffer, numFrames);
147 //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d",
148 // numFrames, framesWritten);
Phil Burkfd34a932017-07-19 07:03:52 -0700149 if (ATRACE_ENABLED()) {
150 ATRACE_INT("aaWrote", framesWritten);
151 }
Phil Burk87c9f642017-05-17 07:22:39 -0700152
153 // Calculate an ideal time to wake up.
154 if (wakeTimePtr != nullptr && framesWritten >= 0) {
155 // By default wake up a few milliseconds from now. // TODO review
156 int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
157 aaudio_stream_state_t state = getState();
158 //ALOGD("AudioStreamInternal::processDataNow() - wakeTime based on %s",
159 // AAudio_convertStreamStateToText(state));
160 switch (state) {
161 case AAUDIO_STREAM_STATE_OPEN:
162 case AAUDIO_STREAM_STATE_STARTING:
163 if (framesWritten != 0) {
164 // Don't wait to write more data. Just prime the buffer.
165 wakeTime = currentNanoTime;
166 }
167 break;
Phil Burkfd34a932017-07-19 07:03:52 -0700168 case AAUDIO_STREAM_STATE_STARTED:
Phil Burk87c9f642017-05-17 07:22:39 -0700169 {
Phil Burkfd34a932017-07-19 07:03:52 -0700170 // When do we expect the next read burst to occur?
Phil Burk87c9f642017-05-17 07:22:39 -0700171
Phil Burkfd34a932017-07-19 07:03:52 -0700172 // Calculate frame position based off of the writeCounter because
173 // the readCounter might have just advanced in the background,
174 // causing us to sleep until a later burst.
Phil Burkbcc36742017-08-31 17:24:51 -0700175 int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
Phil Burkfd34a932017-07-19 07:03:52 -0700176 - mAudioEndpoint.getBufferSizeInFrames();
Phil Burkbcc36742017-08-31 17:24:51 -0700177 wakeTime = mClockModel.convertPositionToTime(nextPosition);
Phil Burk87c9f642017-05-17 07:22:39 -0700178 }
179 break;
180 default:
181 break;
182 }
183 *wakeTimePtr = wakeTime;
184
185 }
Phil Burkfd34a932017-07-19 07:03:52 -0700186
187 ATRACE_END();
Phil Burk87c9f642017-05-17 07:22:39 -0700188 return framesWritten;
189}
190
191
192aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer,
193 int32_t numFrames) {
194 // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)",
195 // buffer, numFrames);
196 WrappingBuffer wrappingBuffer;
Phil Burk41f19d82018-02-13 14:59:10 -0800197 uint8_t *byteBuffer = (uint8_t *) buffer;
Phil Burk87c9f642017-05-17 07:22:39 -0700198 int32_t framesLeft = numFrames;
199
200 mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer);
201
Phil Burkfd34a932017-07-19 07:03:52 -0700202 // Write data in one or two parts.
Phil Burk87c9f642017-05-17 07:22:39 -0700203 int partIndex = 0;
204 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
205 int32_t framesToWrite = framesLeft;
206 int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
207 if (framesAvailable > 0) {
208 if (framesToWrite > framesAvailable) {
209 framesToWrite = framesAvailable;
210 }
Phil Burk41f19d82018-02-13 14:59:10 -0800211
Phil Burk87c9f642017-05-17 07:22:39 -0700212 int32_t numBytes = getBytesPerFrame() * framesToWrite;
Phil Burk87c9f642017-05-17 07:22:39 -0700213 // Data conversion.
214 float levelFrom;
215 float levelTo;
Phil Burk41f19d82018-02-13 14:59:10 -0800216 mVolumeRamp.nextSegment(framesToWrite, &levelFrom, &levelTo);
217
218 AAudioDataConverter::FormattedData source(
219 (void *)byteBuffer,
220 getFormat(),
221 getSamplesPerFrame());
222 AAudioDataConverter::FormattedData destination(
223 wrappingBuffer.data[partIndex],
224 getDeviceFormat(),
225 getDeviceChannelCount());
226
227 AAudioDataConverter::convert(source, destination, framesToWrite,
228 levelFrom, levelTo);
229
230 byteBuffer += numBytes;
Phil Burk87c9f642017-05-17 07:22:39 -0700231 framesLeft -= framesToWrite;
232 } else {
233 break;
234 }
235 partIndex++;
236 }
237 int32_t framesWritten = numFrames - framesLeft;
238 mAudioEndpoint.advanceWriteIndex(framesWritten);
239
Phil Burk87c9f642017-05-17 07:22:39 -0700240 // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
241 return framesWritten;
242}
243
Phil Burk87c9f642017-05-17 07:22:39 -0700244int64_t AudioStreamInternalPlay::getFramesRead()
245{
Phil Burkec89b2e2017-06-20 15:05:06 -0700246 int64_t framesReadHardware;
247 if (isActive()) {
248 framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
249 } else {
250 framesReadHardware = mAudioEndpoint.getDataReadCounter();
251 }
252 int64_t framesRead = framesReadHardware + mFramesOffsetFromService;
Phil Burk87c9f642017-05-17 07:22:39 -0700253 // Prevent retrograde motion.
254 if (framesRead < mLastFramesRead) {
255 framesRead = mLastFramesRead;
256 } else {
257 mLastFramesRead = framesRead;
258 }
Phil Burkec89b2e2017-06-20 15:05:06 -0700259 //ALOGD("AudioStreamInternalPlay::getFramesRead() returns %lld", (long long)framesRead);
Phil Burk87c9f642017-05-17 07:22:39 -0700260 return framesRead;
261}
262
263int64_t AudioStreamInternalPlay::getFramesWritten()
264{
Phil Burkec89b2e2017-06-20 15:05:06 -0700265 int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
Phil Burk87c9f642017-05-17 07:22:39 -0700266 + mFramesOffsetFromService;
Phil Burkec89b2e2017-06-20 15:05:06 -0700267 //ALOGD("AudioStreamInternalPlay::getFramesWritten() returns %lld", (long long)framesWritten);
268 return framesWritten;
Phil Burk87c9f642017-05-17 07:22:39 -0700269}
270
271
272// Render audio in the application callback and then write the data to the stream.
273void *AudioStreamInternalPlay::callbackLoop() {
274 aaudio_result_t result = AAUDIO_OK;
275 aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
Phil Burk134f1972017-12-08 13:06:11 -0800276 if (!isDataCallbackSet()) return NULL;
Phil Burkfd34a932017-07-19 07:03:52 -0700277 int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
Phil Burk87c9f642017-05-17 07:22:39 -0700278
279 // result might be a frame count
280 while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
281 // Call application using the AAudio callback interface.
Phil Burk134f1972017-12-08 13:06:11 -0800282 callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames);
Phil Burk87c9f642017-05-17 07:22:39 -0700283
284 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
Phil Burkfd34a932017-07-19 07:03:52 -0700285 // Write audio data to stream. This is a BLOCKING WRITE!
Phil Burk87c9f642017-05-17 07:22:39 -0700286 result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos);
287 if ((result != mCallbackFrames)) {
288 ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result);
289 if (result >= 0) {
290 // Only wrote some of the frames requested. Must have timed out.
291 result = AAUDIO_ERROR_TIMEOUT;
292 }
Phil Burk134f1972017-12-08 13:06:11 -0800293 maybeCallErrorCallback(result);
Phil Burk87c9f642017-05-17 07:22:39 -0700294 break;
295 }
296 } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
297 ALOGD("AudioStreamInternalPlay(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
298 break;
299 }
300 }
301
302 ALOGD("AudioStreamInternalPlay(): callbackLoop() exiting, result = %d, isActive() = %d",
303 result, (int) isActive());
304 return NULL;
305}
Phil Burk965650e2017-09-07 21:00:09 -0700306
307//------------------------------------------------------------------------------
308// Implementation of PlayerBase
309status_t AudioStreamInternalPlay::doSetVolume() {
310 mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
311 return android::NO_ERROR;
312}