1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "AAudioServiceStreamShared"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
20*ec779b8eSAndroid Build Coastguard Worker
21*ec779b8eSAndroid Build Coastguard Worker #include <iomanip>
22*ec779b8eSAndroid Build Coastguard Worker #include <iostream>
23*ec779b8eSAndroid Build Coastguard Worker #include <mutex>
24*ec779b8eSAndroid Build Coastguard Worker
25*ec779b8eSAndroid Build Coastguard Worker #include <aaudio/AAudio.h>
26*ec779b8eSAndroid Build Coastguard Worker
27*ec779b8eSAndroid Build Coastguard Worker #include "binding/AAudioServiceMessage.h"
28*ec779b8eSAndroid Build Coastguard Worker #include "AAudioServiceStreamBase.h"
29*ec779b8eSAndroid Build Coastguard Worker #include "AAudioServiceStreamShared.h"
30*ec779b8eSAndroid Build Coastguard Worker #include "AAudioEndpointManager.h"
31*ec779b8eSAndroid Build Coastguard Worker #include "AAudioService.h"
32*ec779b8eSAndroid Build Coastguard Worker #include "AAudioServiceEndpoint.h"
33*ec779b8eSAndroid Build Coastguard Worker
34*ec779b8eSAndroid Build Coastguard Worker using namespace android;
35*ec779b8eSAndroid Build Coastguard Worker using namespace aaudio;
36*ec779b8eSAndroid Build Coastguard Worker
37*ec779b8eSAndroid Build Coastguard Worker #define MIN_BURSTS_PER_BUFFER 2
38*ec779b8eSAndroid Build Coastguard Worker #define DEFAULT_BURSTS_PER_BUFFER 16
39*ec779b8eSAndroid Build Coastguard Worker // This is an arbitrary range. TODO review.
40*ec779b8eSAndroid Build Coastguard Worker #define MAX_FRAMES_PER_BUFFER (32 * 1024)
41*ec779b8eSAndroid Build Coastguard Worker
AAudioServiceStreamShared(AAudioService & audioService)42*ec779b8eSAndroid Build Coastguard Worker AAudioServiceStreamShared::AAudioServiceStreamShared(AAudioService &audioService)
43*ec779b8eSAndroid Build Coastguard Worker : AAudioServiceStreamBase(audioService)
44*ec779b8eSAndroid Build Coastguard Worker , mTimestampPositionOffset(0)
45*ec779b8eSAndroid Build Coastguard Worker , mXRunCount(0) {
46*ec779b8eSAndroid Build Coastguard Worker }
47*ec779b8eSAndroid Build Coastguard Worker
dumpHeader()48*ec779b8eSAndroid Build Coastguard Worker std::string AAudioServiceStreamShared::dumpHeader() {
49*ec779b8eSAndroid Build Coastguard Worker std::stringstream result;
50*ec779b8eSAndroid Build Coastguard Worker result << AAudioServiceStreamBase::dumpHeader();
51*ec779b8eSAndroid Build Coastguard Worker result << " Write# Read# Avail XRuns";
52*ec779b8eSAndroid Build Coastguard Worker return result.str();
53*ec779b8eSAndroid Build Coastguard Worker }
54*ec779b8eSAndroid Build Coastguard Worker
dump() const55*ec779b8eSAndroid Build Coastguard Worker std::string AAudioServiceStreamShared::dump() const NO_THREAD_SAFETY_ANALYSIS {
56*ec779b8eSAndroid Build Coastguard Worker std::stringstream result;
57*ec779b8eSAndroid Build Coastguard Worker
58*ec779b8eSAndroid Build Coastguard Worker const bool isLocked = AAudio_tryUntilTrue(
59*ec779b8eSAndroid Build Coastguard Worker [this]()->bool { return audioDataQueueLock.try_lock(); } /* f */,
60*ec779b8eSAndroid Build Coastguard Worker 50 /* times */,
61*ec779b8eSAndroid Build Coastguard Worker 20 /* sleepMs */);
62*ec779b8eSAndroid Build Coastguard Worker if (!isLocked) {
63*ec779b8eSAndroid Build Coastguard Worker result << "AAudioServiceStreamShared may be deadlocked\n";
64*ec779b8eSAndroid Build Coastguard Worker }
65*ec779b8eSAndroid Build Coastguard Worker
66*ec779b8eSAndroid Build Coastguard Worker result << AAudioServiceStreamBase::dump();
67*ec779b8eSAndroid Build Coastguard Worker
68*ec779b8eSAndroid Build Coastguard Worker result << mAudioDataQueue->dump();
69*ec779b8eSAndroid Build Coastguard Worker result << std::setw(8) << getXRunCount();
70*ec779b8eSAndroid Build Coastguard Worker
71*ec779b8eSAndroid Build Coastguard Worker if (isLocked) {
72*ec779b8eSAndroid Build Coastguard Worker audioDataQueueLock.unlock();
73*ec779b8eSAndroid Build Coastguard Worker }
74*ec779b8eSAndroid Build Coastguard Worker
75*ec779b8eSAndroid Build Coastguard Worker return result.str();
76*ec779b8eSAndroid Build Coastguard Worker }
77*ec779b8eSAndroid Build Coastguard Worker
calculateBufferCapacity(int32_t requestedCapacityFrames,int32_t framesPerBurst)78*ec779b8eSAndroid Build Coastguard Worker int32_t AAudioServiceStreamShared::calculateBufferCapacity(int32_t requestedCapacityFrames,
79*ec779b8eSAndroid Build Coastguard Worker int32_t framesPerBurst) {
80*ec779b8eSAndroid Build Coastguard Worker
81*ec779b8eSAndroid Build Coastguard Worker if (requestedCapacityFrames > MAX_FRAMES_PER_BUFFER) {
82*ec779b8eSAndroid Build Coastguard Worker ALOGE("calculateBufferCapacity() requested capacity %d > max %d",
83*ec779b8eSAndroid Build Coastguard Worker requestedCapacityFrames, MAX_FRAMES_PER_BUFFER);
84*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_OUT_OF_RANGE;
85*ec779b8eSAndroid Build Coastguard Worker }
86*ec779b8eSAndroid Build Coastguard Worker
87*ec779b8eSAndroid Build Coastguard Worker // Determine how many bursts will fit in the buffer.
88*ec779b8eSAndroid Build Coastguard Worker int32_t numBursts;
89*ec779b8eSAndroid Build Coastguard Worker if (requestedCapacityFrames == AAUDIO_UNSPECIFIED) {
90*ec779b8eSAndroid Build Coastguard Worker // Use fewer bursts if default is too many.
91*ec779b8eSAndroid Build Coastguard Worker if ((DEFAULT_BURSTS_PER_BUFFER * framesPerBurst) > MAX_FRAMES_PER_BUFFER) {
92*ec779b8eSAndroid Build Coastguard Worker numBursts = MAX_FRAMES_PER_BUFFER / framesPerBurst;
93*ec779b8eSAndroid Build Coastguard Worker } else {
94*ec779b8eSAndroid Build Coastguard Worker numBursts = DEFAULT_BURSTS_PER_BUFFER;
95*ec779b8eSAndroid Build Coastguard Worker }
96*ec779b8eSAndroid Build Coastguard Worker } else {
97*ec779b8eSAndroid Build Coastguard Worker // round up to nearest burst boundary
98*ec779b8eSAndroid Build Coastguard Worker numBursts = (requestedCapacityFrames + framesPerBurst - 1) / framesPerBurst;
99*ec779b8eSAndroid Build Coastguard Worker }
100*ec779b8eSAndroid Build Coastguard Worker
101*ec779b8eSAndroid Build Coastguard Worker // Clip to bare minimum.
102*ec779b8eSAndroid Build Coastguard Worker if (numBursts < MIN_BURSTS_PER_BUFFER) {
103*ec779b8eSAndroid Build Coastguard Worker numBursts = MIN_BURSTS_PER_BUFFER;
104*ec779b8eSAndroid Build Coastguard Worker }
105*ec779b8eSAndroid Build Coastguard Worker // Check for numeric overflow.
106*ec779b8eSAndroid Build Coastguard Worker if (numBursts > 0x8000 || framesPerBurst > 0x8000) {
107*ec779b8eSAndroid Build Coastguard Worker ALOGE("calculateBufferCapacity() overflow, capacity = %d * %d",
108*ec779b8eSAndroid Build Coastguard Worker numBursts, framesPerBurst);
109*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_OUT_OF_RANGE;
110*ec779b8eSAndroid Build Coastguard Worker }
111*ec779b8eSAndroid Build Coastguard Worker int32_t capacityInFrames = numBursts * framesPerBurst;
112*ec779b8eSAndroid Build Coastguard Worker
113*ec779b8eSAndroid Build Coastguard Worker // Final range check.
114*ec779b8eSAndroid Build Coastguard Worker if (capacityInFrames > MAX_FRAMES_PER_BUFFER) {
115*ec779b8eSAndroid Build Coastguard Worker ALOGE("calculateBufferCapacity() calc capacity %d > max %d",
116*ec779b8eSAndroid Build Coastguard Worker capacityInFrames, MAX_FRAMES_PER_BUFFER);
117*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_OUT_OF_RANGE;
118*ec779b8eSAndroid Build Coastguard Worker }
119*ec779b8eSAndroid Build Coastguard Worker ALOGV("calculateBufferCapacity() requested %d frames, actual = %d",
120*ec779b8eSAndroid Build Coastguard Worker requestedCapacityFrames, capacityInFrames);
121*ec779b8eSAndroid Build Coastguard Worker return capacityInFrames;
122*ec779b8eSAndroid Build Coastguard Worker }
123*ec779b8eSAndroid Build Coastguard Worker
open(const aaudio::AAudioStreamRequest & request)124*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamShared::open(const aaudio::AAudioStreamRequest &request) {
125*ec779b8eSAndroid Build Coastguard Worker
126*ec779b8eSAndroid Build Coastguard Worker sp<AAudioServiceStreamShared> keep(this);
127*ec779b8eSAndroid Build Coastguard Worker
128*ec779b8eSAndroid Build Coastguard Worker if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_SHARED) {
129*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() sharingMode mismatch %d", __func__,
130*ec779b8eSAndroid Build Coastguard Worker request.getConstantConfiguration().getSharingMode());
131*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_INTERNAL;
132*ec779b8eSAndroid Build Coastguard Worker }
133*ec779b8eSAndroid Build Coastguard Worker
134*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = AAudioServiceStreamBase::open(request);
135*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
136*ec779b8eSAndroid Build Coastguard Worker return result;
137*ec779b8eSAndroid Build Coastguard Worker }
138*ec779b8eSAndroid Build Coastguard Worker
139*ec779b8eSAndroid Build Coastguard Worker const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
140*ec779b8eSAndroid Build Coastguard Worker
141*ec779b8eSAndroid Build Coastguard Worker sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
142*ec779b8eSAndroid Build Coastguard Worker if (endpoint == nullptr) {
143*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_INVALID_STATE;
144*ec779b8eSAndroid Build Coastguard Worker goto error;
145*ec779b8eSAndroid Build Coastguard Worker }
146*ec779b8eSAndroid Build Coastguard Worker
147*ec779b8eSAndroid Build Coastguard Worker // Use the sample rate of the endpoint as each shared stream should use its own SRC.
148*ec779b8eSAndroid Build Coastguard Worker setSampleRate(endpoint->getSampleRate());
149*ec779b8eSAndroid Build Coastguard Worker
150*ec779b8eSAndroid Build Coastguard Worker // Is the request compatible with the shared endpoint?
151*ec779b8eSAndroid Build Coastguard Worker setFormat(configurationInput.getFormat());
152*ec779b8eSAndroid Build Coastguard Worker if (getFormat() == AUDIO_FORMAT_DEFAULT) {
153*ec779b8eSAndroid Build Coastguard Worker setFormat(AUDIO_FORMAT_PCM_FLOAT);
154*ec779b8eSAndroid Build Coastguard Worker } else if (getFormat() != AUDIO_FORMAT_PCM_FLOAT) {
155*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s() audio_format_t mAudioFormat = %d, need FLOAT", __func__, getFormat());
156*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_INVALID_FORMAT;
157*ec779b8eSAndroid Build Coastguard Worker goto error;
158*ec779b8eSAndroid Build Coastguard Worker }
159*ec779b8eSAndroid Build Coastguard Worker
160*ec779b8eSAndroid Build Coastguard Worker setChannelMask(configurationInput.getChannelMask());
161*ec779b8eSAndroid Build Coastguard Worker if (getChannelMask() == AAUDIO_UNSPECIFIED) {
162*ec779b8eSAndroid Build Coastguard Worker setChannelMask(endpoint->getChannelMask());
163*ec779b8eSAndroid Build Coastguard Worker } else if (getSamplesPerFrame() != endpoint->getSamplesPerFrame()) {
164*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s() mSamplesPerFrame = %#x, need %#x",
165*ec779b8eSAndroid Build Coastguard Worker __func__, getSamplesPerFrame(), endpoint->getSamplesPerFrame());
166*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_OUT_OF_RANGE;
167*ec779b8eSAndroid Build Coastguard Worker goto error;
168*ec779b8eSAndroid Build Coastguard Worker }
169*ec779b8eSAndroid Build Coastguard Worker
170*ec779b8eSAndroid Build Coastguard Worker setBufferCapacity(calculateBufferCapacity(configurationInput.getBufferCapacity(),
171*ec779b8eSAndroid Build Coastguard Worker mFramesPerBurst));
172*ec779b8eSAndroid Build Coastguard Worker if (getBufferCapacity() < 0) {
173*ec779b8eSAndroid Build Coastguard Worker result = getBufferCapacity(); // negative error code
174*ec779b8eSAndroid Build Coastguard Worker setBufferCapacity(0);
175*ec779b8eSAndroid Build Coastguard Worker goto error;
176*ec779b8eSAndroid Build Coastguard Worker }
177*ec779b8eSAndroid Build Coastguard Worker
178*ec779b8eSAndroid Build Coastguard Worker {
179*ec779b8eSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(audioDataQueueLock);
180*ec779b8eSAndroid Build Coastguard Worker // Create audio data shared memory buffer for client.
181*ec779b8eSAndroid Build Coastguard Worker mAudioDataQueue = std::make_shared<SharedRingBuffer>();
182*ec779b8eSAndroid Build Coastguard Worker result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
183*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
184*ec779b8eSAndroid Build Coastguard Worker ALOGE("%s() could not allocate FIFO with %d frames",
185*ec779b8eSAndroid Build Coastguard Worker __func__, getBufferCapacity());
186*ec779b8eSAndroid Build Coastguard Worker result = AAUDIO_ERROR_NO_MEMORY;
187*ec779b8eSAndroid Build Coastguard Worker goto error;
188*ec779b8eSAndroid Build Coastguard Worker }
189*ec779b8eSAndroid Build Coastguard Worker }
190*ec779b8eSAndroid Build Coastguard Worker
191*ec779b8eSAndroid Build Coastguard Worker result = endpoint->registerStream(keep);
192*ec779b8eSAndroid Build Coastguard Worker if (result != AAUDIO_OK) {
193*ec779b8eSAndroid Build Coastguard Worker goto error;
194*ec779b8eSAndroid Build Coastguard Worker }
195*ec779b8eSAndroid Build Coastguard Worker
196*ec779b8eSAndroid Build Coastguard Worker setState(AAUDIO_STREAM_STATE_OPEN);
197*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_OK;
198*ec779b8eSAndroid Build Coastguard Worker
199*ec779b8eSAndroid Build Coastguard Worker error:
200*ec779b8eSAndroid Build Coastguard Worker close();
201*ec779b8eSAndroid Build Coastguard Worker return result;
202*ec779b8eSAndroid Build Coastguard Worker }
203*ec779b8eSAndroid Build Coastguard Worker
204*ec779b8eSAndroid Build Coastguard Worker /**
205*ec779b8eSAndroid Build Coastguard Worker * Get an immutable description of the data queue created by this service.
206*ec779b8eSAndroid Build Coastguard Worker */
getAudioDataDescription_l(AudioEndpointParcelable * parcelable)207*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamShared::getAudioDataDescription_l(
208*ec779b8eSAndroid Build Coastguard Worker AudioEndpointParcelable* parcelable)
209*ec779b8eSAndroid Build Coastguard Worker {
210*ec779b8eSAndroid Build Coastguard Worker std::lock_guard<std::mutex> lock(audioDataQueueLock);
211*ec779b8eSAndroid Build Coastguard Worker if (mAudioDataQueue == nullptr) {
212*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s(): mUpMessageQueue null! - stream not open", __func__);
213*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_NULL;
214*ec779b8eSAndroid Build Coastguard Worker }
215*ec779b8eSAndroid Build Coastguard Worker // Gather information on the data queue.
216*ec779b8eSAndroid Build Coastguard Worker mAudioDataQueue->fillParcelable(parcelable,
217*ec779b8eSAndroid Build Coastguard Worker parcelable->mDownDataQueueParcelable);
218*ec779b8eSAndroid Build Coastguard Worker parcelable->mDownDataQueueParcelable.setFramesPerBurst(getFramesPerBurst());
219*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_OK;
220*ec779b8eSAndroid Build Coastguard Worker }
221*ec779b8eSAndroid Build Coastguard Worker
markTransferTime(Timestamp & timestamp)222*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamShared::markTransferTime(Timestamp ×tamp) {
223*ec779b8eSAndroid Build Coastguard Worker mAtomicStreamTimestamp.write(timestamp);
224*ec779b8eSAndroid Build Coastguard Worker }
225*ec779b8eSAndroid Build Coastguard Worker
226*ec779b8eSAndroid Build Coastguard Worker // Get timestamp that was written by mixer or distributor.
getFreeRunningPosition_l(int64_t * positionFrames,int64_t * timeNanos)227*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamShared::getFreeRunningPosition_l(int64_t *positionFrames,
228*ec779b8eSAndroid Build Coastguard Worker int64_t *timeNanos) {
229*ec779b8eSAndroid Build Coastguard Worker // TODO Get presentation timestamp from the HAL
230*ec779b8eSAndroid Build Coastguard Worker if (mAtomicStreamTimestamp.isValid()) {
231*ec779b8eSAndroid Build Coastguard Worker Timestamp timestamp = mAtomicStreamTimestamp.read();
232*ec779b8eSAndroid Build Coastguard Worker *positionFrames = timestamp.getPosition();
233*ec779b8eSAndroid Build Coastguard Worker *timeNanos = timestamp.getNanoseconds();
234*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_OK;
235*ec779b8eSAndroid Build Coastguard Worker } else {
236*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_UNAVAILABLE;
237*ec779b8eSAndroid Build Coastguard Worker }
238*ec779b8eSAndroid Build Coastguard Worker }
239*ec779b8eSAndroid Build Coastguard Worker
240*ec779b8eSAndroid Build Coastguard Worker // Get timestamp from lower level service.
getHardwareTimestamp_l(int64_t * positionFrames,int64_t * timeNanos)241*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t AAudioServiceStreamShared::getHardwareTimestamp_l(int64_t *positionFrames,
242*ec779b8eSAndroid Build Coastguard Worker int64_t *timeNanos) {
243*ec779b8eSAndroid Build Coastguard Worker
244*ec779b8eSAndroid Build Coastguard Worker int64_t position = 0;
245*ec779b8eSAndroid Build Coastguard Worker sp<AAudioServiceEndpoint> endpoint = mServiceEndpointWeak.promote();
246*ec779b8eSAndroid Build Coastguard Worker if (endpoint == nullptr) {
247*ec779b8eSAndroid Build Coastguard Worker ALOGW("%s() has no endpoint", __func__);
248*ec779b8eSAndroid Build Coastguard Worker return AAUDIO_ERROR_INVALID_STATE;
249*ec779b8eSAndroid Build Coastguard Worker }
250*ec779b8eSAndroid Build Coastguard Worker
251*ec779b8eSAndroid Build Coastguard Worker aaudio_result_t result = endpoint->getTimestamp(&position, timeNanos);
252*ec779b8eSAndroid Build Coastguard Worker if (result == AAUDIO_OK) {
253*ec779b8eSAndroid Build Coastguard Worker int64_t offset = mTimestampPositionOffset.load();
254*ec779b8eSAndroid Build Coastguard Worker // TODO, do not go below starting value
255*ec779b8eSAndroid Build Coastguard Worker position -= offset; // Offset from shared MMAP stream
256*ec779b8eSAndroid Build Coastguard Worker ALOGV("%s() %8lld = %8lld - %8lld",
257*ec779b8eSAndroid Build Coastguard Worker __func__, (long long) position, (long long) (position + offset), (long long) offset);
258*ec779b8eSAndroid Build Coastguard Worker }
259*ec779b8eSAndroid Build Coastguard Worker *positionFrames = position;
260*ec779b8eSAndroid Build Coastguard Worker return result;
261*ec779b8eSAndroid Build Coastguard Worker }
262*ec779b8eSAndroid Build Coastguard Worker
writeDataIfRoom(int64_t mmapFramesRead,const void * buffer,int32_t numFrames)263*ec779b8eSAndroid Build Coastguard Worker void AAudioServiceStreamShared::writeDataIfRoom(int64_t mmapFramesRead,
264*ec779b8eSAndroid Build Coastguard Worker const void *buffer, int32_t numFrames) {
265*ec779b8eSAndroid Build Coastguard Worker int64_t clientFramesWritten = 0;
266*ec779b8eSAndroid Build Coastguard Worker
267*ec779b8eSAndroid Build Coastguard Worker // Lock the AudioFifo to protect against close.
268*ec779b8eSAndroid Build Coastguard Worker std::lock_guard <std::mutex> lock(audioDataQueueLock);
269*ec779b8eSAndroid Build Coastguard Worker
270*ec779b8eSAndroid Build Coastguard Worker if (mAudioDataQueue != nullptr) {
271*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<FifoBuffer> fifo = mAudioDataQueue->getFifoBuffer();
272*ec779b8eSAndroid Build Coastguard Worker // Determine offset between framePosition in client's stream
273*ec779b8eSAndroid Build Coastguard Worker // vs the underlying MMAP stream.
274*ec779b8eSAndroid Build Coastguard Worker clientFramesWritten = fifo->getWriteCounter();
275*ec779b8eSAndroid Build Coastguard Worker // There are two indices that refer to the same frame.
276*ec779b8eSAndroid Build Coastguard Worker int64_t positionOffset = mmapFramesRead - clientFramesWritten;
277*ec779b8eSAndroid Build Coastguard Worker setTimestampPositionOffset(positionOffset);
278*ec779b8eSAndroid Build Coastguard Worker
279*ec779b8eSAndroid Build Coastguard Worker // Is the buffer too full to write a burst?
280*ec779b8eSAndroid Build Coastguard Worker if (fifo->getEmptyFramesAvailable() < getFramesPerBurst()) {
281*ec779b8eSAndroid Build Coastguard Worker incrementXRunCount();
282*ec779b8eSAndroid Build Coastguard Worker } else {
283*ec779b8eSAndroid Build Coastguard Worker fifo->write(buffer, numFrames);
284*ec779b8eSAndroid Build Coastguard Worker }
285*ec779b8eSAndroid Build Coastguard Worker clientFramesWritten = fifo->getWriteCounter();
286*ec779b8eSAndroid Build Coastguard Worker }
287*ec779b8eSAndroid Build Coastguard Worker
288*ec779b8eSAndroid Build Coastguard Worker if (clientFramesWritten > 0) {
289*ec779b8eSAndroid Build Coastguard Worker // This timestamp represents the completion of data being written into the
290*ec779b8eSAndroid Build Coastguard Worker // client buffer. It is sent to the client and used in the timing model
291*ec779b8eSAndroid Build Coastguard Worker // to decide when data will be available to read.
292*ec779b8eSAndroid Build Coastguard Worker Timestamp timestamp(clientFramesWritten, AudioClock::getNanoseconds());
293*ec779b8eSAndroid Build Coastguard Worker markTransferTime(timestamp);
294*ec779b8eSAndroid Build Coastguard Worker }
295*ec779b8eSAndroid Build Coastguard Worker }
296