• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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