1 /*
2 * Copyright 2015 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 "AAudioStream"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20
21 #include <atomic>
22 #include <stdint.h>
23
24 #include <media/MediaMetricsItem.h>
25
26 #include <aaudio/AAudio.h>
27
28 #include "AudioStreamBuilder.h"
29 #include "AudioStream.h"
30 #include "AudioClock.h"
31 #include "AudioGlobal.h"
32
33 namespace aaudio {
34
35 // Sequential number assigned to streams solely for debugging purposes.
AAudio_getNextStreamId()36 static aaudio_stream_id_t AAudio_getNextStreamId() {
37 static std::atomic <aaudio_stream_id_t> nextStreamId{1};
38 return nextStreamId++;
39 }
40
AudioStream()41 AudioStream::AudioStream()
42 : mPlayerBase(new MyPlayerBase())
43 , mStreamId(AAudio_getNextStreamId())
44 {
45 setPeriodNanoseconds(0);
46 }
47
~AudioStream()48 AudioStream::~AudioStream() {
49 // Please preserve these logs because there have been several bugs related to
50 // AudioStream deletion and late callbacks.
51 ALOGD("%s(s#%u) mPlayerBase strongCount = %d",
52 __func__, getId(), mPlayerBase->getStrongCount());
53
54 ALOGE_IF(pthread_equal(pthread_self(), mThread),
55 "%s() destructor running in callback", __func__);
56
57 ALOGE_IF(mHasThread, "%s() callback thread never join()ed", __func__);
58
59 // If the stream is deleted when OPEN or in use then audio resources will leak.
60 // This would indicate an internal error. So we want to find this ASAP.
61 LOG_ALWAYS_FATAL_IF(!(getState() == AAUDIO_STREAM_STATE_CLOSED
62 || getState() == AAUDIO_STREAM_STATE_UNINITIALIZED
63 || getState() == AAUDIO_STREAM_STATE_DISCONNECTED),
64 "~AudioStream() - still in use, state = %s",
65 AudioGlobal_convertStreamStateToText(getState()));
66 }
67
open(const AudioStreamBuilder & builder)68 aaudio_result_t AudioStream::open(const AudioStreamBuilder& builder)
69 {
70 // Call here as well because the AAudioService will call this without calling build().
71 aaudio_result_t result = builder.validate();
72 if (result != AAUDIO_OK) {
73 return result;
74 }
75
76 // Copy parameters from the Builder because the Builder may be deleted after this call.
77 // TODO AudioStream should be a subclass of AudioStreamParameters
78 mSamplesPerFrame = builder.getSamplesPerFrame();
79 mChannelMask = builder.getChannelMask();
80 mSampleRate = builder.getSampleRate();
81 mDeviceId = builder.getDeviceId();
82 mFormat = builder.getFormat();
83 mSharingMode = builder.getSharingMode();
84 mSharingModeMatchRequired = builder.isSharingModeMatchRequired();
85 mPerformanceMode = builder.getPerformanceMode();
86
87 mUsage = builder.getUsage();
88 if (mUsage == AAUDIO_UNSPECIFIED) {
89 mUsage = AAUDIO_USAGE_MEDIA;
90 }
91 mContentType = builder.getContentType();
92 if (mContentType == AAUDIO_UNSPECIFIED) {
93 mContentType = AAUDIO_CONTENT_TYPE_MUSIC;
94 }
95 mSpatializationBehavior = builder.getSpatializationBehavior();
96 // for consistency with other properties, note UNSPECIFIED is the same as AUTO
97 if (mSpatializationBehavior == AAUDIO_UNSPECIFIED) {
98 mSpatializationBehavior = AAUDIO_SPATIALIZATION_BEHAVIOR_AUTO;
99 }
100 mIsContentSpatialized = builder.isContentSpatialized();
101 mInputPreset = builder.getInputPreset();
102 if (mInputPreset == AAUDIO_UNSPECIFIED) {
103 mInputPreset = AAUDIO_INPUT_PRESET_VOICE_RECOGNITION;
104 }
105 mAllowedCapturePolicy = builder.getAllowedCapturePolicy();
106 if (mAllowedCapturePolicy == AAUDIO_UNSPECIFIED) {
107 mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
108 }
109 mIsPrivacySensitive = builder.isPrivacySensitive();
110
111 // callbacks
112 mFramesPerDataCallback = builder.getFramesPerDataCallback();
113 mDataCallbackProc = builder.getDataCallbackProc();
114 mErrorCallbackProc = builder.getErrorCallbackProc();
115 mDataCallbackUserData = builder.getDataCallbackUserData();
116 mErrorCallbackUserData = builder.getErrorCallbackUserData();
117
118 return AAUDIO_OK;
119 }
120
logOpenActual()121 void AudioStream::logOpenActual() {
122 if (mMetricsId.size() > 0) {
123 android::mediametrics::LogItem item(mMetricsId);
124 item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN)
125 .set(AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL,
126 AudioGlobal_convertPerformanceModeToText(getPerformanceMode()))
127 .set(AMEDIAMETRICS_PROP_SHARINGMODEACTUAL,
128 AudioGlobal_convertSharingModeToText(getSharingMode()))
129 .set(AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, getBufferCapacity())
130 .set(AMEDIAMETRICS_PROP_BURSTFRAMES, getFramesPerBurst())
131 .set(AMEDIAMETRICS_PROP_DIRECTION,
132 AudioGlobal_convertDirectionToText(getDirection()));
133
134 if (getDirection() == AAUDIO_DIRECTION_OUTPUT) {
135 item.set(AMEDIAMETRICS_PROP_PLAYERIID, mPlayerBase->getPlayerIId());
136 }
137 item.record();
138 }
139 }
140
logReleaseBufferState()141 void AudioStream::logReleaseBufferState() {
142 if (mMetricsId.size() > 0) {
143 android::mediametrics::LogItem(mMetricsId)
144 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_RELEASE)
145 .set(AMEDIAMETRICS_PROP_BUFFERSIZEFRAMES, (int32_t) getBufferSize())
146 .set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t) getXRunCount())
147 .record();
148 }
149 }
150
systemStart()151 aaudio_result_t AudioStream::systemStart() {
152 if (collidesWithCallback()) {
153 ALOGE("%s cannot be called from a callback!", __func__);
154 return AAUDIO_ERROR_INVALID_STATE;
155 }
156
157 std::lock_guard<std::mutex> lock(mStreamLock);
158
159 switch (getState()) {
160 // Is this a good time to start?
161 case AAUDIO_STREAM_STATE_OPEN:
162 case AAUDIO_STREAM_STATE_PAUSING:
163 case AAUDIO_STREAM_STATE_PAUSED:
164 case AAUDIO_STREAM_STATE_STOPPING:
165 case AAUDIO_STREAM_STATE_STOPPED:
166 case AAUDIO_STREAM_STATE_FLUSHING:
167 case AAUDIO_STREAM_STATE_FLUSHED:
168 break; // Proceed with starting.
169
170 // Already started?
171 case AAUDIO_STREAM_STATE_STARTING:
172 case AAUDIO_STREAM_STATE_STARTED:
173 ALOGW("%s() stream was already started, state = %s", __func__,
174 AudioGlobal_convertStreamStateToText(getState()));
175 return AAUDIO_ERROR_INVALID_STATE;
176
177 // Don't start when the stream is dead!
178 case AAUDIO_STREAM_STATE_DISCONNECTED:
179 case AAUDIO_STREAM_STATE_CLOSING:
180 case AAUDIO_STREAM_STATE_CLOSED:
181 default:
182 ALOGW("%s() stream is dead, state = %s", __func__,
183 AudioGlobal_convertStreamStateToText(getState()));
184 return AAUDIO_ERROR_INVALID_STATE;
185 }
186
187 aaudio_result_t result = requestStart_l();
188 if (result == AAUDIO_OK) {
189 // We only call this for logging in "dumpsys audio". So ignore return code.
190 (void) mPlayerBase->startWithStatus(getDeviceId());
191 }
192 return result;
193 }
194
systemPause()195 aaudio_result_t AudioStream::systemPause() {
196
197 if (!isPauseSupported()) {
198 return AAUDIO_ERROR_UNIMPLEMENTED;
199 }
200
201 if (collidesWithCallback()) {
202 ALOGE("%s cannot be called from a callback!", __func__);
203 return AAUDIO_ERROR_INVALID_STATE;
204 }
205
206 std::lock_guard<std::mutex> lock(mStreamLock);
207 switch (getState()) {
208 // Proceed with pausing.
209 case AAUDIO_STREAM_STATE_STARTING:
210 case AAUDIO_STREAM_STATE_STARTED:
211 case AAUDIO_STREAM_STATE_DISCONNECTED:
212 break;
213
214 // Transition from one inactive state to another.
215 case AAUDIO_STREAM_STATE_OPEN:
216 case AAUDIO_STREAM_STATE_STOPPED:
217 case AAUDIO_STREAM_STATE_FLUSHED:
218 setState(AAUDIO_STREAM_STATE_PAUSED);
219 return AAUDIO_OK;
220
221 // Redundant?
222 case AAUDIO_STREAM_STATE_PAUSING:
223 case AAUDIO_STREAM_STATE_PAUSED:
224 return AAUDIO_OK;
225
226 // Don't interfere with transitional states or when closed.
227 case AAUDIO_STREAM_STATE_STOPPING:
228 case AAUDIO_STREAM_STATE_FLUSHING:
229 case AAUDIO_STREAM_STATE_CLOSING:
230 case AAUDIO_STREAM_STATE_CLOSED:
231 default:
232 ALOGW("%s() stream not running, state = %s",
233 __func__, AudioGlobal_convertStreamStateToText(getState()));
234 return AAUDIO_ERROR_INVALID_STATE;
235 }
236
237 aaudio_result_t result = requestPause_l();
238 if (result == AAUDIO_OK) {
239 // We only call this for logging in "dumpsys audio". So ignore return code.
240 (void) mPlayerBase->pauseWithStatus();
241 }
242 return result;
243 }
244
safeFlush()245 aaudio_result_t AudioStream::safeFlush() {
246 if (!isFlushSupported()) {
247 ALOGE("flush not supported for this stream");
248 return AAUDIO_ERROR_UNIMPLEMENTED;
249 }
250
251 if (collidesWithCallback()) {
252 ALOGE("stream cannot be flushed from a callback!");
253 return AAUDIO_ERROR_INVALID_STATE;
254 }
255
256 std::lock_guard<std::mutex> lock(mStreamLock);
257 aaudio_result_t result = AAudio_isFlushAllowed(getState());
258 if (result != AAUDIO_OK) {
259 return result;
260 }
261
262 return requestFlush_l();
263 }
264
systemStopInternal()265 aaudio_result_t AudioStream::systemStopInternal() {
266 std::lock_guard<std::mutex> lock(mStreamLock);
267 aaudio_result_t result = safeStop_l();
268 if (result == AAUDIO_OK) {
269 // We only call this for logging in "dumpsys audio". So ignore return code.
270 (void) mPlayerBase->stopWithStatus();
271 }
272 return result;
273 }
274
systemStopFromApp()275 aaudio_result_t AudioStream::systemStopFromApp() {
276 // This check can and should be done outside the lock.
277 if (collidesWithCallback()) {
278 ALOGE("stream cannot be stopped by calling from a callback!");
279 return AAUDIO_ERROR_INVALID_STATE;
280 }
281 return systemStopInternal();
282 }
283
safeStop_l()284 aaudio_result_t AudioStream::safeStop_l() {
285
286 switch (getState()) {
287 // Proceed with stopping.
288 case AAUDIO_STREAM_STATE_STARTING:
289 case AAUDIO_STREAM_STATE_STARTED:
290 case AAUDIO_STREAM_STATE_DISCONNECTED:
291 break;
292
293 // Transition from one inactive state to another.
294 case AAUDIO_STREAM_STATE_OPEN:
295 case AAUDIO_STREAM_STATE_PAUSED:
296 case AAUDIO_STREAM_STATE_FLUSHED:
297 setState(AAUDIO_STREAM_STATE_STOPPED);
298 return AAUDIO_OK;
299
300 // Redundant?
301 case AAUDIO_STREAM_STATE_STOPPING:
302 case AAUDIO_STREAM_STATE_STOPPED:
303 return AAUDIO_OK;
304
305 // Don't interfere with transitional states or when closed.
306 case AAUDIO_STREAM_STATE_PAUSING:
307 case AAUDIO_STREAM_STATE_FLUSHING:
308 case AAUDIO_STREAM_STATE_CLOSING:
309 case AAUDIO_STREAM_STATE_CLOSED:
310 default:
311 ALOGW("%s() stream not running, state = %s", __func__,
312 AudioGlobal_convertStreamStateToText(getState()));
313 return AAUDIO_ERROR_INVALID_STATE;
314 }
315
316 return requestStop_l();
317 }
318
safeRelease()319 aaudio_result_t AudioStream::safeRelease() {
320 if (collidesWithCallback()) {
321 ALOGE("%s cannot be called from a callback!", __func__);
322 return AAUDIO_ERROR_INVALID_STATE;
323 }
324 // This may get temporarily unlocked in the MMAP release() when joining callback threads.
325 std::lock_guard<std::mutex> lock(mStreamLock);
326 if (getState() == AAUDIO_STREAM_STATE_CLOSING) { // already released?
327 return AAUDIO_OK;
328 }
329 return release_l();
330 }
331
safeReleaseClose()332 aaudio_result_t AudioStream::safeReleaseClose() {
333 if (collidesWithCallback()) {
334 ALOGE("%s cannot be called from a callback!", __func__);
335 return AAUDIO_ERROR_INVALID_STATE;
336 }
337 return safeReleaseCloseInternal();
338 }
339
safeReleaseCloseInternal()340 aaudio_result_t AudioStream::safeReleaseCloseInternal() {
341 // This get temporarily unlocked in the MMAP release() when joining callback threads.
342 std::lock_guard<std::mutex> lock(mStreamLock);
343 releaseCloseFinal_l();
344 return AAUDIO_OK;
345 }
346
close_l()347 void AudioStream::close_l() {
348 // Releasing the stream will set the state to CLOSING.
349 assert(getState() == AAUDIO_STREAM_STATE_CLOSING);
350 // setState() prevents a transition from CLOSING to any state other than CLOSED.
351 // State is checked by destructor.
352 setState(AAUDIO_STREAM_STATE_CLOSED);
353
354 if (!mMetricsId.empty()) {
355 android::mediametrics::LogItem(mMetricsId)
356 .set(AMEDIAMETRICS_PROP_FRAMESTRANSFERRED,
357 getDirection() == AAUDIO_DIRECTION_INPUT ? getFramesWritten()
358 : getFramesRead())
359 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAAUDIOSTREAM)
360 .record();
361 }
362 }
363
setState(aaudio_stream_state_t state)364 void AudioStream::setState(aaudio_stream_state_t state) {
365 ALOGD("%s(s#%d) from %d to %d", __func__, getId(), mState, state);
366 if (state == mState) {
367 return; // no change
368 }
369 // Track transition to DISCONNECTED state.
370 if (state == AAUDIO_STREAM_STATE_DISCONNECTED) {
371 android::mediametrics::LogItem(mMetricsId)
372 .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT)
373 .set(AMEDIAMETRICS_PROP_STATE, AudioGlobal_convertStreamStateToText(getState()))
374 .record();
375 }
376 // CLOSED is a final state
377 if (mState == AAUDIO_STREAM_STATE_CLOSED) {
378 ALOGW("%s(%d) tried to set to %d but already CLOSED", __func__, getId(), state);
379
380 // Once CLOSING, we can only move to CLOSED state.
381 } else if (mState == AAUDIO_STREAM_STATE_CLOSING
382 && state != AAUDIO_STREAM_STATE_CLOSED) {
383 ALOGW("%s(%d) tried to set to %d but already CLOSING", __func__, getId(), state);
384
385 // Once DISCONNECTED, we can only move to CLOSING or CLOSED state.
386 } else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
387 && !(state == AAUDIO_STREAM_STATE_CLOSING
388 || state == AAUDIO_STREAM_STATE_CLOSED)) {
389 ALOGW("%s(%d) tried to set to %d but already DISCONNECTED", __func__, getId(), state);
390
391 } else {
392 mState = state;
393 }
394 }
395
waitForStateChange(aaudio_stream_state_t currentState,aaudio_stream_state_t * nextState,int64_t timeoutNanoseconds)396 aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
397 aaudio_stream_state_t *nextState,
398 int64_t timeoutNanoseconds)
399 {
400 aaudio_result_t result = updateStateMachine();
401 if (result != AAUDIO_OK) {
402 return result;
403 }
404
405 int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary
406 aaudio_stream_state_t state = getState();
407 while (state == currentState && timeoutNanoseconds > 0) {
408 if (durationNanos > timeoutNanoseconds) {
409 durationNanos = timeoutNanoseconds;
410 }
411 AudioClock::sleepForNanos(durationNanos);
412 timeoutNanoseconds -= durationNanos;
413
414 aaudio_result_t result = updateStateMachine();
415 if (result != AAUDIO_OK) {
416 return result;
417 }
418
419 state = getState();
420 }
421 if (nextState != nullptr) {
422 *nextState = state;
423 }
424 return (state == currentState) ? AAUDIO_ERROR_TIMEOUT : AAUDIO_OK;
425 }
426
427 // This registers the callback thread with the server before
428 // passing control to the app. This gives the server an opportunity to boost
429 // the thread's performance characteristics.
wrapUserThread()430 void* AudioStream::wrapUserThread() {
431 void* procResult = nullptr;
432 mThreadRegistrationResult = registerThread();
433 if (mThreadRegistrationResult == AAUDIO_OK) {
434 // Run callback loop. This may take a very long time.
435 procResult = mThreadProc(mThreadArg);
436 mThreadRegistrationResult = unregisterThread();
437 }
438 return procResult;
439 }
440
441
442 // This is the entry point for the new thread created by createThread_l().
443 // It converts the 'C' function call to a C++ method call.
AudioStream_internalThreadProc(void * threadArg)444 static void* AudioStream_internalThreadProc(void* threadArg) {
445 AudioStream *audioStream = (AudioStream *) threadArg;
446 // Prevent the stream from being deleted while being used.
447 // This is just for extra safety. It is probably not needed because
448 // this callback should be joined before the stream is closed.
449 android::sp<AudioStream> protectedStream(audioStream);
450 // Balance the incStrong() in createThread_l().
451 protectedStream->decStrong(nullptr);
452 return protectedStream->wrapUserThread();
453 }
454
455 // This is not exposed in the API.
456 // But it is still used internally to implement callbacks for MMAP mode.
createThread_l(int64_t periodNanoseconds,aaudio_audio_thread_proc_t threadProc,void * threadArg)457 aaudio_result_t AudioStream::createThread_l(int64_t periodNanoseconds,
458 aaudio_audio_thread_proc_t threadProc,
459 void* threadArg)
460 {
461 if (mHasThread) {
462 ALOGD("%s() - previous thread was not joined, join now to be safe", __func__);
463 joinThread_l(nullptr);
464 }
465 if (threadProc == nullptr) {
466 return AAUDIO_ERROR_NULL;
467 }
468 // Pass input parameters to the background thread.
469 mThreadProc = threadProc;
470 mThreadArg = threadArg;
471 setPeriodNanoseconds(periodNanoseconds);
472 mHasThread = true;
473 // Prevent this object from getting deleted before the thread has a chance to create
474 // its strong pointer. Assume the thread will call decStrong().
475 this->incStrong(nullptr);
476 int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
477 if (err != 0) {
478 android::status_t status = -errno;
479 ALOGE("%s() - pthread_create() failed, %d", __func__, status);
480 this->decStrong(nullptr); // Because the thread won't do it.
481 mHasThread = false;
482 return AAudioConvert_androidToAAudioResult(status);
483 } else {
484 // TODO Use AAudioThread or maybe AndroidThread
485 // Name the thread with an increasing index, "AAudio_#", for debugging.
486 static std::atomic<uint32_t> nextThreadIndex{1};
487 char name[16]; // max length for a pthread_name
488 uint32_t index = nextThreadIndex++;
489 // Wrap the index so that we do not hit the 16 char limit
490 // and to avoid hard-to-read large numbers.
491 index = index % 100000; // arbitrary
492 snprintf(name, sizeof(name), "AAudio_%u", index);
493 err = pthread_setname_np(mThread, name);
494 ALOGW_IF((err != 0), "Could not set name of AAudio thread. err = %d", err);
495
496 return AAUDIO_OK;
497 }
498 }
499
joinThread(void ** returnArg)500 aaudio_result_t AudioStream::joinThread(void** returnArg) {
501 // This may get temporarily unlocked in the MMAP release() when joining callback threads.
502 std::lock_guard<std::mutex> lock(mStreamLock);
503 return joinThread_l(returnArg);
504 }
505
506 // This must be called under mStreamLock.
joinThread_l(void ** returnArg)507 aaudio_result_t AudioStream::joinThread_l(void** returnArg) {
508 if (!mHasThread) {
509 ALOGD("joinThread() - but has no thread or already join()ed");
510 return AAUDIO_ERROR_INVALID_STATE;
511 }
512 aaudio_result_t result = AAUDIO_OK;
513 // If the callback is stopping the stream because the app passed back STOP
514 // then we don't need to join(). The thread is already about to exit.
515 if (!pthread_equal(pthread_self(), mThread)) {
516 // Called from an app thread. Not the callback.
517 // Unlock because the callback may be trying to stop the stream but is blocked.
518 mStreamLock.unlock();
519 int err = pthread_join(mThread, returnArg);
520 mStreamLock.lock();
521 if (err) {
522 ALOGE("%s() pthread_join() returns err = %d", __func__, err);
523 result = AAudioConvert_androidToAAudioResult(-err);
524 } else {
525 ALOGD("%s() pthread_join succeeded", __func__);
526 // Prevent joining a second time, which has undefined behavior.
527 mHasThread = false;
528 }
529 } else {
530 ALOGD("%s() pthread_join() called on itself!", __func__);
531 }
532 return (result != AAUDIO_OK) ? result : mThreadRegistrationResult;
533 }
534
maybeCallDataCallback(void * audioData,int32_t numFrames)535 aaudio_data_callback_result_t AudioStream::maybeCallDataCallback(void *audioData,
536 int32_t numFrames) {
537 aaudio_data_callback_result_t result = AAUDIO_CALLBACK_RESULT_STOP;
538 AAudioStream_dataCallback dataCallback = getDataCallbackProc();
539 if (dataCallback != nullptr) {
540 // Store thread ID of caller to detect stop() and close() calls from callback.
541 pid_t expected = CALLBACK_THREAD_NONE;
542 if (mDataCallbackThread.compare_exchange_strong(expected, gettid())) {
543 result = (*dataCallback)(
544 (AAudioStream *) this,
545 getDataCallbackUserData(),
546 audioData,
547 numFrames);
548 mDataCallbackThread.store(CALLBACK_THREAD_NONE);
549 } else {
550 ALOGW("%s() data callback already running!", __func__);
551 }
552 }
553 return result;
554 }
555
maybeCallErrorCallback(aaudio_result_t result)556 void AudioStream::maybeCallErrorCallback(aaudio_result_t result) {
557 AAudioStream_errorCallback errorCallback = getErrorCallbackProc();
558 if (errorCallback != nullptr) {
559 // Store thread ID of caller to detect stop() and close() calls from callback.
560 pid_t expected = CALLBACK_THREAD_NONE;
561 if (mErrorCallbackThread.compare_exchange_strong(expected, gettid())) {
562 (*errorCallback)(
563 (AAudioStream *) this,
564 getErrorCallbackUserData(),
565 result);
566 mErrorCallbackThread.store(CALLBACK_THREAD_NONE);
567 } else {
568 ALOGW("%s() error callback already running!", __func__);
569 }
570 }
571 }
572
573 // Is this running on the same thread as a callback?
574 // Note: This cannot be implemented using a thread_local because that would
575 // require using a thread_local variable that is shared between streams.
576 // So a thread_local variable would prevent stopping or closing stream A from
577 // a callback on stream B, which is currently legal and not so terrible.
collidesWithCallback() const578 bool AudioStream::collidesWithCallback() const {
579 pid_t thisThread = gettid();
580 // Compare the current thread ID with the thread ID of the callback
581 // threads to see it they match. If so then this code is being
582 // called from one of the stream callback functions.
583 return ((mErrorCallbackThread.load() == thisThread)
584 || (mDataCallbackThread.load() == thisThread));
585 }
586
587 #if AAUDIO_USE_VOLUME_SHAPER
applyVolumeShaper(const::android::media::VolumeShaper::Configuration & configuration,const::android::media::VolumeShaper::Operation & operation)588 ::android::binder::Status AudioStream::MyPlayerBase::applyVolumeShaper(
589 const ::android::media::VolumeShaper::Configuration& configuration,
590 const ::android::media::VolumeShaper::Operation& operation) {
591 android::sp<AudioStream> audioStream;
592 {
593 std::lock_guard<std::mutex> lock(mParentLock);
594 audioStream = mParent.promote();
595 }
596 if (audioStream) {
597 return audioStream->applyVolumeShaper(configuration, operation);
598 }
599 return android::NO_ERROR;
600 }
601 #endif
602
setDuckAndMuteVolume(float duckAndMuteVolume)603 void AudioStream::setDuckAndMuteVolume(float duckAndMuteVolume) {
604 ALOGD("%s() to %f", __func__, duckAndMuteVolume);
605 std::lock_guard<std::mutex> lock(mStreamLock);
606 mDuckAndMuteVolume = duckAndMuteVolume;
607 doSetVolume(); // apply this change
608 }
609
registerWithAudioManager(const android::sp<AudioStream> & parent)610 void AudioStream::MyPlayerBase::registerWithAudioManager(const android::sp<AudioStream>& parent) {
611 std::lock_guard<std::mutex> lock(mParentLock);
612 mParent = parent;
613 if (!mRegistered) {
614 init(android::PLAYER_TYPE_AAUDIO, AAudioConvert_usageToInternal(parent->getUsage()),
615 (audio_session_t)parent->getSessionId());
616 mRegistered = true;
617 }
618 }
619
unregisterWithAudioManager()620 void AudioStream::MyPlayerBase::unregisterWithAudioManager() {
621 std::lock_guard<std::mutex> lock(mParentLock);
622 if (mRegistered) {
623 baseDestroy();
624 mRegistered = false;
625 }
626 }
627
playerSetVolume()628 android::status_t AudioStream::MyPlayerBase::playerSetVolume() {
629 android::sp<AudioStream> audioStream;
630 {
631 std::lock_guard<std::mutex> lock(mParentLock);
632 audioStream = mParent.promote();
633 }
634 if (audioStream) {
635 // No pan and only left volume is taken into account from IPLayer interface
636 audioStream->setDuckAndMuteVolume(mVolumeMultiplierL /* mPanMultiplierL */);
637 }
638 return android::NO_ERROR;
639 }
640
destroy()641 void AudioStream::MyPlayerBase::destroy() {
642 unregisterWithAudioManager();
643 }
644
645 } // namespace aaudio
646