blob: 9dd5e4cdf23aadfb0bad761ff3331ed9c2a3fad1 [file] [log] [blame]
Wei Jiaec044b02018-02-19 12:41:23 -08001/*
2**
3** Copyright 2018, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaPlayer2AudioOutput"
20#include <mediaplayer2/MediaPlayer2AudioOutput.h>
21
22#include <cutils/properties.h> // for property_get
23#include <utils/Log.h>
24
25#include <media/AudioPolicyHelper.h>
26#include <media/AudioTrack.h>
27#include <media/stagefright/foundation/ADebug.h>
28
29namespace {
30
31const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup.
32
33} // anonymous namespace
34
35namespace android {
36
37// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
38/* static */ int MediaPlayer2AudioOutput::mMinBufferCount = 4;
39/* static */ bool MediaPlayer2AudioOutput::mIsOnEmulator = false;
40
41status_t MediaPlayer2AudioOutput::dump(int fd, const Vector<String16>& args) const {
42 const size_t SIZE = 256;
43 char buffer[SIZE];
44 String8 result;
45
46 result.append(" MediaPlayer2AudioOutput\n");
47 snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
48 mStreamType, mLeftVolume, mRightVolume);
49 result.append(buffer);
50 snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
51 mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
52 result.append(buffer);
53 snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
54 mAuxEffectId, mSendLevel);
55 result.append(buffer);
56
57 ::write(fd, result.string(), result.size());
58 if (mTrack != 0) {
59 mTrack->dump(fd, args);
60 }
61 return NO_ERROR;
62}
63
64MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
65 const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
66 : mCallback(NULL),
67 mCallbackCookie(NULL),
68 mCallbackData(NULL),
69 mStreamType(AUDIO_STREAM_MUSIC),
70 mLeftVolume(1.0),
71 mRightVolume(1.0),
72 mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
73 mSampleRateHz(0),
74 mMsecsPerFrame(0),
75 mFrameSize(0),
76 mSessionId(sessionId),
77 mUid(uid),
78 mPid(pid),
79 mSendLevel(0.0),
80 mAuxEffectId(0),
81 mFlags(AUDIO_OUTPUT_FLAG_NONE),
82 mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
83 mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
84 mDeviceCallbackEnabled(false),
85 mDeviceCallback(deviceCallback) {
86 ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
87 if (attr != NULL) {
88 mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
89 if (mAttributes != NULL) {
90 memcpy(mAttributes, attr, sizeof(audio_attributes_t));
91 mStreamType = audio_attributes_to_stream_type(attr);
92 }
93 } else {
94 mAttributes = NULL;
95 }
96
97 setMinBufferCount();
98}
99
100MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
101 close();
102 free(mAttributes);
103 delete mCallbackData;
104}
105
106//static
107void MediaPlayer2AudioOutput::setMinBufferCount() {
108 char value[PROPERTY_VALUE_MAX];
109 if (property_get("ro.kernel.qemu", value, 0)) {
110 mIsOnEmulator = true;
111 mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
112 }
113}
114
115// static
116bool MediaPlayer2AudioOutput::isOnEmulator() {
117 setMinBufferCount(); // benign race wrt other threads
118 return mIsOnEmulator;
119}
120
121// static
122int MediaPlayer2AudioOutput::getMinBufferCount() {
123 setMinBufferCount(); // benign race wrt other threads
124 return mMinBufferCount;
125}
126
127ssize_t MediaPlayer2AudioOutput::bufferSize() const {
128 Mutex::Autolock lock(mLock);
129 if (mTrack == 0) {
130 return NO_INIT;
131 }
132 return mTrack->frameCount() * mFrameSize;
133}
134
135ssize_t MediaPlayer2AudioOutput::frameCount() const {
136 Mutex::Autolock lock(mLock);
137 if (mTrack == 0) {
138 return NO_INIT;
139 }
140 return mTrack->frameCount();
141}
142
143ssize_t MediaPlayer2AudioOutput::channelCount() const {
144 Mutex::Autolock lock(mLock);
145 if (mTrack == 0) {
146 return NO_INIT;
147 }
148 return mTrack->channelCount();
149}
150
151ssize_t MediaPlayer2AudioOutput::frameSize() const {
152 Mutex::Autolock lock(mLock);
153 if (mTrack == 0) {
154 return NO_INIT;
155 }
156 return mFrameSize;
157}
158
159uint32_t MediaPlayer2AudioOutput::latency () const {
160 Mutex::Autolock lock(mLock);
161 if (mTrack == 0) {
162 return 0;
163 }
164 return mTrack->latency();
165}
166
167float MediaPlayer2AudioOutput::msecsPerFrame() const {
168 Mutex::Autolock lock(mLock);
169 return mMsecsPerFrame;
170}
171
172status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const {
173 Mutex::Autolock lock(mLock);
174 if (mTrack == 0) {
175 return NO_INIT;
176 }
177 return mTrack->getPosition(position);
178}
179
180status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const {
181 Mutex::Autolock lock(mLock);
182 if (mTrack == 0) {
183 return NO_INIT;
184 }
185 return mTrack->getTimestamp(ts);
186}
187
188// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
189// as it acquires locks and may query the audio driver.
190//
191// Some calls could conceivably retrieve extrapolated data instead of
192// accessing getTimestamp() or getPosition() every time a data buffer with
193// a media time is received.
194//
195// Calculate duration of played samples if played at normal rate (i.e., 1.0).
196int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const {
197 Mutex::Autolock lock(mLock);
198 if (mTrack == 0 || mSampleRateHz == 0) {
199 return 0;
200 }
201
202 uint32_t numFramesPlayed;
203 int64_t numFramesPlayedAtUs;
204 AudioTimestamp ts;
205
206 status_t res = mTrack->getTimestamp(ts);
207 if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
208 numFramesPlayed = ts.mPosition;
209 numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
210 //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
211 } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
212 numFramesPlayed = 0;
213 numFramesPlayedAtUs = nowUs;
214 //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
215 // numFramesPlayed, (long long)numFramesPlayedAtUs);
216 } else { // case 3: transitory at new track or audio fast tracks.
217 res = mTrack->getPosition(&numFramesPlayed);
218 CHECK_EQ(res, (status_t)OK);
219 numFramesPlayedAtUs = nowUs;
220 numFramesPlayedAtUs += 1000LL * mTrack->latency() / 2; /* XXX */
221 //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
222 }
223
224 // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
225 // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
226 int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
227 + nowUs - numFramesPlayedAtUs;
228 if (durationUs < 0) {
229 // Occurs when numFramesPlayed position is very small and the following:
230 // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
231 // numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
232 // (2) In case 3, using getPosition and adding mAudioSink->latency() to
233 // numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
234 //
235 // Both of these are transitory conditions.
236 ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
237 durationUs = 0;
238 }
239 ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
240 (long long)durationUs, (long long)nowUs,
241 numFramesPlayed, (long long)numFramesPlayedAtUs);
242 return durationUs;
243}
244
245status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const {
246 Mutex::Autolock lock(mLock);
247 if (mTrack == 0) {
248 return NO_INIT;
249 }
250 ExtendedTimestamp ets;
251 status_t status = mTrack->getTimestamp(&ets);
252 if (status == OK || status == WOULD_BLOCK) {
253 *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
254 }
255 return status;
256}
257
258status_t MediaPlayer2AudioOutput::setParameters(const String8& keyValuePairs) {
259 Mutex::Autolock lock(mLock);
260 if (mTrack == 0) {
261 return NO_INIT;
262 }
263 return mTrack->setParameters(keyValuePairs);
264}
265
266String8 MediaPlayer2AudioOutput::getParameters(const String8& keys) {
267 Mutex::Autolock lock(mLock);
268 if (mTrack == 0) {
269 return String8::empty();
270 }
271 return mTrack->getParameters(keys);
272}
273
274void MediaPlayer2AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
275 Mutex::Autolock lock(mLock);
276 if (attributes == NULL) {
277 free(mAttributes);
278 mAttributes = NULL;
279 } else {
280 if (mAttributes == NULL) {
281 mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
282 }
283 memcpy(mAttributes, attributes, sizeof(audio_attributes_t));
284 mStreamType = audio_attributes_to_stream_type(attributes);
285 }
286}
287
288void MediaPlayer2AudioOutput::setAudioStreamType(audio_stream_type_t streamType) {
289 Mutex::Autolock lock(mLock);
290 // do not allow direct stream type modification if attributes have been set
291 if (mAttributes == NULL) {
292 mStreamType = streamType;
293 }
294}
295
296void MediaPlayer2AudioOutput::close_l() {
297 mTrack.clear();
298}
299
300status_t MediaPlayer2AudioOutput::open(
301 uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
Dichen Zhang303bd2d2018-09-28 12:52:49 -0700302 audio_format_t format,
Wei Jiaec044b02018-02-19 12:41:23 -0800303 AudioCallback cb, void *cookie,
304 audio_output_flags_t flags,
305 const audio_offload_info_t *offloadInfo,
306 bool doNotReconnect,
307 uint32_t suggestedFrameCount) {
Dichen Zhang303bd2d2018-09-28 12:52:49 -0700308 ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask,
309 format, mSessionId, flags);
Wei Jiaec044b02018-02-19 12:41:23 -0800310
311 // offloading is only supported in callback mode for now.
312 // offloadInfo must be present if offload flag is set
313 if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
314 ((cb == NULL) || (offloadInfo == NULL))) {
315 return BAD_VALUE;
316 }
317
318 // compute frame count for the AudioTrack internal buffer
Dichen Zhang303bd2d2018-09-28 12:52:49 -0700319 const size_t frameCount =
320 ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) ? 0 : suggestedFrameCount;
Wei Jiaec044b02018-02-19 12:41:23 -0800321
322 if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
323 channelMask = audio_channel_out_mask_from_count(channelCount);
324 if (0 == channelMask) {
325 ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
326 return NO_INIT;
327 }
328 }
329
330 Mutex::Autolock lock(mLock);
331 mCallback = cb;
332 mCallbackCookie = cookie;
333
334 sp<AudioTrack> t;
335 CallbackData *newcbd = NULL;
336
337 ALOGV("creating new AudioTrack");
338
339 if (mCallback != NULL) {
340 newcbd = new CallbackData(this);
341 t = new AudioTrack(
342 mStreamType,
343 sampleRate,
344 format,
345 channelMask,
346 frameCount,
347 flags,
348 CallbackWrapper,
349 newcbd,
350 0, // notification frames
351 mSessionId,
352 AudioTrack::TRANSFER_CALLBACK,
353 offloadInfo,
354 mUid,
355 mPid,
356 mAttributes,
357 doNotReconnect,
358 1.0f, // default value for maxRequiredSpeed
359 mSelectedDeviceId);
360 } else {
361 // TODO: Due to buffer memory concerns, we use a max target playback speed
362 // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
363 // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed.
364 const float targetSpeed =
365 std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed);
366 ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
367 "track target speed:%f clamped from playback speed:%f",
368 targetSpeed, mPlaybackRate.mSpeed);
369 t = new AudioTrack(
370 mStreamType,
371 sampleRate,
372 format,
373 channelMask,
374 frameCount,
375 flags,
376 NULL, // callback
377 NULL, // user data
378 0, // notification frames
379 mSessionId,
380 AudioTrack::TRANSFER_DEFAULT,
381 NULL, // offload info
382 mUid,
383 mPid,
384 mAttributes,
385 doNotReconnect,
386 targetSpeed,
387 mSelectedDeviceId);
388 }
389
390 if ((t == 0) || (t->initCheck() != NO_ERROR)) {
391 ALOGE("Unable to create audio track");
392 delete newcbd;
393 // t goes out of scope, so reference count drops to zero
394 return NO_INIT;
395 } else {
396 // successful AudioTrack initialization implies a legacy stream type was generated
397 // from the audio attributes
398 mStreamType = t->streamType();
399 }
400
401 CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
402
403 mCallbackData = newcbd;
404 ALOGV("setVolume");
405 t->setVolume(mLeftVolume, mRightVolume);
406
407 mSampleRateHz = sampleRate;
408 mFlags = flags;
409 mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
410 mFrameSize = t->frameSize();
411 mTrack = t;
412
413 return updateTrack_l();
414}
415
416status_t MediaPlayer2AudioOutput::updateTrack_l() {
417 if (mTrack == NULL) {
418 return NO_ERROR;
419 }
420
421 status_t res = NO_ERROR;
422 // Note some output devices may give us a direct track even though we don't specify it.
423 // Example: Line application b/17459982.
424 if ((mTrack->getFlags()
425 & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
426 res = mTrack->setPlaybackRate(mPlaybackRate);
427 if (res == NO_ERROR) {
428 mTrack->setAuxEffectSendLevel(mSendLevel);
429 res = mTrack->attachAuxEffect(mAuxEffectId);
430 }
431 }
432 mTrack->setOutputDevice(mSelectedDeviceId);
433 if (mDeviceCallbackEnabled) {
434 mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
435 }
436 ALOGV("updateTrack_l() DONE status %d", res);
437 return res;
438}
439
440status_t MediaPlayer2AudioOutput::start() {
441 ALOGV("start");
442 Mutex::Autolock lock(mLock);
443 if (mCallbackData != NULL) {
444 mCallbackData->endTrackSwitch();
445 }
446 if (mTrack != 0) {
447 mTrack->setVolume(mLeftVolume, mRightVolume);
448 mTrack->setAuxEffectSendLevel(mSendLevel);
449 status_t status = mTrack->start();
450 return status;
451 }
452 return NO_INIT;
453}
454
455ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) {
456 Mutex::Autolock lock(mLock);
457 LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
458
459 //ALOGV("write(%p, %u)", buffer, size);
460 if (mTrack != 0) {
461 return mTrack->write(buffer, size, blocking);
462 }
463 return NO_INIT;
464}
465
466void MediaPlayer2AudioOutput::stop() {
467 ALOGV("stop");
468 Mutex::Autolock lock(mLock);
469 if (mTrack != 0) {
470 mTrack->stop();
471 }
472}
473
474void MediaPlayer2AudioOutput::flush() {
475 ALOGV("flush");
476 Mutex::Autolock lock(mLock);
477 if (mTrack != 0) {
478 mTrack->flush();
479 }
480}
481
482void MediaPlayer2AudioOutput::pause() {
483 ALOGV("pause");
484 Mutex::Autolock lock(mLock);
485 if (mTrack != 0) {
486 mTrack->pause();
487 }
488}
489
490void MediaPlayer2AudioOutput::close() {
491 ALOGV("close");
492 sp<AudioTrack> track;
493 {
494 Mutex::Autolock lock(mLock);
495 track = mTrack;
496 close_l(); // clears mTrack
497 }
498 // destruction of the track occurs outside of mutex.
499}
500
501void MediaPlayer2AudioOutput::setVolume(float left, float right) {
502 ALOGV("setVolume(%f, %f)", left, right);
503 Mutex::Autolock lock(mLock);
504 mLeftVolume = left;
505 mRightVolume = right;
506 if (mTrack != 0) {
507 mTrack->setVolume(left, right);
508 }
509}
510
511status_t MediaPlayer2AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) {
512 ALOGV("setPlaybackRate(%f %f %d %d)",
513 rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
514 Mutex::Autolock lock(mLock);
515 if (mTrack == 0) {
516 // remember rate so that we can set it when the track is opened
517 mPlaybackRate = rate;
518 return OK;
519 }
520 status_t res = mTrack->setPlaybackRate(rate);
521 if (res != NO_ERROR) {
522 return res;
523 }
524 // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
525 CHECK_GT(rate.mSpeed, 0.f);
526 mPlaybackRate = rate;
527 if (mSampleRateHz != 0) {
528 mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
529 }
530 return res;
531}
532
533status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
Dichen Zhang790249b2018-09-13 15:08:14 -0700534 ALOGV("getPlaybackRate");
Wei Jiaec044b02018-02-19 12:41:23 -0800535 Mutex::Autolock lock(mLock);
536 if (mTrack == 0) {
537 return NO_INIT;
538 }
539 *rate = mTrack->getPlaybackRate();
540 return NO_ERROR;
541}
542
543status_t MediaPlayer2AudioOutput::setAuxEffectSendLevel(float level) {
544 ALOGV("setAuxEffectSendLevel(%f)", level);
545 Mutex::Autolock lock(mLock);
546 mSendLevel = level;
547 if (mTrack != 0) {
548 return mTrack->setAuxEffectSendLevel(level);
549 }
550 return NO_ERROR;
551}
552
553status_t MediaPlayer2AudioOutput::attachAuxEffect(int effectId) {
554 ALOGV("attachAuxEffect(%d)", effectId);
555 Mutex::Autolock lock(mLock);
556 mAuxEffectId = effectId;
557 if (mTrack != 0) {
558 return mTrack->attachAuxEffect(effectId);
559 }
560 return NO_ERROR;
561}
562
563status_t MediaPlayer2AudioOutput::setOutputDevice(audio_port_handle_t deviceId) {
564 ALOGV("setOutputDevice(%d)", deviceId);
565 Mutex::Autolock lock(mLock);
566 mSelectedDeviceId = deviceId;
567 if (mTrack != 0) {
568 return mTrack->setOutputDevice(deviceId);
569 }
570 return NO_ERROR;
571}
572
573status_t MediaPlayer2AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId) {
574 ALOGV("getRoutedDeviceId");
575 Mutex::Autolock lock(mLock);
576 if (mTrack != 0) {
577 mRoutedDeviceId = mTrack->getRoutedDeviceId();
578 }
579 *deviceId = mRoutedDeviceId;
580 return NO_ERROR;
581}
582
583status_t MediaPlayer2AudioOutput::enableAudioDeviceCallback(bool enabled) {
584 ALOGV("enableAudioDeviceCallback, %d", enabled);
585 Mutex::Autolock lock(mLock);
586 mDeviceCallbackEnabled = enabled;
587 if (mTrack != 0) {
588 status_t status;
589 if (enabled) {
590 status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
591 } else {
592 status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
593 }
594 return status;
595 }
596 return NO_ERROR;
597}
598
599// static
600void MediaPlayer2AudioOutput::CallbackWrapper(
601 int event, void *cookie, void *info) {
602 //ALOGV("callbackwrapper");
603 CallbackData *data = (CallbackData*)cookie;
604 // lock to ensure we aren't caught in the middle of a track switch.
605 data->lock();
606 MediaPlayer2AudioOutput *me = data->getOutput();
607 AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
608 if (me == NULL) {
609 // no output set, likely because the track was scheduled to be reused
610 // by another player, but the format turned out to be incompatible.
611 data->unlock();
612 if (buffer != NULL) {
613 buffer->size = 0;
614 }
615 return;
616 }
617
618 switch(event) {
619 case AudioTrack::EVENT_MORE_DATA: {
620 size_t actualSize = (*me->mCallback)(
621 me, buffer->raw, buffer->size, me->mCallbackCookie,
622 CB_EVENT_FILL_BUFFER);
623
624 // Log when no data is returned from the callback.
625 // (1) We may have no data (especially with network streaming sources).
626 // (2) We may have reached the EOS and the audio track is not stopped yet.
627 // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS.
628 // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill).
629 //
630 // This is a benign busy-wait, with the next data request generated 10 ms or more later;
631 // nevertheless for power reasons, we don't want to see too many of these.
632
633 ALOGV_IF(actualSize == 0 && buffer->size > 0, "callbackwrapper: empty buffer returned");
634
635 buffer->size = actualSize;
636 } break;
637
638 case AudioTrack::EVENT_STREAM_END:
639 // currently only occurs for offloaded callbacks
640 ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
641 (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
642 me->mCallbackCookie, CB_EVENT_STREAM_END);
643 break;
644
645 case AudioTrack::EVENT_NEW_IAUDIOTRACK :
646 ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
647 (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
648 me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
649 break;
650
651 case AudioTrack::EVENT_UNDERRUN:
652 // This occurs when there is no data available, typically
653 // when there is a failure to supply data to the AudioTrack. It can also
654 // occur in non-offloaded mode when the audio device comes out of standby.
655 //
656 // If an AudioTrack underruns it outputs silence. Since this happens suddenly
657 // it may sound like an audible pop or glitch.
658 //
659 // The underrun event is sent once per track underrun; the condition is reset
660 // when more data is sent to the AudioTrack.
661 ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
662 break;
663
664 default:
665 ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
666 }
667
668 data->unlock();
669}
670
671audio_session_t MediaPlayer2AudioOutput::getSessionId() const
672{
673 Mutex::Autolock lock(mLock);
674 return mSessionId;
675}
676
677uint32_t MediaPlayer2AudioOutput::getSampleRate() const
678{
679 Mutex::Autolock lock(mLock);
680 if (mTrack == 0) {
681 return 0;
682 }
683 return mTrack->getSampleRate();
684}
685
686int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const
687{
688 Mutex::Autolock lock(mLock);
689 if (mTrack == 0) {
690 return 0;
691 }
692 int64_t duration;
693 if (mTrack->getBufferDurationInUs(&duration) != OK) {
694 return 0;
695 }
696 return duration;
697}
698
699} // namespace android