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