summaryrefslogtreecommitdiffstats
path: root/media/libmedia
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit2729ea9262ca60d93047e984739887cfc89e82eb (patch)
tree25962a3f1c5f70586af45c926c037e03c643857f /media/libmedia
downloadframeworks_av-2729ea9262ca60d93047e984739887cfc89e82eb.zip
frameworks_av-2729ea9262ca60d93047e984739887cfc89e82eb.tar.gz
frameworks_av-2729ea9262ca60d93047e984739887cfc89e82eb.tar.bz2
Initial Contribution
Diffstat (limited to 'media/libmedia')
-rw-r--r--media/libmedia/Android.mk34
-rw-r--r--media/libmedia/AudioRecord.cpp397
-rw-r--r--media/libmedia/AudioSystem.cpp255
-rw-r--r--media/libmedia/AudioTrack.cpp596
-rw-r--r--media/libmedia/IAudioFlinger.cpp450
-rw-r--r--media/libmedia/IAudioRecord.cpp100
-rw-r--r--media/libmedia/IAudioTrack.cpp140
-rw-r--r--media/libmedia/IMediaPlayer.cpp295
-rw-r--r--media/libmedia/IMediaPlayerClient.cpp77
-rw-r--r--media/libmedia/IMediaPlayerService.cpp157
-rw-r--r--media/libmedia/MODULE_LICENSE_APACHE20
-rw-r--r--media/libmedia/NOTICE190
-rw-r--r--media/libmedia/ToneGenerator.cpp662
-rw-r--r--media/libmedia/mediametadataretriever.cpp182
-rw-r--r--media/libmedia/mediaplayer.cpp582
15 files changed, 4117 insertions, 0 deletions
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
new file mode 100644
index 0000000..cfa837a
--- /dev/null
+++ b/media/libmedia/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ AudioTrack.cpp \
+ IAudioFlinger.cpp \
+ IAudioTrack.cpp \
+ IAudioRecord.cpp \
+ AudioRecord.cpp \
+ AudioSystem.cpp \
+ mediaplayer.cpp \
+ IMediaPlayerService.cpp \
+ IMediaPlayerClient.cpp \
+ IMediaPlayer.cpp \
+ mediametadataretriever.cpp \
+ ToneGenerator.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libui libcutils libutils
+
+LOCAL_MODULE:= libmedia
+
+ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
+LOCAL_LDLIBS += -ldl
+endif
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_C_INCLUDES := \
+ $(call include-path-for, graphics corecg)
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
new file mode 100644
index 0000000..f3e4123
--- /dev/null
+++ b/media/libmedia/AudioRecord.cpp
@@ -0,0 +1,397 @@
+/*
+**
+** Copyright 2008, 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_TAG "AudioRecord"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <media/AudioSystem.h>
+#include <media/AudioRecord.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Timers.h>
+#include <cutils/atomic.h>
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+AudioRecord::AudioRecord()
+ : mStatus(NO_INIT)
+{
+}
+
+AudioRecord::AudioRecord(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags,
+ callback_t cbf, void* user)
+ : mStatus(NO_INIT)
+{
+ mStatus = set(streamType, sampleRate, format, channelCount,
+ bufferCount, flags, cbf, user);
+}
+
+AudioRecord::~AudioRecord()
+{
+ if (mStatus == NO_ERROR) {
+ if (mPosition) {
+ releaseBuffer(&mAudioBuffer);
+ }
+ // obtainBuffer() will give up with an error
+ mAudioRecord->stop();
+ if (mClientRecordThread != 0) {
+ mClientRecordThread->requestExitAndWait();
+ mClientRecordThread.clear();
+ }
+ mAudioRecord.clear();
+ IPCThreadState::self()->flushCommands();
+ }
+}
+
+status_t AudioRecord::set(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags,
+ callback_t cbf, void* user)
+{
+
+ if (mAudioFlinger != 0) {
+ return INVALID_OPERATION;
+ }
+
+ const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+ if (audioFlinger == 0) {
+ return NO_INIT;
+ }
+
+ if (streamType == DEFAULT_INPUT) {
+ streamType = MIC_INPUT;
+ }
+
+ if (sampleRate == 0) {
+ sampleRate = DEFAULT_SAMPLE_RATE;
+ }
+ // these below should probably come from the audioFlinger too...
+ if (format == 0) {
+ format = AudioSystem::PCM_16_BIT;
+ }
+ if (channelCount == 0) {
+ channelCount = 1;
+ }
+ if (bufferCount == 0) {
+ bufferCount = 2;
+ } else if (bufferCount < 2) {
+ return BAD_VALUE;
+ }
+
+ // validate parameters
+ if (format != AudioSystem::PCM_16_BIT) {
+ return BAD_VALUE;
+ }
+ if (channelCount != 1 && channelCount != 2) {
+ return BAD_VALUE;
+ }
+ if (bufferCount < 2) {
+ return BAD_VALUE;
+ }
+
+ // open record channel
+ sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType,
+ sampleRate, format, channelCount, bufferCount, flags);
+ if (record == 0) {
+ return NO_INIT;
+ }
+ sp<IMemory> cblk = record->getCblk();
+ if (cblk == 0) {
+ return NO_INIT;
+ }
+ if (cbf != 0) {
+ mClientRecordThread = new ClientRecordThread(*this);
+ if (mClientRecordThread == 0) {
+ return NO_INIT;
+ }
+ }
+
+ mStatus = NO_ERROR;
+
+ mAudioFlinger = audioFlinger;
+ mAudioRecord = record;
+ mCblkMemory = cblk;
+ mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ mSampleRate = sampleRate;
+ mFrameCount = audioFlinger->frameCount();
+ mFormat = format;
+ mBufferCount = bufferCount;
+ mChannelCount = channelCount;
+ mActive = 0;
+ mCbf = cbf;
+ mUserData = user;
+ mLatency = seconds(mFrameCount) / mSampleRate;
+ mPosition = 0;
+ return NO_ERROR;
+}
+
+status_t AudioRecord::initCheck() const
+{
+ return mStatus;
+}
+
+// -------------------------------------------------------------------------
+
+nsecs_t AudioRecord::latency() const
+{
+ return mLatency;
+}
+
+uint32_t AudioRecord::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioRecord::format() const
+{
+ return mFormat;
+}
+
+int AudioRecord::channelCount() const
+{
+ return mChannelCount;
+}
+
+int AudioRecord::bufferCount() const
+{
+ return mBufferCount;
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioRecord::start()
+{
+ status_t ret = NO_ERROR;
+
+ // If using record thread, protect start sequence to make sure that
+ // no stop command is processed before the thread is started
+ if (mClientRecordThread != 0) {
+ mRecordThreadLock.lock();
+ }
+
+ if (android_atomic_or(1, &mActive) == 0) {
+ setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+ ret = mAudioRecord->start();
+ if (ret == NO_ERROR) {
+ if (mClientRecordThread != 0) {
+ mClientRecordThread->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
+ }
+ }
+ }
+
+ if (mClientRecordThread != 0) {
+ mRecordThreadLock.unlock();
+ }
+
+ return ret;
+}
+
+status_t AudioRecord::stop()
+{
+ // If using record thread, protect stop sequence to make sure that
+ // no start command is processed before requestExit() is called
+ if (mClientRecordThread != 0) {
+ mRecordThreadLock.lock();
+ }
+
+ if (android_atomic_and(~1, &mActive) == 1) {
+ if (mPosition) {
+ mPosition = 0;
+ releaseBuffer(&mAudioBuffer);
+ }
+ mAudioRecord->stop();
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
+ if (mClientRecordThread != 0) {
+ mClientRecordThread->requestExit();
+ }
+ }
+
+ if (mClientRecordThread != 0) {
+ mRecordThreadLock.unlock();
+ }
+
+ return NO_ERROR;
+}
+
+bool AudioRecord::stopped() const
+{
+ return !mActive;
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking)
+{
+ int active = mActive;
+ int timeout = 0;
+ status_t result;
+ audio_track_cblk_t* cblk = mCblk;
+
+ const uint32_t u = cblk->user;
+ uint32_t s = cblk->server;
+
+ if (u == s) {
+ Mutex::Autolock _l(cblk->lock);
+ goto start_loop_here;
+ while (u == s) {
+ active = mActive;
+ if (UNLIKELY(!active))
+ return NO_MORE_BUFFERS;
+ if (UNLIKELY(!blocking))
+ return WOULD_BLOCK;
+ timeout = 0;
+ result = cblk->cv.waitRelative(cblk->lock, seconds(1));
+ if (__builtin_expect(result!=NO_ERROR, false)) {
+ LOGW( "obtainBuffer timed out (is the CPU pegged?) "
+ "user=%08x, server=%08x", u, s);
+ timeout = 1;
+ }
+ // read the server count again
+ start_loop_here:
+ s = cblk->server;
+ }
+ }
+
+ LOGW_IF(timeout,
+ "*** SERIOUS WARNING *** obtainBuffer() timed out "
+ "but didn't need to be locked. We recovered, but "
+ "this shouldn't happen (user=%08x, server=%08x)", u, s);
+
+ audioBuffer->flags = 0;
+ audioBuffer->channelCount= mChannelCount;
+ audioBuffer->format = mFormat;
+ audioBuffer->frameCount = mFrameCount;
+ audioBuffer->size = cblk->size;
+ audioBuffer->raw = (int8_t*)
+ cblk->buffer(cblk->user & audio_track_cblk_t::BUFFER_MASK);
+ return active ? status_t(NO_ERROR) : status_t(STOPPED);
+}
+
+void AudioRecord::releaseBuffer(Buffer* audioBuffer)
+{
+ // next buffer...
+ if (UNLIKELY(mPosition)) {
+ // clean the remaining part of the buffer
+ size_t capacity = mAudioBuffer.size - mPosition;
+ memset(mAudioBuffer.i8 + mPosition, 0, capacity);
+ }
+ audio_track_cblk_t* cblk = mCblk;
+ cblk->stepUser(mBufferCount);
+}
+
+// -------------------------------------------------------------------------
+
+ssize_t AudioRecord::read(void* buffer, size_t userSize)
+{
+ ssize_t read = 0;
+ do {
+ if (mPosition == 0) {
+ status_t err = obtainBuffer(&mAudioBuffer, true);
+ if (err < 0) {
+ // out of buffers, return #bytes written
+ if (err == status_t(NO_MORE_BUFFERS))
+ break;
+ return ssize_t(err);
+ }
+ }
+
+ size_t capacity = mAudioBuffer.size - mPosition;
+ size_t toRead = userSize < capacity ? userSize : capacity;
+
+ memcpy(buffer, mAudioBuffer.i8 + mPosition, toRead);
+
+ buffer = static_cast<int8_t*>(buffer) + toRead;
+ mPosition += toRead;
+ userSize -= toRead;
+ capacity -= toRead;
+ read += toRead;
+
+ if (capacity == 0) {
+ mPosition = 0;
+ releaseBuffer(&mAudioBuffer);
+ }
+ } while (userSize);
+
+ return read;
+}
+
+// -------------------------------------------------------------------------
+
+bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread)
+{
+ Buffer audioBuffer;
+ bool more;
+
+ do {
+ status_t err = obtainBuffer(&audioBuffer, true);
+ if (err < NO_ERROR) {
+ LOGE("Error obtaining an audio buffer, giving up.");
+ return false;
+ }
+ more = mCbf(mUserData, audioBuffer);
+ releaseBuffer(&audioBuffer);
+ } while (more && !thread->exitPending());
+
+ // stop the track automatically
+ this->stop();
+
+ return true;
+}
+
+// =========================================================================
+
+AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver)
+ : Thread(false), mReceiver(receiver)
+{
+}
+
+bool AudioRecord::ClientRecordThread::threadLoop()
+{
+ return mReceiver.processAudioBuffer(this);
+}
+
+// -------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
new file mode 100644
index 0000000..22de463
--- /dev/null
+++ b/media/libmedia/AudioSystem.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2006-2007 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_TAG "AudioSystem"
+#include <utils/Log.h>
+#include <utils/IServiceManager.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+#include <math.h>
+
+namespace android {
+
+// client singleton for AudioFlinger binder interface
+Mutex AudioSystem::gLock;
+sp<IAudioFlinger> AudioSystem::gAudioFlinger;
+sp<AudioSystem::DeathNotifier> AudioSystem::gDeathNotifier;
+audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
+
+// establish binder interface to AudioFlinger service
+const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
+{
+ Mutex::Autolock _l(gLock);
+ if (gAudioFlinger.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.audio_flinger"));
+ if (binder != 0)
+ break;
+ LOGW("AudioFlinger not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+ if (gDeathNotifier == NULL) {
+ gDeathNotifier = new DeathNotifier();
+ } else {
+ if (gAudioErrorCallback) {
+ gAudioErrorCallback(NO_ERROR);
+ }
+ }
+ binder->linkToDeath(gDeathNotifier);
+ gAudioFlinger = interface_cast<IAudioFlinger>(binder);
+ }
+ LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");
+ return gAudioFlinger;
+}
+
+// routing helper functions
+status_t AudioSystem::speakerphone(bool state) {
+ uint32_t routes = state ? ROUTE_SPEAKER : ROUTE_EARPIECE;
+ return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
+}
+
+status_t AudioSystem::isSpeakerphoneOn(bool* state) {
+ uint32_t routes = 0;
+ status_t s = getRouting(MODE_IN_CALL, &routes);
+ *state = !!(routes & ROUTE_SPEAKER);
+ return s;
+}
+
+status_t AudioSystem::bluetoothSco(bool state) {
+ uint32_t mask = ROUTE_BLUETOOTH;
+ uint32_t routes = state ? mask : ROUTE_EARPIECE;
+ return setRouting(MODE_IN_CALL, routes, ROUTE_ALL);
+}
+
+status_t AudioSystem::isBluetoothScoOn(bool* state) {
+ uint32_t routes = 0;
+ status_t s = getRouting(MODE_IN_CALL, &routes);
+ *state = !!(routes & ROUTE_BLUETOOTH);
+ return s;
+}
+
+status_t AudioSystem::muteMicrophone(bool state) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setMicMute(state);
+}
+
+status_t AudioSystem::isMicrophoneMuted(bool* state) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *state = af->getMicMute();
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setMasterVolume(float value)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ af->setMasterVolume(value);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setMasterMute(bool mute)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ af->setMasterMute(mute);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getMasterVolume(float* volume)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *volume = af->masterVolume();
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getMasterMute(bool* mute)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *mute = af->masterMute();
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setStreamVolume(int stream, float value)
+{
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ af->setStreamVolume(stream, value);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setStreamMute(int stream, bool mute)
+{
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ af->setStreamMute(stream, mute);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getStreamVolume(int stream, float* volume)
+{
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *volume = af->streamVolume(stream);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::getStreamMute(int stream, bool* mute)
+{
+ if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *mute = af->streamMute(stream);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setMode(int mode)
+{
+ if (mode >= NUM_MODES) return BAD_VALUE;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setMode(mode);
+}
+
+status_t AudioSystem::getMode(int* mode)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *mode = af->getMode();
+ return NO_ERROR;
+}
+
+status_t AudioSystem::setRouting(int mode, uint32_t routes, uint32_t mask)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setRouting(mode, routes, mask);
+}
+
+status_t AudioSystem::getRouting(int mode, uint32_t* routes)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ uint32_t r = af->getRouting(mode);
+ *routes = r;
+ return NO_ERROR;
+}
+
+status_t AudioSystem::isMusicActive(bool* state) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *state = af->isMusicActive();
+ return NO_ERROR;
+}
+
+// Temporary interface, do not use
+// TODO: Replace with a more generic key:value get/set mechanism
+status_t AudioSystem::setParameter(const char* key, const char* value) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setParameter(key, value);
+}
+
+// convert volume steps to natural log scale
+
+// change this value to change volume scaling
+static const float dBPerStep = 0.5f;
+// shouldn't need to touch these
+static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f;
+static const float dBConvertInverse = 1.0f / dBConvert;
+
+float AudioSystem::linearToLog(int volume)
+{
+ // float v = volume ? exp(float(100 - volume) * dBConvert) : 0;
+ // LOGD("linearToLog(%d)=%f", volume, v);
+ // return v;
+ return volume ? exp(float(100 - volume) * dBConvert) : 0;
+}
+
+int AudioSystem::logToLinear(float volume)
+{
+ // int v = volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
+ // LOGD("logTolinear(%d)=%f", v, volume);
+ // return v;
+ return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0;
+}
+
+// ---------------------------------------------------------------------------
+
+void AudioSystem::DeathNotifier::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ AudioSystem::gAudioFlinger.clear();
+ if (gAudioErrorCallback) {
+ gAudioErrorCallback(DEAD_OBJECT);
+ }
+ LOGW("AudioFlinger server died!");
+}
+
+void AudioSystem::setErrorCallback(audio_error_callback cb) {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ gAudioErrorCallback = cb;
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
new file mode 100644
index 0000000..298170a
--- /dev/null
+++ b/media/libmedia/AudioTrack.cpp
@@ -0,0 +1,596 @@
+/* //device/extlibs/pv/android/AudioTrack.cpp
+**
+** Copyright 2007, 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 "AudioTrack"
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <sched.h>
+#include <sys/resource.h>
+
+#include <private/media/AudioTrackShared.h>
+
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+
+#include <utils/Log.h>
+#include <utils/MemoryDealer.h>
+#include <utils/Parcel.h>
+#include <utils/IPCThreadState.h>
+#include <utils/Timers.h>
+#include <cutils/atomic.h>
+
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+static volatile size_t gFrameCount = 0;
+
+size_t AudioTrack::frameCount()
+{
+ if (gFrameCount) return gFrameCount;
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ gFrameCount = af->frameCount();
+ return gFrameCount;
+}
+
+// ---------------------------------------------------------------------------
+
+AudioTrack::AudioTrack()
+ : mStatus(NO_INIT)
+{
+}
+
+AudioTrack::AudioTrack(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags,
+ callback_t cbf, void* user)
+ : mStatus(NO_INIT)
+{
+ mStatus = set(streamType, sampleRate, format, channelCount,
+ bufferCount, flags, cbf, user);
+}
+
+AudioTrack::~AudioTrack()
+{
+ if (mStatus == NO_ERROR) {
+ if (mPosition) {
+ releaseBuffer(&mAudioBuffer);
+ }
+ // obtainBuffer() will give up with an error
+ mAudioTrack->stop();
+ if (mAudioTrackThread != 0) {
+ mAudioTrackThread->requestExitAndWait();
+ mAudioTrackThread.clear();
+ }
+ mAudioTrack.clear();
+ IPCThreadState::self()->flushCommands();
+ }
+}
+
+status_t AudioTrack::set(
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags,
+ callback_t cbf, void* user)
+{
+
+ if (mAudioFlinger != 0) {
+ LOGE("Track already in use");
+ return INVALID_OPERATION;
+ }
+
+ const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+ if (audioFlinger == 0) {
+ LOGE("Could not get audioflinger");
+ return NO_INIT;
+ }
+
+ // handle default values first.
+ if (streamType == DEFAULT) {
+ streamType = MUSIC;
+ }
+ if (sampleRate == 0) {
+ sampleRate = audioFlinger->sampleRate();
+ }
+ // these below should probably come from the audioFlinger too...
+ if (format == 0) {
+ format = AudioSystem::PCM_16_BIT;
+ }
+ if (channelCount == 0) {
+ channelCount = 2;
+ }
+ if (bufferCount == 0) {
+ bufferCount = 2;
+ }
+
+ // validate parameters
+ if (format != AudioSystem::PCM_16_BIT) {
+ LOGE("Invalid format");
+ return BAD_VALUE;
+ }
+ if (channelCount != 1 && channelCount != 2) {
+ LOGE("Invalid channel number");
+ return BAD_VALUE;
+ }
+ if (bufferCount < 2) {
+ LOGE("Invalid buffer count");
+ return BAD_VALUE;
+ }
+
+ // create the track
+ sp<IAudioTrack> track = audioFlinger->createTrack(getpid(),
+ streamType, sampleRate, format, channelCount, bufferCount, flags);
+ if (track == 0) {
+ LOGE("AudioFlinger could not create track");
+ return NO_INIT;
+ }
+ sp<IMemory> cblk = track->getCblk();
+ if (cblk == 0) {
+ LOGE("Could not get control block");
+ return NO_INIT;
+ }
+ if (cbf != 0) {
+ mAudioTrackThread = new AudioTrackThread(*this);
+ if (mAudioTrackThread == 0) {
+ LOGE("Could not create callback thread");
+ return NO_INIT;
+ }
+ }
+
+ mStatus = NO_ERROR;
+
+ mAudioFlinger = audioFlinger;
+ mAudioTrack = track;
+ mCblkMemory = cblk;
+ mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
+ mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
+ mCblk->volume[0] = mCblk->volume[1] = 0x1000;
+ mVolume[LEFT] = 1.0f;
+ mVolume[RIGHT] = 1.0f;
+ mSampleRate = sampleRate;
+ mFrameCount = audioFlinger->frameCount();
+ mStreamType = streamType;
+ mFormat = format;
+ mBufferCount = bufferCount;
+ mChannelCount = channelCount;
+ mMuted = false;
+ mActive = 0;
+ mReserved = 0;
+ mCbf = cbf;
+ mUserData = user;
+ mLatency = seconds(mFrameCount) / mSampleRate;
+ mPosition = 0;
+ return NO_ERROR;
+}
+
+status_t AudioTrack::initCheck() const
+{
+ return mStatus;
+}
+
+// -------------------------------------------------------------------------
+
+nsecs_t AudioTrack::latency() const
+{
+ return mLatency;
+}
+
+int AudioTrack::streamType() const
+{
+ return mStreamType;
+}
+
+uint32_t AudioTrack::sampleRate() const
+{
+ return mSampleRate;
+}
+
+int AudioTrack::format() const
+{
+ return mFormat;
+}
+
+int AudioTrack::channelCount() const
+{
+ return mChannelCount;
+}
+
+int AudioTrack::bufferCount() const
+{
+ return mBufferCount;
+}
+
+// -------------------------------------------------------------------------
+
+void AudioTrack::start()
+{
+ sp<AudioTrackThread> t = mAudioTrackThread;
+
+ LOGV("start");
+ if (t != 0) {
+ if (t->exitPending()) {
+ if (t->requestExitAndWait() == WOULD_BLOCK) {
+ LOGE("AudioTrack::start called from thread");
+ return;
+ }
+ }
+ t->mLock.lock();
+ }
+
+ if (android_atomic_or(1, &mActive) == 0) {
+ if (t != 0) {
+ t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
+ } else {
+ setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
+ }
+ mAudioTrack->start();
+ }
+
+ if (t != 0) {
+ t->mLock.unlock();
+ }
+}
+
+void AudioTrack::stop()
+{
+ sp<AudioTrackThread> t = mAudioTrackThread;
+
+ LOGV("stop");
+ if (t != 0) {
+ t->mLock.lock();
+ }
+
+ if (android_atomic_and(~1, &mActive) == 1) {
+ if (mPosition) {
+ releaseBuffer(&mAudioBuffer);
+ }
+ mAudioTrack->stop();
+ if (t != 0) {
+ t->requestExit();
+ } else {
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
+ }
+ }
+
+ if (t != 0) {
+ t->mLock.unlock();
+ }
+}
+
+bool AudioTrack::stopped() const
+{
+ return !mActive;
+}
+
+void AudioTrack::flush()
+{
+ LOGV("flush");
+ if (!mActive) {
+ mCblk->lock.lock();
+ mAudioTrack->flush();
+ // Release AudioTrack callback thread in case it was waiting for new buffers
+ // in AudioTrack::obtainBuffer()
+ mCblk->cv.signal();
+ mCblk->lock.unlock();
+ }
+}
+
+void AudioTrack::pause()
+{
+ LOGV("pause");
+ if (android_atomic_and(~1, &mActive) == 1) {
+ mActive = 0;
+ mAudioTrack->pause();
+ }
+}
+
+void AudioTrack::mute(bool e)
+{
+ mAudioTrack->mute(e);
+ mMuted = e;
+}
+
+bool AudioTrack::muted() const
+{
+ return mMuted;
+}
+
+void AudioTrack::setVolume(float left, float right)
+{
+ mVolume[LEFT] = left;
+ mVolume[RIGHT] = right;
+
+ // write must be atomic
+ mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000);
+}
+
+void AudioTrack::getVolume(float* left, float* right)
+{
+ *left = mVolume[LEFT];
+ *right = mVolume[RIGHT];
+}
+
+void AudioTrack::setSampleRate(int rate)
+{
+ if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE;
+ mCblk->sampleRate = rate;
+}
+
+uint32_t AudioTrack::getSampleRate()
+{
+ return uint32_t(mCblk->sampleRate);
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking)
+{
+ int active;
+ int timeout = 0;
+ status_t result;
+ audio_track_cblk_t* cblk = mCblk;
+
+ uint32_t u = cblk->user;
+ uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
+ uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
+
+ uint32_t s = cblk->server;
+ uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
+ uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
+
+ LOGW_IF(u_seq < s_seq, "user doesn't fill buffers fast enough");
+
+ if (u_seq > s_seq && u_buf == s_buf) {
+ Mutex::Autolock _l(cblk->lock);
+ goto start_loop_here;
+ while (u_seq > s_seq && u_buf == s_buf) {
+ active = mActive;
+ if (UNLIKELY(!active)) {
+ LOGV("Not active and NO_MORE_BUFFERS");
+ return NO_MORE_BUFFERS;
+ }
+ if (UNLIKELY(!blocking))
+ return WOULD_BLOCK;
+ timeout = 0;
+ result = cblk->cv.waitRelative(cblk->lock, seconds(1));
+ if (__builtin_expect(result!=NO_ERROR, false)) {
+ LOGW( "obtainBuffer timed out (is the CPU pegged?) "
+ "user=%08x, server=%08x", u, s);
+ mAudioTrack->start(); // FIXME: Wake up audioflinger
+ timeout = 1;
+ }
+ // Read user count in case a flush has reset while we where waiting on cv.
+ u = cblk->user;
+ u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
+ u_buf = u & audio_track_cblk_t::BUFFER_MASK;
+
+ // read the server count again
+ start_loop_here:
+ s = cblk->server;
+ s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
+ s_buf = s & audio_track_cblk_t::BUFFER_MASK;
+ }
+ }
+
+ LOGW_IF(timeout,
+ "*** SERIOUS WARNING *** obtainBuffer() timed out "
+ "but didn't need to be locked. We recovered, but "
+ "this shouldn't happen (user=%08x, server=%08x)", u, s);
+
+ audioBuffer->flags = mMuted ? Buffer::MUTE : 0;
+ audioBuffer->channelCount= mChannelCount;
+ audioBuffer->format = mFormat;
+ audioBuffer->frameCount = mFrameCount;
+ audioBuffer->size = cblk->size;
+ audioBuffer->raw = (int8_t *)cblk->buffer(u_buf);
+ active = mActive;
+ return active ? status_t(NO_ERROR) : status_t(STOPPED);
+}
+
+void AudioTrack::releaseBuffer(Buffer* audioBuffer)
+{
+ // next buffer...
+ if (UNLIKELY(mPosition)) {
+ // clean the remaining part of the buffer
+ size_t capacity = mAudioBuffer.size - mPosition;
+ memset(mAudioBuffer.i8 + mPosition, 0, capacity);
+ mPosition = 0;
+ }
+ audio_track_cblk_t* cblk = mCblk;
+ cblk->stepUser(mBufferCount);
+}
+
+// -------------------------------------------------------------------------
+
+ssize_t AudioTrack::write(const void* buffer, size_t userSize)
+{
+ if (ssize_t(userSize) < 0) {
+ // sanity-check. user is most-likely passing an error code.
+ LOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
+ buffer, userSize, userSize);
+ return BAD_VALUE;
+ }
+
+ LOGV("write %d bytes, mActive=%d", userSize, mActive);
+ ssize_t written = 0;
+ do {
+ if (mPosition == 0) {
+ status_t err = obtainBuffer(&mAudioBuffer, true);
+ if (err < 0) {
+ // out of buffers, return #bytes written
+ if (err == status_t(NO_MORE_BUFFERS))
+ break;
+ return ssize_t(err);
+ }
+ }
+
+ size_t capacity = mAudioBuffer.size - mPosition;
+ size_t toWrite = userSize < capacity ? userSize : capacity;
+
+ memcpy(mAudioBuffer.i8 + mPosition, buffer, toWrite);
+ buffer = static_cast<const int8_t*>(buffer) + toWrite;
+ mPosition += toWrite;
+ userSize -= toWrite;
+ capacity -= toWrite;
+ written += toWrite;
+
+ if (capacity == 0) {
+ mPosition = 0;
+ releaseBuffer(&mAudioBuffer);
+ }
+ } while (userSize);
+
+ return written;
+}
+
+// -------------------------------------------------------------------------
+
+bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
+{
+ Buffer audioBuffer;
+
+ status_t err = obtainBuffer(&audioBuffer, true);
+ if (err < NO_ERROR) {
+ LOGE("Error obtaining an audio buffer, giving up.");
+ return false;
+ }
+ if (err == status_t(STOPPED)) return false;
+ mCbf(mUserData, audioBuffer);
+ releaseBuffer(&audioBuffer);
+
+ return true;
+}
+
+status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
+{
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ result.append(" AudioTrack::dump\n");
+ snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]);
+ result.append(buffer);
+ snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d), buffer count(%d)\n", mFormat, mChannelCount, mFrameCount, mBufferCount);
+ result.append(buffer);
+ snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d), reserved(%d)\n", mSampleRate, mStatus, mMuted, mReserved);
+ result.append(buffer);
+ snprintf(buffer, 255, " active(%d), latency (%lld), position(%d)\n", mActive, mLatency, mPosition);
+ result.append(buffer);
+ ::write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// =========================================================================
+
+AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver)
+ : Thread(false), mReceiver(receiver)
+{
+}
+
+bool AudioTrack::AudioTrackThread::threadLoop()
+{
+ return mReceiver.processAudioBuffer(this);
+}
+
+status_t AudioTrack::AudioTrackThread::readyToRun()
+{
+ return NO_ERROR;
+}
+
+void AudioTrack::AudioTrackThread::onFirstRef()
+{
+}
+
+// =========================================================================
+
+audio_track_cblk_t::audio_track_cblk_t()
+ : user(0), server(0), volumeLR(0), buffers(0), size(0)
+{
+}
+
+uint32_t audio_track_cblk_t::stepUser(int bufferCount)
+{
+ uint32_t u = this->user;
+ uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK;
+ uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK;
+ if (++u_buf >= uint32_t(bufferCount)) {
+ u_seq += 0x100;
+ u_buf = 0;
+ }
+ u = u_seq | u_buf;
+ this->user = u;
+ return u;
+}
+
+bool audio_track_cblk_t::stepServer(int bufferCount)
+{
+ // the code below simulates lock-with-timeout
+ // we MUST do this to protect the AudioFlinger server
+ // as this lock is shared with the client.
+ status_t err;
+
+ err = lock.tryLock();
+ if (err == -EBUSY) { // just wait a bit
+ usleep(1000);
+ err = lock.tryLock();
+ }
+ if (err != NO_ERROR) {
+ // probably, the client just died.
+ return false;
+ }
+
+ uint32_t s = this->server;
+ uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK;
+ uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK;
+ s_buf++;
+ if (s_buf >= uint32_t(bufferCount)) {
+ s_seq += 0x100;
+ s_buf = 0;
+ }
+ s = s_seq | s_buf;
+
+ this->server = s;
+ cv.signal();
+ lock.unlock();
+ return true;
+}
+
+void* audio_track_cblk_t::buffer(int id) const
+{
+ return (char*)this->buffers + id * this->size;
+}
+
+// -------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
new file mode 100644
index 0000000..474381b
--- /dev/null
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -0,0 +1,450 @@
+/* //device/extlibs/pv/android/IAudioflinger.cpp
+**
+** Copyright 2007, 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_TAG "IAudioFlinger"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioFlinger.h>
+
+namespace android {
+
+enum {
+ CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION,
+ OPEN_RECORD,
+ SAMPLE_RATE,
+ CHANNEL_COUNT,
+ FORMAT,
+ FRAME_COUNT,
+ SET_MASTER_VOLUME,
+ SET_MASTER_MUTE,
+ MASTER_VOLUME,
+ MASTER_MUTE,
+ SET_STREAM_VOLUME,
+ SET_STREAM_MUTE,
+ STREAM_VOLUME,
+ STREAM_MUTE,
+ SET_MODE,
+ GET_MODE,
+ SET_ROUTING,
+ GET_ROUTING,
+ SET_MIC_MUTE,
+ GET_MIC_MUTE,
+ IS_MUSIC_ACTIVE,
+ SET_PARAMETER,
+};
+
+class BpAudioFlinger : public BpInterface<IAudioFlinger>
+{
+public:
+ BpAudioFlinger(const sp<IBinder>& impl)
+ : BpInterface<IAudioFlinger>(impl)
+ {
+ }
+
+ virtual sp<IAudioTrack> createTrack(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeInt32(streamType);
+ data.writeInt32(sampleRate);
+ data.writeInt32(format);
+ data.writeInt32(channelCount);
+ data.writeInt32(bufferCount);
+ data.writeInt32(flags);
+ status_t status = remote()->transact(CREATE_TRACK, data, &reply);
+ if ( status != NO_ERROR) {
+ LOGE("createTrack error: %s", strerror(-status));
+ }
+
+ return interface_cast<IAudioTrack>(reply.readStrongBinder());
+ }
+
+ virtual sp<IAudioRecord> openRecord(
+ pid_t pid,
+ int streamType,
+ uint32_t sampleRate,
+ int format,
+ int channelCount,
+ int bufferCount,
+ uint32_t flags)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeInt32(streamType);
+ data.writeInt32(sampleRate);
+ data.writeInt32(format);
+ data.writeInt32(channelCount);
+ data.writeInt32(bufferCount);
+ data.writeInt32(flags);
+ remote()->transact(OPEN_RECORD, data, &reply);
+ return interface_cast<IAudioRecord>(reply.readStrongBinder());
+ }
+
+ virtual uint32_t sampleRate() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(SAMPLE_RATE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual int channelCount() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(CHANNEL_COUNT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual int format() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(FORMAT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual size_t frameCount() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(FRAME_COUNT, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMasterVolume(float value)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeFloat(value);
+ remote()->transact(SET_MASTER_VOLUME, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMasterMute(bool muted)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(muted);
+ remote()->transact(SET_MASTER_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual float masterVolume() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(MASTER_VOLUME, data, &reply);
+ return reply.readFloat();
+ }
+
+ virtual bool masterMute() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(MASTER_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setStreamVolume(int stream, float value)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ data.writeFloat(value);
+ remote()->transact(SET_STREAM_VOLUME, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setStreamMute(int stream, bool muted)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ data.writeInt32(muted);
+ remote()->transact(SET_STREAM_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual float streamVolume(int stream) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ remote()->transact(STREAM_VOLUME, data, &reply);
+ return reply.readFloat();
+ }
+
+ virtual bool streamMute(int stream) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(stream);
+ remote()->transact(STREAM_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ data.writeInt32(routes);
+ data.writeInt32(mask);
+ remote()->transact(SET_ROUTING, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual uint32_t getRouting(int mode) const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(GET_ROUTING, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMode(int mode)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(SET_MODE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual int getMode() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(GET_MODE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMicMute(bool state)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeInt32(state);
+ remote()->transact(SET_MIC_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual bool getMicMute() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(GET_MIC_MUTE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual bool isMusicActive() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ remote()->transact(IS_MUSIC_ACTIVE, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setParameter(const char* key, const char* value)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeCString(key);
+ data.writeCString(value);
+ remote()->transact(SET_PARAMETER, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnAudioFlinger::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case CREATE_TRACK: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ pid_t pid = data.readInt32();
+ int streamType = data.readInt32();
+ uint32_t sampleRate = data.readInt32();
+ int format = data.readInt32();
+ int channelCount = data.readInt32();
+ size_t bufferCount = data.readInt32();
+ uint32_t flags = data.readInt32();
+ sp<IAudioTrack> track = createTrack(pid,
+ streamType, sampleRate, format,
+ channelCount, bufferCount, flags);
+ reply->writeStrongBinder(track->asBinder());
+ return NO_ERROR;
+ } break;
+ case OPEN_RECORD: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ pid_t pid = data.readInt32();
+ int streamType = data.readInt32();
+ uint32_t sampleRate = data.readInt32();
+ int format = data.readInt32();
+ int channelCount = data.readInt32();
+ size_t bufferCount = data.readInt32();
+ uint32_t flags = data.readInt32();
+ sp<IAudioRecord> record = openRecord(pid, streamType,
+ sampleRate, format, channelCount, bufferCount, flags);
+ reply->writeStrongBinder(record->asBinder());
+ return NO_ERROR;
+ } break;
+ case SAMPLE_RATE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( sampleRate() );
+ return NO_ERROR;
+ } break;
+ case CHANNEL_COUNT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( channelCount() );
+ return NO_ERROR;
+ } break;
+ case FORMAT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( format() );
+ return NO_ERROR;
+ } break;
+ case FRAME_COUNT: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( frameCount() );
+ return NO_ERROR;
+ } break;
+ case SET_MASTER_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( setMasterVolume(data.readFloat()) );
+ return NO_ERROR;
+ } break;
+ case SET_MASTER_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( setMasterMute(data.readInt32()) );
+ return NO_ERROR;
+ } break;
+ case MASTER_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeFloat( masterVolume() );
+ return NO_ERROR;
+ } break;
+ case MASTER_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( masterMute() );
+ return NO_ERROR;
+ } break;
+ case SET_STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int stream = data.readInt32();
+ reply->writeInt32( setStreamVolume(stream, data.readFloat()) );
+ return NO_ERROR;
+ } break;
+ case SET_STREAM_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int stream = data.readInt32();
+ reply->writeInt32( setStreamMute(stream, data.readInt32()) );
+ return NO_ERROR;
+ } break;
+ case STREAM_VOLUME: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int stream = data.readInt32();
+ reply->writeFloat( streamVolume(stream) );
+ return NO_ERROR;
+ } break;
+ case STREAM_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int stream = data.readInt32();
+ reply->writeInt32( streamMute(stream) );
+ return NO_ERROR;
+ } break;
+ case SET_ROUTING: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int mode = data.readInt32();
+ uint32_t routes = data.readInt32();
+ uint32_t mask = data.readInt32();
+ reply->writeInt32( setRouting(mode, routes, mask) );
+ return NO_ERROR;
+ } break;
+ case GET_ROUTING: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int mode = data.readInt32();
+ reply->writeInt32( getRouting(mode) );
+ return NO_ERROR;
+ } break;
+ case SET_MODE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int mode = data.readInt32();
+ reply->writeInt32( setMode(mode) );
+ return NO_ERROR;
+ } break;
+ case GET_MODE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( getMode() );
+ return NO_ERROR;
+ } break;
+ case SET_MIC_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ int state = data.readInt32();
+ reply->writeInt32( setMicMute(state) );
+ return NO_ERROR;
+ } break;
+ case GET_MIC_MUTE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( getMicMute() );
+ return NO_ERROR;
+ } break;
+ case IS_MUSIC_ACTIVE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( isMusicActive() );
+ return NO_ERROR;
+ } break;
+ case SET_PARAMETER: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ const char *key = data.readCString();
+ const char *value = data.readCString();
+ reply->writeInt32( setParameter(key, value) );
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
new file mode 100644
index 0000000..6e42dac
--- /dev/null
+++ b/media/libmedia/IAudioRecord.cpp
@@ -0,0 +1,100 @@
+/*
+**
+** Copyright 2007, 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioRecord.h>
+
+namespace android {
+
+enum {
+ GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+ START,
+ STOP
+};
+
+class BpAudioRecord : public BpInterface<IAudioRecord>
+{
+public:
+ BpAudioRecord(const sp<IBinder>& impl)
+ : BpInterface<IAudioRecord>(impl)
+ {
+ }
+
+ virtual status_t start()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+ remote()->transact(START, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void stop()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ }
+
+ virtual sp<IMemory> getCblk() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+ remote()->transact(GET_CBLK, data, &reply);
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioRecord, "android.media.IAudioRecord");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnAudioRecord::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case GET_CBLK: {
+ CHECK_INTERFACE(IAudioRecord, data, reply);
+ reply->writeStrongBinder(getCblk()->asBinder());
+ return NO_ERROR;
+ } break;
+ case START: {
+ CHECK_INTERFACE(IAudioRecord, data, reply);
+ reply->writeInt32(start());
+ return NO_ERROR;
+ } break;
+ case STOP: {
+ CHECK_INTERFACE(IAudioRecord, data, reply);
+ stop();
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
new file mode 100644
index 0000000..abc202d
--- /dev/null
+++ b/media/libmedia/IAudioTrack.cpp
@@ -0,0 +1,140 @@
+/* //device/extlibs/pv/android/IAudioTrack.cpp
+**
+** Copyright 2007, 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IAudioTrack.h>
+
+namespace android {
+
+enum {
+ GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
+ START,
+ STOP,
+ FLUSH,
+ MUTE,
+ PAUSE
+};
+
+class BpAudioTrack : public BpInterface<IAudioTrack>
+{
+public:
+ BpAudioTrack(const sp<IBinder>& impl)
+ : BpInterface<IAudioTrack>(impl)
+ {
+ }
+
+ virtual status_t start()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(START, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual void stop()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ }
+
+ virtual void flush()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(FLUSH, data, &reply);
+ }
+
+ virtual void mute(bool e)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ data.writeInt32(e);
+ remote()->transact(MUTE, data, &reply);
+ }
+
+ virtual void pause()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(PAUSE, data, &reply);
+ }
+
+ virtual sp<IMemory> getCblk() const
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ remote()->transact(GET_CBLK, data, &reply);
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnAudioTrack::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case GET_CBLK: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ reply->writeStrongBinder(getCblk()->asBinder());
+ return NO_ERROR;
+ } break;
+ case START: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ reply->writeInt32(start());
+ return NO_ERROR;
+ } break;
+ case STOP: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ stop();
+ return NO_ERROR;
+ } break;
+ case FLUSH: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ flush();
+ return NO_ERROR;
+ } break;
+ case MUTE: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ mute( data.readInt32() );
+ return NO_ERROR;
+ } break;
+ case PAUSE: {
+ CHECK_INTERFACE(IAudioTrack, data, reply);
+ pause();
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
new file mode 100644
index 0000000..8385114
--- /dev/null
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -0,0 +1,295 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Parcel.h>
+
+#include <media/IMediaPlayer.h>
+#include <ui/ISurface.h>
+
+namespace android {
+
+enum {
+ DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
+ SET_VIDEO_SURFACE,
+ PREPARE_ASYNC,
+ START,
+ STOP,
+ IS_PLAYING,
+ PAUSE,
+ GET_VIDEO_SIZE,
+ SEEK_TO,
+ GET_CURRENT_POSITION,
+ GET_DURATION,
+ RESET,
+ SET_AUDIO_STREAM_TYPE,
+ SET_LOOPING,
+ SET_VOLUME
+};
+
+class BpMediaPlayer: public BpInterface<IMediaPlayer>
+{
+public:
+ BpMediaPlayer(const sp<IBinder>& impl)
+ : BpInterface<IMediaPlayer>(impl)
+ {
+ }
+
+ // disconnect from media player service
+ void disconnect()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(DISCONNECT, data, &reply);
+ }
+
+ status_t setVideoSurface(const sp<ISurface>& surface)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeStrongBinder(surface->asBinder());
+ remote()->transact(SET_VIDEO_SURFACE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t prepareAsync()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(PREPARE_ASYNC, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t start()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(START, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t stop()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(STOP, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t isPlaying(bool* state)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(IS_PLAYING, data, &reply);
+ *state = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ status_t pause()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(PAUSE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getVideoSize(int* w, int* h)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(GET_VIDEO_SIZE, data, &reply);
+ *w = reply.readInt32();
+ *h = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ status_t seekTo(int msec)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(msec);
+ remote()->transact(SEEK_TO, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t getCurrentPosition(int* msec)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(GET_CURRENT_POSITION, data, &reply);
+ *msec = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ status_t getDuration(int* msec)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(GET_DURATION, data, &reply);
+ *msec = reply.readInt32();
+ return reply.readInt32();
+ }
+
+ status_t reset()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ remote()->transact(RESET, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setAudioStreamType(int type)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(type);
+ remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setLooping(int loop)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeInt32(loop);
+ remote()->transact(SET_LOOPING, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t setVolume(float leftVolume, float rightVolume)
+ {
+ Parcel data, reply;
+ data.writeFloat(leftVolume);
+ data.writeFloat(rightVolume);
+ remote()->transact(SET_VOLUME, data, &reply);
+ return reply.readInt32();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnMediaPlayer::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case DISCONNECT: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ disconnect();
+ return NO_ERROR;
+ } break;
+ case SET_VIDEO_SURFACE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+ reply->writeInt32(setVideoSurface(surface));
+ return NO_ERROR;
+ } break;
+ case PREPARE_ASYNC: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(prepareAsync());
+ return NO_ERROR;
+ } break;
+ case START: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(start());
+ return NO_ERROR;
+ } break;
+ case STOP: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(stop());
+ return NO_ERROR;
+ } break;
+ case IS_PLAYING: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ bool state;
+ status_t ret = isPlaying(&state);
+ reply->writeInt32(state);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case PAUSE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(pause());
+ return NO_ERROR;
+ } break;
+ case GET_VIDEO_SIZE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ int w, h;
+ status_t ret = getVideoSize(&w, &h);
+ reply->writeInt32(w);
+ reply->writeInt32(h);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case SEEK_TO: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(seekTo(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case GET_CURRENT_POSITION: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ int msec;
+ status_t ret = getCurrentPosition(&msec);
+ reply->writeInt32(msec);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case GET_DURATION: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ int msec;
+ status_t ret = getDuration(&msec);
+ reply->writeInt32(msec);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case RESET: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(reset());
+ return NO_ERROR;
+ } break;
+ case SET_AUDIO_STREAM_TYPE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(setAudioStreamType(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case SET_LOOPING: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(setLooping(data.readInt32()));
+ return NO_ERROR;
+ } break;
+ case SET_VOLUME: {
+ reply->writeInt32(setVolume(data.readFloat(), data.readFloat()));
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
new file mode 100644
index 0000000..65022cd
--- /dev/null
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -0,0 +1,77 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+#include <utils/RefBase.h>
+#include <utils/IInterface.h>
+#include <utils/Parcel.h>
+
+#include <media/IMediaPlayerClient.h>
+
+namespace android {
+
+enum {
+ NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
+{
+public:
+ BpMediaPlayerClient(const sp<IBinder>& impl)
+ : BpInterface<IMediaPlayerClient>(impl)
+ {
+ }
+
+ virtual void notify(int msg, int ext1, int ext2)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
+ data.writeInt32(msg);
+ data.writeInt32(ext1);
+ data.writeInt32(ext2);
+ remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnMediaPlayerClient::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case NOTIFY: {
+ CHECK_INTERFACE(IMediaPlayerClient, data, reply);
+ int msg = data.readInt32();
+ int ext1 = data.readInt32();
+ int ext2 = data.readInt32();
+ notify(msg, ext1, ext2);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
+
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
new file mode 100644
index 0000000..b087100
--- /dev/null
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -0,0 +1,157 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Parcel.h>
+
+#include <utils/IMemory.h>
+#include <media/IMediaPlayerService.h>
+
+namespace android {
+
+enum {
+ CREATE_URL = IBinder::FIRST_CALL_TRANSACTION,
+ CREATE_FD,
+ DECODE_URL,
+ DECODE_FD,
+};
+
+class BpMediaPlayerService: public BpInterface<IMediaPlayerService>
+{
+public:
+ BpMediaPlayerService(const sp<IBinder>& impl)
+ : BpInterface<IMediaPlayerService>(impl)
+ {
+ }
+
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeStrongBinder(client->asBinder());
+ data.writeCString(url);
+ remote()->transact(CREATE_URL, data, &reply);
+ return interface_cast<IMediaPlayer>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeStrongBinder(client->asBinder());
+ data.writeFileDescriptor(fd);
+ data.writeInt64(offset);
+ data.writeInt64(length);
+ remote()->transact(CREATE_FD, data, &reply);
+ return interface_cast<IMediaPlayer>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeCString(url);
+ remote()->transact(DECODE_URL, data, &reply);
+ *pSampleRate = uint32_t(reply.readInt32());
+ *pNumChannels = reply.readInt32();
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+
+ virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
+ data.writeFileDescriptor(fd);
+ data.writeInt64(offset);
+ data.writeInt64(length);
+ remote()->transact(DECODE_FD, data, &reply);
+ *pSampleRate = uint32_t(reply.readInt32());
+ *pNumChannels = reply.readInt32();
+ return interface_cast<IMemory>(reply.readStrongBinder());
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService");
+
+// ----------------------------------------------------------------------
+
+#define CHECK_INTERFACE(interface, data, reply) \
+ do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \
+ LOGW("Call incorrectly routed to " #interface); \
+ return PERMISSION_DENIED; \
+ } } while (0)
+
+status_t BnMediaPlayerService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case CREATE_URL: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ pid_t pid = data.readInt32();
+ sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+ const char* url = data.readCString();
+ sp<IMediaPlayer> player = create(pid, client, url);
+ reply->writeStrongBinder(player->asBinder());
+ return NO_ERROR;
+ } break;
+ case CREATE_FD: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ pid_t pid = data.readInt32();
+ sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+ int fd = dup(data.readFileDescriptor());
+ int64_t offset = data.readInt64();
+ int64_t length = data.readInt64();
+ sp<IMediaPlayer> player = create(pid, client, fd, offset, length);
+ reply->writeStrongBinder(player->asBinder());
+ return NO_ERROR;
+ } break;
+ case DECODE_URL: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ const char* url = data.readCString();
+ uint32_t sampleRate;
+ int numChannels;
+ sp<IMemory> player = decode(url, &sampleRate, &numChannels);
+ reply->writeInt32(sampleRate);
+ reply->writeInt32(numChannels);
+ reply->writeStrongBinder(player->asBinder());
+ return NO_ERROR;
+ } break;
+ case DECODE_FD: {
+ CHECK_INTERFACE(IMediaPlayerService, data, reply);
+ int fd = dup(data.readFileDescriptor());
+ int64_t offset = data.readInt64();
+ int64_t length = data.readInt64();
+ uint32_t sampleRate;
+ int numChannels;
+ sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels);
+ reply->writeInt32(sampleRate);
+ reply->writeInt32(numChannels);
+ reply->writeStrongBinder(player->asBinder());
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
diff --git a/media/libmedia/MODULE_LICENSE_APACHE2 b/media/libmedia/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/media/libmedia/MODULE_LICENSE_APACHE2
diff --git a/media/libmedia/NOTICE b/media/libmedia/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/media/libmedia/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
new file mode 100644
index 0000000..89ab2be
--- /dev/null
+++ b/media/libmedia/ToneGenerator.cpp
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2008 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 "ToneGenerator"
+#include <utils/threads.h>
+
+#include <stdio.h>
+#include <math.h>
+#include <utils/Log.h>
+#include <sys/resource.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include "media/ToneGenerator.h"
+
+namespace android {
+
+// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details)
+const ToneGenerator::ToneDescriptor
+ ToneGenerator::toneDescriptors[NUM_TONES] = {
+ // waveFreq[] segments[] repeatCnt
+ { { 1336, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_0
+ { { 1209, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_1
+ { { 1336, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_2
+ { { 1477, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_3
+ { { 1209, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_4
+ { { 1336, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_5
+ { { 1477, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_6
+ { { 1209, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_7
+ { { 1336, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_8
+ { { 1477, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_9
+ { { 1209, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_S
+ { { 1477, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_P
+ { { 1633, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_A
+ { { 1633, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_B
+ { { 1633, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_C
+ { { 1633, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_D
+ { { 425, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_DIAL
+ { { 425, 0 }, { 500, 500, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_BUSY
+ { { 425, 0 }, { 200, 200, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CONGESTION
+ { { 425, 0 }, { 200, 0 }, 0 }, // TONE_SUP_RADIO_ACK
+ { { 425, 0 }, { 200, 200, 0 }, 2 }, // TONE_SUP_RADIO_NOTAVAIL
+ { { 950, 1400, 1800, 0 }, { 330, 1000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_ERROR
+ { { 425, 0 }, { 200, 600, 200, 3000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CALL_WAITING
+ { { 425, 0 }, { 1000, 4000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_RINGTONE
+ { { 400, 1200, 0 }, { 35, 0 }, 0 }, // TONE_PROP_BEEP
+ { { 1200, 0 }, { 100, 100, 0 }, 1 }, // TONE_PROP_ACK
+ { { 300, 400, 500, 0 }, { 400, 0 }, 0 }, // TONE_PROP_NACK
+ { { 400, 1200, 0 }, { 200, 0 }, 0 }, // TONE_PROP_PROMPT
+ { { 400, 1200, 0 }, { 35, 200, 35, 0 }, 0 } // TONE_PROP_BEEP2
+ };
+
+////////////////////////////////////////////////////////////////////////////////
+// ToneGenerator class Implementation
+////////////////////////////////////////////////////////////////////////////////
+
+
+//---------------------------------- public methods ----------------------------
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::ToneGenerator()
+//
+// Description: Constructor. Initializes the tone sequencer, intantiates required sine wave
+// generators, instantiates output audio track.
+//
+// Input:
+// toneType: Type of tone generated (values in enum tone_type)
+// streamType: Type of stream used for tone playback (enum AudioTrack::stream_type)
+// volume: volume applied to tone (0.0 to 1.0)
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::ToneGenerator(int streamType, float volume) {
+ const sp<IAudioFlinger>& lpAudioFlinger = AudioSystem::get_audio_flinger();
+
+ LOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume);
+
+ mState = TONE_IDLE;
+ mpAudioTrack = 0;
+ mpToneDesc = 0;
+ mpNewToneDesc = 0;
+
+ if (lpAudioFlinger == 0) {
+ LOGE("Unable to marshal AudioFlinger");
+ goto ToneGenerator_exit;
+ }
+
+ mSamplingRate = lpAudioFlinger->sampleRate();
+
+ mVolume = volume;
+ // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers
+ mpAudioTrack
+ = new AudioTrack(streamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS, 0, audioCallback, this);
+
+ if (mpAudioTrack == 0) {
+ LOGE("AudioTrack allocation failed");
+ goto ToneGenerator_exit;
+ }
+ LOGV("Create Track: %p\n", mpAudioTrack);
+
+ if (mpAudioTrack->initCheck() != NO_ERROR) {
+ LOGE("AudioTrack->initCheck failed");
+ goto ToneGenerator_exit;
+ }
+
+ mpAudioTrack->setVolume(volume, volume);
+
+ LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000));
+
+ mState = TONE_INIT;
+
+ return;
+
+ToneGenerator_exit:
+
+ // Cleanup
+ if (mpAudioTrack) {
+ LOGV("Delete Track I: %p\n", mpAudioTrack);
+ delete mpAudioTrack;
+ }
+
+ LOGV("!!!ToneGenerator INIT FAILED!!!\n");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::~ToneGenerator()
+//
+// Description: Destructor. Stop sound playback and delete audio track if
+// needed and delete sine wave generators.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::~ToneGenerator() {
+ LOGV("ToneGenerator destructor\n");
+
+ if (mpAudioTrack) {
+ stopTone();
+ LOGV("Delete Track: %p\n", mpAudioTrack);
+ delete mpAudioTrack;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::startTone()
+//
+// Description: Starts tone playback.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::startTone(int toneType) {
+ bool lResult = false;
+
+ if (mState == TONE_IDLE || toneType >= NUM_TONES)
+ return lResult;
+
+ LOGV("startTone\n");
+
+ mLock.lock();
+
+ // Get descriptor for requested tone
+ mpNewToneDesc = &toneDescriptors[toneType];
+
+ if (mState == TONE_INIT) {
+ if (prepareWave()) {
+ LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000));
+
+ mState = TONE_STARTING;
+ mLock.unlock();
+ mpAudioTrack->start();
+ mLock.lock();
+ if (mState == TONE_STARTING) {
+ if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR)
+ LOGE("--- timed out");
+ }
+
+ if (mState == TONE_PLAYING)
+ lResult = true;
+ }
+ } else {
+ LOGV("Delayed start\n");
+
+ mState = TONE_RESTARTING;
+ if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) {
+ if (mState != TONE_INIT) {
+ lResult = true;
+ }
+ LOGV("cond received");
+ } else {
+ LOGE("--- timed out");
+ }
+ }
+ mLock.unlock();
+
+ LOGV("Tone started, time %d\n", (unsigned int)(systemTime()/1000000));
+
+ return lResult;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::stopTone()
+//
+// Description: Stops tone playback.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::stopTone() {
+ LOGV("stopTone");
+
+ mLock.lock();
+ if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) {
+ mState = TONE_STOPPING;
+ LOGV("waiting cond");
+ status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1));
+ if (lStatus == NO_ERROR) {
+ LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000));
+ } else {
+ LOGE("--- timed out");
+ mState = TONE_INIT;
+ }
+ }
+
+ clearWaveGens();
+
+ mLock.unlock();
+}
+
+//---------------------------------- private methods ---------------------------
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::audioCallback()
+//
+// Description: AudioTrack callback implementation. Generates a block of
+// PCM samples
+// and manages tone generator sequencer: tones pulses, tone duration...
+//
+// Input:
+// user reference (pointer to our ToneGenerator)
+// info audio buffer descriptor
+//
+// Output:
+// returned value: always true.
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::audioCallback(void* user, const AudioTrack::Buffer& info) {
+ ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user);
+ short *lpOut = info.i16;
+ unsigned int lReqSmp = info.size/sizeof(short);
+ unsigned int lGenSmp;
+ unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT;
+ bool lSignal = false;
+
+
+ lpToneGen->mLock.lock();
+
+ // Clear output buffer: WaveGenerator accumulates into lpOut buffer
+ memset(lpOut, 0, info.size);
+
+ // Update pcm frame count and end time (current time at the end of this process)
+ lpToneGen->mTotalSmp += lReqSmp;
+
+ // Update tone gen state machine and select wave gen command
+ switch (lpToneGen->mState) {
+ case TONE_PLAYING:
+ lWaveCmd = WaveGenerator::WAVEGEN_CONT;
+ break;
+ case TONE_STARTING:
+ LOGV("Starting Cbk");
+
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+ break;
+ case TONE_STOPPING:
+ case TONE_RESTARTING:
+ LOGV("Stop/restart Cbk");
+
+ lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+ lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below
+ break;
+ default:
+ LOGV("Extra Cbk");
+ goto audioCallback_Exit;
+ }
+
+ // Exit if to sequence is over
+ if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) {
+ goto audioCallback_Exit;
+ }
+
+ if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) {
+ // Time to go to next sequence segment
+
+ LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000));
+
+ lGenSmp = lReqSmp;
+
+ if (lpToneGen->mCurSegment & 0x0001) {
+ // If odd segment, OFF -> ON transition : reset wave generator
+ lWaveCmd = WaveGenerator::WAVEGEN_START;
+
+ LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ } else {
+ // If even segment, ON -> OFF transition : ramp volume down
+ lWaveCmd = WaveGenerator::WAVEGEN_STOP;
+
+ LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp);
+ }
+
+ // Pre increment segment index and handle loop if last segment reached
+ if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) {
+ LOGV("Last Seg: %d\n", lpToneGen->mCurSegment);
+
+ // Pre increment loop count and restart if total count not reached. Stop sequence otherwise
+ if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) {
+ LOGV("Repeating Count: %d\n", lpToneGen->mCurCount);
+
+ lpToneGen->mCurSegment = 0;
+
+ LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+
+ } else {
+ LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000));
+
+ // Cancel OFF->ON transition in case previous segment tone state was OFF
+ if (!(lpToneGen->mCurSegment & 0x0001)) {
+ lGenSmp = 0;
+ }
+ }
+ } else {
+ LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment,
+ (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate);
+ }
+
+ // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more
+ lpToneGen->mNextSegSmp
+ += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000;
+
+ } else {
+ // Inside a segment keep tone ON or OFF
+ if (lpToneGen->mCurSegment & 0x0001) {
+ lGenSmp = 0; // If odd segment, tone is currently OFF
+ } else {
+ lGenSmp = lReqSmp; // If event segment, tone is currently ON
+ }
+ }
+
+ if (lGenSmp) {
+ // If samples must be generated, call all active wave generators and acumulate waves in lpOut
+ unsigned int lWaveIdx;
+
+ for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) {
+ WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx];
+ lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd);
+ }
+ }
+
+audioCallback_Exit:
+
+ switch (lpToneGen->mState) {
+ case TONE_RESTARTING:
+ LOGV("Cbk restarting track\n");
+ if (lpToneGen->prepareWave()) {
+ lpToneGen->mState = TONE_STARTING;
+ } else {
+ lpToneGen->mState = TONE_INIT;
+ lpToneGen->mpAudioTrack->stop();
+ }
+ lSignal = true;
+ break;
+ case TONE_STOPPING:
+ lpToneGen->mState = TONE_INIT;
+ LOGV("Cbk Stopping track\n");
+ lSignal = true;
+ lpToneGen->mpAudioTrack->stop();
+ break;
+ case TONE_STARTING:
+ LOGV("Cbk starting track\n");
+ lpToneGen->mState = TONE_PLAYING;
+ lSignal = true;
+ break;
+ default:
+ break;
+ }
+
+ if (lSignal)
+ lpToneGen->mWaitCbkCond.signal();
+ lpToneGen->mLock.unlock();
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::prepareWave()
+//
+// Description: Prepare wave generators and reset tone sequencer state machine.
+// mpNewToneDesc must have been initialized befoire calling this function.
+// Input:
+// none
+//
+// Output:
+// returned value: true if wave generators have been created, false otherwise
+//
+////////////////////////////////////////////////////////////////////////////////
+bool ToneGenerator::prepareWave() {
+ unsigned int lCnt = 0;
+ unsigned int lNumWaves;
+
+ if (!mpNewToneDesc) {
+ return false;
+ }
+ // Remove existing wave generators if any
+ clearWaveGens();
+
+ mpToneDesc = mpNewToneDesc;
+
+ // Get total number of sine waves: needed to adapt sine wave gain.
+ lNumWaves = numWaves();
+
+ // Instantiate as many wave generators as listed in descriptor
+ while (lCnt < lNumWaves) {
+ ToneGenerator::WaveGenerator *lpWaveGen =
+ new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate,
+ mpToneDesc->waveFreq[lCnt],
+ TONEGEN_GAIN/lNumWaves);
+ if (lpWaveGen == 0) {
+ goto prepareWave_exit;
+ }
+
+ mWaveGens.push(lpWaveGen);
+ LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]);
+ lCnt++;
+ }
+
+ // Initialize tone sequencer
+ mTotalSmp = 0;
+ mCurSegment = 0;
+ mCurCount = 0;
+ mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000;
+
+ return true;
+
+prepareWave_exit:
+
+ clearWaveGens();
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::numWaves()
+//
+// Description: Count number of sine waves needed to generate tone (e.g 2 for DTMF).
+//
+// Input:
+// none
+//
+// Output:
+// returned value: nummber of sine waves
+//
+////////////////////////////////////////////////////////////////////////////////
+unsigned int ToneGenerator::numWaves() {
+ unsigned int lCnt = 0;
+
+ while (mpToneDesc->waveFreq[lCnt]) {
+ lCnt++;
+ }
+
+ return lCnt;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: ToneGenerator::clearWaveGens()
+//
+// Description: Removes all wave generators.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::clearWaveGens() {
+ LOGV("Clearing mWaveGens:");
+
+ while (!mWaveGens.isEmpty()) {
+ delete mWaveGens.top();
+ mWaveGens.pop();
+ }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// WaveGenerator::WaveGenerator class Implementation
+////////////////////////////////////////////////////////////////////////////////
+
+//---------------------------------- public methods ----------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: WaveGenerator::WaveGenerator()
+//
+// Description: Constructor.
+//
+// Input:
+// samplingRate: Output sampling rate in Hz
+// frequency: Frequency of the sine wave to generate in Hz
+// volume: volume (0.0 to 1.0)
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::WaveGenerator::WaveGenerator(unsigned short samplingRate,
+ unsigned short frequency, float volume) {
+ double d0;
+ double F_div_Fs; // frequency / samplingRate
+
+ F_div_Fs = frequency / (double)samplingRate;
+ d0 = - (float)GEN_AMP * sin(2 * M_PI * F_div_Fs);
+ mS2_0 = (short)d0;
+ mS1 = 0;
+ mS2 = mS2_0;
+
+ mAmplitude_Q15 = (short)(32767. * 32767. * volume / GEN_AMP);
+ // take some margin for amplitude fluctuation
+ if (mAmplitude_Q15 > 32500)
+ mAmplitude_Q15 = 32500;
+
+ d0 = 32768.0 * cos(2 * M_PI * F_div_Fs); // Q14*2*cos()
+ if (d0 > 32767)
+ d0 = 32767;
+ mA1_Q14 = (short) d0;
+
+ LOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n",
+ mA1_Q14, mS2_0, mAmplitude_Q15);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: WaveGenerator::~WaveGenerator()
+//
+// Description: Destructor.
+//
+// Input:
+// none
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+ToneGenerator::WaveGenerator::~WaveGenerator() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Method: WaveGenerator::getSamples()
+//
+// Description: Generates count samples of a sine wave and accumulates
+// result in outBuffer.
+//
+// Input:
+// outBuffer: Output buffer where to accumulate samples.
+// count: number of samples to produce.
+// command: special action requested (see enum gen_command).
+//
+// Output:
+// none
+//
+////////////////////////////////////////////////////////////////////////////////
+void ToneGenerator::WaveGenerator::getSamples(short *outBuffer,
+ unsigned int count, unsigned int command) {
+ long lS1, lS2;
+ long lA1, lAmplitude;
+ long Sample; // current sample
+
+ // init local
+ if (command == WAVEGEN_START) {
+ lS1 = (long)0;
+ lS2 = (long)mS2_0;
+ } else {
+ lS1 = (long)mS1;
+ lS2 = (long)mS2;
+ }
+ lA1 = (long)mA1_Q14;
+ lAmplitude = (long)mAmplitude_Q15;
+
+ if (command == WAVEGEN_STOP) {
+ lAmplitude <<= 16;
+ if (count == 0) {
+ return;
+ }
+ long dec = lAmplitude/count;
+ // loop generation
+ while (count--) {
+ Sample = ((lA1 * lS1) >> S_Q14) - lS2;
+ // shift delay
+ lS2 = lS1;
+ lS1 = Sample;
+ Sample = ((lAmplitude>>16) * Sample) >> S_Q15;
+ *(outBuffer++) += (short)Sample; // put result in buffer
+ lAmplitude -= dec;
+ }
+ } else {
+ // loop generation
+ while (count--) {
+ Sample = ((lA1 * lS1) >> S_Q14) - lS2;
+ // shift delay
+ lS2 = lS1;
+ lS1 = Sample;
+ Sample = (lAmplitude * Sample) >> S_Q15;
+ *(outBuffer++) += (short)Sample; // put result in buffer
+ }
+ }
+
+ // save status
+ mS1 = (short)lS1;
+ mS2 = (short)lS2;
+}
+
+} // end namespace android
+
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
new file mode 100644
index 0000000..9cbafbc
--- /dev/null
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -0,0 +1,182 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+#include <media/mediametadataretriever.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#define LOG_TAG "MediaMetadataRetriever"
+#endif
+
+#include <utils/Log.h>
+#include <dlfcn.h>
+
+namespace android {
+
+// Factory class function in shared libpvplayer.so
+typedef MediaMetadataRetrieverImpl* (*createRetriever_f)();
+
+MediaMetadataRetrieverImpl *MediaMetadataRetriever::mRetriever = NULL;
+void *MediaMetadataRetriever::mLibHandler = NULL;
+
+void MediaMetadataRetriever::create()
+{
+ // Load libpvplayer library once and only once.
+ if (!mLibHandler) {
+ mLibHandler = dlopen("libopencoreplayer.so", RTLD_NOW);
+ if (!mLibHandler) {
+ LOGE("setDataSource: dlopen failed on libopencoreplayer.so");
+ return;
+ }
+ }
+
+ // Each time create a new MediaMetadataRetrieverImpl object.
+ if (mRetriever) {
+ delete mRetriever;
+ }
+ createRetriever_f createRetriever = reinterpret_cast<createRetriever_f>(dlsym(mLibHandler, "createRetriever"));
+ if (!createRetriever) {
+ LOGE("setDataSource: dlsym failed on createRetriever in libpvplayer.so");
+ return;
+ }
+ mRetriever = createRetriever();
+ if (!mRetriever) {
+ LOGE("setDataSource: createRetriever failed in libpvplayer.so");
+ }
+}
+
+status_t MediaMetadataRetriever::setDataSource(const char* srcUrl)
+{
+ if (srcUrl == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (mRetriever) {
+ return mRetriever->setDataSource(srcUrl);
+ }
+ return UNKNOWN_ERROR;
+}
+
+const char* MediaMetadataRetriever::extractMetadata(int keyCode)
+{
+ if (mRetriever) {
+ return mRetriever->extractMetadata(keyCode);
+ }
+ return NULL;
+}
+
+MediaAlbumArt* MediaMetadataRetriever::extractAlbumArt()
+{
+ if (mRetriever) {
+ return mRetriever->extractAlbumArt();
+ }
+ return NULL;
+}
+
+SkBitmap* MediaMetadataRetriever::captureFrame()
+{
+ if (mRetriever) {
+ return mRetriever->captureFrame();
+ }
+ return NULL;
+}
+
+void MediaMetadataRetriever::setMode(int mode)
+{
+ if (mRetriever) {
+ mRetriever->setMode(mode);
+ }
+}
+
+void MediaMetadataRetriever::release()
+{
+ if (!mLibHandler) {
+ dlclose(mLibHandler);
+ mLibHandler = NULL;
+ }
+ if (!mRetriever) {
+ delete mRetriever;
+ mRetriever = NULL;
+ }
+}
+
+void MediaAlbumArt::clearData() {
+ if (data != NULL) {
+ delete []data;
+ data = NULL;
+ }
+ length = 0;
+}
+
+
+MediaAlbumArt::MediaAlbumArt(const char* url)
+{
+ length = 0;
+ data = NULL;
+ FILE *in = fopen(url, "r");
+ if (!in) {
+ LOGE("extractExternalAlbumArt: Failed to open external album art url: %s.", url);
+ return;
+ }
+ fseek(in, 0, SEEK_END);
+ length = ftell(in); // Allocating buffer of size equals to the external file size.
+ if (length == 0 || (data = new char[length]) == NULL) {
+ if (length == 0) {
+ LOGE("extractExternalAlbumArt: External album art url: %s has a size of 0.", url);
+ } else if (data == NULL) {
+ LOGE("extractExternalAlbumArt: No enough memory for storing the retrieved album art.");
+ length = 0;
+ }
+ fclose(in);
+ return;
+ }
+ rewind(in);
+ if (fread(data, 1, length, in) != length) { // Read failed.
+ length = 0;
+ delete []data;
+ data = NULL;
+ LOGE("extractExternalAlbumArt: Failed to retrieve the contents of an external album art.");
+ }
+ fclose(in);
+}
+
+status_t MediaAlbumArt::setData(unsigned int len, const char* buf) {
+ clearData();
+ length = len;
+ data = copyData(len, buf);
+ return (data != NULL)? OK: UNKNOWN_ERROR;
+}
+
+char* MediaAlbumArt::copyData(unsigned int len, const char* buf) {
+ if (len == 0 || !buf) {
+ if (len == 0) {
+ LOGE("copyData: Length is 0.");
+ } else if (!buf) {
+ LOGE("copyData: buf is NULL pointer");
+ }
+ return NULL;
+ }
+ char* copy = new char[len];
+ if (!copy) {
+ LOGE("copyData: No enough memory to copy out the data.");
+ return NULL;
+ }
+ memcpy(copy, buf, len);
+ return copy;
+}
+
+}; // namespace android
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
new file mode 100644
index 0000000..736d84a
--- /dev/null
+++ b/media/libmedia/mediaplayer.cpp
@@ -0,0 +1,582 @@
+/* mediaplayer.cpp
+**
+** Copyright 2006, 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 "MediaPlayer"
+#include <utils/Log.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <utils/IServiceManager.h>
+#include <utils/IPCThreadState.h>
+
+#include <media/mediaplayer.h>
+#include <libsonivox/eas.h>
+
+#include <utils/MemoryBase.h>
+
+namespace android {
+
+// client singleton for binder interface to service
+Mutex MediaPlayer::mServiceLock;
+sp<IMediaPlayerService> MediaPlayer::mMediaPlayerService;
+sp<MediaPlayer::DeathNotifier> MediaPlayer::mDeathNotifier;
+
+// establish binder interface to service
+const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
+{
+ Mutex::Autolock _l(mServiceLock);
+ if (mMediaPlayerService.get() == 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ do {
+ binder = sm->getService(String16("media.player"));
+ if (binder != 0)
+ break;
+ LOGW("MediaPlayerService not published, waiting...");
+ usleep(500000); // 0.5 s
+ } while(true);
+ if (mDeathNotifier == NULL) {
+ mDeathNotifier = new DeathNotifier();
+ }
+ binder->linkToDeath(mDeathNotifier);
+ mMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
+ }
+ LOGE_IF(mMediaPlayerService==0, "no MediaPlayerService!?");
+ return mMediaPlayerService;
+}
+
+MediaPlayer::MediaPlayer()
+{
+ LOGV("constructor");
+ mListener = NULL;
+ mCookie = NULL;
+ mDuration = -1;
+ mStreamType = AudioTrack::MUSIC;
+ mCurrentPosition = -1;
+ mSeekPosition = -1;
+ mCurrentState = MEDIA_PLAYER_IDLE;
+ mPrepareSync = false;
+ mPrepareStatus = NO_ERROR;
+ mLoop = false;
+ mLeftVolume = mRightVolume = 1.0;
+}
+
+MediaPlayer::~MediaPlayer()
+{
+ LOGV("destructor");
+ disconnect();
+ IPCThreadState::self()->flushCommands();
+}
+
+void MediaPlayer::disconnect()
+{
+ LOGV("disconnect");
+ sp<IMediaPlayer> p;
+ {
+ Mutex::Autolock _l(mLock);
+ p = mPlayer;
+ mPlayer.clear();
+ }
+
+ if (p != 0) {
+ p->disconnect();
+ p->asBinder()->unlinkToDeath(this);
+ }
+}
+
+// always call with lock held
+void MediaPlayer::clear_l()
+{
+ mDuration = -1;
+ mCurrentPosition = -1;
+ mSeekPosition = -1;
+}
+
+status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
+{
+ LOGV("setListener");
+ Mutex::Autolock _l(mLock);
+ mListener = listener;
+ return NO_ERROR;
+}
+
+
+status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player)
+{
+ status_t err = UNKNOWN_ERROR;
+ sp<IMediaPlayer> p;
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+
+ if ( !( mCurrentState & ( MEDIA_PLAYER_IDLE | MEDIA_PLAYER_STATE_ERROR ) ) ) {
+ LOGE("setDataSource called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ clear_l();
+ p = mPlayer;
+ mPlayer = player;
+ if (player != 0) {
+ mCurrentState = MEDIA_PLAYER_INITIALIZED;
+ player->asBinder()->linkToDeath(this);
+ err = NO_ERROR;
+ } else {
+ LOGE("Unable to to create media player");
+ }
+ }
+
+ if (p != 0) {
+ p->disconnect();
+ p->asBinder()->unlinkToDeath(this);
+ }
+ return err;
+}
+
+status_t MediaPlayer::setDataSource(const char *url)
+{
+ LOGV("setDataSource(%s)", url);
+ status_t err = UNKNOWN_ERROR;
+ if (url != NULL) {
+ const sp<IMediaPlayerService>& service(getMediaPlayerService());
+ if (service != 0) {
+ sp<IMediaPlayer> player(service->create(getpid(), this, url));
+ err = setDataSource(player);
+ }
+ }
+ return err;
+}
+
+status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
+{
+ LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
+ status_t err = UNKNOWN_ERROR;
+ const sp<IMediaPlayerService>& service(getMediaPlayerService());
+ if (service != 0) {
+ sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length));
+ err = setDataSource(player);
+ }
+ return err;
+}
+
+status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
+{
+ LOGV("setVideoSurface");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer == 0) return UNKNOWN_ERROR;
+ return mPlayer->setVideoSurface(surface->getISurface());
+}
+
+// must call with lock held
+status_t MediaPlayer::prepareAsync_l()
+{
+ if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
+ mPlayer->setAudioStreamType(mStreamType);
+ mCurrentState = MEDIA_PLAYER_PREPARING;
+ return mPlayer->prepareAsync();
+ }
+ LOGE("prepareAsync called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::prepare()
+{
+ LOGV("prepare");
+ Mutex::Autolock _l(mLock);
+ if (mPrepareSync) return UNKNOWN_ERROR;
+ mPrepareSync = true;
+ status_t ret = prepareAsync_l();
+ if (ret != NO_ERROR) return ret;
+
+ if (mPrepareSync) {
+ mSignal.wait(mLock); // wait for prepare done
+ mPrepareSync = false;
+ }
+ LOGV("prepare complete - status=%d", mPrepareStatus);
+ return mPrepareStatus;
+}
+
+status_t MediaPlayer::prepareAsync()
+{
+ LOGV("prepareAsync");
+ Mutex::Autolock _l(mLock);
+ return prepareAsync_l();
+}
+
+status_t MediaPlayer::start()
+{
+ LOGV("start");
+ Mutex::Autolock _l(mLock);
+ if (mCurrentState & MEDIA_PLAYER_STARTED)
+ return NO_ERROR;
+ if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
+ MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
+ mPlayer->setLooping(mLoop);
+ mPlayer->setVolume(mLeftVolume, mRightVolume);
+ mCurrentState = MEDIA_PLAYER_STARTED;
+ status_t ret = mPlayer->start();
+ if (ret != NO_ERROR) {
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ ret = UNKNOWN_ERROR;
+ } else {
+ if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
+ LOGV("playback completed immediately following start()");
+ }
+ }
+ return ret;
+ }
+ LOGE("start called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::stop()
+{
+ LOGV("stop");
+ Mutex::Autolock _l(mLock);
+ if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR;
+ if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED |
+ MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) {
+ status_t ret = mPlayer->stop();
+ if (ret != NO_ERROR) {
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ ret = UNKNOWN_ERROR;
+ } else {
+ mCurrentState = MEDIA_PLAYER_STOPPED;
+ }
+ return ret;
+ }
+ LOGE("stop called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::pause()
+{
+ LOGV("pause");
+ Mutex::Autolock _l(mLock);
+ if (mCurrentState & MEDIA_PLAYER_PAUSED)
+ return NO_ERROR;
+ if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) {
+ status_t ret = mPlayer->pause();
+ if (ret != NO_ERROR) {
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ ret = UNKNOWN_ERROR;
+ } else {
+ mCurrentState = MEDIA_PLAYER_PAUSED;
+ }
+ return ret;
+ }
+ LOGE("pause called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+}
+
+bool MediaPlayer::isPlaying()
+{
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ bool temp = false;
+ mPlayer->isPlaying(&temp);
+ LOGV("isPlaying: %d", temp);
+ if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) {
+ LOGE("internal/external state mismatch corrected");
+ mCurrentState = MEDIA_PLAYER_PAUSED;
+ }
+ return temp;
+ }
+ LOGV("isPlaying: no active player");
+ return false;
+}
+
+status_t MediaPlayer::getVideoWidth(int *w)
+{
+ LOGV("getVideoWidth");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ int h;
+ return mPlayer->getVideoSize(w, &h);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getVideoHeight(int *h)
+{
+ LOGV("getVideoHeight");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ int w;
+ return mPlayer->getVideoSize(&w, h);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getCurrentPosition(int *msec)
+{
+ LOGV("getCurrentPosition");
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ if (mCurrentPosition >= 0) {
+ LOGV("Using cached seek position: %d", mCurrentPosition);
+ *msec = mCurrentPosition;
+ return NO_ERROR;
+ }
+ return mPlayer->getCurrentPosition(msec);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getDuration_l(int *msec)
+{
+ LOGV("getDuration");
+ bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE));
+ if (mPlayer != 0 && isValidState) {
+ status_t ret = NO_ERROR;
+ if (mDuration <= 0)
+ ret = mPlayer->getDuration(&mDuration);
+ if (msec)
+ *msec = mDuration;
+ return ret;
+ }
+ LOGE("Attempt to call getDuration without a valid mediaplayer");
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::getDuration(int *msec)
+{
+ Mutex::Autolock _l(mLock);
+ return getDuration_l(msec);
+}
+
+status_t MediaPlayer::seekTo_l(int msec)
+{
+ LOGV("seekTo %d", msec);
+ if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) {
+ if ( msec < 0 ) {
+ LOGW("Attempt to seek to invalid position: %d", msec);
+ msec = 0;
+ } else if ((mDuration > 0) && (msec > mDuration)) {
+ LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration);
+ msec = mDuration;
+ }
+ // cache duration
+ mCurrentPosition = msec;
+ if (mSeekPosition < 0) {
+ getDuration_l(NULL);
+ mSeekPosition = msec;
+ return mPlayer->seekTo(msec);
+ }
+ else {
+ LOGV("Seek in progress - queue up seekTo[%d]", msec);
+ return NO_ERROR;
+ }
+ }
+ LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState);
+ return INVALID_OPERATION;
+}
+
+status_t MediaPlayer::seekTo(int msec)
+{
+ Mutex::Autolock _l(mLock);
+ return seekTo_l(msec);
+}
+
+status_t MediaPlayer::reset()
+{
+ LOGV("reset");
+ Mutex::Autolock _l(mLock);
+ mLoop = false;
+ if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR;
+ mPrepareSync = false;
+ if (mPlayer != 0) {
+ status_t ret = mPlayer->reset();
+ if (ret != NO_ERROR) {
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ ret = UNKNOWN_ERROR;
+ } else {
+ mCurrentState = MEDIA_PLAYER_IDLE;
+ }
+ return ret;
+ }
+ clear_l();
+ return NO_ERROR;
+}
+
+status_t MediaPlayer::setAudioStreamType(int type)
+{
+ LOGV("MediaPlayer::setAudioStreamType");
+ Mutex::Autolock _l(mLock);
+ if (mStreamType == type) return NO_ERROR;
+ if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED |
+ MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) {
+ // Can't change the stream type after prepare
+ LOGE("setAudioStream called in state %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+ // cache
+ mStreamType = type;
+ return OK;
+}
+
+status_t MediaPlayer::setLooping(int loop)
+{
+ LOGV("MediaPlayer::setLooping");
+ Mutex::Autolock _l(mLock);
+ mLoop = (loop != 0);
+ if (mPlayer != 0) {
+ return mPlayer->setLooping(loop);
+ }
+ return OK;
+}
+
+status_t MediaPlayer::setVolume(float leftVolume, float rightVolume)
+{
+ LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume);
+ Mutex::Autolock _l(mLock);
+ mLeftVolume = leftVolume;
+ mRightVolume = rightVolume;
+ if (mPlayer != 0) {
+ return mPlayer->setVolume(leftVolume, rightVolume);
+ }
+ return OK;
+}
+
+void MediaPlayer::notify(int msg, int ext1, int ext2)
+{
+ LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
+ bool send = true;
+
+ // TODO: In the future, we might be on the same thread if the app is
+ // running in the same process as the media server. In that case,
+ // this will deadlock.
+ mLock.lock();
+ if (mPlayer == 0) {
+ LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2);
+ return;
+ }
+
+ switch (msg) {
+ case MEDIA_NOP: // interface test message
+ break;
+ case MEDIA_PREPARED:
+ LOGV("prepared");
+ mCurrentState = MEDIA_PLAYER_PREPARED;
+ if (mPrepareSync) {
+ LOGV("signal application thread");
+ mPrepareSync = false;
+ mPrepareStatus = NO_ERROR;
+ mSignal.signal();
+ }
+ break;
+ case MEDIA_PLAYBACK_COMPLETE:
+ LOGV("playback complete");
+ if (!mLoop) {
+ mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE;
+ }
+ break;
+ case MEDIA_ERROR:
+ LOGV("error (%d, %d)", ext1, ext2);
+ mCurrentState = MEDIA_PLAYER_STATE_ERROR;
+ if (mPrepareSync)
+ {
+ LOGV("signal application thread");
+ mPrepareSync = false;
+ mPrepareStatus = ext1;
+ mSignal.signal();
+ send = false;
+ }
+ break;
+ case MEDIA_SEEK_COMPLETE:
+ LOGV("Received seek complete");
+ if (mSeekPosition != mCurrentPosition) {
+ LOGV("Executing queued seekTo(%d)", mSeekPosition);
+ mSeekPosition = -1;
+ seekTo_l(mCurrentPosition);
+ }
+ else {
+ LOGV("All seeks complete - return to regularly scheduled program");
+ mCurrentPosition = mSeekPosition = -1;
+ }
+ break;
+ case MEDIA_BUFFERING_UPDATE:
+ LOGV("buffering %d", ext1);
+ break;
+ default:
+ LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
+ break;
+ }
+
+ sp<MediaPlayerListener> listener = mListener;
+ mLock.unlock();
+
+ // this prevents re-entrant calls into client code
+ if ((listener != 0) && send) {
+ Mutex::Autolock _l(mNotifyLock);
+ LOGV("callback application");
+ listener->notify(msg, ext1, ext2);
+ LOGV("back from callback");
+ }
+}
+
+void MediaPlayer::binderDied(const wp<IBinder>& who) {
+ LOGW("IMediaplayer died");
+ notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+}
+
+void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) {
+ Mutex::Autolock _l(MediaPlayer::mServiceLock);
+ MediaPlayer::mMediaPlayerService.clear();
+ LOGW("MediaPlayer server died!");
+}
+
+MediaPlayer::DeathNotifier::~DeathNotifier()
+{
+ Mutex::Autolock _l(mServiceLock);
+ if (mMediaPlayerService != 0) {
+ mMediaPlayerService->asBinder()->unlinkToDeath(this);
+ }
+}
+
+/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels)
+{
+ LOGV("decode(%s)", url);
+ sp<IMemory> p;
+ const sp<IMediaPlayerService>& service = getMediaPlayerService();
+ if (service != 0) {
+ p = mMediaPlayerService->decode(url, pSampleRate, pNumChannels);
+ } else {
+ LOGE("Unable to locate media service");
+ }
+ return p;
+
+}
+
+/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels)
+{
+ LOGV("decode(%d, %lld, %lld)", fd, offset, length);
+ sp<IMemory> p;
+ const sp<IMediaPlayerService>& service = getMediaPlayerService();
+ if (service != 0) {
+ p = mMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels);
+ } else {
+ LOGE("Unable to locate media service");
+ }
+ return p;
+
+}
+
+}; // namespace android