blob: 0c3b1fa182f7c981ff7a2807f39f583daacf477e [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 Burk19e990e2018-03-22 13:59:34 -070060 ALOGE("%s() mServiceStreamHandle invalid", __func__);
Phil Burkb336e892017-07-05 15:35:43 -070061 return AAUDIO_ERROR_INVALID_STATE;
62 }
63
64 mClockModel.stop(AudioClock::getNanoseconds());
65 setState(AAUDIO_STREAM_STATE_PAUSING);
Phil Burkbcc36742017-08-31 17:24:51 -070066 mAtomicTimestamp.clear();
Phil Burk965650e2017-09-07 21:00:09 -070067 return mServiceInterface.pauseStream(mServiceStreamHandle);
Phil Burkb336e892017-07-05 15:35:43 -070068}
69
Phil Burkb336e892017-07-05 15:35:43 -070070aaudio_result_t AudioStreamInternalPlay::requestFlush() {
71 if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
Phil Burk19e990e2018-03-22 13:59:34 -070072 ALOGE("%s() mServiceStreamHandle invalid", __func__);
Phil Burkb336e892017-07-05 15:35:43 -070073 return AAUDIO_ERROR_INVALID_STATE;
74 }
75
76 setState(AAUDIO_STREAM_STATE_FLUSHING);
77 return mServiceInterface.flushStream(mServiceStreamHandle);
78}
79
Phil Burkbcc36742017-08-31 17:24:51 -070080void AudioStreamInternalPlay::advanceClientToMatchServerPosition() {
Phil Burkb336e892017-07-05 15:35:43 -070081 int64_t readCounter = mAudioEndpoint.getDataReadCounter();
82 int64_t writeCounter = mAudioEndpoint.getDataWriteCounter();
83
84 // Bump offset so caller does not see the retrograde motion in getFramesRead().
Phil Burkbcc36742017-08-31 17:24:51 -070085 int64_t offset = writeCounter - readCounter;
86 mFramesOffsetFromService += offset;
Phil Burk19e990e2018-03-22 13:59:34 -070087 ALOGV("%s() readN = %lld, writeN = %lld, offset = %lld", __func__,
Phil Burkb336e892017-07-05 15:35:43 -070088 (long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
89
Phil Burkbcc36742017-08-31 17:24:51 -070090 // Force writeCounter to match readCounter.
91 // This is because we cannot change the read counter in the hardware.
Phil Burkb336e892017-07-05 15:35:43 -070092 mAudioEndpoint.setDataWriteCounter(readCounter);
93}
94
Phil Burkbcc36742017-08-31 17:24:51 -070095void AudioStreamInternalPlay::onFlushFromServer() {
96 advanceClientToMatchServerPosition();
97}
98
Phil Burk87c9f642017-05-17 07:22:39 -070099// Write the data, block if needed and timeoutMillis > 0
100aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
Phil Burk19e990e2018-03-22 13:59:34 -0700101 int64_t timeoutNanoseconds) {
Phil Burk87c9f642017-05-17 07:22:39 -0700102 return processData((void *)buffer, numFrames, timeoutNanoseconds);
103}
104
105// Write as much data as we can without blocking.
106aaudio_result_t AudioStreamInternalPlay::processDataNow(void *buffer, int32_t numFrames,
107 int64_t currentNanoTime, int64_t *wakeTimePtr) {
108 aaudio_result_t result = processCommands();
109 if (result != AAUDIO_OK) {
110 return result;
111 }
112
Phil Burkfd34a932017-07-19 07:03:52 -0700113 const char *traceName = "aaWrNow";
114 ATRACE_BEGIN(traceName);
115
Phil Burkbcc36742017-08-31 17:24:51 -0700116 if (mClockModel.isStarting()) {
117 // Still haven't got any timestamps from server.
118 // Keep waiting until we get some valid timestamps then start writing to the
119 // current buffer position.
Phil Burk19e990e2018-03-22 13:59:34 -0700120 ALOGD("%s() wait for valid timestamps", __func__);
Phil Burkbcc36742017-08-31 17:24:51 -0700121 // Sleep very briefly and hope we get a timestamp soon.
122 *wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
123 ATRACE_END();
124 return 0;
125 }
126 // If we have gotten this far then we have at least one timestamp from server.
127
Phil Burkfd34a932017-07-19 07:03:52 -0700128 // 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 -0700129 if (mAudioEndpoint.isFreeRunning()) {
Phil Burk87c9f642017-05-17 07:22:39 -0700130 // Update data queue based on the timing model.
131 int64_t estimatedReadCounter = mClockModel.convertTimeToPosition(currentNanoTime);
Phil Burkec89b2e2017-06-20 15:05:06 -0700132 // ALOGD("AudioStreamInternal::processDataNow() - estimatedReadCounter = %d", (int)estimatedReadCounter);
Phil Burk87c9f642017-05-17 07:22:39 -0700133 mAudioEndpoint.setDataReadCounter(estimatedReadCounter);
134 }
Phil Burk87c9f642017-05-17 07:22:39 -0700135
Phil Burkbcc36742017-08-31 17:24:51 -0700136 if (mNeedCatchUp.isRequested()) {
137 // Catch an MMAP pointer that is already advancing.
138 // This will avoid initial underruns caused by a slow cold start.
139 advanceClientToMatchServerPosition();
140 mNeedCatchUp.acknowledge();
141 }
142
Phil Burk87c9f642017-05-17 07:22:39 -0700143 // If the read index passed the write index then consider it an underrun.
Phil Burk23296382017-11-20 15:45:11 -0800144 // For shared streams, the xRunCount is passed up from the service.
145 if (mAudioEndpoint.isFreeRunning() && mAudioEndpoint.getFullFramesAvailable() < 0) {
Phil Burk87c9f642017-05-17 07:22:39 -0700146 mXRunCount++;
Phil Burkfd34a932017-07-19 07:03:52 -0700147 if (ATRACE_ENABLED()) {
148 ATRACE_INT("aaUnderRuns", mXRunCount);
149 }
Phil Burk87c9f642017-05-17 07:22:39 -0700150 }
151
152 // Write some data to the buffer.
153 //ALOGD("AudioStreamInternal::processDataNow() - writeNowWithConversion(%d)", numFrames);
154 int32_t framesWritten = writeNowWithConversion(buffer, numFrames);
155 //ALOGD("AudioStreamInternal::processDataNow() - tried to write %d frames, wrote %d",
156 // numFrames, framesWritten);
Phil Burkfd34a932017-07-19 07:03:52 -0700157 if (ATRACE_ENABLED()) {
158 ATRACE_INT("aaWrote", framesWritten);
159 }
Phil Burk87c9f642017-05-17 07:22:39 -0700160
161 // Calculate an ideal time to wake up.
162 if (wakeTimePtr != nullptr && framesWritten >= 0) {
163 // By default wake up a few milliseconds from now. // TODO review
164 int64_t wakeTime = currentNanoTime + (1 * AAUDIO_NANOS_PER_MILLISECOND);
165 aaudio_stream_state_t state = getState();
166 //ALOGD("AudioStreamInternal::processDataNow() - wakeTime based on %s",
167 // AAudio_convertStreamStateToText(state));
168 switch (state) {
169 case AAUDIO_STREAM_STATE_OPEN:
170 case AAUDIO_STREAM_STATE_STARTING:
171 if (framesWritten != 0) {
172 // Don't wait to write more data. Just prime the buffer.
173 wakeTime = currentNanoTime;
174 }
175 break;
Phil Burkfd34a932017-07-19 07:03:52 -0700176 case AAUDIO_STREAM_STATE_STARTED:
Phil Burk87c9f642017-05-17 07:22:39 -0700177 {
Phil Burkfd34a932017-07-19 07:03:52 -0700178 // When do we expect the next read burst to occur?
Phil Burk87c9f642017-05-17 07:22:39 -0700179
Phil Burkfd34a932017-07-19 07:03:52 -0700180 // Calculate frame position based off of the writeCounter because
181 // the readCounter might have just advanced in the background,
182 // causing us to sleep until a later burst.
Phil Burkbcc36742017-08-31 17:24:51 -0700183 int64_t nextPosition = mAudioEndpoint.getDataWriteCounter() + mFramesPerBurst
Phil Burkfd34a932017-07-19 07:03:52 -0700184 - mAudioEndpoint.getBufferSizeInFrames();
Phil Burkbcc36742017-08-31 17:24:51 -0700185 wakeTime = mClockModel.convertPositionToTime(nextPosition);
Phil Burk87c9f642017-05-17 07:22:39 -0700186 }
187 break;
188 default:
189 break;
190 }
191 *wakeTimePtr = wakeTime;
192
193 }
Phil Burkfd34a932017-07-19 07:03:52 -0700194
195 ATRACE_END();
Phil Burk87c9f642017-05-17 07:22:39 -0700196 return framesWritten;
197}
198
199
200aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer,
201 int32_t numFrames) {
Phil Burk87c9f642017-05-17 07:22:39 -0700202 WrappingBuffer wrappingBuffer;
Phil Burk41f19d82018-02-13 14:59:10 -0800203 uint8_t *byteBuffer = (uint8_t *) buffer;
Phil Burk87c9f642017-05-17 07:22:39 -0700204 int32_t framesLeft = numFrames;
205
206 mAudioEndpoint.getEmptyFramesAvailable(&wrappingBuffer);
207
Phil Burkfd34a932017-07-19 07:03:52 -0700208 // Write data in one or two parts.
Phil Burk87c9f642017-05-17 07:22:39 -0700209 int partIndex = 0;
210 while (framesLeft > 0 && partIndex < WrappingBuffer::SIZE) {
211 int32_t framesToWrite = framesLeft;
212 int32_t framesAvailable = wrappingBuffer.numFrames[partIndex];
213 if (framesAvailable > 0) {
214 if (framesToWrite > framesAvailable) {
215 framesToWrite = framesAvailable;
216 }
Phil Burk41f19d82018-02-13 14:59:10 -0800217
Phil Burk87c9f642017-05-17 07:22:39 -0700218 int32_t numBytes = getBytesPerFrame() * framesToWrite;
Phil Burk87c9f642017-05-17 07:22:39 -0700219 // Data conversion.
220 float levelFrom;
221 float levelTo;
Phil Burk41f19d82018-02-13 14:59:10 -0800222 mVolumeRamp.nextSegment(framesToWrite, &levelFrom, &levelTo);
223
224 AAudioDataConverter::FormattedData source(
225 (void *)byteBuffer,
226 getFormat(),
227 getSamplesPerFrame());
228 AAudioDataConverter::FormattedData destination(
229 wrappingBuffer.data[partIndex],
230 getDeviceFormat(),
231 getDeviceChannelCount());
232
233 AAudioDataConverter::convert(source, destination, framesToWrite,
234 levelFrom, levelTo);
235
236 byteBuffer += numBytes;
Phil Burk87c9f642017-05-17 07:22:39 -0700237 framesLeft -= framesToWrite;
238 } else {
239 break;
240 }
241 partIndex++;
242 }
243 int32_t framesWritten = numFrames - framesLeft;
244 mAudioEndpoint.advanceWriteIndex(framesWritten);
245
Phil Burk87c9f642017-05-17 07:22:39 -0700246 return framesWritten;
247}
248
Phil Burk87c9f642017-05-17 07:22:39 -0700249int64_t AudioStreamInternalPlay::getFramesRead()
250{
Phil Burkec89b2e2017-06-20 15:05:06 -0700251 int64_t framesReadHardware;
252 if (isActive()) {
253 framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
254 } else {
255 framesReadHardware = mAudioEndpoint.getDataReadCounter();
256 }
257 int64_t framesRead = framesReadHardware + mFramesOffsetFromService;
Phil Burk87c9f642017-05-17 07:22:39 -0700258 // Prevent retrograde motion.
259 if (framesRead < mLastFramesRead) {
260 framesRead = mLastFramesRead;
261 } else {
262 mLastFramesRead = framesRead;
263 }
Phil Burk87c9f642017-05-17 07:22:39 -0700264 return framesRead;
265}
266
267int64_t AudioStreamInternalPlay::getFramesWritten()
268{
Phil Burkec89b2e2017-06-20 15:05:06 -0700269 int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
Phil Burk87c9f642017-05-17 07:22:39 -0700270 + mFramesOffsetFromService;
Phil Burkec89b2e2017-06-20 15:05:06 -0700271 return framesWritten;
Phil Burk87c9f642017-05-17 07:22:39 -0700272}
273
274
275// Render audio in the application callback and then write the data to the stream.
276void *AudioStreamInternalPlay::callbackLoop() {
Phil Burk19e990e2018-03-22 13:59:34 -0700277 ALOGD("%s() entering >>>>>>>>>>>>>>>", __func__);
Phil Burk87c9f642017-05-17 07:22:39 -0700278 aaudio_result_t result = AAUDIO_OK;
279 aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
Phil Burk134f1972017-12-08 13:06:11 -0800280 if (!isDataCallbackSet()) return NULL;
Phil Burkfd34a932017-07-19 07:03:52 -0700281 int64_t timeoutNanos = calculateReasonableTimeout(mCallbackFrames);
Phil Burk87c9f642017-05-17 07:22:39 -0700282
283 // result might be a frame count
284 while (mCallbackEnabled.load() && isActive() && (result >= 0)) {
285 // Call application using the AAudio callback interface.
Phil Burk134f1972017-12-08 13:06:11 -0800286 callbackResult = maybeCallDataCallback(mCallbackBuffer, mCallbackFrames);
Phil Burk87c9f642017-05-17 07:22:39 -0700287
288 if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
Phil Burkfd34a932017-07-19 07:03:52 -0700289 // Write audio data to stream. This is a BLOCKING WRITE!
Phil Burk87c9f642017-05-17 07:22:39 -0700290 result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos);
291 if ((result != mCallbackFrames)) {
Phil Burk87c9f642017-05-17 07:22:39 -0700292 if (result >= 0) {
293 // Only wrote some of the frames requested. Must have timed out.
294 result = AAUDIO_ERROR_TIMEOUT;
295 }
Phil Burk134f1972017-12-08 13:06:11 -0800296 maybeCallErrorCallback(result);
Phil Burk87c9f642017-05-17 07:22:39 -0700297 break;
298 }
299 } else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
Phil Burk19e990e2018-03-22 13:59:34 -0700300 ALOGV("%s(): callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
Phil Burk87c9f642017-05-17 07:22:39 -0700301 break;
302 }
303 }
304
Phil Burk19e990e2018-03-22 13:59:34 -0700305 ALOGD("%s() exiting, result = %d, isActive() = %d <<<<<<<<<<<<<<",
306 __func__, result, (int) isActive());
Phil Burk87c9f642017-05-17 07:22:39 -0700307 return NULL;
308}
Phil Burk965650e2017-09-07 21:00:09 -0700309
310//------------------------------------------------------------------------------
311// Implementation of PlayerBase
312status_t AudioStreamInternalPlay::doSetVolume() {
313 mVolumeRamp.setTarget(mStreamVolume * getDuckAndMuteVolume());
314 return android::NO_ERROR;
315}