MediaPlayer2: remove MediaPlayer2Engine
Test: MediaPlayer2 plays
Bug: 63934228
Change-Id: I2459082bf6bbe2384ed94901b1f8f28559345888
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index 17fa01c..1fa8789 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -9,7 +9,7 @@
srcs: [
"JAudioTrack.cpp",
- "MediaPlayer2Manager.cpp",
+ "MediaPlayer2AudioOutput.cpp",
"mediaplayer2.cpp",
],
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
new file mode 100644
index 0000000..a8e1d1f
--- /dev/null
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -0,0 +1,727 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaPlayer2AudioOutput"
+#include <mediaplayer2/MediaPlayer2AudioOutput.h>
+
+#include <cutils/properties.h> // for property_get
+#include <utils/Log.h>
+
+#include <media/AudioPolicyHelper.h>
+#include <media/AudioTrack.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace {
+
+const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup.
+
+} // anonymous namespace
+
+namespace android {
+
+// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
+/* static */ int MediaPlayer2AudioOutput::mMinBufferCount = 4;
+/* static */ bool MediaPlayer2AudioOutput::mIsOnEmulator = false;
+
+status_t MediaPlayer2AudioOutput::dump(int fd, const Vector<String16>& args) const {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append(" MediaPlayer2AudioOutput\n");
+ snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
+ mStreamType, mLeftVolume, mRightVolume);
+ result.append(buffer);
+ snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
+ mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
+ result.append(buffer);
+ snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
+ mAuxEffectId, mSendLevel);
+ result.append(buffer);
+
+ ::write(fd, result.string(), result.size());
+ if (mTrack != 0) {
+ mTrack->dump(fd, args);
+ }
+ return NO_ERROR;
+}
+
+MediaPlayer2AudioOutput::MediaPlayer2AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
+ const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
+ : mCallback(NULL),
+ mCallbackCookie(NULL),
+ mCallbackData(NULL),
+ mStreamType(AUDIO_STREAM_MUSIC),
+ mLeftVolume(1.0),
+ mRightVolume(1.0),
+ mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
+ mSampleRateHz(0),
+ mMsecsPerFrame(0),
+ mFrameSize(0),
+ mSessionId(sessionId),
+ mUid(uid),
+ mPid(pid),
+ mSendLevel(0.0),
+ mAuxEffectId(0),
+ mFlags(AUDIO_OUTPUT_FLAG_NONE),
+ mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
+ mDeviceCallbackEnabled(false),
+ mDeviceCallback(deviceCallback) {
+ ALOGV("MediaPlayer2AudioOutput(%d)", sessionId);
+ if (attr != NULL) {
+ mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+ if (mAttributes != NULL) {
+ memcpy(mAttributes, attr, sizeof(audio_attributes_t));
+ mStreamType = audio_attributes_to_stream_type(attr);
+ }
+ } else {
+ mAttributes = NULL;
+ }
+
+ setMinBufferCount();
+}
+
+MediaPlayer2AudioOutput::~MediaPlayer2AudioOutput() {
+ close();
+ free(mAttributes);
+ delete mCallbackData;
+}
+
+//static
+void MediaPlayer2AudioOutput::setMinBufferCount() {
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("ro.kernel.qemu", value, 0)) {
+ mIsOnEmulator = true;
+ mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
+ }
+}
+
+// static
+bool MediaPlayer2AudioOutput::isOnEmulator() {
+ setMinBufferCount(); // benign race wrt other threads
+ return mIsOnEmulator;
+}
+
+// static
+int MediaPlayer2AudioOutput::getMinBufferCount() {
+ setMinBufferCount(); // benign race wrt other threads
+ return mMinBufferCount;
+}
+
+ssize_t MediaPlayer2AudioOutput::bufferSize() const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ return mTrack->frameCount() * mFrameSize;
+}
+
+ssize_t MediaPlayer2AudioOutput::frameCount() const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ return mTrack->frameCount();
+}
+
+ssize_t MediaPlayer2AudioOutput::channelCount() const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ return mTrack->channelCount();
+}
+
+ssize_t MediaPlayer2AudioOutput::frameSize() const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ return mFrameSize;
+}
+
+uint32_t MediaPlayer2AudioOutput::latency () const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return 0;
+ }
+ return mTrack->latency();
+}
+
+float MediaPlayer2AudioOutput::msecsPerFrame() const {
+ Mutex::Autolock lock(mLock);
+ return mMsecsPerFrame;
+}
+
+status_t MediaPlayer2AudioOutput::getPosition(uint32_t *position) const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ return mTrack->getPosition(position);
+}
+
+status_t MediaPlayer2AudioOutput::getTimestamp(AudioTimestamp &ts) const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ return mTrack->getTimestamp(ts);
+}
+
+// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
+// as it acquires locks and may query the audio driver.
+//
+// Some calls could conceivably retrieve extrapolated data instead of
+// accessing getTimestamp() or getPosition() every time a data buffer with
+// a media time is received.
+//
+// Calculate duration of played samples if played at normal rate (i.e., 1.0).
+int64_t MediaPlayer2AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0 || mSampleRateHz == 0) {
+ return 0;
+ }
+
+ uint32_t numFramesPlayed;
+ int64_t numFramesPlayedAtUs;
+ AudioTimestamp ts;
+
+ status_t res = mTrack->getTimestamp(ts);
+ if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
+ numFramesPlayed = ts.mPosition;
+ numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
+ //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
+ } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
+ numFramesPlayed = 0;
+ numFramesPlayedAtUs = nowUs;
+ //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
+ // numFramesPlayed, (long long)numFramesPlayedAtUs);
+ } else { // case 3: transitory at new track or audio fast tracks.
+ res = mTrack->getPosition(&numFramesPlayed);
+ CHECK_EQ(res, (status_t)OK);
+ numFramesPlayedAtUs = nowUs;
+ numFramesPlayedAtUs += 1000LL * mTrack->latency() / 2; /* XXX */
+ //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
+ }
+
+ // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
+ // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
+ int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
+ + nowUs - numFramesPlayedAtUs;
+ if (durationUs < 0) {
+ // Occurs when numFramesPlayed position is very small and the following:
+ // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
+ // numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
+ // (2) In case 3, using getPosition and adding mAudioSink->latency() to
+ // numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
+ //
+ // Both of these are transitory conditions.
+ ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
+ durationUs = 0;
+ }
+ ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
+ (long long)durationUs, (long long)nowUs,
+ numFramesPlayed, (long long)numFramesPlayedAtUs);
+ return durationUs;
+}
+
+status_t MediaPlayer2AudioOutput::getFramesWritten(uint32_t *frameswritten) const {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ ExtendedTimestamp ets;
+ status_t status = mTrack->getTimestamp(&ets);
+ if (status == OK || status == WOULD_BLOCK) {
+ *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
+ }
+ return status;
+}
+
+status_t MediaPlayer2AudioOutput::setParameters(const String8& keyValuePairs) {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ return mTrack->setParameters(keyValuePairs);
+}
+
+String8 MediaPlayer2AudioOutput::getParameters(const String8& keys) {
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return String8::empty();
+ }
+ return mTrack->getParameters(keys);
+}
+
+void MediaPlayer2AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
+ Mutex::Autolock lock(mLock);
+ if (attributes == NULL) {
+ free(mAttributes);
+ mAttributes = NULL;
+ } else {
+ if (mAttributes == NULL) {
+ mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+ }
+ memcpy(mAttributes, attributes, sizeof(audio_attributes_t));
+ mStreamType = audio_attributes_to_stream_type(attributes);
+ }
+}
+
+void MediaPlayer2AudioOutput::setAudioStreamType(audio_stream_type_t streamType) {
+ Mutex::Autolock lock(mLock);
+ // do not allow direct stream type modification if attributes have been set
+ if (mAttributes == NULL) {
+ mStreamType = streamType;
+ }
+}
+
+void MediaPlayer2AudioOutput::close_l() {
+ mTrack.clear();
+}
+
+status_t MediaPlayer2AudioOutput::open(
+ uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
+ audio_format_t format, int bufferCount,
+ AudioCallback cb, void *cookie,
+ audio_output_flags_t flags,
+ const audio_offload_info_t *offloadInfo,
+ bool doNotReconnect,
+ uint32_t suggestedFrameCount) {
+ ALOGV("open(%u, %d, 0x%x, 0x%x, %d, %d 0x%x)", sampleRate, channelCount, channelMask,
+ format, bufferCount, mSessionId, flags);
+
+ // offloading is only supported in callback mode for now.
+ // offloadInfo must be present if offload flag is set
+ if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
+ ((cb == NULL) || (offloadInfo == NULL))) {
+ return BAD_VALUE;
+ }
+
+ // compute frame count for the AudioTrack internal buffer
+ size_t frameCount;
+ if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ frameCount = 0; // AudioTrack will get frame count from AudioFlinger
+ } else {
+ // try to estimate the buffer processing fetch size from AudioFlinger.
+ // framesPerBuffer is approximate and generally correct, except when it's not :-).
+ uint32_t afSampleRate;
+ size_t afFrameCount;
+ if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+ if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
+ return NO_INIT;
+ }
+ const size_t framesPerBuffer =
+ (unsigned long long)sampleRate * afFrameCount / afSampleRate;
+
+ if (bufferCount == 0) {
+ // use suggestedFrameCount
+ bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
+ }
+ // Check argument bufferCount against the mininum buffer count
+ if (bufferCount != 0 && bufferCount < mMinBufferCount) {
+ ALOGV("bufferCount (%d) increased to %d", bufferCount, mMinBufferCount);
+ bufferCount = mMinBufferCount;
+ }
+ // if frameCount is 0, then AudioTrack will get frame count from AudioFlinger
+ // which will be the minimum size permitted.
+ frameCount = bufferCount * framesPerBuffer;
+ }
+
+ if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
+ channelMask = audio_channel_out_mask_from_count(channelCount);
+ if (0 == channelMask) {
+ ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
+ return NO_INIT;
+ }
+ }
+
+ Mutex::Autolock lock(mLock);
+ mCallback = cb;
+ mCallbackCookie = cookie;
+
+ sp<AudioTrack> t;
+ CallbackData *newcbd = NULL;
+
+ ALOGV("creating new AudioTrack");
+
+ if (mCallback != NULL) {
+ newcbd = new CallbackData(this);
+ t = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ channelMask,
+ frameCount,
+ flags,
+ CallbackWrapper,
+ newcbd,
+ 0, // notification frames
+ mSessionId,
+ AudioTrack::TRANSFER_CALLBACK,
+ offloadInfo,
+ mUid,
+ mPid,
+ mAttributes,
+ doNotReconnect,
+ 1.0f, // default value for maxRequiredSpeed
+ mSelectedDeviceId);
+ } else {
+ // TODO: Due to buffer memory concerns, we use a max target playback speed
+ // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
+ // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed.
+ const float targetSpeed =
+ std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed);
+ ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
+ "track target speed:%f clamped from playback speed:%f",
+ targetSpeed, mPlaybackRate.mSpeed);
+ t = new AudioTrack(
+ mStreamType,
+ sampleRate,
+ format,
+ channelMask,
+ frameCount,
+ flags,
+ NULL, // callback
+ NULL, // user data
+ 0, // notification frames
+ mSessionId,
+ AudioTrack::TRANSFER_DEFAULT,
+ NULL, // offload info
+ mUid,
+ mPid,
+ mAttributes,
+ doNotReconnect,
+ targetSpeed,
+ mSelectedDeviceId);
+ }
+
+ if ((t == 0) || (t->initCheck() != NO_ERROR)) {
+ ALOGE("Unable to create audio track");
+ delete newcbd;
+ // t goes out of scope, so reference count drops to zero
+ return NO_INIT;
+ } else {
+ // successful AudioTrack initialization implies a legacy stream type was generated
+ // from the audio attributes
+ mStreamType = t->streamType();
+ }
+
+ CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
+
+ mCallbackData = newcbd;
+ ALOGV("setVolume");
+ t->setVolume(mLeftVolume, mRightVolume);
+
+ mSampleRateHz = sampleRate;
+ mFlags = flags;
+ mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
+ mFrameSize = t->frameSize();
+ mTrack = t;
+
+ return updateTrack_l();
+}
+
+status_t MediaPlayer2AudioOutput::updateTrack_l() {
+ if (mTrack == NULL) {
+ return NO_ERROR;
+ }
+
+ status_t res = NO_ERROR;
+ // Note some output devices may give us a direct track even though we don't specify it.
+ // Example: Line application b/17459982.
+ if ((mTrack->getFlags()
+ & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
+ res = mTrack->setPlaybackRate(mPlaybackRate);
+ if (res == NO_ERROR) {
+ mTrack->setAuxEffectSendLevel(mSendLevel);
+ res = mTrack->attachAuxEffect(mAuxEffectId);
+ }
+ }
+ mTrack->setOutputDevice(mSelectedDeviceId);
+ if (mDeviceCallbackEnabled) {
+ mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+ }
+ ALOGV("updateTrack_l() DONE status %d", res);
+ return res;
+}
+
+status_t MediaPlayer2AudioOutput::start() {
+ ALOGV("start");
+ Mutex::Autolock lock(mLock);
+ if (mCallbackData != NULL) {
+ mCallbackData->endTrackSwitch();
+ }
+ if (mTrack != 0) {
+ mTrack->setVolume(mLeftVolume, mRightVolume);
+ mTrack->setAuxEffectSendLevel(mSendLevel);
+ status_t status = mTrack->start();
+ return status;
+ }
+ return NO_INIT;
+}
+
+ssize_t MediaPlayer2AudioOutput::write(const void* buffer, size_t size, bool blocking) {
+ Mutex::Autolock lock(mLock);
+ LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
+
+ //ALOGV("write(%p, %u)", buffer, size);
+ if (mTrack != 0) {
+ return mTrack->write(buffer, size, blocking);
+ }
+ return NO_INIT;
+}
+
+void MediaPlayer2AudioOutput::stop() {
+ ALOGV("stop");
+ Mutex::Autolock lock(mLock);
+ if (mTrack != 0) {
+ mTrack->stop();
+ }
+}
+
+void MediaPlayer2AudioOutput::flush() {
+ ALOGV("flush");
+ Mutex::Autolock lock(mLock);
+ if (mTrack != 0) {
+ mTrack->flush();
+ }
+}
+
+void MediaPlayer2AudioOutput::pause() {
+ ALOGV("pause");
+ Mutex::Autolock lock(mLock);
+ if (mTrack != 0) {
+ mTrack->pause();
+ }
+}
+
+void MediaPlayer2AudioOutput::close() {
+ ALOGV("close");
+ sp<AudioTrack> track;
+ {
+ Mutex::Autolock lock(mLock);
+ track = mTrack;
+ close_l(); // clears mTrack
+ }
+ // destruction of the track occurs outside of mutex.
+}
+
+void MediaPlayer2AudioOutput::setVolume(float left, float right) {
+ ALOGV("setVolume(%f, %f)", left, right);
+ Mutex::Autolock lock(mLock);
+ mLeftVolume = left;
+ mRightVolume = right;
+ if (mTrack != 0) {
+ mTrack->setVolume(left, right);
+ }
+}
+
+status_t MediaPlayer2AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) {
+ ALOGV("setPlaybackRate(%f %f %d %d)",
+ rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ // remember rate so that we can set it when the track is opened
+ mPlaybackRate = rate;
+ return OK;
+ }
+ status_t res = mTrack->setPlaybackRate(rate);
+ if (res != NO_ERROR) {
+ return res;
+ }
+ // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
+ CHECK_GT(rate.mSpeed, 0.f);
+ mPlaybackRate = rate;
+ if (mSampleRateHz != 0) {
+ mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
+ }
+ return res;
+}
+
+status_t MediaPlayer2AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) {
+ ALOGV("setPlaybackRate");
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return NO_INIT;
+ }
+ *rate = mTrack->getPlaybackRate();
+ return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::setAuxEffectSendLevel(float level) {
+ ALOGV("setAuxEffectSendLevel(%f)", level);
+ Mutex::Autolock lock(mLock);
+ mSendLevel = level;
+ if (mTrack != 0) {
+ return mTrack->setAuxEffectSendLevel(level);
+ }
+ return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::attachAuxEffect(int effectId) {
+ ALOGV("attachAuxEffect(%d)", effectId);
+ Mutex::Autolock lock(mLock);
+ mAuxEffectId = effectId;
+ if (mTrack != 0) {
+ return mTrack->attachAuxEffect(effectId);
+ }
+ return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::setOutputDevice(audio_port_handle_t deviceId) {
+ ALOGV("setOutputDevice(%d)", deviceId);
+ Mutex::Autolock lock(mLock);
+ mSelectedDeviceId = deviceId;
+ if (mTrack != 0) {
+ return mTrack->setOutputDevice(deviceId);
+ }
+ return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId) {
+ ALOGV("getRoutedDeviceId");
+ Mutex::Autolock lock(mLock);
+ if (mTrack != 0) {
+ mRoutedDeviceId = mTrack->getRoutedDeviceId();
+ }
+ *deviceId = mRoutedDeviceId;
+ return NO_ERROR;
+}
+
+status_t MediaPlayer2AudioOutput::enableAudioDeviceCallback(bool enabled) {
+ ALOGV("enableAudioDeviceCallback, %d", enabled);
+ Mutex::Autolock lock(mLock);
+ mDeviceCallbackEnabled = enabled;
+ if (mTrack != 0) {
+ status_t status;
+ if (enabled) {
+ status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
+ } else {
+ status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
+ }
+ return status;
+ }
+ return NO_ERROR;
+}
+
+// static
+void MediaPlayer2AudioOutput::CallbackWrapper(
+ int event, void *cookie, void *info) {
+ //ALOGV("callbackwrapper");
+ CallbackData *data = (CallbackData*)cookie;
+ // lock to ensure we aren't caught in the middle of a track switch.
+ data->lock();
+ MediaPlayer2AudioOutput *me = data->getOutput();
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+ if (me == NULL) {
+ // no output set, likely because the track was scheduled to be reused
+ // by another player, but the format turned out to be incompatible.
+ data->unlock();
+ if (buffer != NULL) {
+ buffer->size = 0;
+ }
+ return;
+ }
+
+ switch(event) {
+ case AudioTrack::EVENT_MORE_DATA: {
+ size_t actualSize = (*me->mCallback)(
+ me, buffer->raw, buffer->size, me->mCallbackCookie,
+ CB_EVENT_FILL_BUFFER);
+
+ // Log when no data is returned from the callback.
+ // (1) We may have no data (especially with network streaming sources).
+ // (2) We may have reached the EOS and the audio track is not stopped yet.
+ // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS.
+ // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill).
+ //
+ // This is a benign busy-wait, with the next data request generated 10 ms or more later;
+ // nevertheless for power reasons, we don't want to see too many of these.
+
+ ALOGV_IF(actualSize == 0 && buffer->size > 0, "callbackwrapper: empty buffer returned");
+
+ buffer->size = actualSize;
+ } break;
+
+ case AudioTrack::EVENT_STREAM_END:
+ // currently only occurs for offloaded callbacks
+ ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
+ (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+ me->mCallbackCookie, CB_EVENT_STREAM_END);
+ break;
+
+ case AudioTrack::EVENT_NEW_IAUDIOTRACK :
+ ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
+ (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
+ me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
+ break;
+
+ case AudioTrack::EVENT_UNDERRUN:
+ // This occurs when there is no data available, typically
+ // when there is a failure to supply data to the AudioTrack. It can also
+ // occur in non-offloaded mode when the audio device comes out of standby.
+ //
+ // If an AudioTrack underruns it outputs silence. Since this happens suddenly
+ // it may sound like an audible pop or glitch.
+ //
+ // The underrun event is sent once per track underrun; the condition is reset
+ // when more data is sent to the AudioTrack.
+ ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
+ break;
+
+ default:
+ ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
+ }
+
+ data->unlock();
+}
+
+audio_session_t MediaPlayer2AudioOutput::getSessionId() const
+{
+ Mutex::Autolock lock(mLock);
+ return mSessionId;
+}
+
+uint32_t MediaPlayer2AudioOutput::getSampleRate() const
+{
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return 0;
+ }
+ return mTrack->getSampleRate();
+}
+
+int64_t MediaPlayer2AudioOutput::getBufferDurationInUs() const
+{
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0) {
+ return 0;
+ }
+ int64_t duration;
+ if (mTrack->getBufferDurationInUs(&duration) != OK) {
+ return 0;
+ }
+ return duration;
+}
+
+} // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.cpp b/media/libmediaplayer2/MediaPlayer2Manager.cpp
deleted file mode 100644
index 39b102c..0000000
--- a/media/libmediaplayer2/MediaPlayer2Manager.cpp
+++ /dev/null
@@ -1,2119 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-// Proxy for media player implementations
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "MediaPlayer2Manager"
-#include <utils/Log.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <unistd.h>
-
-#include <string.h>
-
-#include <cutils/atomic.h>
-#include <cutils/properties.h> // for property_get
-
-#include <utils/misc.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
-#include <utils/Errors.h> // for status_t
-#include <utils/String8.h>
-#include <utils/SystemClock.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-#include <media/AudioPolicyHelper.h>
-#include <media/DataSourceDesc.h>
-#include <media/MediaHTTPService.h>
-#include <media/Metadata.h>
-#include <media/AudioTrack.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/NdkWrapper.h>
-
-#include <media/stagefright/InterfaceUtils.h>
-#include <media/stagefright/MediaCodecList.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooperRoster.h>
-#include <media/stagefright/SurfaceUtils.h>
-#include <mediautils/BatteryNotifier.h>
-
-#include <mediaplayer2/MediaPlayer2EngineClient.h>
-#include <mediaplayer2/MediaPlayer2Interface.h>
-
-#include <memunreachable/memunreachable.h>
-#include <system/audio.h>
-#include <system/window.h>
-
-#include <private/android_filesystem_config.h>
-
-#include <nuplayer2/NuPlayer2Driver.h>
-#include "MediaPlayer2Manager.h"
-
-static const int kDumpLockRetries = 50;
-static const int kDumpLockSleepUs = 20000;
-
-namespace {
-using android::media::Metadata;
-using android::status_t;
-using android::OK;
-using android::BAD_VALUE;
-using android::NOT_ENOUGH_DATA;
-using android::Parcel;
-
-// Max number of entries in the filter.
-const int kMaxFilterSize = 64; // I pulled that out of thin air.
-
-const float kMaxRequiredSpeed = 8.0f; // for PCM tracks allow up to 8x speedup.
-
-// FIXME: Move all the metadata related function in the Metadata.cpp
-
-
-// Unmarshall a filter from a Parcel.
-// Filter format in a parcel:
-//
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | number of entries (n) |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | metadata type 1 |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | metadata type 2 |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// ....
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | metadata type n |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-// @param p Parcel that should start with a filter.
-// @param[out] filter On exit contains the list of metadata type to be
-// filtered.
-// @param[out] status On exit contains the status code to be returned.
-// @return true if the parcel starts with a valid filter.
-bool unmarshallFilter(const Parcel& p,
- Metadata::Filter *filter,
- status_t *status)
-{
- int32_t val;
- if (p.readInt32(&val) != OK)
- {
- ALOGE("Failed to read filter's length");
- *status = NOT_ENOUGH_DATA;
- return false;
- }
-
- if( val > kMaxFilterSize || val < 0)
- {
- ALOGE("Invalid filter len %d", val);
- *status = BAD_VALUE;
- return false;
- }
-
- const size_t num = val;
-
- filter->clear();
- filter->setCapacity(num);
-
- size_t size = num * sizeof(Metadata::Type);
-
-
- if (p.dataAvail() < size)
- {
- ALOGE("Filter too short expected %zu but got %zu", size, p.dataAvail());
- *status = NOT_ENOUGH_DATA;
- return false;
- }
-
- const Metadata::Type *data =
- static_cast<const Metadata::Type*>(p.readInplace(size));
-
- if (NULL == data)
- {
- ALOGE("Filter had no data");
- *status = BAD_VALUE;
- return false;
- }
-
- // TODO: The stl impl of vector would be more efficient here
- // because it degenerates into a memcpy on pod types. Try to
- // replace later or use stl::set.
- for (size_t i = 0; i < num; ++i)
- {
- filter->add(*data);
- ++data;
- }
- *status = OK;
- return true;
-}
-
-// @param filter Of metadata type.
-// @param val To be searched.
-// @return true if a match was found.
-bool findMetadata(const Metadata::Filter& filter, const int32_t val)
-{
- // Deal with empty and ANY right away
- if (filter.isEmpty()) return false;
- if (filter[0] == Metadata::kAny) return true;
-
- return filter.indexOf(val) >= 0;
-}
-
-} // anonymous namespace
-
-
-namespace {
-using android::Parcel;
-using android::String16;
-
-// marshalling tag indicating flattened utf16 tags
-// keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java
-const int32_t kAudioAttributesMarshallTagFlattenTags = 1;
-
-// Audio attributes format in a parcel:
-//
-// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | usage |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | content_type |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | source |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | flags |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | kAudioAttributesMarshallTagFlattenTags | // ignore tags if not found
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-// | flattened tags in UTF16 |
-// | ... |
-// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-//
-// @param p Parcel that contains audio attributes.
-// @param[out] attributes On exit points to an initialized audio_attributes_t structure
-// @param[out] status On exit contains the status code to be returned.
-void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attributes)
-{
- attributes->usage = (audio_usage_t) parcel.readInt32();
- attributes->content_type = (audio_content_type_t) parcel.readInt32();
- attributes->source = (audio_source_t) parcel.readInt32();
- attributes->flags = (audio_flags_mask_t) parcel.readInt32();
- const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags);
- if (hasFlattenedTag) {
- // the tags are UTF16, convert to UTF8
- String16 tags = parcel.readString16();
- ssize_t realTagSize = utf16_to_utf8_length(tags.string(), tags.size());
- if (realTagSize <= 0) {
- strcpy(attributes->tags, "");
- } else {
- // copy the flattened string into the attributes as the destination for the conversion:
- // copying array size -1, array for tags was calloc'd, no need to NULL-terminate it
- size_t tagSize = realTagSize > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 ?
- AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 : realTagSize;
- utf16_to_utf8(tags.string(), tagSize, attributes->tags,
- sizeof(attributes->tags) / sizeof(attributes->tags[0]));
- }
- } else {
- ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values");
- strcpy(attributes->tags, "");
- }
-}
-} // anonymous namespace
-
-
-namespace android {
-
-extern ALooperRoster gLooperRoster;
-
-MediaPlayer2Manager gMediaPlayer2Manager;
-
-// TODO: Find real cause of Audio/Video delay in PV framework and remove this workaround
-/* static */ int MediaPlayer2Manager::AudioOutput::mMinBufferCount = 4;
-/* static */ bool MediaPlayer2Manager::AudioOutput::mIsOnEmulator = false;
-
-// static
-MediaPlayer2Manager& MediaPlayer2Manager::get() {
- return gMediaPlayer2Manager;
-}
-
-MediaPlayer2Manager::MediaPlayer2Manager() {
- ALOGV("MediaPlayer2Manager created");
- // TODO: remove all unnecessary pid/uid handling.
- mPid = IPCThreadState::self()->getCallingPid();
- mUid = IPCThreadState::self()->getCallingUid();
- mNextConnId = 1;
-}
-
-MediaPlayer2Manager::~MediaPlayer2Manager() {
- ALOGV("MediaPlayer2Manager destroyed");
-}
-
-sp<MediaPlayer2Engine> MediaPlayer2Manager::create(
- const sp<MediaPlayer2EngineClient>& client,
- audio_session_t audioSessionId)
-{
- int32_t connId = android_atomic_inc(&mNextConnId);
-
- sp<Client> c = new Client(
- mPid, connId, client, audioSessionId, mUid);
-
- if (!c->init()) {
- return NULL;
- }
-
- ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, mPid, mUid);
-
- wp<Client> w = c;
- {
- Mutex::Autolock lock(mLock);
- mClients.add(w);
- }
- return c;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::dump(int fd, const Vector<String16>& args) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- result.append(" AudioOutput\n");
- snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n",
- mStreamType, mLeftVolume, mRightVolume);
- result.append(buffer);
- snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n",
- mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1);
- result.append(buffer);
- snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n",
- mAuxEffectId, mSendLevel);
- result.append(buffer);
-
- ::write(fd, result.string(), result.size());
- if (mTrack != 0) {
- mTrack->dump(fd, args);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::dump(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- result.append(" Client\n");
- snprintf(buffer, 255, " pid(%d), connId(%d), status(%d), looping(%s)\n",
- mPid, mConnId, mStatus, mLoop?"true": "false");
- result.append(buffer);
-
- sp<MediaPlayer2Interface> p;
- sp<AudioOutput> audioOutput;
- bool locked = false;
- for (int i = 0; i < kDumpLockRetries; ++i) {
- if (mLock.tryLock() == NO_ERROR) {
- locked = true;
- break;
- }
- usleep(kDumpLockSleepUs);
- }
-
- if (locked) {
- p = mPlayer;
- audioOutput = mAudioOutput;
- mLock.unlock();
- } else {
- result.append(" lock is taken, no dump from player and audio output\n");
- }
- write(fd, result.string(), result.size());
-
- if (p != NULL) {
- p->dump(fd, args);
- }
- if (audioOutput != 0) {
- audioOutput->dump(fd, args);
- }
- write(fd, "\n", 1);
- return NO_ERROR;
-}
-
-/**
- * The only arguments this understands right now are -c, -von and -voff,
- * which are parsed by ALooperRoster::dump()
- */
-status_t MediaPlayer2Manager::dump(int fd, const Vector<String16>& args)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- SortedVector< sp<Client> > clients; //to serialise the mutex unlock & client destruction.
-
- if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
- snprintf(buffer, SIZE, "Permission Denial: "
- "can't dump MediaPlayer2Manager from pid=%d, uid=%d\n",
- mPid, mUid);
- result.append(buffer);
- } else {
- Mutex::Autolock lock(mLock);
- for (int i = 0, n = mClients.size(); i < n; ++i) {
- sp<Client> c = mClients[i].promote();
- if (c != 0) c->dump(fd, args);
- clients.add(c);
- }
-
- result.append(" Files opened and/or mapped:\n");
- snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
- FILE *f = fopen(buffer, "r");
- if (f) {
- while (!feof(f)) {
- fgets(buffer, SIZE, f);
- if (strstr(buffer, " /storage/") ||
- strstr(buffer, " /system/sounds/") ||
- strstr(buffer, " /data/") ||
- strstr(buffer, " /system/media/")) {
- result.append(" ");
- result.append(buffer);
- }
- }
- fclose(f);
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- result.append("\n");
- }
-
- snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
- DIR *d = opendir(buffer);
- if (d) {
- struct dirent *ent;
- while((ent = readdir(d)) != NULL) {
- if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
- snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
- struct stat s;
- if (lstat(buffer, &s) == 0) {
- if ((s.st_mode & S_IFMT) == S_IFLNK) {
- char linkto[256];
- int len = readlink(buffer, linkto, sizeof(linkto));
- if(len > 0) {
- if(len > 255) {
- linkto[252] = '.';
- linkto[253] = '.';
- linkto[254] = '.';
- linkto[255] = 0;
- } else {
- linkto[len] = 0;
- }
- if (strstr(linkto, "/storage/") == linkto ||
- strstr(linkto, "/system/sounds/") == linkto ||
- strstr(linkto, "/data/") == linkto ||
- strstr(linkto, "/system/media/") == linkto) {
- result.append(" ");
- result.append(buffer);
- result.append(" -> ");
- result.append(linkto);
- result.append("\n");
- }
- }
- } else {
- result.append(" unexpected type for ");
- result.append(buffer);
- result.append("\n");
- }
- }
- }
- }
- closedir(d);
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- result.append("\n");
- }
-
- gLooperRoster.dump(fd, args);
-
- bool dumpMem = false;
- bool unreachableMemory = false;
- for (size_t i = 0; i < args.size(); i++) {
- if (args[i] == String16("-m")) {
- dumpMem = true;
- } else if (args[i] == String16("--unreachable")) {
- unreachableMemory = true;
- }
- }
- if (dumpMem) {
- result.append("\nDumping memory:\n");
- std::string s = dumpMemoryAddresses(100 /* limit */);
- result.append(s.c_str(), s.size());
- }
- if (unreachableMemory) {
- result.append("\nDumping unreachable memory:\n");
- // TODO - should limit be an argument parameter?
- // TODO: enable GetUnreachableMemoryString if it's part of stable API
- //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
- //result.append(s.c_str(), s.size());
- }
- }
- write(fd, result.string(), result.size());
- return NO_ERROR;
-}
-
-void MediaPlayer2Manager::removeClient(const wp<Client>& client)
-{
- Mutex::Autolock lock(mLock);
- mClients.remove(client);
-}
-
-bool MediaPlayer2Manager::hasClient(wp<Client> client)
-{
- Mutex::Autolock lock(mLock);
- return mClients.indexOf(client) != NAME_NOT_FOUND;
-}
-
-MediaPlayer2Manager::Client::Client(
- pid_t pid,
- int32_t connId,
- const sp<MediaPlayer2EngineClient>& client,
- audio_session_t audioSessionId,
- uid_t uid)
-{
- ALOGV("Client(%d) constructor", connId);
- mPid = pid;
- mConnId = connId;
- mClient = client;
- mLoop = false;
- mStatus = NO_INIT;
- mAudioSessionId = audioSessionId;
- mUid = uid;
- mAudioAttributes = NULL;
-
-#if CALLBACK_ANTAGONIZER
- ALOGD("create Antagonizer");
- mAntagonizer = new Antagonizer(notify, this);
-#endif
-}
-
-bool MediaPlayer2Manager::Client::init() {
- sp<MediaPlayer2Interface> p = new NuPlayer2Driver(mPid, mUid);
- status_t init_result = p->initCheck();
- if (init_result != NO_ERROR) {
- ALOGE("Failed to create player object, initCheck failed(%d)", init_result);
- return false;
- }
-
- p->setNotifyCallback(this, notify);
- mAudioDeviceUpdatedListener = new AudioDeviceUpdatedNotifier(p);
- mAudioOutput = new AudioOutput(mAudioSessionId, mUid,
- mPid, mAudioAttributes, mAudioDeviceUpdatedListener);
- p->setAudioSink(mAudioOutput);
-
- mPlayer = p;
- return true;
-}
-
-MediaPlayer2Manager::Client::~Client()
-{
- ALOGV("Client(%d) destructor pid = %d", mConnId, mPid);
- mAudioOutput.clear();
- wp<Client> client(this);
- disconnect();
- gMediaPlayer2Manager.removeClient(client);
- if (mAudioAttributes != NULL) {
- free(mAudioAttributes);
- }
- mAudioDeviceUpdatedListener.clear();
-}
-
-void MediaPlayer2Manager::Client::disconnect()
-{
- ALOGV("disconnect(%d) from pid %d", mConnId, mPid);
- // grab local reference and clear main reference to prevent future
- // access to object
- sp<MediaPlayer2Interface> p;
- {
- Mutex::Autolock l(mLock);
- p = mPlayer;
- mClient.clear();
- mPlayer.clear();
- }
-
- // clear the notification to prevent callbacks to dead client
- // and reset the player. We assume the player will serialize
- // access to itself if necessary.
- if (p != 0) {
- p->setNotifyCallback(0, 0);
-#if CALLBACK_ANTAGONIZER
- ALOGD("kill Antagonizer");
- mAntagonizer->kill();
-#endif
- p->reset();
- }
-
- {
- Mutex::Autolock l(mLock);
- disconnectNativeWindow_l();
- }
-
- IPCThreadState::self()->flushCommands();
-}
-
-void MediaPlayer2Manager::Client::AudioDeviceUpdatedNotifier::onAudioDeviceUpdate(
- audio_io_handle_t audioIo,
- audio_port_handle_t deviceId) {
- sp<MediaPlayer2Interface> listener = mListener.promote();
- if (listener != NULL) {
- listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
- } else {
- ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
- }
-}
-
-status_t MediaPlayer2Manager::Client::setDataSource(
- const sp<DataSourceDesc> &dsd) {
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == NULL) {
- return NO_INIT;
- }
-
- if (dsd == NULL) {
- return BAD_VALUE;
- }
-
- status_t status = p->setDataSource(dsd);
- if (status != OK) {
- ALOGE("setDataSource error: %d", status);
- return status;
- }
-
- return status;
-}
-
-status_t MediaPlayer2Manager::Client::prepareNextDataSource(
- const sp<DataSourceDesc> &dsd) {
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == NULL) {
- return NO_INIT;
- }
-
- if (dsd == NULL) {
- return BAD_VALUE;
- }
-
- status_t status = p->prepareNextDataSource(dsd);
- if (status != OK) {
- ALOGE("prepareNextDataSource error: %d", status);
- }
-
- return status;
-}
-
-status_t MediaPlayer2Manager::Client::playNextDataSource(int64_t srcId) {
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == NULL) {
- return NO_INIT;
- }
-
- status_t status = p->playNextDataSource(srcId);
- if (status != OK) {
- ALOGE("playNextDataSource error: %d", status);
- }
-
- return status;
-}
-
-void MediaPlayer2Manager::Client::disconnectNativeWindow_l() {
- if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
- status_t err = native_window_api_disconnect(
- mConnectedWindow->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
- mConnectedWindow.clear();
-}
-
-status_t MediaPlayer2Manager::Client::setVideoSurfaceTexture(
- const sp<ANativeWindowWrapper>& nww)
-{
- ALOGV("[%d] setVideoSurfaceTexture(%p)",
- mConnId,
- (nww == NULL ? NULL : nww->getANativeWindow()));
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
-
- if (nww != NULL && nww->getANativeWindow() != NULL) {
- if (mConnectedWindow != NULL
- && mConnectedWindow->getANativeWindow() == nww->getANativeWindow()) {
- return OK;
- }
- status_t err = native_window_api_connect(
- nww->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGE("setVideoSurfaceTexture failed: %d", err);
- // Note that we must do the reset before disconnecting from the ANW.
- // Otherwise queue/dequeue calls could be made on the disconnected
- // ANW, which may result in errors.
- reset();
-
- Mutex::Autolock lock(mLock);
- disconnectNativeWindow_l();
-
- return err;
- }
- }
-
- // Note that we must set the player's new GraphicBufferProducer before
- // disconnecting the old one. Otherwise queue/dequeue calls could be made
- // on the disconnected ANW, which may result in errors.
- status_t err = p->setVideoSurfaceTexture(nww);
-
- mLock.lock();
- disconnectNativeWindow_l();
-
- if (err == OK) {
- mConnectedWindow = nww;
- mLock.unlock();
- } else if (nww != NULL) {
- mLock.unlock();
- status_t err = native_window_api_disconnect(
- nww->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
-
- if (err != OK) {
- ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
- strerror(-err), err);
- }
- }
-
- return err;
-}
-
-status_t MediaPlayer2Manager::Client::invoke(const Parcel& request,
- Parcel *reply)
-{
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == NULL) return UNKNOWN_ERROR;
- return p->invoke(request, reply);
-}
-
-// This call doesn't need to access the native player.
-status_t MediaPlayer2Manager::Client::setMetadataFilter(const Parcel& filter)
-{
- status_t status;
- media::Metadata::Filter allow, drop;
-
- if (unmarshallFilter(filter, &allow, &status) &&
- unmarshallFilter(filter, &drop, &status)) {
- Mutex::Autolock lock(mLock);
-
- mMetadataAllow = allow;
- mMetadataDrop = drop;
- }
- return status;
-}
-
-status_t MediaPlayer2Manager::Client::getMetadata(
- bool update_only, bool /*apply_filter*/, Parcel *reply)
-{
- sp<MediaPlayer2Interface> player = getPlayer();
- if (player == 0) return UNKNOWN_ERROR;
-
- status_t status;
- // Placeholder for the return code, updated by the caller.
- reply->writeInt32(-1);
-
- media::Metadata::Filter ids;
-
- // We don't block notifications while we fetch the data. We clear
- // mMetadataUpdated first so we don't lose notifications happening
- // during the rest of this call.
- {
- Mutex::Autolock lock(mLock);
- if (update_only) {
- ids = mMetadataUpdated;
- }
- mMetadataUpdated.clear();
- }
-
- media::Metadata metadata(reply);
-
- metadata.appendHeader();
- status = player->getMetadata(ids, reply);
-
- if (status != OK) {
- metadata.resetParcel();
- ALOGE("getMetadata failed %d", status);
- return status;
- }
-
- // FIXME: ement filtering on the result. Not critical since
- // filtering takes place on the update notifications already. This
- // would be when all the metadata are fetch and a filter is set.
-
- // Everything is fine, update the metadata length.
- metadata.updateLength();
- return OK;
-}
-
-status_t MediaPlayer2Manager::Client::setBufferingSettings(
- const BufferingSettings& buffering)
-{
- ALOGV("[%d] setBufferingSettings{%s}",
- mConnId, buffering.toString().string());
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->setBufferingSettings(buffering);
-}
-
-status_t MediaPlayer2Manager::Client::getBufferingSettings(
- BufferingSettings* buffering /* nonnull */)
-{
- sp<MediaPlayer2Interface> p = getPlayer();
- // TODO: create mPlayer on demand.
- if (p == 0) return UNKNOWN_ERROR;
- status_t ret = p->getBufferingSettings(buffering);
- if (ret == NO_ERROR) {
- ALOGV("[%d] getBufferingSettings{%s}",
- mConnId, buffering->toString().string());
- } else {
- ALOGE("[%d] getBufferingSettings returned %d", mConnId, ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2Manager::Client::prepareAsync()
-{
- ALOGV("[%d] prepareAsync", mConnId);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- status_t ret = p->prepareAsync();
-#if CALLBACK_ANTAGONIZER
- ALOGD("start Antagonizer");
- if (ret == NO_ERROR) mAntagonizer->start();
-#endif
- return ret;
-}
-
-status_t MediaPlayer2Manager::Client::start()
-{
- ALOGV("[%d] start", mConnId);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- p->setLooping(mLoop);
- return p->start();
-}
-
-status_t MediaPlayer2Manager::Client::stop()
-{
- ALOGV("[%d] stop", mConnId);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->stop();
-}
-
-status_t MediaPlayer2Manager::Client::pause()
-{
- ALOGV("[%d] pause", mConnId);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->pause();
-}
-
-status_t MediaPlayer2Manager::Client::isPlaying(bool* state)
-{
- *state = false;
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- *state = p->isPlaying();
- ALOGV("[%d] isPlaying: %d", mConnId, *state);
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setPlaybackSettings(const AudioPlaybackRate& rate)
-{
- ALOGV("[%d] setPlaybackSettings(%f, %f, %d, %d)",
- mConnId, rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->setPlaybackSettings(rate);
-}
-
-status_t MediaPlayer2Manager::Client::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
-{
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- status_t ret = p->getPlaybackSettings(rate);
- if (ret == NO_ERROR) {
- ALOGV("[%d] getPlaybackSettings(%f, %f, %d, %d)",
- mConnId, rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
- } else {
- ALOGV("[%d] getPlaybackSettings returned %d", mConnId, ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2Manager::Client::setSyncSettings(
- const AVSyncSettings& sync, float videoFpsHint)
-{
- ALOGV("[%d] setSyncSettings(%u, %u, %f, %f)",
- mConnId, sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->setSyncSettings(sync, videoFpsHint);
-}
-
-status_t MediaPlayer2Manager::Client::getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
-{
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- status_t ret = p->getSyncSettings(sync, videoFps);
- if (ret == NO_ERROR) {
- ALOGV("[%d] getSyncSettings(%u, %u, %f, %f)",
- mConnId, sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
- } else {
- ALOGV("[%d] getSyncSettings returned %d", mConnId, ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2Manager::Client::getCurrentPosition(int *msec)
-{
- ALOGV("getCurrentPosition");
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- status_t ret = p->getCurrentPosition(msec);
- if (ret == NO_ERROR) {
- ALOGV("[%d] getCurrentPosition = %d", mConnId, *msec);
- } else {
- ALOGE("getCurrentPosition returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2Manager::Client::getDuration(int *msec)
-{
- ALOGV("getDuration");
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- status_t ret = p->getDuration(msec);
- if (ret == NO_ERROR) {
- ALOGV("[%d] getDuration = %d", mConnId, *msec);
- } else {
- ALOGE("getDuration returned %d", ret);
- }
- return ret;
-}
-
-status_t MediaPlayer2Manager::Client::setNextPlayer(const sp<MediaPlayer2Engine>& player) {
- ALOGV("setNextPlayer");
- Mutex::Autolock l(mLock);
- sp<Client> c = static_cast<Client*>(player.get());
- if (c != NULL && !gMediaPlayer2Manager.hasClient(c)) {
- return BAD_VALUE;
- }
-
- mNextClient = c;
-
- if (c != NULL) {
- if (mAudioOutput != NULL) {
- mAudioOutput->setNextOutput(c->mAudioOutput);
- } else {
- ALOGE("no current audio output");
- }
-
- if ((mPlayer != NULL) && (mNextClient->getPlayer() != NULL)) {
- mPlayer->setNextPlayer(mNextClient->getPlayer());
- }
- }
-
- return OK;
-}
-
-status_t MediaPlayer2Manager::Client::seekTo(int msec, MediaPlayer2SeekMode mode)
-{
- ALOGV("[%d] seekTo(%d, %d)", mConnId, msec, mode);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->seekTo(msec, mode);
-}
-
-status_t MediaPlayer2Manager::Client::reset()
-{
- ALOGV("[%d] reset", mConnId);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->reset();
-}
-
-status_t MediaPlayer2Manager::Client::notifyAt(int64_t mediaTimeUs)
-{
- ALOGV("[%d] notifyAt(%lld)", mConnId, (long long)mediaTimeUs);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->notifyAt(mediaTimeUs);
-}
-
-status_t MediaPlayer2Manager::Client::setAudioStreamType(audio_stream_type_t type)
-{
- ALOGV("[%d] setAudioStreamType(%d)", mConnId, type);
- // TODO: for hardware output, call player instead
- Mutex::Autolock l(mLock);
- if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type);
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setAudioAttributes_l(const Parcel &parcel)
-{
- if (mAudioAttributes != NULL) { free(mAudioAttributes); }
- mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
- if (mAudioAttributes == NULL) {
- return NO_MEMORY;
- }
- unmarshallAudioAttributes(parcel, mAudioAttributes);
-
- ALOGV("setAudioAttributes_l() usage=%d content=%d flags=0x%x tags=%s",
- mAudioAttributes->usage, mAudioAttributes->content_type, mAudioAttributes->flags,
- mAudioAttributes->tags);
-
- if (mAudioOutput != 0) {
- mAudioOutput->setAudioAttributes(mAudioAttributes);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setLooping(int loop)
-{
- ALOGV("[%d] setLooping(%d)", mConnId, loop);
- mLoop = loop;
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p != 0) return p->setLooping(loop);
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setVolume(float leftVolume, float rightVolume)
-{
- ALOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
-
- // for hardware output, call player instead
- sp<MediaPlayer2Interface> p = getPlayer();
- {
- Mutex::Autolock l(mLock);
- if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
- }
-
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setAuxEffectSendLevel(float level)
-{
- ALOGV("[%d] setAuxEffectSendLevel(%f)", mConnId, level);
- Mutex::Autolock l(mLock);
- if (mAudioOutput != 0) return mAudioOutput->setAuxEffectSendLevel(level);
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::attachAuxEffect(int effectId)
-{
- ALOGV("[%d] attachAuxEffect(%d)", mConnId, effectId);
- Mutex::Autolock l(mLock);
- if (mAudioOutput != 0) return mAudioOutput->attachAuxEffect(effectId);
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::Client::setParameter(int key, const Parcel &request) {
- ALOGV("[%d] setParameter(%d)", mConnId, key);
- switch (key) {
- case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
- {
- Mutex::Autolock l(mLock);
- return setAudioAttributes_l(request);
- }
- default:
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) { return UNKNOWN_ERROR; }
- return p->setParameter(key, request);
- }
-}
-
-status_t MediaPlayer2Manager::Client::getParameter(int key, Parcel *reply) {
- ALOGV("[%d] getParameter(%d)", mConnId, key);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
- return p->getParameter(key, reply);
-}
-
-void MediaPlayer2Manager::Client::notify(
- const wp<MediaPlayer2Engine> &listener, int64_t srcId,
- int msg, int ext1, int ext2, const Parcel *obj)
-{
- sp<MediaPlayer2Engine> spListener = listener.promote();
- if (spListener == NULL) {
- return;
- }
- Client* client = static_cast<Client*>(spListener.get());
-
- sp<MediaPlayer2EngineClient> c;
- sp<Client> nextClient;
- status_t errStartNext = NO_ERROR;
- {
- Mutex::Autolock l(client->mLock);
- c = client->mClient;
- if (msg == MEDIA2_PLAYBACK_COMPLETE && client->mNextClient != NULL) {
- nextClient = client->mNextClient;
-
- if (client->mAudioOutput != NULL)
- client->mAudioOutput->switchToNextOutput();
-
- errStartNext = nextClient->start();
- }
- }
-
- if (nextClient != NULL) {
- sp<MediaPlayer2EngineClient> nc;
- {
- Mutex::Autolock l(nextClient->mLock);
- nc = nextClient->mClient;
- }
- if (nc != NULL) {
- if (errStartNext == NO_ERROR) {
- nc->notify(srcId, MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0, obj);
- } else {
- nc->notify(srcId, MEDIA2_ERROR, MEDIA2_ERROR_UNKNOWN , 0, obj);
- ALOGE("gapless:start playback for next track failed, err(%d)", errStartNext);
- }
- }
- }
-
- if (MEDIA2_INFO == msg &&
- MEDIA2_INFO_METADATA_UPDATE == ext1) {
- const media::Metadata::Type metadata_type = ext2;
-
- if(client->shouldDropMetadata(metadata_type)) {
- return;
- }
-
- // Update the list of metadata that have changed. getMetadata
- // also access mMetadataUpdated and clears it.
- client->addNewMetadataUpdate(metadata_type);
- }
-
- if (c != NULL) {
- ALOGV("[%d] notify (%p, %lld, %d, %d, %d)", client->mConnId, spListener.get(),
- (long long)srcId, msg, ext1, ext2);
- c->notify(srcId, msg, ext1, ext2, obj);
- }
-}
-
-
-bool MediaPlayer2Manager::Client::shouldDropMetadata(media::Metadata::Type code) const
-{
- Mutex::Autolock lock(mLock);
-
- if (findMetadata(mMetadataDrop, code)) {
- return true;
- }
-
- if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
- return false;
- } else {
- return true;
- }
-}
-
-
-void MediaPlayer2Manager::Client::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
- Mutex::Autolock lock(mLock);
- if (mMetadataUpdated.indexOf(metadata_type) < 0) {
- mMetadataUpdated.add(metadata_type);
- }
-}
-
-// Modular DRM
-status_t MediaPlayer2Manager::Client::prepareDrm(const uint8_t uuid[16],
- const Vector<uint8_t>& drmSessionId)
-{
- ALOGV("[%d] prepareDrm", mConnId);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
-
- status_t ret = p->prepareDrm(uuid, drmSessionId);
- ALOGV("prepareDrm ret: %d", ret);
-
- return ret;
-}
-
-status_t MediaPlayer2Manager::Client::releaseDrm()
-{
- ALOGV("[%d] releaseDrm", mConnId);
- sp<MediaPlayer2Interface> p = getPlayer();
- if (p == 0) return UNKNOWN_ERROR;
-
- status_t ret = p->releaseDrm();
- ALOGV("releaseDrm ret: %d", ret);
-
- return ret;
-}
-
-status_t MediaPlayer2Manager::Client::setOutputDevice(audio_port_handle_t deviceId)
-{
- ALOGV("[%d] setOutputDevice", mConnId);
- {
- Mutex::Autolock l(mLock);
- if (mAudioOutput.get() != nullptr) {
- return mAudioOutput->setOutputDevice(deviceId);
- }
- }
- return NO_INIT;
-}
-
-status_t MediaPlayer2Manager::Client::getRoutedDeviceId(audio_port_handle_t* deviceId)
-{
- ALOGV("[%d] getRoutedDeviceId", mConnId);
- {
- Mutex::Autolock l(mLock);
- if (mAudioOutput.get() != nullptr) {
- return mAudioOutput->getRoutedDeviceId(deviceId);
- }
- }
- return NO_INIT;
-}
-
-status_t MediaPlayer2Manager::Client::enableAudioDeviceCallback(bool enabled)
-{
- ALOGV("[%d] enableAudioDeviceCallback, %d", mConnId, enabled);
- {
- Mutex::Autolock l(mLock);
- if (mAudioOutput.get() != nullptr) {
- return mAudioOutput->enableAudioDeviceCallback(enabled);
- }
- }
- return NO_INIT;
-}
-
-#if CALLBACK_ANTAGONIZER
-const int Antagonizer::interval = 10000; // 10 msecs
-
-Antagonizer::Antagonizer(
- MediaPlayer2Manager::NotifyCallback cb,
- const wp<MediaPlayer2Engine> &client) :
- mExit(false), mActive(false), mClient(client), mCb(cb)
-{
- createThread(callbackThread, this);
-}
-
-void Antagonizer::kill()
-{
- Mutex::Autolock _l(mLock);
- mActive = false;
- mExit = true;
- mCondition.wait(mLock);
-}
-
-int Antagonizer::callbackThread(void* user)
-{
- ALOGD("Antagonizer started");
- Antagonizer* p = reinterpret_cast<Antagonizer*>(user);
- while (!p->mExit) {
- if (p->mActive) {
- ALOGV("send event");
- p->mCb(p->mClient, 0, 0, 0);
- }
- usleep(interval);
- }
- Mutex::Autolock _l(p->mLock);
- p->mCondition.signal();
- ALOGD("Antagonizer stopped");
- return 0;
-}
-#endif
-
-#undef LOG_TAG
-#define LOG_TAG "AudioSink"
-MediaPlayer2Manager::AudioOutput::AudioOutput(audio_session_t sessionId, uid_t uid, int pid,
- const audio_attributes_t* attr, const sp<AudioSystem::AudioDeviceCallback>& deviceCallback)
- : mCallback(NULL),
- mCallbackCookie(NULL),
- mCallbackData(NULL),
- mStreamType(AUDIO_STREAM_MUSIC),
- mLeftVolume(1.0),
- mRightVolume(1.0),
- mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
- mSampleRateHz(0),
- mMsecsPerFrame(0),
- mFrameSize(0),
- mSessionId(sessionId),
- mUid(uid),
- mPid(pid),
- mSendLevel(0.0),
- mAuxEffectId(0),
- mFlags(AUDIO_OUTPUT_FLAG_NONE),
- mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
- mDeviceCallbackEnabled(false),
- mDeviceCallback(deviceCallback)
-{
- ALOGV("AudioOutput(%d)", sessionId);
- if (attr != NULL) {
- mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
- if (mAttributes != NULL) {
- memcpy(mAttributes, attr, sizeof(audio_attributes_t));
- mStreamType = audio_attributes_to_stream_type(attr);
- }
- } else {
- mAttributes = NULL;
- }
-
- setMinBufferCount();
-}
-
-MediaPlayer2Manager::AudioOutput::~AudioOutput()
-{
- close();
- free(mAttributes);
- delete mCallbackData;
-}
-
-//static
-void MediaPlayer2Manager::AudioOutput::setMinBufferCount()
-{
- char value[PROPERTY_VALUE_MAX];
- if (property_get("ro.kernel.qemu", value, 0)) {
- mIsOnEmulator = true;
- mMinBufferCount = 12; // to prevent systematic buffer underrun for emulator
- }
-}
-
-// static
-bool MediaPlayer2Manager::AudioOutput::isOnEmulator()
-{
- setMinBufferCount(); // benign race wrt other threads
- return mIsOnEmulator;
-}
-
-// static
-int MediaPlayer2Manager::AudioOutput::getMinBufferCount()
-{
- setMinBufferCount(); // benign race wrt other threads
- return mMinBufferCount;
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::bufferSize() const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return NO_INIT;
- return mTrack->frameCount() * mFrameSize;
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::frameCount() const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return NO_INIT;
- return mTrack->frameCount();
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::channelCount() const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return NO_INIT;
- return mTrack->channelCount();
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::frameSize() const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return NO_INIT;
- return mFrameSize;
-}
-
-uint32_t MediaPlayer2Manager::AudioOutput::latency () const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return 0;
- return mTrack->latency();
-}
-
-float MediaPlayer2Manager::AudioOutput::msecsPerFrame() const
-{
- Mutex::Autolock lock(mLock);
- return mMsecsPerFrame;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getPosition(uint32_t *position) const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return NO_INIT;
- return mTrack->getPosition(position);
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getTimestamp(AudioTimestamp &ts) const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return NO_INIT;
- return mTrack->getTimestamp(ts);
-}
-
-// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
-// as it acquires locks and may query the audio driver.
-//
-// Some calls could conceivably retrieve extrapolated data instead of
-// accessing getTimestamp() or getPosition() every time a data buffer with
-// a media time is received.
-//
-// Calculate duration of played samples if played at normal rate (i.e., 1.0).
-int64_t MediaPlayer2Manager::AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0 || mSampleRateHz == 0) {
- return 0;
- }
-
- uint32_t numFramesPlayed;
- int64_t numFramesPlayedAtUs;
- AudioTimestamp ts;
-
- status_t res = mTrack->getTimestamp(ts);
- if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
- numFramesPlayed = ts.mPosition;
- numFramesPlayedAtUs = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
- //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
- } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
- numFramesPlayed = 0;
- numFramesPlayedAtUs = nowUs;
- //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAtUs);
- } else { // case 3: transitory at new track or audio fast tracks.
- res = mTrack->getPosition(&numFramesPlayed);
- CHECK_EQ(res, (status_t)OK);
- numFramesPlayedAtUs = nowUs;
- numFramesPlayedAtUs += 1000LL * mTrack->latency() / 2; /* XXX */
- //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAtUs);
- }
-
- // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
- int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
- + nowUs - numFramesPlayedAtUs;
- if (durationUs < 0) {
- // Occurs when numFramesPlayed position is very small and the following:
- // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
- // numFramesPlayedAtUs is greater than nowUs by time more than numFramesPlayed.
- // (2) In case 3, using getPosition and adding mAudioSink->latency() to
- // numFramesPlayedAtUs, by a time amount greater than numFramesPlayed.
- //
- // Both of these are transitory conditions.
- ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
- durationUs = 0;
- }
- ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
- (long long)durationUs, (long long)nowUs,
- numFramesPlayed, (long long)numFramesPlayedAtUs);
- return durationUs;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return NO_INIT;
- ExtendedTimestamp ets;
- status_t status = mTrack->getTimestamp(&ets);
- if (status == OK || status == WOULD_BLOCK) {
- *frameswritten = (uint32_t)ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT];
- }
- return status;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::setParameters(const String8& keyValuePairs)
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return NO_INIT;
- return mTrack->setParameters(keyValuePairs);
-}
-
-String8 MediaPlayer2Manager::AudioOutput::getParameters(const String8& keys)
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return String8::empty();
- return mTrack->getParameters(keys);
-}
-
-void MediaPlayer2Manager::AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
- Mutex::Autolock lock(mLock);
- if (attributes == NULL) {
- free(mAttributes);
- mAttributes = NULL;
- } else {
- if (mAttributes == NULL) {
- mAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
- }
- memcpy(mAttributes, attributes, sizeof(audio_attributes_t));
- mStreamType = audio_attributes_to_stream_type(attributes);
- }
-}
-
-void MediaPlayer2Manager::AudioOutput::setAudioStreamType(audio_stream_type_t streamType)
-{
- Mutex::Autolock lock(mLock);
- // do not allow direct stream type modification if attributes have been set
- if (mAttributes == NULL) {
- mStreamType = streamType;
- }
-}
-
-void MediaPlayer2Manager::AudioOutput::deleteRecycledTrack_l()
-{
- ALOGV("deleteRecycledTrack_l");
- if (mRecycledTrack != 0) {
-
- if (mCallbackData != NULL) {
- mCallbackData->setOutput(NULL);
- mCallbackData->endTrackSwitch();
- }
-
- if ((mRecycledTrack->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) {
- int32_t msec = 0;
- if (!mRecycledTrack->stopped()) { // check if active
- (void)mRecycledTrack->pendingDuration(&msec);
- }
- mRecycledTrack->stop(); // ensure full data drain
- ALOGD("deleting recycled track, waiting for data drain (%d msec)", msec);
- if (msec > 0) {
- static const int32_t WAIT_LIMIT_MS = 3000;
- if (msec > WAIT_LIMIT_MS) {
- msec = WAIT_LIMIT_MS;
- }
- usleep(msec * 1000LL);
- }
- }
- // An offloaded track isn't flushed because the STREAM_END is reported
- // slightly prematurely to allow time for the gapless track switch
- // but this means that if we decide not to recycle the track there
- // could be a small amount of residual data still playing. We leave
- // AudioFlinger to drain the track.
-
- mRecycledTrack.clear();
- close_l();
- delete mCallbackData;
- mCallbackData = NULL;
- }
-}
-
-void MediaPlayer2Manager::AudioOutput::close_l()
-{
- mTrack.clear();
-}
-
-status_t MediaPlayer2Manager::AudioOutput::open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags,
- const audio_offload_info_t *offloadInfo,
- bool doNotReconnect,
- uint32_t suggestedFrameCount)
-{
- ALOGV("open(%u, %d, 0x%x, 0x%x, %d, %d 0x%x)", sampleRate, channelCount, channelMask,
- format, bufferCount, mSessionId, flags);
-
- // offloading is only supported in callback mode for now.
- // offloadInfo must be present if offload flag is set
- if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) &&
- ((cb == NULL) || (offloadInfo == NULL))) {
- return BAD_VALUE;
- }
-
- // compute frame count for the AudioTrack internal buffer
- size_t frameCount;
- if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
- frameCount = 0; // AudioTrack will get frame count from AudioFlinger
- } else {
- // try to estimate the buffer processing fetch size from AudioFlinger.
- // framesPerBuffer is approximate and generally correct, except when it's not :-).
- uint32_t afSampleRate;
- size_t afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
- return NO_INIT;
- }
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
- return NO_INIT;
- }
- const size_t framesPerBuffer =
- (unsigned long long)sampleRate * afFrameCount / afSampleRate;
-
- if (bufferCount == 0) {
- // use suggestedFrameCount
- bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
- }
- // Check argument bufferCount against the mininum buffer count
- if (bufferCount != 0 && bufferCount < mMinBufferCount) {
- ALOGV("bufferCount (%d) increased to %d", bufferCount, mMinBufferCount);
- bufferCount = mMinBufferCount;
- }
- // if frameCount is 0, then AudioTrack will get frame count from AudioFlinger
- // which will be the minimum size permitted.
- frameCount = bufferCount * framesPerBuffer;
- }
-
- if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
- channelMask = audio_channel_out_mask_from_count(channelCount);
- if (0 == channelMask) {
- ALOGE("open() error, can\'t derive mask for %d audio channels", channelCount);
- return NO_INIT;
- }
- }
-
- Mutex::Autolock lock(mLock);
- mCallback = cb;
- mCallbackCookie = cookie;
-
- // Check whether we can recycle the track
- bool reuse = false;
- bool bothOffloaded = false;
-
- if (mRecycledTrack != 0) {
- // check whether we are switching between two offloaded tracks
- bothOffloaded = (flags & mRecycledTrack->getFlags()
- & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0;
-
- // check if the existing track can be reused as-is, or if a new track needs to be created.
- reuse = true;
-
- if ((mCallbackData == NULL && mCallback != NULL) ||
- (mCallbackData != NULL && mCallback == NULL)) {
- // recycled track uses callbacks but the caller wants to use writes, or vice versa
- ALOGV("can't chain callback and write");
- reuse = false;
- } else if ((mRecycledTrack->getSampleRate() != sampleRate) ||
- (mRecycledTrack->channelCount() != (uint32_t)channelCount) ) {
- ALOGV("samplerate, channelcount differ: %u/%u Hz, %u/%d ch",
- mRecycledTrack->getSampleRate(), sampleRate,
- mRecycledTrack->channelCount(), channelCount);
- reuse = false;
- } else if (flags != mFlags) {
- ALOGV("output flags differ %08x/%08x", flags, mFlags);
- reuse = false;
- } else if (mRecycledTrack->format() != format) {
- reuse = false;
- }
- } else {
- ALOGV("no track available to recycle");
- }
-
- ALOGV_IF(bothOffloaded, "both tracks offloaded");
-
- // If we can't recycle and both tracks are offloaded
- // we must close the previous output before opening a new one
- if (bothOffloaded && !reuse) {
- ALOGV("both offloaded and not recycling");
- deleteRecycledTrack_l();
- }
-
- sp<AudioTrack> t;
- CallbackData *newcbd = NULL;
-
- // We don't attempt to create a new track if we are recycling an
- // offloaded track. But, if we are recycling a non-offloaded or we
- // are switching where one is offloaded and one isn't then we create
- // the new track in advance so that we can read additional stream info
-
- if (!(reuse && bothOffloaded)) {
- ALOGV("creating new AudioTrack");
-
- if (mCallback != NULL) {
- newcbd = new CallbackData(this);
- t = new AudioTrack(
- mStreamType,
- sampleRate,
- format,
- channelMask,
- frameCount,
- flags,
- CallbackWrapper,
- newcbd,
- 0, // notification frames
- mSessionId,
- AudioTrack::TRANSFER_CALLBACK,
- offloadInfo,
- mUid,
- mPid,
- mAttributes,
- doNotReconnect,
- 1.0f, // default value for maxRequiredSpeed
- mSelectedDeviceId);
- } else {
- // TODO: Due to buffer memory concerns, we use a max target playback speed
- // based on mPlaybackRate at the time of open (instead of kMaxRequiredSpeed),
- // also clamping the target speed to 1.0 <= targetSpeed <= kMaxRequiredSpeed.
- const float targetSpeed =
- std::min(std::max(mPlaybackRate.mSpeed, 1.0f), kMaxRequiredSpeed);
- ALOGW_IF(targetSpeed != mPlaybackRate.mSpeed,
- "track target speed:%f clamped from playback speed:%f",
- targetSpeed, mPlaybackRate.mSpeed);
- t = new AudioTrack(
- mStreamType,
- sampleRate,
- format,
- channelMask,
- frameCount,
- flags,
- NULL, // callback
- NULL, // user data
- 0, // notification frames
- mSessionId,
- AudioTrack::TRANSFER_DEFAULT,
- NULL, // offload info
- mUid,
- mPid,
- mAttributes,
- doNotReconnect,
- targetSpeed,
- mSelectedDeviceId);
- }
-
- if ((t == 0) || (t->initCheck() != NO_ERROR)) {
- ALOGE("Unable to create audio track");
- delete newcbd;
- // t goes out of scope, so reference count drops to zero
- return NO_INIT;
- } else {
- // successful AudioTrack initialization implies a legacy stream type was generated
- // from the audio attributes
- mStreamType = t->streamType();
- }
- }
-
- if (reuse) {
- CHECK(mRecycledTrack != NULL);
-
- if (!bothOffloaded) {
- if (mRecycledTrack->frameCount() != t->frameCount()) {
- ALOGV("framecount differs: %zu/%zu frames",
- mRecycledTrack->frameCount(), t->frameCount());
- reuse = false;
- }
- }
-
- if (reuse) {
- ALOGV("chaining to next output and recycling track");
- close_l();
- mTrack = mRecycledTrack;
- mRecycledTrack.clear();
- if (mCallbackData != NULL) {
- mCallbackData->setOutput(this);
- }
- delete newcbd;
- return updateTrack();
- }
- }
-
- // we're not going to reuse the track, unblock and flush it
- // this was done earlier if both tracks are offloaded
- if (!bothOffloaded) {
- deleteRecycledTrack_l();
- }
-
- CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
-
- mCallbackData = newcbd;
- ALOGV("setVolume");
- t->setVolume(mLeftVolume, mRightVolume);
-
- mSampleRateHz = sampleRate;
- mFlags = flags;
- mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
- mFrameSize = t->frameSize();
- mTrack = t;
-
- return updateTrack();
-}
-
-status_t MediaPlayer2Manager::AudioOutput::updateTrack() {
- if (mTrack == NULL) {
- return NO_ERROR;
- }
-
- status_t res = NO_ERROR;
- // Note some output devices may give us a direct track even though we don't specify it.
- // Example: Line application b/17459982.
- if ((mTrack->getFlags()
- & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT)) == 0) {
- res = mTrack->setPlaybackRate(mPlaybackRate);
- if (res == NO_ERROR) {
- mTrack->setAuxEffectSendLevel(mSendLevel);
- res = mTrack->attachAuxEffect(mAuxEffectId);
- }
- }
- mTrack->setOutputDevice(mSelectedDeviceId);
- if (mDeviceCallbackEnabled) {
- mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
- }
- ALOGV("updateTrack() DONE status %d", res);
- return res;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::start()
-{
- ALOGV("start");
- Mutex::Autolock lock(mLock);
- if (mCallbackData != NULL) {
- mCallbackData->endTrackSwitch();
- }
- if (mTrack != 0) {
- mTrack->setVolume(mLeftVolume, mRightVolume);
- mTrack->setAuxEffectSendLevel(mSendLevel);
- status_t status = mTrack->start();
- return status;
- }
- return NO_INIT;
-}
-
-void MediaPlayer2Manager::AudioOutput::setNextOutput(const sp<AudioOutput>& nextOutput) {
- Mutex::Autolock lock(mLock);
- mNextOutput = nextOutput;
-}
-
-void MediaPlayer2Manager::AudioOutput::switchToNextOutput() {
- ALOGV("switchToNextOutput");
-
- // Try to acquire the callback lock before moving track (without incurring deadlock).
- const unsigned kMaxSwitchTries = 100;
- Mutex::Autolock lock(mLock);
- for (unsigned tries = 0;;) {
- if (mTrack == 0) {
- return;
- }
- if (mNextOutput != NULL && mNextOutput != this) {
- if (mCallbackData != NULL) {
- // two alternative approaches
-#if 1
- CallbackData *callbackData = mCallbackData;
- mLock.unlock();
- // proper acquisition sequence
- callbackData->lock();
- mLock.lock();
- // Caution: it is unlikely that someone deleted our callback or changed our target
- if (callbackData != mCallbackData || mNextOutput == NULL || mNextOutput == this) {
- // fatal if we are starved out.
- LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries,
- "switchToNextOutput() cannot obtain correct lock sequence");
- callbackData->unlock();
- continue;
- }
- callbackData->mSwitching = true; // begin track switch
- callbackData->setOutput(NULL);
-#else
- // tryBeginTrackSwitch() returns false if the callback has the lock.
- if (!mCallbackData->tryBeginTrackSwitch()) {
- // fatal if we are starved out.
- LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries,
- "switchToNextOutput() cannot obtain callback lock");
- mLock.unlock();
- usleep(5 * 1000 /* usec */); // allow callback to use AudioOutput
- mLock.lock();
- continue;
- }
-#endif
- }
-
- Mutex::Autolock nextLock(mNextOutput->mLock);
-
- // If the next output track is not NULL, then it has been
- // opened already for playback.
- // This is possible even without the next player being started,
- // for example, the next player could be prepared and seeked.
- //
- // Presuming it isn't advisable to force the track over.
- if (mNextOutput->mTrack == NULL) {
- ALOGD("Recycling track for gapless playback");
- delete mNextOutput->mCallbackData;
- mNextOutput->mCallbackData = mCallbackData;
- mNextOutput->mRecycledTrack = mTrack;
- mNextOutput->mSampleRateHz = mSampleRateHz;
- mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
- mNextOutput->mFlags = mFlags;
- mNextOutput->mFrameSize = mFrameSize;
- close_l();
- mCallbackData = NULL; // destruction handled by mNextOutput
- } else {
- ALOGW("Ignoring gapless playback because next player has already started");
- // remove track in case resource needed for future players.
- if (mCallbackData != NULL) {
- mCallbackData->endTrackSwitch(); // release lock for callbacks before close.
- }
- close_l();
- }
- }
- break;
- }
-}
-
-ssize_t MediaPlayer2Manager::AudioOutput::write(const void* buffer, size_t size, bool blocking)
-{
- Mutex::Autolock lock(mLock);
- LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
-
- //ALOGV("write(%p, %u)", buffer, size);
- if (mTrack != 0) {
- return mTrack->write(buffer, size, blocking);
- }
- return NO_INIT;
-}
-
-void MediaPlayer2Manager::AudioOutput::stop()
-{
- ALOGV("stop");
- Mutex::Autolock lock(mLock);
- if (mTrack != 0) mTrack->stop();
-}
-
-void MediaPlayer2Manager::AudioOutput::flush()
-{
- ALOGV("flush");
- Mutex::Autolock lock(mLock);
- if (mTrack != 0) mTrack->flush();
-}
-
-void MediaPlayer2Manager::AudioOutput::pause()
-{
- ALOGV("pause");
- Mutex::Autolock lock(mLock);
- if (mTrack != 0) mTrack->pause();
-}
-
-void MediaPlayer2Manager::AudioOutput::close()
-{
- ALOGV("close");
- sp<AudioTrack> track;
- {
- Mutex::Autolock lock(mLock);
- track = mTrack;
- close_l(); // clears mTrack
- }
- // destruction of the track occurs outside of mutex.
-}
-
-void MediaPlayer2Manager::AudioOutput::setVolume(float left, float right)
-{
- ALOGV("setVolume(%f, %f)", left, right);
- Mutex::Autolock lock(mLock);
- mLeftVolume = left;
- mRightVolume = right;
- if (mTrack != 0) {
- mTrack->setVolume(left, right);
- }
-}
-
-status_t MediaPlayer2Manager::AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate)
-{
- ALOGV("setPlaybackRate(%f %f %d %d)",
- rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
- // remember rate so that we can set it when the track is opened
- mPlaybackRate = rate;
- return OK;
- }
- status_t res = mTrack->setPlaybackRate(rate);
- if (res != NO_ERROR) {
- return res;
- }
- // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded
- CHECK_GT(rate.mSpeed, 0.f);
- mPlaybackRate = rate;
- if (mSampleRateHz != 0) {
- mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz);
- }
- return res;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getPlaybackRate(AudioPlaybackRate *rate)
-{
- ALOGV("setPlaybackRate");
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
- return NO_INIT;
- }
- *rate = mTrack->getPlaybackRate();
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::setAuxEffectSendLevel(float level)
-{
- ALOGV("setAuxEffectSendLevel(%f)", level);
- Mutex::Autolock lock(mLock);
- mSendLevel = level;
- if (mTrack != 0) {
- return mTrack->setAuxEffectSendLevel(level);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::attachAuxEffect(int effectId)
-{
- ALOGV("attachAuxEffect(%d)", effectId);
- Mutex::Autolock lock(mLock);
- mAuxEffectId = effectId;
- if (mTrack != 0) {
- return mTrack->attachAuxEffect(effectId);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::setOutputDevice(audio_port_handle_t deviceId)
-{
- ALOGV("setOutputDevice(%d)", deviceId);
- Mutex::Autolock lock(mLock);
- mSelectedDeviceId = deviceId;
- if (mTrack != 0) {
- return mTrack->setOutputDevice(deviceId);
- }
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::getRoutedDeviceId(audio_port_handle_t* deviceId)
-{
- ALOGV("getRoutedDeviceId");
- Mutex::Autolock lock(mLock);
- if (mTrack != 0) {
- mRoutedDeviceId = mTrack->getRoutedDeviceId();
- }
- *deviceId = mRoutedDeviceId;
- return NO_ERROR;
-}
-
-status_t MediaPlayer2Manager::AudioOutput::enableAudioDeviceCallback(bool enabled)
-{
- ALOGV("enableAudioDeviceCallback, %d", enabled);
- Mutex::Autolock lock(mLock);
- mDeviceCallbackEnabled = enabled;
- if (mTrack != 0) {
- status_t status;
- if (enabled) {
- status = mTrack->addAudioDeviceCallback(mDeviceCallback.promote());
- } else {
- status = mTrack->removeAudioDeviceCallback(mDeviceCallback.promote());
- }
- return status;
- }
- return NO_ERROR;
-}
-
-// static
-void MediaPlayer2Manager::AudioOutput::CallbackWrapper(
- int event, void *cookie, void *info) {
- //ALOGV("callbackwrapper");
- CallbackData *data = (CallbackData*)cookie;
- // lock to ensure we aren't caught in the middle of a track switch.
- data->lock();
- AudioOutput *me = data->getOutput();
- AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
- if (me == NULL) {
- // no output set, likely because the track was scheduled to be reused
- // by another player, but the format turned out to be incompatible.
- data->unlock();
- if (buffer != NULL) {
- buffer->size = 0;
- }
- return;
- }
-
- switch(event) {
- case AudioTrack::EVENT_MORE_DATA: {
- size_t actualSize = (*me->mCallback)(
- me, buffer->raw, buffer->size, me->mCallbackCookie,
- CB_EVENT_FILL_BUFFER);
-
- // Log when no data is returned from the callback.
- // (1) We may have no data (especially with network streaming sources).
- // (2) We may have reached the EOS and the audio track is not stopped yet.
- // Note that AwesomePlayer/AudioPlayer will only return zero size when it reaches the EOS.
- // NuPlayer2Renderer will return zero when it doesn't have data (it doesn't block to fill).
- //
- // This is a benign busy-wait, with the next data request generated 10 ms or more later;
- // nevertheless for power reasons, we don't want to see too many of these.
-
- ALOGV_IF(actualSize == 0 && buffer->size > 0, "callbackwrapper: empty buffer returned");
-
- buffer->size = actualSize;
- } break;
-
- case AudioTrack::EVENT_STREAM_END:
- // currently only occurs for offloaded callbacks
- ALOGV("callbackwrapper: deliver EVENT_STREAM_END");
- (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_STREAM_END);
- break;
-
- case AudioTrack::EVENT_NEW_IAUDIOTRACK :
- ALOGV("callbackwrapper: deliver EVENT_TEAR_DOWN");
- (*me->mCallback)(me, NULL /* buffer */, 0 /* size */,
- me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
- break;
-
- case AudioTrack::EVENT_UNDERRUN:
- // This occurs when there is no data available, typically
- // when there is a failure to supply data to the AudioTrack. It can also
- // occur in non-offloaded mode when the audio device comes out of standby.
- //
- // If an AudioTrack underruns it outputs silence. Since this happens suddenly
- // it may sound like an audible pop or glitch.
- //
- // The underrun event is sent once per track underrun; the condition is reset
- // when more data is sent to the AudioTrack.
- ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
- break;
-
- default:
- ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
- }
-
- data->unlock();
-}
-
-audio_session_t MediaPlayer2Manager::AudioOutput::getSessionId() const
-{
- Mutex::Autolock lock(mLock);
- return mSessionId;
-}
-
-uint32_t MediaPlayer2Manager::AudioOutput::getSampleRate() const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) return 0;
- return mTrack->getSampleRate();
-}
-
-int64_t MediaPlayer2Manager::AudioOutput::getBufferDurationInUs() const
-{
- Mutex::Autolock lock(mLock);
- if (mTrack == 0) {
- return 0;
- }
- int64_t duration;
- if (mTrack->getBufferDurationInUs(&duration) != OK) {
- return 0;
- }
- return duration;
-}
-
-} // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2Manager.h b/media/libmediaplayer2/MediaPlayer2Manager.h
deleted file mode 100644
index 52bb9c6..0000000
--- a/media/libmediaplayer2/MediaPlayer2Manager.h
+++ /dev/null
@@ -1,387 +0,0 @@
-/*
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_MEDIAPLAYER2MANAGER_H
-#define ANDROID_MEDIAPLAYER2MANAGER_H
-
-#include <arpa/inet.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
-#include <media/Metadata.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <mediaplayer2/MediaPlayer2Engine.h>
-#include <mediaplayer2/MediaPlayer2Interface.h>
-
-#include <system/audio.h>
-
-namespace android {
-
-struct ANativeWindowWrapper;
-struct AudioPlaybackRate;
-class AudioTrack;
-struct AVSyncSettings;
-class DataSource;
-struct MediaHTTPService;
-class MediaPlayer2EngineClient;
-
-#define CALLBACK_ANTAGONIZER 0
-#if CALLBACK_ANTAGONIZER
-class Antagonizer {
-public:
- Antagonizer(
- MediaPlayer2Interface::NotifyCallback cb,
- const wp<MediaPlayer2Engine> &client);
- void start() { mActive = true; }
- void stop() { mActive = false; }
- void kill();
-private:
- static const int interval;
- Antagonizer();
- static int callbackThread(void *cookie);
- Mutex mLock;
- Condition mCondition;
- bool mExit;
- bool mActive;
- wp<MediaPlayer2Engine> mClient;
- MediaPlayer2Interface::NotifyCallback mCb;
-};
-#endif
-
-class MediaPlayer2Manager {
- class Client;
-
- class AudioOutput : public MediaPlayer2Interface::AudioSink
- {
- class CallbackData;
-
- public:
- AudioOutput(
- audio_session_t sessionId,
- uid_t uid,
- int pid,
- const audio_attributes_t * attr,
- const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
- virtual ~AudioOutput();
-
- virtual bool ready() const { return mTrack != 0; }
- virtual ssize_t bufferSize() const;
- virtual ssize_t frameCount() const;
- virtual ssize_t channelCount() const;
- virtual ssize_t frameSize() const;
- virtual uint32_t latency() const;
- virtual float msecsPerFrame() const;
- virtual status_t getPosition(uint32_t *position) const;
- virtual status_t getTimestamp(AudioTimestamp &ts) const;
- virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const;
- virtual audio_session_t getSessionId() const;
- virtual uint32_t getSampleRate() const;
- virtual int64_t getBufferDurationInUs() const;
-
- virtual status_t open(
- uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format, int bufferCount,
- AudioCallback cb, void *cookie,
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
- const audio_offload_info_t *offloadInfo = NULL,
- bool doNotReconnect = false,
- uint32_t suggestedFrameCount = 0);
-
- virtual status_t start();
- virtual ssize_t write(const void* buffer, size_t size, bool blocking = true);
- virtual void stop();
- virtual void flush();
- virtual void pause();
- virtual void close();
- void setAudioStreamType(audio_stream_type_t streamType);
- virtual audio_stream_type_t getAudioStreamType() const { return mStreamType; }
- void setAudioAttributes(const audio_attributes_t * attributes);
-
- void setVolume(float left, float right);
- virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
- virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
-
- status_t setAuxEffectSendLevel(float level);
- status_t attachAuxEffect(int effectId);
- virtual status_t dump(int fd, const Vector<String16>& args) const;
-
- static bool isOnEmulator();
- static int getMinBufferCount();
- void setNextOutput(const sp<AudioOutput>& nextOutput);
- void switchToNextOutput();
- virtual bool needsTrailingPadding() { return mNextOutput == NULL; }
- virtual status_t setParameters(const String8& keyValuePairs);
- virtual String8 getParameters(const String8& keys);
-
- // AudioRouting
- virtual status_t setOutputDevice(audio_port_handle_t deviceId);
- virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
- virtual status_t enableAudioDeviceCallback(bool enabled);
-
- private:
- static void setMinBufferCount();
- static void CallbackWrapper(
- int event, void *me, void *info);
- void deleteRecycledTrack_l();
- void close_l();
- status_t updateTrack();
-
- sp<AudioTrack> mTrack;
- sp<AudioTrack> mRecycledTrack;
- sp<AudioOutput> mNextOutput;
- AudioCallback mCallback;
- void * mCallbackCookie;
- CallbackData * mCallbackData;
- audio_stream_type_t mStreamType;
- audio_attributes_t * mAttributes;
- float mLeftVolume;
- float mRightVolume;
- AudioPlaybackRate mPlaybackRate;
- uint32_t mSampleRateHz; // sample rate of the content, as set in open()
- float mMsecsPerFrame;
- size_t mFrameSize;
- audio_session_t mSessionId;
- uid_t mUid;
- int mPid;
- float mSendLevel;
- int mAuxEffectId;
- audio_output_flags_t mFlags;
- audio_port_handle_t mSelectedDeviceId;
- audio_port_handle_t mRoutedDeviceId;
- bool mDeviceCallbackEnabled;
- wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
- mutable Mutex mLock;
-
- // static variables below not protected by mutex
- static bool mIsOnEmulator;
- static int mMinBufferCount; // 12 for emulator; otherwise 4
-
- // CallbackData is what is passed to the AudioTrack as the "user" data.
- // We need to be able to target this to a different Output on the fly,
- // so we can't use the Output itself for this.
- class CallbackData {
- friend AudioOutput;
- public:
- explicit CallbackData(AudioOutput *cookie) {
- mData = cookie;
- mSwitching = false;
- }
- AudioOutput * getOutput() const { return mData; }
- void setOutput(AudioOutput* newcookie) { mData = newcookie; }
- // lock/unlock are used by the callback before accessing the payload of this object
- void lock() const { mLock.lock(); }
- void unlock() const { mLock.unlock(); }
-
- // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
- // to the next sink.
-
- // tryBeginTrackSwitch() returns true only if it obtains the lock.
- bool tryBeginTrackSwitch() {
- LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
- if (mLock.tryLock() != OK) {
- return false;
- }
- mSwitching = true;
- return true;
- }
- void endTrackSwitch() {
- if (mSwitching) {
- mLock.unlock();
- }
- mSwitching = false;
- }
- private:
- AudioOutput * mData;
- mutable Mutex mLock; // a recursive mutex might make this unnecessary.
- bool mSwitching;
- DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
- };
-
- }; // AudioOutput
-
-
-public:
- MediaPlayer2Manager();
- virtual ~MediaPlayer2Manager();
-
- static MediaPlayer2Manager& get();
-
- // MediaPlayer2Manager interface
- virtual sp<MediaPlayer2Engine> create(const sp<MediaPlayer2EngineClient>& client,
- audio_session_t audioSessionId);
-
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- void removeClient(const wp<Client>& client);
- bool hasClient(wp<Client> client);
-
-private:
- class Client : public MediaPlayer2Engine {
- // MediaPlayer2Engine interface
- virtual void disconnect();
- virtual status_t setVideoSurfaceTexture(
- const sp<ANativeWindowWrapper>& nww) override;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) override;
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) override;
- virtual status_t prepareAsync();
- virtual status_t start();
- virtual status_t stop();
- virtual status_t pause();
- virtual status_t isPlaying(bool* state);
- virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate);
- virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
- virtual status_t setSyncSettings(const AVSyncSettings& rate, float videoFpsHint);
- virtual status_t getSyncSettings(AVSyncSettings* rate /* nonnull */,
- float* videoFps /* nonnull */);
- virtual status_t seekTo(
- int msec,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC);
- virtual status_t getCurrentPosition(int* msec);
- virtual status_t getDuration(int* msec);
- virtual status_t reset();
- virtual status_t notifyAt(int64_t mediaTimeUs);
- virtual status_t setAudioStreamType(audio_stream_type_t type);
- virtual status_t setLooping(int loop);
- virtual status_t setVolume(float leftVolume, float rightVolume);
- virtual status_t invoke(const Parcel& request, Parcel *reply);
- virtual status_t setMetadataFilter(const Parcel& filter);
- virtual status_t getMetadata(bool update_only,
- bool apply_filter,
- Parcel *reply);
- virtual status_t setAuxEffectSendLevel(float level);
- virtual status_t attachAuxEffect(int effectId);
- virtual status_t setParameter(int key, const Parcel &request);
- virtual status_t getParameter(int key, Parcel *reply);
- virtual status_t setNextPlayer(const sp<MediaPlayer2Engine>& player);
-
- virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) override;
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) override;
- virtual status_t playNextDataSource(int64_t srcId) override;
-
- static void notify(const wp<MediaPlayer2Engine> &listener, int64_t srcId,
- int msg, int ext1, int ext2, const Parcel *obj);
-
- pid_t pid() const { return mPid; }
- virtual status_t dump(int fd, const Vector<String16>& args);
-
- audio_session_t getAudioSessionId() { return mAudioSessionId; }
- // Modular DRM
- virtual status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
- virtual status_t releaseDrm();
- // AudioRouting
- virtual status_t setOutputDevice(audio_port_handle_t deviceId);
- virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
- virtual status_t enableAudioDeviceCallback(bool enabled);
-
- private:
- class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback
- {
- public:
- AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Interface>& listener) {
- mListener = listener;
- }
- ~AudioDeviceUpdatedNotifier() {}
-
- virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
- audio_port_handle_t deviceId);
-
- private:
- wp<MediaPlayer2Interface> mListener;
- };
-
- friend class MediaPlayer2Manager;
- Client(pid_t pid,
- int32_t connId,
- const sp<MediaPlayer2EngineClient>& client,
- audio_session_t audioSessionId,
- uid_t uid);
- Client();
- virtual ~Client();
- bool init();
-
- void deletePlayer();
-
- sp<MediaPlayer2Interface> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
-
-
-
- // @param type Of the metadata to be tested.
- // @return true if the metadata should be dropped according to
- // the filters.
- bool shouldDropMetadata(media::Metadata::Type type) const;
-
- // Add a new element to the set of metadata updated. Noop if
- // the element exists already.
- // @param type Of the metadata to be recorded.
- void addNewMetadataUpdate(media::Metadata::Type type);
-
- // Disconnect from the currently connected ANativeWindow.
- void disconnectNativeWindow_l();
-
- status_t setAudioAttributes_l(const Parcel &request);
-
- mutable Mutex mLock;
- sp<MediaPlayer2Interface> mPlayer;
- sp<MediaPlayer2EngineClient> mClient;
- sp<AudioOutput> mAudioOutput;
- pid_t mPid;
- status_t mStatus;
- bool mLoop;
- int32_t mConnId;
- audio_session_t mAudioSessionId;
- audio_attributes_t * mAudioAttributes;
- uid_t mUid;
- sp<ANativeWindowWrapper> mConnectedWindow;
- sp<Client> mNextClient;
-
- // Metadata filters.
- media::Metadata::Filter mMetadataAllow; // protected by mLock
- media::Metadata::Filter mMetadataDrop; // protected by mLock
-
- // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
- // notification we try to update mMetadataUpdated which is a
- // set: no duplicate.
- // getMetadata clears this set.
- media::Metadata::Filter mMetadataUpdated; // protected by mLock
-
- sp<AudioDeviceUpdatedNotifier> mAudioDeviceUpdatedListener;
-#if CALLBACK_ANTAGONIZER
- Antagonizer* mAntagonizer;
-#endif
- }; // Client
-
-// ----------------------------------------------------------------------------
-
- pid_t mPid;
- uid_t mUid;
-
- mutable Mutex mLock;
- SortedVector< wp<Client> > mClients;
- int32_t mNextConnId;
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2MANAGER_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
new file mode 100644
index 0000000..ad4937a
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -0,0 +1,192 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
+#define ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
+
+#include <mediaplayer2/MediaPlayer2Interface.h>
+
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class AudioTrack;
+
+class MediaPlayer2AudioOutput : public MediaPlayer2Interface::AudioSink
+{
+ class CallbackData;
+
+public:
+ MediaPlayer2AudioOutput(audio_session_t sessionId,
+ uid_t uid,
+ int pid,
+ const audio_attributes_t * attr,
+ const sp<AudioSystem::AudioDeviceCallback>& deviceCallback);
+ virtual ~MediaPlayer2AudioOutput();
+
+ virtual bool ready() const {
+ return mTrack != 0;
+ }
+ virtual ssize_t bufferSize() const;
+ virtual ssize_t frameCount() const;
+ virtual ssize_t channelCount() const;
+ virtual ssize_t frameSize() const;
+ virtual uint32_t latency() const;
+ virtual float msecsPerFrame() const;
+ virtual status_t getPosition(uint32_t *position) const;
+ virtual status_t getTimestamp(AudioTimestamp &ts) const;
+ virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
+ virtual status_t getFramesWritten(uint32_t *frameswritten) const;
+ virtual audio_session_t getSessionId() const;
+ virtual uint32_t getSampleRate() const;
+ virtual int64_t getBufferDurationInUs() const;
+
+ virtual status_t open(
+ uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
+ audio_format_t format, int bufferCount,
+ AudioCallback cb, void *cookie,
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
+ const audio_offload_info_t *offloadInfo = NULL,
+ bool doNotReconnect = false,
+ uint32_t suggestedFrameCount = 0);
+
+ virtual status_t start();
+ virtual ssize_t write(const void* buffer, size_t size, bool blocking = true);
+ virtual void stop();
+ virtual void flush();
+ virtual void pause();
+ virtual void close();
+ void setAudioStreamType(audio_stream_type_t streamType);
+ virtual audio_stream_type_t getAudioStreamType() const {
+ return mStreamType;
+ }
+ void setAudioAttributes(const audio_attributes_t * attributes);
+
+ void setVolume(float left, float right);
+ virtual status_t setPlaybackRate(const AudioPlaybackRate& rate);
+ virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */);
+
+ status_t setAuxEffectSendLevel(float level);
+ status_t attachAuxEffect(int effectId);
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
+
+ static bool isOnEmulator();
+ static int getMinBufferCount();
+ void setNextOutput(const sp<MediaPlayer2AudioOutput>& nextOutput);
+ virtual bool needsTrailingPadding() {
+ return true;
+ // TODO: return correct value.
+ //return mNextOutput == NULL;
+ }
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ // AudioRouting
+ virtual status_t setOutputDevice(audio_port_handle_t deviceId);
+ virtual status_t getRoutedDeviceId(audio_port_handle_t* deviceId);
+ virtual status_t enableAudioDeviceCallback(bool enabled);
+
+private:
+ static void setMinBufferCount();
+ static void CallbackWrapper(int event, void *me, void *info);
+ void deleteRecycledTrack_l();
+ void close_l();
+ status_t updateTrack_l();
+
+ sp<AudioTrack> mTrack;
+ AudioCallback mCallback;
+ void * mCallbackCookie;
+ CallbackData * mCallbackData;
+ audio_stream_type_t mStreamType;
+ audio_attributes_t * mAttributes;
+ float mLeftVolume;
+ float mRightVolume;
+ AudioPlaybackRate mPlaybackRate;
+ uint32_t mSampleRateHz; // sample rate of the content, as set in open()
+ float mMsecsPerFrame;
+ size_t mFrameSize;
+ audio_session_t mSessionId;
+ uid_t mUid;
+ int mPid;
+ float mSendLevel;
+ int mAuxEffectId;
+ audio_output_flags_t mFlags;
+ audio_port_handle_t mSelectedDeviceId;
+ audio_port_handle_t mRoutedDeviceId;
+ bool mDeviceCallbackEnabled;
+ wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+ mutable Mutex mLock;
+
+ // static variables below not protected by mutex
+ static bool mIsOnEmulator;
+ static int mMinBufferCount; // 12 for emulator; otherwise 4
+
+ // CallbackData is what is passed to the AudioTrack as the "user" data.
+ // We need to be able to target this to a different Output on the fly,
+ // so we can't use the Output itself for this.
+ class CallbackData {
+ friend MediaPlayer2AudioOutput;
+ public:
+ explicit CallbackData(MediaPlayer2AudioOutput *cookie) {
+ mData = cookie;
+ mSwitching = false;
+ }
+ MediaPlayer2AudioOutput *getOutput() const {
+ return mData;
+ }
+ void setOutput(MediaPlayer2AudioOutput* newcookie) {
+ mData = newcookie;
+ }
+ // lock/unlock are used by the callback before accessing the payload of this object
+ void lock() const {
+ mLock.lock();
+ }
+ void unlock() const {
+ mLock.unlock();
+ }
+
+ // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
+ // to the next sink.
+
+ // tryBeginTrackSwitch() returns true only if it obtains the lock.
+ bool tryBeginTrackSwitch() {
+ LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
+ if (mLock.tryLock() != OK) {
+ return false;
+ }
+ mSwitching = true;
+ return true;
+ }
+ void endTrackSwitch() {
+ if (mSwitching) {
+ mLock.unlock();
+ }
+ mSwitching = false;
+ }
+
+ private:
+ MediaPlayer2AudioOutput *mData;
+ mutable Mutex mLock; // a recursive mutex might make this unnecessary.
+ bool mSwitching;
+ DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
+ };
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAPLAYER2AUDIOOUTPUT_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
deleted file mode 100644
index 749d83c..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Engine.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2ENGINE_H
-#define ANDROID_MEDIAPLAYER2ENGINE_H
-
-#include <utils/RefBase.h>
-#include <binder/Parcel.h>
-#include <utils/KeyedVector.h>
-#include <system/audio.h>
-
-#include <media/MediaSource.h>
-
-// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
-// global, and not in android::
-struct sockaddr_in;
-
-namespace android {
-
-struct ANativeWindowWrapper;
-struct AVSyncSettings;
-struct AudioPlaybackRate;
-struct BufferingSettings;
-class DataSource;
-struct DataSourceDesc;
-struct IStreamSource;
-struct MediaHTTPService;
-class Parcel;
-
-typedef MediaSource::ReadOptions::SeekMode MediaPlayer2SeekMode;
-
-class MediaPlayer2Engine: public RefBase
-{
-public:
- virtual void disconnect() = 0;
-
- virtual status_t setDataSource(const sp<DataSourceDesc>& source) = 0;
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc>& source) = 0;
- virtual status_t playNextDataSource(int64_t srcId) = 0;
- virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) = 0;
- virtual status_t setBufferingSettings(const BufferingSettings& buffering) = 0;
- virtual status_t prepareAsync() = 0;
- virtual status_t start() = 0;
- virtual status_t stop() = 0;
- virtual status_t pause() = 0;
- virtual status_t isPlaying(bool* state) = 0;
- virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) = 0;
- virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) = 0;
- virtual status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) = 0;
- virtual status_t getSyncSettings(AVSyncSettings* sync /* nonnull */,
- float* videoFps /* nonnull */) = 0;
- virtual status_t seekTo(
- int msec,
- MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) = 0;
- virtual status_t getCurrentPosition(int* msec) = 0;
- virtual status_t getDuration(int* msec) = 0;
- virtual status_t notifyAt(int64_t mediaTimeUs) = 0;
- virtual status_t reset() = 0;
- virtual status_t setAudioStreamType(audio_stream_type_t type) = 0;
- virtual status_t setLooping(int loop) = 0;
- virtual status_t setVolume(float leftVolume, float rightVolume) = 0;
- virtual status_t setAuxEffectSendLevel(float level) = 0;
- virtual status_t attachAuxEffect(int effectId) = 0;
- virtual status_t setParameter(int key, const Parcel& request) = 0;
- virtual status_t getParameter(int key, Parcel* reply) = 0;
- virtual status_t setNextPlayer(const sp<MediaPlayer2Engine>& next) = 0;
-
- // Modular DRM
- virtual status_t prepareDrm(const uint8_t uuid[16],
- const Vector<uint8_t>& drmSessionId) = 0;
- virtual status_t releaseDrm() = 0;
-
- // Invoke a generic method on the player by using opaque parcels
- // for the request and reply.
- // @param request Parcel that must start with the media player
- // interface token.
- // @param[out] reply Parcel to hold the reply data. Cannot be null.
- // @return OK if the invocation was made successfully.
- virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
-
- // Set a new metadata filter.
- // @param filter A set of allow and drop rules serialized in a Parcel.
- // @return OK if the invocation was made successfully.
- virtual status_t setMetadataFilter(const Parcel& filter) = 0;
-
- // Retrieve a set of metadata.
- // @param update_only Include only the metadata that have changed
- // since the last invocation of getMetadata.
- // The set is built using the unfiltered
- // notifications the native player sent to the
- // MediaPlayer2Manager during that period of
- // time. If false, all the metadatas are considered.
- // @param apply_filter If true, once the metadata set has been built based
- // on the value update_only, the current filter is
- // applied.
- // @param[out] metadata On exit contains a set (possibly empty) of metadata.
- // Valid only if the call returned OK.
- // @return OK if the invocation was made successfully.
- virtual status_t getMetadata(bool update_only,
- bool apply_filter,
- Parcel *metadata) = 0;
-
- // AudioRouting
- virtual status_t setOutputDevice(audio_port_handle_t deviceId) = 0;
- virtual status_t getRoutedDeviceId(audio_port_handle_t *deviceId) = 0;
- virtual status_t enableAudioDeviceCallback(bool enabled) = 0;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2ENGINE_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
deleted file mode 100644
index 0b066aa..0000000
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2EngineClient.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIAPLAYER2ENGINECLIENT_H
-#define ANDROID_MEDIAPLAYER2ENGINECLIENT_H
-
-#include <utils/RefBase.h>
-#include <binder/Parcel.h>
-
-namespace android {
-
-class MediaPlayer2EngineClient: public RefBase
-{
-public:
- virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
-};
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAPLAYER2ENGINECLIENT_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index c0c490b..96aea7f 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -21,18 +21,17 @@
#include <sys/types.h>
#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/RefBase.h>
+#include <media/AVSyncSettings.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
#include <media/AudioTimestamp.h>
-#include <media/AVSyncSettings.h>
#include <media/BufferingSettings.h>
#include <media/Metadata.h>
#include <media/stagefright/foundation/AHandler.h>
-#include <mediaplayer2/mediaplayer2.h>
+#include <mediaplayer2/MediaPlayer2Types.h>
// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
// global, and not in android::
@@ -40,14 +39,10 @@
namespace android {
-class DataSource;
struct DataSourceDesc;
-struct MediaHTTPService;
class Parcel;
struct ANativeWindowWrapper;
-template<typename T> class SortedVector;
-
#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
@@ -58,14 +53,14 @@
// duration below which we do not allow deep audio buffering
#define AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US 5000000
-// abstract base class - use MediaPlayer2Interface
-class MediaPlayer2Interface : public AHandler
+class MediaPlayer2InterfaceListener: public RefBase
{
public:
- // callback mechanism for passing messages to MediaPlayer2 object
- typedef void (*NotifyCallback)(const wp<MediaPlayer2Engine> &listener,
- int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj);
+ virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
+};
+class MediaPlayer2Interface : public AHandler {
+public:
// AudioSink: abstraction layer for audio output
class AudioSink : public RefBase {
public:
@@ -79,29 +74,28 @@
// Callback returns the number of bytes actually written to the buffer.
typedef size_t (*AudioCallback)(
- AudioSink *audioSink, void *buffer, size_t size, void *cookie,
- cb_event_t event);
+ AudioSink *audioSink, void *buffer, size_t size, void *cookie, cb_event_t event);
- virtual ~AudioSink() {}
- virtual bool ready() const = 0; // audio output is open and ready
- virtual ssize_t bufferSize() const = 0;
- virtual ssize_t frameCount() const = 0;
- virtual ssize_t channelCount() const = 0;
- virtual ssize_t frameSize() const = 0;
- virtual uint32_t latency() const = 0;
- virtual float msecsPerFrame() const = 0;
- virtual status_t getPosition(uint32_t *position) const = 0;
- virtual status_t getTimestamp(AudioTimestamp &ts) const = 0;
- virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const = 0;
- virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
+ virtual ~AudioSink() {}
+ virtual bool ready() const = 0; // audio output is open and ready
+ virtual ssize_t bufferSize() const = 0;
+ virtual ssize_t frameCount() const = 0;
+ virtual ssize_t channelCount() const = 0;
+ virtual ssize_t frameSize() const = 0;
+ virtual uint32_t latency() const = 0;
+ virtual float msecsPerFrame() const = 0;
+ virtual status_t getPosition(uint32_t *position) const = 0;
+ virtual status_t getTimestamp(AudioTimestamp &ts) const = 0;
+ virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const = 0;
+ virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
virtual audio_session_t getSessionId() const = 0;
virtual audio_stream_type_t getAudioStreamType() const = 0;
- virtual uint32_t getSampleRate() const = 0;
- virtual int64_t getBufferDurationInUs() const = 0;
+ virtual uint32_t getSampleRate() const = 0;
+ virtual int64_t getBufferDurationInUs() const = 0;
// If no callback is specified, use the "write" API below to submit
// audio data.
- virtual status_t open(
+ virtual status_t open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
@@ -112,7 +106,7 @@
bool doNotReconnect = false,
uint32_t suggestedFrameCount = 0) = 0;
- virtual status_t start() = 0;
+ virtual status_t start() = 0;
/* Input parameter |size| is in byte units stored in |buffer|.
* Data is copied over and actual number of bytes written (>= 0)
@@ -124,19 +118,25 @@
* buffer, unless an error occurs or the copy operation is
* prematurely stopped.
*/
- virtual ssize_t write(const void* buffer, size_t size, bool blocking = true) = 0;
+ virtual ssize_t write(const void* buffer, size_t size, bool blocking = true) = 0;
- virtual void stop() = 0;
- virtual void flush() = 0;
- virtual void pause() = 0;
- virtual void close() = 0;
+ virtual void stop() = 0;
+ virtual void flush() = 0;
+ virtual void pause() = 0;
+ virtual void close() = 0;
- virtual status_t setPlaybackRate(const AudioPlaybackRate& rate) = 0;
- virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0;
- virtual bool needsTrailingPadding() { return true; }
+ virtual status_t setPlaybackRate(const AudioPlaybackRate& rate) = 0;
+ virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0;
+ virtual bool needsTrailingPadding() {
+ return true;
+ }
- virtual status_t setParameters(const String8& /* keyValuePairs */) { return NO_ERROR; }
- virtual String8 getParameters(const String8& /* keys */) { return String8::empty(); }
+ virtual status_t setParameters(const String8& /* keyValuePairs */) {
+ return NO_ERROR;
+ }
+ virtual String8 getParameters(const String8& /* keys */) {
+ return String8::empty();
+ }
// AudioRouting
virtual status_t setOutputDevice(audio_port_handle_t deviceId);
@@ -144,47 +144,48 @@
virtual status_t enableAudioDeviceCallback(bool enabled);
};
- MediaPlayer2Interface() : mClient(0), mNotify(0) { }
- virtual ~MediaPlayer2Interface() { }
- virtual status_t initCheck() = 0;
+ MediaPlayer2Interface() : mListener(NULL) { }
+ virtual ~MediaPlayer2Interface() { }
+ virtual status_t initCheck() = 0;
- virtual void setAudioSink(const sp<AudioSink>& audioSink) { mAudioSink = audioSink; }
+ virtual void setAudioSink(const sp<AudioSink>& audioSink) {
+ mAudioSink = audioSink;
+ }
- virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) = 0;
+ virtual status_t setDataSource(const sp<DataSourceDesc> &dsd) = 0;
- virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) = 0;
+ virtual status_t prepareNextDataSource(const sp<DataSourceDesc> &dsd) = 0;
- virtual status_t playNextDataSource(int64_t srcId) = 0;
+ virtual status_t playNextDataSource(int64_t srcId) = 0;
// pass the buffered native window to the media player service
- virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
+ virtual status_t setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) = 0;
- virtual status_t getBufferingSettings(
- BufferingSettings* buffering /* nonnull */) {
+ virtual status_t getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
*buffering = BufferingSettings();
return OK;
}
- virtual status_t setBufferingSettings(const BufferingSettings& /* buffering */) {
+ virtual status_t setBufferingSettings(const BufferingSettings& /* buffering */) {
return OK;
}
- virtual status_t prepareAsync() = 0;
- virtual status_t start() = 0;
- virtual status_t stop() = 0;
- virtual status_t pause() = 0;
- virtual bool isPlaying() = 0;
- virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) {
+ virtual status_t prepareAsync() = 0;
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t pause() = 0;
+ virtual bool isPlaying() = 0;
+ virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) {
// by default, players only support setting rate to the default
if (!isAudioPlaybackRateEqual(rate, AUDIO_PLAYBACK_RATE_DEFAULT)) {
return BAD_VALUE;
}
return OK;
}
- virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
+ virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
*rate = AUDIO_PLAYBACK_RATE_DEFAULT;
return OK;
}
- virtual status_t setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) {
+ virtual status_t setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) {
// By default, players only support setting sync source to default; all other sync
// settings are ignored. There is no requirement for getters to return set values.
if (sync.mSource != AVSYNC_SOURCE_DEFAULT) {
@@ -192,27 +193,23 @@
}
return OK;
}
- virtual status_t getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
+ virtual status_t getSyncSettings(
+ AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
*sync = AVSyncSettings();
*videoFps = -1.f;
return OK;
}
- virtual status_t seekTo(
+ virtual status_t seekTo(
int msec, MediaPlayer2SeekMode mode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC) = 0;
- virtual status_t getCurrentPosition(int *msec) = 0;
- virtual status_t getDuration(int *msec) = 0;
- virtual status_t reset() = 0;
- virtual status_t notifyAt(int64_t /* mediaTimeUs */) {
+ virtual status_t getCurrentPosition(int *msec) = 0;
+ virtual status_t getDuration(int *msec) = 0;
+ virtual status_t reset() = 0;
+ virtual status_t notifyAt(int64_t /* mediaTimeUs */) {
return INVALID_OPERATION;
}
- virtual status_t setLooping(int loop) = 0;
- virtual status_t setParameter(int key, const Parcel &request) = 0;
- virtual status_t getParameter(int key, Parcel *reply) = 0;
-
- virtual status_t setNextPlayer(const sp<MediaPlayer2Interface>& /* next */) {
- return OK;
- }
+ virtual status_t setLooping(int loop) = 0;
+ virtual status_t setParameter(int key, const Parcel &request) = 0;
+ virtual status_t getParameter(int key, Parcel *reply) = 0;
// Invoke a generic method on the player by using opaque parcels
// for the request and reply.
@@ -221,7 +218,7 @@
// data sent by the java layer.
// @param[out] reply Parcel to hold the reply data. Cannot be null.
// @return OK if the call was successful.
- virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
+ virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
// The Client in the MetadataPlayerService calls this method on
// the native player to retrieve all or a subset of metadata.
@@ -230,28 +227,26 @@
// the known metadata should be returned.
// @param[inout] records Parcel where the player appends its metadata.
// @return OK if the call was successful.
- virtual status_t getMetadata(const media::Metadata::Filter& /* ids */,
- Parcel* /* records */) {
+ virtual status_t getMetadata(const media::Metadata::Filter& /* ids */,
+ Parcel* /* records */) {
return INVALID_OPERATION;
};
- void setNotifyCallback(
- const wp<MediaPlayer2Engine> &client, NotifyCallback notifyFunc) {
- Mutex::Autolock autoLock(mNotifyLock);
- mClient = client; mNotify = notifyFunc;
+ void setListener(const sp<MediaPlayer2InterfaceListener> &listener) {
+ Mutex::Autolock autoLock(mListenerLock);
+ mListener = listener;
}
- void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0,
- const Parcel *obj=NULL) {
- NotifyCallback notifyCB;
- wp<MediaPlayer2Engine> client;
+ void sendEvent(int64_t srcId, int msg, int ext1=0, int ext2=0, const Parcel *obj=NULL) {
+ sp<MediaPlayer2InterfaceListener> listener;
{
- Mutex::Autolock autoLock(mNotifyLock);
- notifyCB = mNotify;
- client = mClient;
+ Mutex::Autolock autoLock(mListenerLock);
+ listener = mListener;
}
- if (notifyCB) notifyCB(client, srcId, msg, ext1, ext2, obj);
+ if (listener) {
+ listener->notify(srcId, msg, ext1, ext2, obj);
+ }
}
virtual status_t dump(int /* fd */, const Vector<String16>& /* args */) const {
@@ -261,7 +256,8 @@
virtual void onMessageReceived(const sp<AMessage> & /* msg */) override { }
// Modular DRM
- virtual status_t prepareDrm(const uint8_t /* uuid */[16], const Vector<uint8_t>& /* drmSessionId */) {
+ virtual status_t prepareDrm(const uint8_t /* uuid */[16],
+ const Vector<uint8_t>& /* drmSessionId */) {
return INVALID_OPERATION;
}
virtual status_t releaseDrm() {
@@ -269,14 +265,11 @@
}
protected:
- sp<AudioSink> mAudioSink;
+ sp<AudioSink> mAudioSink;
private:
- friend class MediaPlayer2Manager;
-
- Mutex mNotifyLock;
- wp<MediaPlayer2Engine> mClient;
- NotifyCallback mNotify;
+ Mutex mListenerLock;
+ sp<MediaPlayer2InterfaceListener> mListener;
};
}; // namespace android
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
new file mode 100644
index 0000000..260c7ed
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIAPLAYER2_TYPES_H
+#define ANDROID_MEDIAPLAYER2_TYPES_H
+
+#include <media/mediaplayer_common.h>
+
+#include <media/MediaSource.h>
+
+namespace android {
+
+typedef MediaSource::ReadOptions::SeekMode MediaPlayer2SeekMode;
+
+enum media2_event_type {
+ MEDIA2_NOP = 0, // interface test message
+ MEDIA2_PREPARED = 1,
+ MEDIA2_PLAYBACK_COMPLETE = 2,
+ MEDIA2_BUFFERING_UPDATE = 3,
+ MEDIA2_SEEK_COMPLETE = 4,
+ MEDIA2_SET_VIDEO_SIZE = 5,
+ MEDIA2_STARTED = 6,
+ MEDIA2_PAUSED = 7,
+ MEDIA2_STOPPED = 8,
+ MEDIA2_SKIPPED = 9,
+ MEDIA2_NOTIFY_TIME = 98,
+ MEDIA2_TIMED_TEXT = 99,
+ MEDIA2_ERROR = 100,
+ MEDIA2_INFO = 200,
+ MEDIA2_SUBTITLE_DATA = 201,
+ MEDIA2_META_DATA = 202,
+ MEDIA2_DRM_INFO = 210,
+ MEDIA2_AUDIO_ROUTING_CHANGED = 10000,
+};
+
+// Generic error codes for the media player framework. Errors are fatal, the
+// playback must abort.
+//
+// Errors are communicated back to the client using the
+// MediaPlayer2Listener::notify method defined below.
+// In this situation, 'notify' is invoked with the following:
+// 'msg' is set to MEDIA_ERROR.
+// 'ext1' should be a value from the enum media2_error_type.
+// 'ext2' contains an implementation dependant error code to provide
+// more details. Should default to 0 when not used.
+//
+// The codes are distributed as follow:
+// 0xx: Reserved
+// 1xx: Android Player errors. Something went wrong inside the MediaPlayer2.
+// 2xx: Media errors (e.g Codec not supported). There is a problem with the
+// media itself.
+// 3xx: Runtime errors. Some extraordinary condition arose making the playback
+// impossible.
+//
+enum media2_error_type {
+ // 0xx
+ MEDIA2_ERROR_UNKNOWN = 1,
+ // 1xx
+ // MEDIA2_ERROR_SERVER_DIED = 100,
+ // 2xx
+ MEDIA2_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
+ // 3xx
+ MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE = 300,
+};
+
+
+// Info and warning codes for the media player framework. These are non fatal,
+// the playback is going on but there might be some user visible issues.
+//
+// Info and warning messages are communicated back to the client using the
+// MediaPlayer2Listener::notify method defined below. In this situation,
+// 'notify' is invoked with the following:
+// 'msg' is set to MEDIA_INFO.
+// 'ext1' should be a value from the enum media2_info_type.
+// 'ext2' contains an implementation dependant info code to provide
+// more details. Should default to 0 when not used.
+//
+// The codes are distributed as follow:
+// 0xx: Reserved
+// 7xx: Android Player info/warning (e.g player lagging behind.)
+// 8xx: Media info/warning (e.g media badly interleaved.)
+//
+enum media2_info_type {
+ // 0xx
+ MEDIA2_INFO_UNKNOWN = 1,
+ // The player was started because it was used as the next player for another
+ // player, which just completed playback
+ MEDIA2_INFO_STARTED_AS_NEXT = 2,
+ // The player just pushed the very first video frame for rendering
+ MEDIA2_INFO_VIDEO_RENDERING_START = 3,
+ // The player just pushed the very first audio frame for rendering
+ MEDIA2_INFO_AUDIO_RENDERING_START = 4,
+ // The player just completed the playback of this data source
+ MEDIA2_INFO_PLAYBACK_COMPLETE = 5,
+ // The player just completed the playback of the full play list
+ MEDIA2_INFO_PLAYLIST_END = 6,
+
+ //1xx
+ // The player just prepared a data source.
+ MEDIA2_INFO_PREPARED = 100,
+ // The player just completed a call play().
+ MEDIA2_INFO_COMPLETE_CALL_PLAY = 101,
+ // The player just completed a call pause().
+ MEDIA2_INFO_COMPLETE_CALL_PAUSE = 102,
+ // The player just completed a call seekTo.
+ MEDIA2_INFO_COMPLETE_CALL_SEEK = 103,
+
+ // 7xx
+ // The video is too complex for the decoder: it can't decode frames fast
+ // enough. Possibly only the audio plays fine at this stage.
+ MEDIA2_INFO_VIDEO_TRACK_LAGGING = 700,
+ // MediaPlayer2 is temporarily pausing playback internally in order to
+ // buffer more data.
+ MEDIA2_INFO_BUFFERING_START = 701,
+ // MediaPlayer2 is resuming playback after filling buffers.
+ MEDIA2_INFO_BUFFERING_END = 702,
+ // Bandwidth in recent past
+ MEDIA2_INFO_NETWORK_BANDWIDTH = 703,
+
+ // 8xx
+ // Bad interleaving means that a media has been improperly interleaved or not
+ // interleaved at all, e.g has all the video samples first then all the audio
+ // ones. Video is playing but a lot of disk seek may be happening.
+ MEDIA2_INFO_BAD_INTERLEAVING = 800,
+ // The media is not seekable (e.g live stream).
+ MEDIA2_INFO_NOT_SEEKABLE = 801,
+ // New media metadata is available.
+ MEDIA2_INFO_METADATA_UPDATE = 802,
+ // Audio can not be played.
+ MEDIA2_INFO_PLAY_AUDIO_ERROR = 804,
+ // Video can not be played.
+ MEDIA2_INFO_PLAY_VIDEO_ERROR = 805,
+
+ //9xx
+ MEDIA2_INFO_TIMED_TEXT_ERROR = 900,
+};
+
+enum media_player2_states {
+ MEDIA_PLAYER2_STATE_ERROR = 0,
+ MEDIA_PLAYER2_IDLE = 1 << 0,
+ MEDIA_PLAYER2_INITIALIZED = 1 << 1,
+ MEDIA_PLAYER2_PREPARING = 1 << 2,
+ MEDIA_PLAYER2_PREPARED = 1 << 3,
+ MEDIA_PLAYER2_STARTED = 1 << 4,
+ MEDIA_PLAYER2_PAUSED = 1 << 5,
+ MEDIA_PLAYER2_STOPPED = 1 << 6,
+ MEDIA_PLAYER2_PLAYBACK_COMPLETE = 1 << 7
+};
+
+// Keep KEY_PARAMETER_* in sync with MediaPlayer2.java.
+// The same enum space is used for both set and get, in case there are future keys that
+// can be both set and get. But as of now, all parameters are either set only or get only.
+enum media2_parameter_keys {
+ // Streaming/buffering parameters
+ MEDIA2_KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS = 1100, // set only
+
+ // Return a Parcel containing a single int, which is the channel count of the
+ // audio track, or zero for error (e.g. no audio track) or unknown.
+ MEDIA2_KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200, // get only
+
+ // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
+ // values used for rewinding or reverse playback.
+ MEDIA2_KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300, // set only
+
+ // Set a Parcel containing the value of a parcelled Java AudioAttribute instance
+ MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400 // set only
+};
+
+// Keep INVOKE_ID_* in sync with MediaPlayer2.java.
+enum media_player2_invoke_ids {
+ MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO = 1,
+ MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
+ MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
+ MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK = 4,
+ MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK = 5,
+ MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
+ MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK = 7
+};
+
+}; // namespace android
+
+#endif // ANDROID_MEDIAPLAYER2_TYPES_H
diff --git a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
index 0afef1e..11e4f42 100644
--- a/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
+++ b/media/libmediaplayer2/include/mediaplayer2/mediaplayer2.h
@@ -17,196 +17,27 @@
#ifndef ANDROID_MEDIAPLAYER2_H
#define ANDROID_MEDIAPLAYER2_H
-#include <media/mediaplayer_common.h>
-
-#include <arpa/inet.h>
-
+#include <media/AVSyncSettings.h>
#include <media/AudioResamplerPublic.h>
#include <media/BufferingSettings.h>
-#include <mediaplayer2/MediaPlayer2EngineClient.h>
-#include <mediaplayer2/MediaPlayer2Engine.h>
+#include <media/Metadata.h>
+#include <media/mediaplayer_common.h>
+#include <mediaplayer2/MediaPlayer2Interface.h>
+#include <mediaplayer2/MediaPlayer2Types.h>
-#include <utils/Condition.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/ThreadDefs.h>
+#include <utils/Errors.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+#include <system/audio-base.h>
namespace android {
-struct AVSyncSettings;
struct ANativeWindowWrapper;
-class DataSource;
struct DataSourceDesc;
-struct MediaHTTPService;
+class MediaPlayer2AudioOutput;
-enum media2_event_type {
- MEDIA2_NOP = 0, // interface test message
- MEDIA2_PREPARED = 1,
- MEDIA2_PLAYBACK_COMPLETE = 2,
- MEDIA2_BUFFERING_UPDATE = 3,
- MEDIA2_SEEK_COMPLETE = 4,
- MEDIA2_SET_VIDEO_SIZE = 5,
- MEDIA2_STARTED = 6,
- MEDIA2_PAUSED = 7,
- MEDIA2_STOPPED = 8,
- MEDIA2_SKIPPED = 9,
- MEDIA2_NOTIFY_TIME = 98,
- MEDIA2_TIMED_TEXT = 99,
- MEDIA2_ERROR = 100,
- MEDIA2_INFO = 200,
- MEDIA2_SUBTITLE_DATA = 201,
- MEDIA2_META_DATA = 202,
- MEDIA2_DRM_INFO = 210,
- MEDIA2_AUDIO_ROUTING_CHANGED = 10000,
-};
-
-// Generic error codes for the media player framework. Errors are fatal, the
-// playback must abort.
-//
-// Errors are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below.
-// In this situation, 'notify' is invoked with the following:
-// 'msg' is set to MEDIA_ERROR.
-// 'ext1' should be a value from the enum media2_error_type.
-// 'ext2' contains an implementation dependant error code to provide
-// more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-// 0xx: Reserved
-// 1xx: Android Player errors. Something went wrong inside the MediaPlayer2.
-// 2xx: Media errors (e.g Codec not supported). There is a problem with the
-// media itself.
-// 3xx: Runtime errors. Some extraordinary condition arose making the playback
-// impossible.
-//
-enum media2_error_type {
- // 0xx
- MEDIA2_ERROR_UNKNOWN = 1,
- // 1xx
- // MEDIA2_ERROR_SERVER_DIED = 100,
- // 2xx
- MEDIA2_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200,
- // 3xx
- MEDIA2_ERROR_FAILED_TO_SET_DATA_SOURCE = 300,
-};
-
-
-// Info and warning codes for the media player framework. These are non fatal,
-// the playback is going on but there might be some user visible issues.
-//
-// Info and warning messages are communicated back to the client using the
-// MediaPlayer2Listener::notify method defined below. In this situation,
-// 'notify' is invoked with the following:
-// 'msg' is set to MEDIA_INFO.
-// 'ext1' should be a value from the enum media2_info_type.
-// 'ext2' contains an implementation dependant info code to provide
-// more details. Should default to 0 when not used.
-//
-// The codes are distributed as follow:
-// 0xx: Reserved
-// 7xx: Android Player info/warning (e.g player lagging behind.)
-// 8xx: Media info/warning (e.g media badly interleaved.)
-//
-enum media2_info_type {
- // 0xx
- MEDIA2_INFO_UNKNOWN = 1,
- // The player was started because it was used as the next player for another
- // player, which just completed playback
- MEDIA2_INFO_STARTED_AS_NEXT = 2,
- // The player just pushed the very first video frame for rendering
- MEDIA2_INFO_VIDEO_RENDERING_START = 3,
- // The player just pushed the very first audio frame for rendering
- MEDIA2_INFO_AUDIO_RENDERING_START = 4,
- // The player just completed the playback of this data source
- MEDIA2_INFO_PLAYBACK_COMPLETE = 5,
- // The player just completed the playback of the full play list
- MEDIA2_INFO_PLAYLIST_END = 6,
-
- //1xx
- // The player just prepared a data source.
- MEDIA2_INFO_PREPARED = 100,
- // The player just completed a call play().
- MEDIA2_INFO_COMPLETE_CALL_PLAY = 101,
- // The player just completed a call pause().
- MEDIA2_INFO_COMPLETE_CALL_PAUSE = 102,
- // The player just completed a call seekTo.
- MEDIA2_INFO_COMPLETE_CALL_SEEK = 103,
-
- // 7xx
- // The video is too complex for the decoder: it can't decode frames fast
- // enough. Possibly only the audio plays fine at this stage.
- MEDIA2_INFO_VIDEO_TRACK_LAGGING = 700,
- // MediaPlayer2 is temporarily pausing playback internally in order to
- // buffer more data.
- MEDIA2_INFO_BUFFERING_START = 701,
- // MediaPlayer2 is resuming playback after filling buffers.
- MEDIA2_INFO_BUFFERING_END = 702,
- // Bandwidth in recent past
- MEDIA2_INFO_NETWORK_BANDWIDTH = 703,
-
- // 8xx
- // Bad interleaving means that a media has been improperly interleaved or not
- // interleaved at all, e.g has all the video samples first then all the audio
- // ones. Video is playing but a lot of disk seek may be happening.
- MEDIA2_INFO_BAD_INTERLEAVING = 800,
- // The media is not seekable (e.g live stream).
- MEDIA2_INFO_NOT_SEEKABLE = 801,
- // New media metadata is available.
- MEDIA2_INFO_METADATA_UPDATE = 802,
- // Audio can not be played.
- MEDIA2_INFO_PLAY_AUDIO_ERROR = 804,
- // Video can not be played.
- MEDIA2_INFO_PLAY_VIDEO_ERROR = 805,
-
- //9xx
- MEDIA2_INFO_TIMED_TEXT_ERROR = 900,
-};
-
-
-
-enum media_player2_states {
- MEDIA_PLAYER2_STATE_ERROR = 0,
- MEDIA_PLAYER2_IDLE = 1 << 0,
- MEDIA_PLAYER2_INITIALIZED = 1 << 1,
- MEDIA_PLAYER2_PREPARING = 1 << 2,
- MEDIA_PLAYER2_PREPARED = 1 << 3,
- MEDIA_PLAYER2_STARTED = 1 << 4,
- MEDIA_PLAYER2_PAUSED = 1 << 5,
- MEDIA_PLAYER2_STOPPED = 1 << 6,
- MEDIA_PLAYER2_PLAYBACK_COMPLETE = 1 << 7
-};
-
-// Keep KEY_PARAMETER_* in sync with MediaPlayer2.java.
-// The same enum space is used for both set and get, in case there are future keys that
-// can be both set and get. But as of now, all parameters are either set only or get only.
-enum media2_parameter_keys {
- // Streaming/buffering parameters
- MEDIA2_KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS = 1100, // set only
-
- // Return a Parcel containing a single int, which is the channel count of the
- // audio track, or zero for error (e.g. no audio track) or unknown.
- MEDIA2_KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200, // get only
-
- // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
- // values used for rewinding or reverse playback.
- MEDIA2_KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300, // set only
-
- // Set a Parcel containing the value of a parcelled Java AudioAttribute instance
- MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES = 1400 // set only
-};
-
-// Keep INVOKE_ID_* in sync with MediaPlayer2.java.
-enum media_player2_invoke_ids {
- MEDIA_PLAYER2_INVOKE_ID_GET_TRACK_INFO = 1,
- MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE = 2,
- MEDIA_PLAYER2_INVOKE_ID_ADD_EXTERNAL_SOURCE_FD = 3,
- MEDIA_PLAYER2_INVOKE_ID_SELECT_TRACK = 4,
- MEDIA_PLAYER2_INVOKE_ID_UNSELECT_TRACK = 5,
- MEDIA_PLAYER2_INVOKE_ID_SET_VIDEO_SCALING_MODE = 6,
- MEDIA_PLAYER2_INVOKE_ID_GET_SELECTED_TRACK = 7
-};
-
-// ----------------------------------------------------------------------------
// ref-counted object for callbacks
class MediaPlayer2Listener: virtual public RefBase
{
@@ -214,11 +45,14 @@
virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) = 0;
};
-class MediaPlayer2 : public MediaPlayer2EngineClient
+class MediaPlayer2 : public MediaPlayer2InterfaceListener
{
public:
- MediaPlayer2();
~MediaPlayer2();
+
+ static sp<MediaPlayer2> Create();
+ static status_t DumpAll(int fd, const Vector<String16>& args);
+
void disconnect();
status_t getSrcId(int64_t *srcId);
@@ -275,22 +109,43 @@
audio_port_handle_t getRoutedDeviceId();
status_t enableAudioDeviceCallback(bool enabled);
-private:
- void clear_l();
- status_t seekTo_l(int msec, MediaPlayer2SeekMode mode);
- status_t prepareAsync_l();
- status_t getDuration_l(int *msec);
- status_t attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId);
- status_t reset_l();
- status_t checkStateForKeySet_l(int key);
+ status_t dump(int fd, const Vector<String16>& args);
- sp<MediaPlayer2Engine> mPlayer;
+private:
+ MediaPlayer2();
+ bool init();
+
+ // @param type Of the metadata to be tested.
+ // @return true if the metadata should be dropped according to
+ // the filters.
+ bool shouldDropMetadata(media::Metadata::Type type) const;
+
+ // Add a new element to the set of metadata updated. Noop if
+ // the element exists already.
+ // @param type Of the metadata to be recorded.
+ void addNewMetadataUpdate(media::Metadata::Type type);
+
+ // Disconnect from the currently connected ANativeWindow.
+ void disconnectNativeWindow_l();
+
+ status_t setAudioAttributes_l(const Parcel &request);
+
+ void clear_l();
+ status_t seekTo_l(int msec, MediaPlayer2SeekMode mode);
+ status_t prepareAsync_l();
+ status_t getDuration_l(int *msec);
+ status_t reset_l();
+ status_t checkStateForKeySet_l(int key);
+
+ pid_t mPid;
+ uid_t mUid;
+ sp<MediaPlayer2Interface> mPlayer;
+ sp<MediaPlayer2AudioOutput> mAudioOutput;
int64_t mSrcId;
thread_id_t mLockThreadId;
- Mutex mLock;
+ mutable Mutex mLock;
Mutex mNotifyLock;
sp<MediaPlayer2Listener> mListener;
- void* mCookie;
media_player2_states mCurrentState;
int mCurrentPosition;
MediaPlayer2SeekMode mCurrentSeekMode;
@@ -304,7 +159,20 @@
int mVideoWidth;
int mVideoHeight;
audio_session_t mAudioSessionId;
+ audio_attributes_t * mAudioAttributes;
float mSendLevel;
+
+ sp<ANativeWindowWrapper> mConnectedWindow;
+
+ // Metadata filters.
+ media::Metadata::Filter mMetadataAllow; // protected by mLock
+ media::Metadata::Filter mMetadataDrop; // protected by mLock
+
+ // Metadata updated. For each MEDIA_INFO_METADATA_UPDATE
+ // notification we try to update mMetadataUpdated which is a
+ // set: no duplicate.
+ // getMetadata clears this set.
+ media::Metadata::Filter mMetadataUpdated; // protected by mLock
};
}; // namespace android
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 75d06b8..b401ee8 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -18,44 +18,391 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaPlayer2Native"
-#include <fcntl.h>
-#include <inttypes.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <utils/Log.h>
-
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
-#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
-#include <media/AVSyncSettings.h>
-#include <media/DataSource.h>
#include <media/DataSourceDesc.h>
#include <media/MediaAnalyticsItem.h>
+#include <media/MemoryLeakTrackUtil.h>
+#include <media/Metadata.h>
#include <media/NdkWrapper.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooperRoster.h>
+#include <mediaplayer2/MediaPlayer2AudioOutput.h>
#include <mediaplayer2/mediaplayer2.h>
-#include <binder/MemoryBase.h>
-
-#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <system/audio.h>
#include <system/window.h>
-#include "MediaPlayer2Manager.h"
+#include <nuplayer2/NuPlayer2Driver.h>
+
+#include <dirent.h>
+#include <sys/stat.h>
namespace android {
-MediaPlayer2::MediaPlayer2()
-{
+extern ALooperRoster gLooperRoster;
+
+namespace {
+
+const int kDumpLockRetries = 50;
+const int kDumpLockSleepUs = 20000;
+
+// Max number of entries in the filter.
+const int kMaxFilterSize = 64; // I pulled that out of thin air.
+
+// FIXME: Move all the metadata related function in the Metadata.cpp
+
+// Unmarshall a filter from a Parcel.
+// Filter format in a parcel:
+//
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | number of entries (n) |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type 1 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type 2 |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// ....
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | metadata type n |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that should start with a filter.
+// @param[out] filter On exit contains the list of metadata type to be
+// filtered.
+// @param[out] status On exit contains the status code to be returned.
+// @return true if the parcel starts with a valid filter.
+bool unmarshallFilter(const Parcel& p,
+ media::Metadata::Filter *filter,
+ status_t *status) {
+ int32_t val;
+ if (p.readInt32(&val) != OK) {
+ ALOGE("Failed to read filter's length");
+ *status = NOT_ENOUGH_DATA;
+ return false;
+ }
+
+ if (val > kMaxFilterSize || val < 0) {
+ ALOGE("Invalid filter len %d", val);
+ *status = BAD_VALUE;
+ return false;
+ }
+
+ const size_t num = val;
+
+ filter->clear();
+ filter->setCapacity(num);
+
+ size_t size = num * sizeof(media::Metadata::Type);
+
+
+ if (p.dataAvail() < size) {
+ ALOGE("Filter too short expected %zu but got %zu", size, p.dataAvail());
+ *status = NOT_ENOUGH_DATA;
+ return false;
+ }
+
+ const media::Metadata::Type *data =
+ static_cast<const media::Metadata::Type*>(p.readInplace(size));
+
+ if (NULL == data) {
+ ALOGE("Filter had no data");
+ *status = BAD_VALUE;
+ return false;
+ }
+
+ // TODO: The stl impl of vector would be more efficient here
+ // because it degenerates into a memcpy on pod types. Try to
+ // replace later or use stl::set.
+ for (size_t i = 0; i < num; ++i) {
+ filter->add(*data);
+ ++data;
+ }
+ *status = OK;
+ return true;
+}
+
+// @param filter Of metadata type.
+// @param val To be searched.
+// @return true if a match was found.
+bool findMetadata(const media::Metadata::Filter& filter, const int32_t val) {
+ // Deal with empty and ANY right away
+ if (filter.isEmpty()) {
+ return false;
+ }
+ if (filter[0] == media::Metadata::kAny) {
+ return true;
+ }
+
+ return filter.indexOf(val) >= 0;
+}
+
+// marshalling tag indicating flattened utf16 tags
+// keep in sync with frameworks/base/media/java/android/media/AudioAttributes.java
+const int32_t kAudioAttributesMarshallTagFlattenTags = 1;
+
+// Audio attributes format in a parcel:
+//
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | usage |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | content_type |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | flags |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | kAudioAttributesMarshallTagFlattenTags | // ignore tags if not found
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | flattened tags in UTF16 |
+// | ... |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that contains audio attributes.
+// @param[out] attributes On exit points to an initialized audio_attributes_t structure
+// @param[out] status On exit contains the status code to be returned.
+void unmarshallAudioAttributes(const Parcel& parcel, audio_attributes_t *attributes) {
+ attributes->usage = (audio_usage_t) parcel.readInt32();
+ attributes->content_type = (audio_content_type_t) parcel.readInt32();
+ attributes->source = (audio_source_t) parcel.readInt32();
+ attributes->flags = (audio_flags_mask_t) parcel.readInt32();
+ const bool hasFlattenedTag = (parcel.readInt32() == kAudioAttributesMarshallTagFlattenTags);
+ if (hasFlattenedTag) {
+ // the tags are UTF16, convert to UTF8
+ String16 tags = parcel.readString16();
+ ssize_t realTagSize = utf16_to_utf8_length(tags.string(), tags.size());
+ if (realTagSize <= 0) {
+ strcpy(attributes->tags, "");
+ } else {
+ // copy the flattened string into the attributes as the destination for the conversion:
+ // copying array size -1, array for tags was calloc'd, no need to NULL-terminate it
+ size_t tagSize = realTagSize > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 ?
+ AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1 : realTagSize;
+ utf16_to_utf8(tags.string(), tagSize, attributes->tags,
+ sizeof(attributes->tags) / sizeof(attributes->tags[0]));
+ }
+ } else {
+ ALOGE("unmarshallAudioAttributes() received unflattened tags, ignoring tag values");
+ strcpy(attributes->tags, "");
+ }
+}
+
+class AudioDeviceUpdatedNotifier: public AudioSystem::AudioDeviceCallback {
+public:
+ AudioDeviceUpdatedNotifier(const sp<MediaPlayer2Interface>& listener)
+ : mListener(listener) { }
+
+ ~AudioDeviceUpdatedNotifier() { }
+
+ virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+ audio_port_handle_t deviceId) override {
+ sp<MediaPlayer2Interface> listener = mListener.promote();
+ if (listener != NULL) {
+ listener->sendEvent(0, MEDIA2_AUDIO_ROUTING_CHANGED, audioIo, deviceId);
+ } else {
+ ALOGW("listener for process %d death is gone", MEDIA2_AUDIO_ROUTING_CHANGED);
+ }
+ }
+
+private:
+ wp<MediaPlayer2Interface> mListener;
+};
+
+class proxyListener : public MediaPlayer2InterfaceListener {
+public:
+ proxyListener(const wp<MediaPlayer2> &player)
+ : mPlayer(player) { }
+
+ ~proxyListener() { };
+
+ virtual void notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) override {
+ sp<MediaPlayer2> player = mPlayer.promote();
+ if (player != NULL) {
+ player->notify(srcId, msg, ext1, ext2, obj);
+ }
+ }
+
+private:
+ wp<MediaPlayer2> mPlayer;
+};
+
+Mutex sRecordLock;
+SortedVector<wp<MediaPlayer2> > *sPlayers;
+
+void ensureInit_l() {
+ if (sPlayers == NULL) {
+ sPlayers = new SortedVector<wp<MediaPlayer2> >();
+ }
+}
+
+void addPlayer(const wp<MediaPlayer2>& player) {
+ Mutex::Autolock lock(sRecordLock);
+ ensureInit_l();
+ sPlayers->add(player);
+}
+
+void removePlayer(const wp<MediaPlayer2>& player) {
+ Mutex::Autolock lock(sRecordLock);
+ ensureInit_l();
+ sPlayers->remove(player);
+}
+
+/**
+ * The only arguments this understands right now are -c, -von and -voff,
+ * which are parsed by ALooperRoster::dump()
+ */
+status_t dumpPlayers(int fd, const Vector<String16>& args) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ SortedVector< sp<MediaPlayer2> > players; //to serialise the mutex unlock & client destruction.
+
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ snprintf(buffer, SIZE, "Permission Denial: can't dump MediaPlayer2\n");
+ result.append(buffer);
+ } else {
+ {
+ Mutex::Autolock lock(sRecordLock);
+ ensureInit_l();
+ for (int i = 0, n = sPlayers->size(); i < n; ++i) {
+ sp<MediaPlayer2> p = (*sPlayers)[i].promote();
+ if (p != 0) {
+ p->dump(fd, args);
+ }
+ players.add(p);
+ }
+ }
+
+ result.append(" Files opened and/or mapped:\n");
+ snprintf(buffer, SIZE, "/proc/%d/maps", getpid());
+ FILE *f = fopen(buffer, "r");
+ if (f) {
+ while (!feof(f)) {
+ fgets(buffer, SIZE, f);
+ if (strstr(buffer, " /storage/") ||
+ strstr(buffer, " /system/sounds/") ||
+ strstr(buffer, " /data/") ||
+ strstr(buffer, " /system/media/")) {
+ result.append(" ");
+ result.append(buffer);
+ }
+ }
+ fclose(f);
+ } else {
+ result.append("couldn't open ");
+ result.append(buffer);
+ result.append("\n");
+ }
+
+ snprintf(buffer, SIZE, "/proc/%d/fd", getpid());
+ DIR *d = opendir(buffer);
+ if (d) {
+ struct dirent *ent;
+ while((ent = readdir(d)) != NULL) {
+ if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) {
+ snprintf(buffer, SIZE, "/proc/%d/fd/%s", getpid(), ent->d_name);
+ struct stat s;
+ if (lstat(buffer, &s) == 0) {
+ if ((s.st_mode & S_IFMT) == S_IFLNK) {
+ char linkto[256];
+ int len = readlink(buffer, linkto, sizeof(linkto));
+ if(len > 0) {
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+ if (strstr(linkto, "/storage/") == linkto ||
+ strstr(linkto, "/system/sounds/") == linkto ||
+ strstr(linkto, "/data/") == linkto ||
+ strstr(linkto, "/system/media/") == linkto) {
+ result.append(" ");
+ result.append(buffer);
+ result.append(" -> ");
+ result.append(linkto);
+ result.append("\n");
+ }
+ }
+ } else {
+ result.append(" unexpected type for ");
+ result.append(buffer);
+ result.append("\n");
+ }
+ }
+ }
+ }
+ closedir(d);
+ } else {
+ result.append("couldn't open ");
+ result.append(buffer);
+ result.append("\n");
+ }
+
+ gLooperRoster.dump(fd, args);
+
+ bool dumpMem = false;
+ bool unreachableMemory = false;
+ for (size_t i = 0; i < args.size(); i++) {
+ if (args[i] == String16("-m")) {
+ dumpMem = true;
+ } else if (args[i] == String16("--unreachable")) {
+ unreachableMemory = true;
+ }
+ }
+ if (dumpMem) {
+ result.append("\nDumping memory:\n");
+ std::string s = dumpMemoryAddresses(100 /* limit */);
+ result.append(s.c_str(), s.size());
+ }
+ if (unreachableMemory) {
+ result.append("\nDumping unreachable memory:\n");
+ // TODO - should limit be an argument parameter?
+ // TODO: enable GetUnreachableMemoryString if it's part of stable API
+ //std::string s = GetUnreachableMemoryString(true /* contents */, 10000 /* limit */);
+ //result.append(s.c_str(), s.size());
+ }
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+} // anonymous namespace
+
+//static
+sp<MediaPlayer2> MediaPlayer2::Create() {
+ sp<MediaPlayer2> player = new MediaPlayer2();
+
+ if (!player->init()) {
+ return NULL;
+ }
+
+ ALOGV("Create new player(%p)", player.get());
+
+ addPlayer(player);
+ return player;
+}
+
+// static
+status_t MediaPlayer2::DumpAll(int fd, const Vector<String16>& args) {
+ return dumpPlayers(fd, args);
+}
+
+MediaPlayer2::MediaPlayer2() {
ALOGV("constructor");
mSrcId = 0;
+ mLockThreadId = 0;
mListener = NULL;
- mCookie = NULL;
mStreamType = AUDIO_STREAM_MUSIC;
mAudioAttributesParcel = NULL;
mCurrentPosition = -1;
@@ -66,14 +413,18 @@
mLoop = false;
mLeftVolume = mRightVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
- mLockThreadId = 0;
mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
mSendLevel = 0;
+
+ // TODO: get pid and uid from JAVA
+ mPid = IPCThreadState::self()->getCallingPid();
+ mUid = IPCThreadState::self()->getCallingUid();
+
+ mAudioAttributes = NULL;
}
-MediaPlayer2::~MediaPlayer2()
-{
+MediaPlayer2::~MediaPlayer2() {
ALOGV("destructor");
if (mAudioAttributesParcel != NULL) {
delete mAudioAttributesParcel;
@@ -81,13 +432,21 @@
}
AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
disconnect();
- IPCThreadState::self()->flushCommands();
+ removePlayer(this);
+ if (mAudioAttributes != NULL) {
+ free(mAudioAttributes);
+ }
}
-void MediaPlayer2::disconnect()
-{
+bool MediaPlayer2::init() {
+ // TODO: after merge with NuPlayer2Driver, MediaPlayer2 will have its own
+ // looper for notification.
+ return true;
+}
+
+void MediaPlayer2::disconnect() {
ALOGV("disconnect");
- sp<MediaPlayer2Engine> p;
+ sp<MediaPlayer2Interface> p;
{
Mutex::Autolock _l(mLock);
p = mPlayer;
@@ -95,13 +454,17 @@
}
if (p != 0) {
- p->disconnect();
+ p->setListener(NULL);
+ p->reset();
+ }
+
+ {
+ Mutex::Autolock _l(mLock);
+ disconnectNativeWindow_l();
}
}
-// always call with lock held
-void MediaPlayer2::clear_l()
-{
+void MediaPlayer2::clear_l() {
mCurrentPosition = -1;
mCurrentSeekMode = MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC;
mSeekPosition = -1;
@@ -109,8 +472,7 @@
mVideoWidth = mVideoHeight = 0;
}
-status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener)
-{
+status_t MediaPlayer2::setListener(const sp<MediaPlayer2Listener>& listener) {
ALOGV("setListener");
Mutex::Autolock _l(mLock);
mListener = listener;
@@ -127,51 +489,54 @@
return OK;
}
-status_t MediaPlayer2::attachNewPlayer(const sp<MediaPlayer2Engine>& player, long srcId)
-{
- status_t err = UNKNOWN_ERROR;
- sp<MediaPlayer2Engine> p;
- { // scope for the lock
- Mutex::Autolock _l(mLock);
-
- if ( !( (mCurrentState & MEDIA_PLAYER2_IDLE) ||
- (mCurrentState == MEDIA_PLAYER2_STATE_ERROR ) ) ) {
- ALOGE("attachNewPlayer called in state %d", mCurrentState);
- return INVALID_OPERATION;
- }
-
- clear_l();
- p = mPlayer;
- mPlayer = player;
- mSrcId = srcId;
- if (player != 0) {
- mCurrentState = MEDIA_PLAYER2_INITIALIZED;
- err = NO_ERROR;
- } else {
- ALOGE("Unable to create media player");
- }
- }
-
- if (p != 0) {
- p->disconnect();
- }
-
- return err;
-}
-
-status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd)
-{
+status_t MediaPlayer2::setDataSource(const sp<DataSourceDesc> &dsd) {
if (dsd == NULL) {
return BAD_VALUE;
}
- ALOGV("setDataSource type(%d)", dsd->mType);
- status_t err = UNKNOWN_ERROR;
- sp<MediaPlayer2Engine> player(MediaPlayer2Manager::get().create(this, mAudioSessionId));
- if (NO_ERROR != player->setDataSource(dsd)) {
- player.clear();
+ ALOGV("setDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
+
+ sp<MediaPlayer2Interface> oldPlayer;
+
+ Mutex::Autolock _l(mLock);
+ {
+ if (!((mCurrentState & MEDIA_PLAYER2_IDLE)
+ || mCurrentState == MEDIA_PLAYER2_STATE_ERROR)) {
+ ALOGE("setDataSource called in wrong state %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ sp<MediaPlayer2Interface> player = new NuPlayer2Driver(mPid, mUid);
+ status_t err = player->initCheck();
+ if (err != NO_ERROR) {
+ ALOGE("Failed to create player object, initCheck failed(%d)", err);
+ return err;
+ }
+
+ clear_l();
+
+ player->setListener(new proxyListener(this));
+ mAudioOutput = new MediaPlayer2AudioOutput(mAudioSessionId, mUid,
+ mPid, mAudioAttributes, new AudioDeviceUpdatedNotifier(player));
+ player->setAudioSink(mAudioOutput);
+
+ err = player->setDataSource(dsd);
+ if (err != OK) {
+ ALOGE("setDataSource error: %d", err);
+ return err;
+ }
+
+ sp<MediaPlayer2Interface> oldPlayer = mPlayer;
+ mPlayer = player;
+ mSrcId = dsd->mId;
+ mCurrentState = MEDIA_PLAYER2_INITIALIZED;
}
- err = attachNewPlayer(player, dsd->mId);
- return err;
+
+ if (oldPlayer != NULL) {
+ oldPlayer->setListener(NULL);
+ oldPlayer->reset();
+ }
+
+ return OK;
}
status_t MediaPlayer2::prepareNextDataSource(const sp<DataSourceDesc> &dsd) {
@@ -181,81 +546,179 @@
ALOGV("prepareNextDataSource type(%d), srcId(%lld)", dsd->mType, (long long)dsd->mId);
Mutex::Autolock _l(mLock);
- if (mPlayer != NULL) {
- return mPlayer->prepareNextDataSource(dsd);
+ if (mPlayer == NULL) {
+ ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+ return INVALID_OPERATION;
}
- ALOGE("prepareNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
+ return mPlayer->prepareNextDataSource(dsd);
}
status_t MediaPlayer2::playNextDataSource(int64_t srcId) {
ALOGV("playNextDataSource srcId(%lld)", (long long)srcId);
Mutex::Autolock _l(mLock);
- if (mPlayer != NULL) {
- mSrcId = srcId;
- return mPlayer->playNextDataSource(srcId);
+ if (mPlayer == NULL) {
+ ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+ return INVALID_OPERATION;
}
- ALOGE("playNextDataSource failed: state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
+ mSrcId = srcId;
+ return mPlayer->playNextDataSource(srcId);
}
-status_t MediaPlayer2::invoke(const Parcel& request, Parcel *reply)
-{
+status_t MediaPlayer2::invoke(const Parcel& request, Parcel *reply) {
Mutex::Autolock _l(mLock);
const bool hasBeenInitialized =
(mCurrentState != MEDIA_PLAYER2_STATE_ERROR) &&
((mCurrentState & MEDIA_PLAYER2_IDLE) != MEDIA_PLAYER2_IDLE);
- if ((mPlayer != NULL) && hasBeenInitialized) {
- ALOGV("invoke %zu", request.dataSize());
- return mPlayer->invoke(request, reply);
+ if ((mPlayer == NULL) || !hasBeenInitialized) {
+ ALOGE("invoke failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
+ return INVALID_OPERATION;
}
- ALOGE("invoke failed: wrong state %X, mPlayer(%p)", mCurrentState, mPlayer.get());
- return INVALID_OPERATION;
+ ALOGV("invoke %zu", request.dataSize());
+ return mPlayer->invoke(request, reply);
}
-status_t MediaPlayer2::setMetadataFilter(const Parcel& filter)
-{
+// This call doesn't need to access the native player.
+status_t MediaPlayer2::setMetadataFilter(const Parcel& filter) {
ALOGD("setMetadataFilter");
- Mutex::Autolock lock(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
+
+ status_t status;
+ media::Metadata::Filter allow, drop;
+
+ if (unmarshallFilter(filter, &allow, &status) &&
+ unmarshallFilter(filter, &drop, &status)) {
+ Mutex::Autolock lock(mLock);
+
+ mMetadataAllow = allow;
+ mMetadataDrop = drop;
}
- return mPlayer->setMetadataFilter(filter);
+ return status;
}
-status_t MediaPlayer2::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
-{
+status_t MediaPlayer2::getMetadata(bool update_only, bool /* apply_filter */, Parcel *reply) {
ALOGD("getMetadata");
+ sp<MediaPlayer2Interface> player;
+ media::Metadata::Filter ids;
Mutex::Autolock lock(mLock);
- if (mPlayer == NULL) {
+ {
+ if (mPlayer == NULL) {
+ return NO_INIT;
+ }
+
+ player = mPlayer;
+ // Placeholder for the return code, updated by the caller.
+ reply->writeInt32(-1);
+
+ // We don't block notifications while we fetch the data. We clear
+ // mMetadataUpdated first so we don't lose notifications happening
+ // during the rest of this call.
+ if (update_only) {
+ ids = mMetadataUpdated;
+ }
+ mMetadataUpdated.clear();
+ }
+
+ media::Metadata metadata(reply);
+
+ metadata.appendHeader();
+ status_t status = player->getMetadata(ids, reply);
+
+ if (status != OK) {
+ metadata.resetParcel();
+ ALOGE("getMetadata failed %d", status);
+ return status;
+ }
+
+ // FIXME: ement filtering on the result. Not critical since
+ // filtering takes place on the update notifications already. This
+ // would be when all the metadata are fetch and a filter is set.
+
+ // Everything is fine, update the metadata length.
+ metadata.updateLength();
+ return OK;
+}
+
+void MediaPlayer2::disconnectNativeWindow_l() {
+ if (mConnectedWindow != NULL && mConnectedWindow->getANativeWindow() != NULL) {
+ status_t err = native_window_api_disconnect(
+ mConnectedWindow->getANativeWindow(), NATIVE_WINDOW_API_MEDIA);
+
+ if (err != OK) {
+ ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
+ strerror(-err), err);
+ }
+ }
+ mConnectedWindow.clear();
+}
+
+status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww) {
+ ANativeWindow *anw = (nww == NULL ? NULL : nww->getANativeWindow());
+ ALOGV("setVideoSurfaceTexture(%p)", anw);
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) {
return NO_INIT;
}
- return mPlayer->getMetadata(update_only, apply_filter, metadata);
+
+ if (anw != NULL) {
+ if (mConnectedWindow != NULL
+ && mConnectedWindow->getANativeWindow() == anw) {
+ return OK;
+ }
+ status_t err = native_window_api_connect(anw, NATIVE_WINDOW_API_MEDIA);
+
+ if (err != OK) {
+ ALOGE("setVideoSurfaceTexture failed: %d", err);
+ // Note that we must do the reset before disconnecting from the ANW.
+ // Otherwise queue/dequeue calls could be made on the disconnected
+ // ANW, which may result in errors.
+ mPlayer->reset();
+ disconnectNativeWindow_l();
+ return err;
+ }
+ }
+
+ // Note that we must set the player's new GraphicBufferProducer before
+ // disconnecting the old one. Otherwise queue/dequeue calls could be made
+ // on the disconnected ANW, which may result in errors.
+ status_t err = mPlayer->setVideoSurfaceTexture(nww);
+
+ disconnectNativeWindow_l();
+
+ if (err == OK) {
+ mConnectedWindow = nww;
+ mLock.unlock();
+ } else if (anw != NULL) {
+ mLock.unlock();
+ status_t err = native_window_api_disconnect(anw, NATIVE_WINDOW_API_MEDIA);
+
+ if (err != OK) {
+ ALOGW("nativeWindowDisconnect returned an error: %s (%d)",
+ strerror(-err), err);
+ }
+ }
+
+ return err;
}
-status_t MediaPlayer2::setVideoSurfaceTexture(const sp<ANativeWindowWrapper>& nww)
-{
- ALOGV("setVideoSurfaceTexture");
- Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return NO_INIT;
- return mPlayer->setVideoSurfaceTexture(nww);
-}
-
-status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */)
-{
+status_t MediaPlayer2::getBufferingSettings(BufferingSettings* buffering /* nonnull */) {
ALOGV("getBufferingSettings");
Mutex::Autolock _l(mLock);
if (mPlayer == 0) {
return NO_INIT;
}
- return mPlayer->getBufferingSettings(buffering);
+
+ status_t ret = mPlayer->getBufferingSettings(buffering);
+ if (ret == NO_ERROR) {
+ ALOGV("getBufferingSettings{%s}", buffering->toString().string());
+ } else {
+ ALOGE("getBufferingSettings returned %d", ret);
+ }
+ return ret;
}
-status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering)
-{
- ALOGV("setBufferingSettings");
+status_t MediaPlayer2::setBufferingSettings(const BufferingSettings& buffering) {
+ ALOGV("setBufferingSettings{%s}", buffering.toString().string());
Mutex::Autolock _l(mLock);
if (mPlayer == 0) {
@@ -264,14 +727,37 @@
return mPlayer->setBufferingSettings(buffering);
}
-// must call with lock held
-status_t MediaPlayer2::prepareAsync_l()
-{
- if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_STOPPED) ) ) {
+status_t MediaPlayer2::setAudioAttributes_l(const Parcel &parcel) {
+ if (mAudioAttributes != NULL) {
+ free(mAudioAttributes);
+ }
+ mAudioAttributes = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t));
+ if (mAudioAttributes == NULL) {
+ return NO_MEMORY;
+ }
+ unmarshallAudioAttributes(parcel, mAudioAttributes);
+
+ ALOGV("setAudioAttributes_l() usage=%d content=%d flags=0x%x tags=%s",
+ mAudioAttributes->usage, mAudioAttributes->content_type, mAudioAttributes->flags,
+ mAudioAttributes->tags);
+
+ if (mAudioOutput != 0) {
+ mAudioOutput->setAudioAttributes(mAudioAttributes);
+ }
+ return NO_ERROR;
+}
+
+status_t MediaPlayer2::prepareAsync() {
+ ALOGV("prepareAsync");
+ Mutex::Autolock _l(mLock);
+ if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_INITIALIZED | MEDIA_PLAYER2_STOPPED))) {
if (mAudioAttributesParcel != NULL) {
- mPlayer->setParameter(MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
- } else {
- mPlayer->setAudioStreamType(mStreamType);
+ status_t err = setAudioAttributes_l(*mAudioAttributesParcel);
+ if (err != OK) {
+ return err;
+ }
+ } else if (mAudioOutput != 0) {
+ mAudioOutput->setAudioStreamType(mStreamType);
}
mCurrentState = MEDIA_PLAYER2_PREPARING;
return mPlayer->prepareAsync();
@@ -280,15 +766,7 @@
return INVALID_OPERATION;
}
-status_t MediaPlayer2::prepareAsync()
-{
- ALOGV("prepareAsync");
- Mutex::Autolock _l(mLock);
- return prepareAsync_l();
-}
-
-status_t MediaPlayer2::start()
-{
+status_t MediaPlayer2::start() {
ALOGV("start");
status_t ret = NO_ERROR;
@@ -301,8 +779,14 @@
} else if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_PREPARED |
MEDIA_PLAYER2_PLAYBACK_COMPLETE | MEDIA_PLAYER2_PAUSED ) ) ) {
mPlayer->setLooping(mLoop);
- mPlayer->setVolume(mLeftVolume, mRightVolume);
- mPlayer->setAuxEffectSendLevel(mSendLevel);
+
+ if (mAudioOutput != 0) {
+ mAudioOutput->setVolume(mLeftVolume, mRightVolume);
+ }
+
+ if (mAudioOutput != 0) {
+ mAudioOutput->setAuxEffectSendLevel(mSendLevel);
+ }
mCurrentState = MEDIA_PLAYER2_STARTED;
ret = mPlayer->start();
if (ret != NO_ERROR) {
@@ -322,8 +806,7 @@
return ret;
}
-status_t MediaPlayer2::stop()
-{
+status_t MediaPlayer2::stop() {
ALOGV("stop");
Mutex::Autolock _l(mLock);
if (mCurrentState & MEDIA_PLAYER2_STOPPED) return NO_ERROR;
@@ -341,8 +824,7 @@
return INVALID_OPERATION;
}
-status_t MediaPlayer2::pause()
-{
+status_t MediaPlayer2::pause() {
ALOGV("pause");
Mutex::Autolock _l(mLock);
if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
@@ -360,12 +842,10 @@
return INVALID_OPERATION;
}
-bool MediaPlayer2::isPlaying()
-{
+bool MediaPlayer2::isPlaying() {
Mutex::Autolock _l(mLock);
if (mPlayer != 0) {
- bool temp = false;
- mPlayer->isPlaying(&temp);
+ bool temp = mPlayer->isPlaying();
ALOGV("isPlaying: %d", temp);
if ((mCurrentState & MEDIA_PLAYER2_STARTED) && ! temp) {
ALOGE("internal/external state mismatch corrected");
@@ -380,13 +860,12 @@
return false;
}
-status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate)
-{
+status_t MediaPlayer2::setPlaybackSettings(const AudioPlaybackRate& rate) {
ALOGV("setPlaybackSettings: %f %f %d %d",
rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
// Negative speed and pitch does not make sense. Further validation will
// be done by the respective mediaplayers.
- if (rate.mSpeed < 0.f || rate.mPitch < 0.f) {
+ if (rate.mSpeed <= 0.f || rate.mPitch < 0.f) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
@@ -394,36 +873,27 @@
return INVALID_OPERATION;
}
- if (rate.mSpeed != 0.f && !(mCurrentState & MEDIA_PLAYER2_STARTED)
- && (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED
- | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
- mPlayer->setLooping(mLoop);
- mPlayer->setVolume(mLeftVolume, mRightVolume);
- mPlayer->setAuxEffectSendLevel(mSendLevel);
- }
-
status_t err = mPlayer->setPlaybackSettings(rate);
- if (err == OK) {
- if (rate.mSpeed == 0.f && mCurrentState == MEDIA_PLAYER2_STARTED) {
- mCurrentState = MEDIA_PLAYER2_PAUSED;
- } else if (rate.mSpeed != 0.f
- && (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED
- | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
- mCurrentState = MEDIA_PLAYER2_STARTED;
- }
- }
return err;
}
-status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
-{
+status_t MediaPlayer2::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
+ if (mPlayer == 0) {
+ return INVALID_OPERATION;
+ }
return mPlayer->getPlaybackSettings(rate);
+ status_t ret = mPlayer->getPlaybackSettings(rate);
+ if (ret == NO_ERROR) {
+ ALOGV("getPlaybackSettings(%f, %f, %d, %d)",
+ rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode);
+ } else {
+ ALOGV("getPlaybackSettings returned %d", ret);
+ }
+ return ret;
}
-status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint)
-{
+status_t MediaPlayer2::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) {
ALOGV("setSyncSettings: %u %u %f %f",
sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint);
Mutex::Autolock _l(mLock);
@@ -432,83 +902,92 @@
}
status_t MediaPlayer2::getSyncSettings(
- AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
-{
+ AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
Mutex::Autolock _l(mLock);
if (mPlayer == 0) return INVALID_OPERATION;
- return mPlayer->getSyncSettings(sync, videoFps);
+ status_t ret = mPlayer->getSyncSettings(sync, videoFps);
+ if (ret == NO_ERROR) {
+ ALOGV("getSyncSettings(%u, %u, %f, %f)",
+ sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps);
+ } else {
+ ALOGV("getSyncSettings returned %d", ret);
+ }
+ return ret;
+
}
-status_t MediaPlayer2::getVideoWidth(int *w)
-{
+status_t MediaPlayer2::getVideoWidth(int *w) {
ALOGV("getVideoWidth");
Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
+ if (mPlayer == 0) {
+ return INVALID_OPERATION;
+ }
*w = mVideoWidth;
return NO_ERROR;
}
-status_t MediaPlayer2::getVideoHeight(int *h)
-{
+status_t MediaPlayer2::getVideoHeight(int *h) {
ALOGV("getVideoHeight");
Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
+ if (mPlayer == 0) {
+ return INVALID_OPERATION;
+ }
*h = mVideoHeight;
return NO_ERROR;
}
-status_t MediaPlayer2::getCurrentPosition(int *msec)
-{
+status_t MediaPlayer2::getCurrentPosition(int *msec) {
ALOGV("getCurrentPosition");
Mutex::Autolock _l(mLock);
- if (mPlayer != 0) {
- if (mCurrentPosition >= 0) {
- ALOGV("Using cached seek position: %d", mCurrentPosition);
- *msec = mCurrentPosition;
- return NO_ERROR;
- }
- return mPlayer->getCurrentPosition(msec);
+ if (mPlayer == 0) {
+ return INVALID_OPERATION;
}
- return INVALID_OPERATION;
+ if (mCurrentPosition >= 0) {
+ ALOGV("Using cached seek position: %d", mCurrentPosition);
+ *msec = mCurrentPosition;
+ return NO_ERROR;
+ }
+ status_t ret = mPlayer->getCurrentPosition(msec);
+ if (ret == NO_ERROR) {
+ ALOGV("getCurrentPosition = %d", *msec);
+ } else {
+ ALOGE("getCurrentPosition returned %d", ret);
+ }
+ return ret;
}
-status_t MediaPlayer2::getDuration_l(int *msec)
-{
+status_t MediaPlayer2::getDuration(int *msec) {
+ Mutex::Autolock _l(mLock);
ALOGV("getDuration_l");
bool isValidState = (mCurrentState & (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_STOPPED | MEDIA_PLAYER2_PLAYBACK_COMPLETE));
- if (mPlayer != 0 && isValidState) {
- int durationMs;
- status_t ret = mPlayer->getDuration(&durationMs);
-
- if (ret != OK) {
- // Do not enter error state just because no duration was available.
- durationMs = -1;
- ret = OK;
- }
-
- if (msec) {
- *msec = durationMs;
- }
- return ret;
+ if (mPlayer == 0 || !isValidState) {
+ ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
+ mPlayer.get(), mCurrentState);
+ return INVALID_OPERATION;
}
- ALOGE("Attempt to call getDuration in wrong state: mPlayer=%p, mCurrentState=%u",
- mPlayer.get(), mCurrentState);
- return INVALID_OPERATION;
+ int durationMs;
+ status_t ret = mPlayer->getDuration(&durationMs);
+
+ if (ret == NO_ERROR) {
+ ALOGV("getDuration = %d", durationMs);
+ } else {
+ ALOGE("getDuration returned %d", ret);
+ // Do not enter error state just because no duration was available.
+ durationMs = -1;
+ }
+
+ if (msec) {
+ *msec = durationMs;
+ }
+ return OK;
}
-status_t MediaPlayer2::getDuration(int *msec)
-{
- Mutex::Autolock _l(mLock);
- return getDuration_l(msec);
-}
-
-status_t MediaPlayer2::seekTo_l(int msec, MediaPlayer2SeekMode mode)
-{
+status_t MediaPlayer2::seekTo_l(int msec, MediaPlayer2SeekMode mode) {
ALOGV("seekTo (%d, %d)", msec, mode);
if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED |
MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE) ) ) {
- if ( msec < 0 ) {
+ if (msec < 0) {
ALOGW("Attempt to seek to invalid position: %d", msec);
msec = 0;
}
@@ -537,8 +1016,7 @@
mSeekPosition = msec;
mSeekMode = mode;
return mPlayer->seekTo(msec, mode);
- }
- else {
+ } else {
ALOGV("Seek in progress - queue up seekTo[%d, %d]", msec, mode);
return NO_ERROR;
}
@@ -548,8 +1026,7 @@
return INVALID_OPERATION;
}
-status_t MediaPlayer2::seekTo(int msec, MediaPlayer2SeekMode mode)
-{
+status_t MediaPlayer2::seekTo(int msec, MediaPlayer2SeekMode mode) {
mLockThreadId = getThreadId();
Mutex::Autolock _l(mLock);
status_t result = seekTo_l(msec, mode);
@@ -558,26 +1035,27 @@
return result;
}
-status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs)
-{
+status_t MediaPlayer2::notifyAt(int64_t mediaTimeUs) {
Mutex::Autolock _l(mLock);
if (mPlayer != 0) {
- return mPlayer->notifyAt(mediaTimeUs);
+ return INVALID_OPERATION;
}
- return INVALID_OPERATION;
+
+ return mPlayer->notifyAt(mediaTimeUs);
}
-status_t MediaPlayer2::reset_l()
-{
+status_t MediaPlayer2::reset_l() {
mLoop = false;
- if (mCurrentState == MEDIA_PLAYER2_IDLE) return NO_ERROR;
+ if (mCurrentState == MEDIA_PLAYER2_IDLE) {
+ return NO_ERROR;
+ }
if (mPlayer != 0) {
status_t ret = mPlayer->reset();
if (ret != NO_ERROR) {
ALOGE("reset() failed with return code (%d)", ret);
mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
} else {
- mPlayer->disconnect();
+ mPlayer->setListener(NULL);
mCurrentState = MEDIA_PLAYER2_IDLE;
}
// setDataSource has to be called again to create a
@@ -589,8 +1067,7 @@
return NO_ERROR;
}
-status_t MediaPlayer2::reset()
-{
+status_t MediaPlayer2::reset() {
ALOGV("reset");
mLockThreadId = getThreadId();
Mutex::Autolock _l(mLock);
@@ -600,8 +1077,7 @@
return result;
}
-status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type)
-{
+status_t MediaPlayer2::setAudioStreamType(audio_stream_type_t type) {
ALOGV("MediaPlayer2::setAudioStreamType");
Mutex::Autolock _l(mLock);
if (mStreamType == type) return NO_ERROR;
@@ -616,16 +1092,14 @@
return OK;
}
-status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type)
-{
+status_t MediaPlayer2::getAudioStreamType(audio_stream_type_t *type) {
ALOGV("getAudioStreamType");
Mutex::Autolock _l(mLock);
*type = mStreamType;
return OK;
}
-status_t MediaPlayer2::setLooping(int loop)
-{
+status_t MediaPlayer2::setLooping(int loop) {
ALOGV("MediaPlayer2::setLooping");
Mutex::Autolock _l(mLock);
mLoop = (loop != 0);
@@ -645,20 +1119,18 @@
return false;
}
-status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume)
-{
+status_t MediaPlayer2::setVolume(float leftVolume, float rightVolume) {
ALOGV("MediaPlayer2::setVolume(%f, %f)", leftVolume, rightVolume);
Mutex::Autolock _l(mLock);
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
- if (mPlayer != 0) {
- return mPlayer->setVolume(leftVolume, rightVolume);
+ if (mAudioOutput != 0) {
+ mAudioOutput->setVolume(leftVolume, rightVolume);
}
return OK;
}
-status_t MediaPlayer2::setAudioSessionId(audio_session_t sessionId)
-{
+status_t MediaPlayer2::setAudioSessionId(audio_session_t sessionId) {
ALOGV("MediaPlayer2::setAudioSessionId(%d)", sessionId);
Mutex::Autolock _l(mLock);
if (!(mCurrentState & MEDIA_PLAYER2_IDLE)) {
@@ -676,40 +1148,36 @@
return NO_ERROR;
}
-audio_session_t MediaPlayer2::getAudioSessionId()
-{
+audio_session_t MediaPlayer2::getAudioSessionId() {
Mutex::Autolock _l(mLock);
return mAudioSessionId;
}
-status_t MediaPlayer2::setAuxEffectSendLevel(float level)
-{
+status_t MediaPlayer2::setAuxEffectSendLevel(float level) {
ALOGV("MediaPlayer2::setAuxEffectSendLevel(%f)", level);
Mutex::Autolock _l(mLock);
mSendLevel = level;
- if (mPlayer != 0) {
- return mPlayer->setAuxEffectSendLevel(level);
+ if (mAudioOutput != 0) {
+ return mAudioOutput->setAuxEffectSendLevel(level);
}
return OK;
}
-status_t MediaPlayer2::attachAuxEffect(int effectId)
-{
+status_t MediaPlayer2::attachAuxEffect(int effectId) {
ALOGV("MediaPlayer2::attachAuxEffect(%d)", effectId);
Mutex::Autolock _l(mLock);
- if (mPlayer == 0 ||
+ if (mAudioOutput == 0 ||
(mCurrentState & MEDIA_PLAYER2_IDLE) ||
(mCurrentState == MEDIA_PLAYER2_STATE_ERROR )) {
ALOGE("attachAuxEffect called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
return INVALID_OPERATION;
}
- return mPlayer->attachAuxEffect(effectId);
+ return mAudioOutput->attachAuxEffect(effectId);
}
// always call with lock held
-status_t MediaPlayer2::checkStateForKeySet_l(int key)
-{
+status_t MediaPlayer2::checkStateForKeySet_l(int key) {
switch(key) {
case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
if (mCurrentState & ( MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_STARTED |
@@ -726,8 +1194,7 @@
return OK;
}
-status_t MediaPlayer2::setParameter(int key, const Parcel& request)
-{
+status_t MediaPlayer2::setParameter(int key, const Parcel& request) {
ALOGV("MediaPlayer2::setParameter(%d)", key);
status_t status = INVALID_OPERATION;
Mutex::Autolock _l(mLock);
@@ -737,10 +1204,15 @@
switch (key) {
case MEDIA2_KEY_PARAMETER_AUDIO_ATTRIBUTES:
// save the marshalled audio attributes
- if (mAudioAttributesParcel != NULL) { delete mAudioAttributesParcel; };
+ if (mAudioAttributesParcel != NULL) {
+ delete mAudioAttributesParcel;
+ }
mAudioAttributesParcel = new Parcel();
mAudioAttributesParcel->appendFrom(&request, 0, request.dataSize());
- status = OK;
+ status = setAudioAttributes_l(request);
+ if (status != OK) {
+ return status;
+ }
break;
default:
ALOGV_IF(mPlayer == NULL, "setParameter: no active player");
@@ -753,25 +1225,59 @@
return status;
}
-status_t MediaPlayer2::getParameter(int key, Parcel *reply)
-{
+status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
ALOGV("MediaPlayer2::getParameter(%d)", key);
Mutex::Autolock _l(mLock);
- if (mPlayer != NULL) {
- status_t status = mPlayer->getParameter(key, reply);
- if (status != OK) {
- ALOGD("getParameter returns %d", status);
- }
- return status;
+ if (mPlayer == NULL) {
+ ALOGV("getParameter: no active player");
+ return INVALID_OPERATION;
}
- ALOGV("getParameter: no active player");
- return INVALID_OPERATION;
+
+ status_t status = mPlayer->getParameter(key, reply);
+ if (status != OK) {
+ ALOGD("getParameter returns %d", status);
+ }
+ return status;
}
-void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj)
-{
+bool MediaPlayer2::shouldDropMetadata(media::Metadata::Type code) const {
+ Mutex::Autolock lock(mLock);
+
+ if (findMetadata(mMetadataDrop, code)) {
+ return true;
+ }
+
+ if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code)) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+
+void MediaPlayer2::addNewMetadataUpdate(media::Metadata::Type metadata_type) {
+ Mutex::Autolock lock(mLock);
+ if (mMetadataUpdated.indexOf(metadata_type) < 0) {
+ mMetadataUpdated.add(metadata_type);
+ }
+}
+
+void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj) {
ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
(long long)srcId, msg, ext1, ext2);
+
+ if (MEDIA2_INFO == msg && MEDIA2_INFO_METADATA_UPDATE == ext1) {
+ const media::Metadata::Type metadata_type = ext2;
+
+ if(shouldDropMetadata(metadata_type)) {
+ return;
+ }
+
+ // Update the list of metadata that have changed. getMetadata
+ // also access mMetadataUpdated and clears it.
+ addNewMetadataUpdate(metadata_type);
+ }
+
bool send = true;
bool locked = false;
@@ -881,24 +1387,12 @@
}
}
-status_t MediaPlayer2::setNextMediaPlayer(const sp<MediaPlayer2>& next) {
- Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- return NO_INIT;
- }
-
- if (next != NULL && !(next->mCurrentState &
- (MEDIA_PLAYER2_PREPARED | MEDIA_PLAYER2_PAUSED | MEDIA_PLAYER2_PLAYBACK_COMPLETE))) {
- ALOGE("next player is not prepared");
- return INVALID_OPERATION;
- }
-
- return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer);
+status_t MediaPlayer2::setNextMediaPlayer(const sp<MediaPlayer2>& /* next */) {
+ return INVALID_OPERATION;
}
// Modular DRM
-status_t MediaPlayer2::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId)
-{
+status_t MediaPlayer2::prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId) {
// TODO change to ALOGV
ALOGD("prepareDrm: uuid: %p drmSessionId: %p(%zu)", uuid,
drmSessionId.array(), drmSessionId.size());
@@ -931,8 +1425,7 @@
return status;
}
-status_t MediaPlayer2::releaseDrm()
-{
+status_t MediaPlayer2::releaseDrm() {
Mutex::Autolock _l(mLock);
if (mPlayer == NULL) {
return NO_INIT;
@@ -960,39 +1453,74 @@
return status;
}
-status_t MediaPlayer2::setOutputDevice(audio_port_handle_t deviceId)
-{
+status_t MediaPlayer2::setOutputDevice(audio_port_handle_t deviceId) {
Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("setOutputDevice: player not init");
+ if (mAudioOutput == NULL) {
+ ALOGV("setOutputDevice: audio sink not init");
return NO_INIT;
}
- return mPlayer->setOutputDevice(deviceId);
+ return mAudioOutput->setOutputDevice(deviceId);
}
-audio_port_handle_t MediaPlayer2::getRoutedDeviceId()
-{
+audio_port_handle_t MediaPlayer2::getRoutedDeviceId() {
Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
- ALOGV("getRoutedDeviceId: player not init");
+ if (mAudioOutput == NULL) {
+ ALOGV("getRoutedDeviceId: audio sink not init");
return AUDIO_PORT_HANDLE_NONE;
}
audio_port_handle_t deviceId;
- status_t status = mPlayer->getRoutedDeviceId(&deviceId);
+ status_t status = mAudioOutput->getRoutedDeviceId(&deviceId);
if (status != NO_ERROR) {
return AUDIO_PORT_HANDLE_NONE;
}
return deviceId;
}
-status_t MediaPlayer2::enableAudioDeviceCallback(bool enabled)
-{
+status_t MediaPlayer2::enableAudioDeviceCallback(bool enabled) {
Mutex::Autolock _l(mLock);
- if (mPlayer == NULL) {
+ if (mAudioOutput == NULL) {
ALOGV("addAudioDeviceCallback: player not init");
return NO_INIT;
}
- return mPlayer->enableAudioDeviceCallback(enabled);
+ return mAudioOutput->enableAudioDeviceCallback(enabled);
+}
+
+status_t MediaPlayer2::dump(int fd, const Vector<String16>& args) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ result.append(" MediaPlayer2\n");
+ snprintf(buffer, 255, " pid(%d), looping(%s)\n", mPid, mLoop?"true": "false");
+ result.append(buffer);
+
+ sp<MediaPlayer2Interface> player;
+ sp<MediaPlayer2AudioOutput> audioOutput;
+ bool locked = false;
+ for (int i = 0; i < kDumpLockRetries; ++i) {
+ if (mLock.tryLock() == NO_ERROR) {
+ locked = true;
+ break;
+ }
+ usleep(kDumpLockSleepUs);
+ }
+
+ if (locked) {
+ player = mPlayer;
+ audioOutput = mAudioOutput;
+ mLock.unlock();
+ } else {
+ result.append(" lock is taken, no dump from player and audio output\n");
+ }
+ write(fd, result.string(), result.size());
+
+ if (player != NULL) {
+ player->dump(fd, args);
+ }
+ if (audioOutput != 0) {
+ audioOutput->dump(fd, args);
+ }
+ write(fd, "\n", 1);
+ return NO_ERROR;
}
} // namespace android