blob: 11b43c39662957d2eee372cb7c31ccca778ad7f2 [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 Burk02fec702018-02-16 18:25:55 -080041constexpr int kRampMSec = 10; // time to apply a change in volume
42
43aaudio_result_t AudioStreamInternalPlay::open(const AudioStreamBuilder &builder) {
44 aaudio_result_t result = AudioStreamInternal::open(builder);
45 if (result == AAUDIO_OK) {
46 // Sample rate is constrained to common values by now and should not overflow.
47 int32_t numFrames = kRampMSec * getSampleRate() / AAUDIO_MILLIS_PER_SECOND;
48 mVolumeRamp.setLengthInFrames(numFrames);
49 }
50 return result;
51}
52
Phil Burk5cc83c32017-11-28 15:43:18 -080053aaudio_result_t AudioStreamInternalPlay::requestPause()
Phil Burkb336e892017-07-05 15:35:43 -070054{
Phil Burk5cc83c32017-11-28 15:43:18 -080055 aaudio_result_t result = stopCallback();
56 if (result != AAUDIO_OK) {
57 return result;
58 }
Phil Burkb336e892017-07-05 15:35:43 -070059 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
Phil Burk02fec702018-02-16 18:25:55 -080060 ALOGE("requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
Phil Burkb336e892017-07-05 15:35:43 -070061 mServiceStreamHandle);
62 return AAUDIO_ERROR_INVALID_STATE;
63 }
64
65 mClockModel.stop(AudioClock::getNanoseconds());
66 setState(AAUDIO_STREAM_STATE_PAUSING);
Phil Burkbcc36742017-08-31 17:24:51 -070067 mAtomicTimestamp.clear();
Phil Burk965650e2017-09-07 21:00:09 -070068 return mServiceInterface.pauseStream(mServiceStreamHandle);
Phil Burkb336e892017-07-05 15:35:43 -070069}
70
Phil Burkb336e892017-07-05 15:35:43 -070071aaudio_result_t AudioStreamInternalPlay::requestFlush() {
72 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
73 ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
74 mServiceStreamHandle);
75 return AAUDIO_ERROR_INVALID_STATE;
76 }
77
78 setState(AAUDIO_STREAM_STATE_FLUSHING);
79 return mServiceInterface.flushStream(mServiceStreamHandle);
80}
81
Phil Burkbcc36742017-08-31 17:24:51 -070082void AudioStreamInternalPlay::advanceClientToMatchServerPosition() {
Phil Burkb336e892017-07-05 15:35:43 -070083 int64_t readCounter = mAudioEndpoint.getDataReadCounter();
84 int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
85
86 // Bump offset so caller does not see the retrograde motion in getFramesRead().
Phil Burkbcc36742017-08-31 17:24:51 -070087 int64_t offset = writeCounter - readCounter;
88 mFramesOffsetFromService += offset;
89 ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
Phil Burkb336e892017-07-05 15:35:43 -070090 (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
91
Phil Burkbcc36742017-08-31 17:24:51 -070092 // Force writeCounter to match readCounter.
93 // This is because we cannot change the read counter in the hardware.
Phil Burkb336e892017-07-05 15:35:43 -070094 mAudioEndpoint.setDataWriteCounter(readCounter);
95}
96
Phil Burkbcc36742017-08-31 17:24:51 -070097void AudioStreamInternalPlay::onFlushFromServer() {
98 advanceClientToMatchServerPosition();
99}
100
Phil Burk87c9f642017-05-17 07:22:39 -0700101// Write the data, block if needed and timeoutMillis > 0
102aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
103 int64_t timeoutNanoseconds)
104
105{
106 return processData((void *)buffer, numFrames, timeoutNanoseconds);
107}
108
109// Write as much data as we can without blocking.
110aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t numFrames,
111 int64_t currentNanoTime, int64_t *wakeTimePtr) {
112 aaudio_result_t result = processCommands();
113 if (result != AAUDIO_OK) {
114 return result;
115 }
116
Phil Burkfd34a932017-07-19 07:03:52 -0700117 const char *traceName = "aaWrNow";
118 ATRACE_BEGIN(traceName);
119
Phil Burkbcc36742017-08-31 17:24:51 -0700120 if (mClockModel.isStarting()) {
121 // Still haven't got any timestamps from server.
122 // Keep waiting until we get some valid timestamps then start writing to the
123 // current buffer position.
124 ALOGD("processDataNow() wait for valid timestamps");
125 // Sleep very briefly and hope we get a timestamp soon.
126 *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
127 ATRACE_END();
128 return 0;
129 }
130 // If we have gotten this far then we have at least one timestamp from server.
131
Phil Burkfd34a932017-07-19 07:03:52 -0700132 // 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 -0700133 if (mAudioEndpoint.isFreeRunning()) {
Phil Burk87c9f642017-05-17 07:22:39 -0700134 // Update data queue based on the timing model.
135 int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
Phil Burkec89b2e2017-06-20 15:05:06 -0700136 // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter);
Phil Burk87c9f642017-05-17 07:22:39 -0700137 mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
138 }
Phil Burk87c9f642017-05-17 07:22:39 -0700139
Phil Burkbcc36742017-08-31 17:24:51 -0700140 if (mNeedCatchUp.isRequested()) {
141 // Catch an MMAP pointer that is already advancing.
142 // This will avoid initial underruns caused by a slow cold start.
143 advanceClientToMatchServerPosition();
144 mNeedCatchUp.acknowledge();
145 }
146
Phil Burk87c9f642017-05-17 07:22:39 -0700147 // If the read index passed the write index then consider it an underrun.
Phil Burk23296382017-11-20 15:45:11 -0800148 // For shared streams, the xRunCount is passed up from the service.
149 if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getFullFramesAvailable() < 0) {
Phil Burk87c9f642017-05-17 07:22:39 -0700150 mXRunCount++;
Phil Burkfd34a932017-07-19 07:03:52 -0700151 if (ATRACE_ENABLED()) {
152 ATRACE_INT("aaUnderRuns", mXRunCount);
153 }
Phil Burk87c9f642017-05-17 07:22:39 -0700154 }
155
156 // Write some data to the buffer.
157 //ALOGD("AudioStreamInternal::processDataNow() - writeNowWithConversion(%d)", numFrames);
158 int32_t framesWritten = writeNowWithConversion(buffer, numFrames);
159 //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d",
160 // numFrames, framesWritten);
Phil Burkfd34a932017-07-19 07:03:52 -0700161 if (ATRACE_ENABLED()) {
162 ATRACE_INT("aaWrote", framesWritten);
163 }
Phil Burk87c9f642017-05-17 07:22:39 -0700164
165 // Calculate an ideal time to wake up.
166 if (wakeTimePtr != nullptr && framesWritten >= 0) {
167 // By default wake up a few milliseconds from now. // TODO review
168 int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
169 aaudio_stream_state_t state = getState();
170 //ALOGD("AudioStreamInternal::processDataNow() - wakeTime based on %s",
171 // AAudio_convertStreamStateToText(state));
172 switch (state) {
173 case AAUDIO_STREAM_STATE_OPEN:
174 case AAUDIO_STREAM_STATE_STARTING:
175 if (framesWritten != 0) {
176 // Don't wait to write more data. Just prime the buffer.
177 wakeTime = currentNanoTime;
178 }
179 break;
Phil Burkfd34a932017-07-19 07:03:52 -0700180 case AAUDIO_STREAM_STATE_STARTED:
Phil Burk87c9f642017-05-17 07:22:39 -0700181 {
Phil Burkfd34a932017-07-19 07:03:52 -0700182 // When do we expect the next read burst to occur?
Phil Burk87c9f642017-05-17 07:22:39 -0700183
Phil Burkfd34a932017-07-19 07:03:52 -0700184 // Calculate frame position based off of the writeCounter because
185 // the readCounter might have just advanced in the background,
186 // causing us to sleep until a later burst.
Phil Burkbcc36742017-08-31 17:24:51 -0700187 int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
Phil Burkfd34a932017-07-19 07:03:52 -0700188 - mAudioEndpoint.getBufferSizeInFrames();
Phil Burkbcc36742017-08-31 17:24:51 -0700189 wakeTime = mClockModel.convertPositionToTime(nextPosition);
Phil Burk87c9f642017-05-17 07:22:39 -0700190 }
191 break;
192 default:
193 break;
194 }
195 *wakeTimePtr = wakeTime;
196
197 }
Phil Burkfd34a932017-07-19 07:03:52 -0700198
199 ATRACE_END();
Phil Burk87c9f642017-05-17 07:22:39 -0700200 return framesWritten;
201}
202
203
204aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer,
205 int32_t numFrames) {
206 // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)",
207 // buffer, numFrames);
208 WrappingBuffer wrappingBuffer;
Phil Burk41f19d82018-02-13 14:59:10 -0800209 uint8_t *byteBuffer = (uint8_t *) buffer;
Phil Burk87c9f642017-05-17 07:22:39 -0700210 int32_t framesLeft = numFrames;
211
212 mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer);
213
Phil Burkfd34a932017-07-19 07:03:52 -0700214 // Write data in one or two parts.
Phil Burk87c9f642017-05-17 07:22:39 -0700215 int partIndex = 0;
216 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
217 int32_t framesToWrite = framesLeft;
218 int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
219 if (framesAvailable > 0) {
220 if (framesToWrite > framesAvailable) {
221 framesToWrite = framesAvailable;
222 }
Phil Burk41f19d82018-02-13 14:59:10 -0800223
Phil Burk87c9f642017-05-17 07:22:39 -0700224 int32_t numBytes = getBytesPerFrame() * framesToWrite;
Phil Burk87c9f642017-05-17 07:22:39 -0700225 // Data conversion.
226 float levelFrom;
227 float levelTo;
Phil Burk41f19d82018-02-13 14:59:10 -0800228 mVolumeRamp.nextSegment(framesToWrite, &levelFrom, &levelTo);
229
230 AAudioDataConverter::FormattedData source(
231 (void *)byteBuffer,
232 getFormat(),
233 getSamplesPerFrame());
234 AAudioDataConverter::FormattedData destination(
235 wrappingBuffer.data[partIndex],
236 getDeviceFormat(),
237 getDeviceChannelCount());
238
239 AAudioDataConverter::convert(source, destination, framesToWrite,
240 levelFrom, levelTo);
241
242 byteBuffer += numBytes;
Phil Burk87c9f642017-05-17 07:22:39 -0700243 framesLeft -= framesToWrite;
244 } else {
245 break;
246 }
247 partIndex++;
248 }
249 int32_t framesWritten = numFrames - framesLeft;
250 mAudioEndpoint.advanceWriteIndex(framesWritten);
251
Phil Burk87c9f642017-05-17 07:22:39 -0700252 // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
253 return framesWritten;
254}
255
Phil Burk87c9f642017-05-17 07:22:39 -0700256int64_t AudioStreamInternalPlay::getFramesRead()
257{
Phil Burkec89b2e2017-06-20 15:05:06 -0700258 int64_t framesReadHardware;
259 if (isActive()) {
260 framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
261 } else {
262 framesReadHardware = mAudioEndpoint.getDataReadCounter();
263 }
264 int64_t framesRead = framesReadHardware + mFramesOffsetFromService;
Phil Burk87c9f642017-05-17 07:22:39 -0700265 // Prevent retrograde motion.
266 if (framesRead < mLastFramesRead) {
267 framesRead = mLastFramesRead;
268 } else {
269 mLastFramesRead = framesRead;
270 }
Phil Burkec89b2e2017-06-20 15:05:06 -0700271 //ALOGD("AudioStreamInternalPlay::getFramesRead() returns %lld", (long long)framesRead);
Phil Burk87c9f642017-05-17 07:22:39 -0700272 return framesRead;
273}
274
275int64_t AudioStreamInternalPlay::getFramesWritten()
276{
Phil Burkec89b2e2017-06-20 15:05:06 -0700277 int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
Phil Burk87c9f642017-05-17 07:22:39 -0700278 + mFramesOffsetFromService;
Phil Burkec89b2e2017-06-20 15:05:06 -0700279 //ALOGD("AudioStreamInternalPlay::getFramesWritten() returns %lld", (long long)framesWritten);
280 return framesWritten;
Phil Burk87c9f642017-05-17 07:22:39 -0700281}
282
283
284// Render audio in the application callback and then write the data to the stream.
285void *AudioStreamInternalPlay::callbackLoop() {
286 aaudio_result_t result = AAUDIO_OK;
287 aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
Phil Burk134f1972017-12-08 13:06:11 -0800288 if (!isDataCallbackSet()) return NULL;
Phil Burkfd34a932017-07-19 07:03:52 -0700289 int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
Phil Burk87c9f642017-05-17 07:22:39 -0700290
291 // result might be a frame count
292 while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
293 // Call application using the AAudio callback interface.
Phil Burk134f1972017-12-08 13:06:11 -0800294 callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames);
Phil Burk87c9f642017-05-17 07:22:39 -0700295
296 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
Phil Burkfd34a932017-07-19 07:03:52 -0700297 // Write audio data to stream. This is a BLOCKING WRITE!
Phil Burk87c9f642017-05-17 07:22:39 -0700298 result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos);
299 if ((result != mCallbackFrames)) {
300 ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result);
301 if (result >= 0) {
302 // Only wrote some of the frames requested. Must have timed out.
303 result = AAUDIO_ERROR_TIMEOUT;
304 }
Phil Burk134f1972017-12-08 13:06:11 -0800305 maybeCallErrorCallback(result);
Phil Burk87c9f642017-05-17 07:22:39 -0700306 break;
307 }
308 } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
309 ALOGD("AudioStreamInternalPlay(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
310 break;
311 }
312 }
313
314 ALOGD("AudioStreamInternalPlay(): callbackLoop() exiting, result = %d, isActive() = %d",
315 result, (int) isActive());
316 return NULL;
317}
Phil Burk965650e2017-09-07 21:00:09 -0700318
319//------------------------------------------------------------------------------
320// Implementation of PlayerBase
321status_t AudioStreamInternalPlay::doSetVolume() {
322 mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
323 return android::NO_ERROR;
324}