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