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