summaryrefslogtreecommitdiffstats
path: root/media/jni
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:43 -0800
commitf013e1afd1e68af5e3b868c26a653bbfb39538f8 (patch)
tree7ad6c8fd9c7b55f4b4017171dec1cb760bbd26bf /media/jni
parente70cfafe580c6f2994c4827cd8a534aabf3eb05c (diff)
downloadframeworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.zip
frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.gz
frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'media/jni')
-rw-r--r--media/jni/Android.mk11
-rw-r--r--media/jni/android_media_AmrInputStream.cpp184
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp229
-rw-r--r--media/jni/android_media_MediaPlayer.cpp18
-rw-r--r--media/jni/android_media_MediaRecorder.cpp136
-rw-r--r--media/jni/android_media_MediaScanner.cpp20
-rw-r--r--media/jni/soundpool/SoundPool.cpp558
-rw-r--r--media/jni/soundpool/SoundPool.h73
8 files changed, 847 insertions, 382 deletions
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index 32c8360..cb0fc83 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -6,7 +6,8 @@ LOCAL_SRC_FILES:= \
android_media_MediaPlayer.cpp \
android_media_MediaRecorder.cpp \
android_media_MediaScanner.cpp \
- android_media_MediaMetadataRetriever.cpp
+ android_media_MediaMetadataRetriever.cpp \
+ android_media_AmrInputStream.cpp
LOCAL_SHARED_LIBRARIES := \
libopencoreplayer \
@@ -15,12 +16,15 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper \
libcutils \
libutils \
- libmedia
+ libmedia \
+ libsgl \
+ libui
LOCAL_STATIC_LIBRARIES :=
LOCAL_C_INCLUDES += \
external/tremor/Tremor \
+ $(PV_INCLUDES) \
$(JNI_H_INCLUDE) \
$(call include-path-for, corecg graphics)
@@ -31,4 +35,7 @@ LOCAL_LDLIBS := -lpthread
LOCAL_MODULE:= libmedia_jni
include $(BUILD_SHARED_LIBRARY)
+
+# build libsoundpool.so
+include $(LOCAL_PATH)/soundpool/Android.mk
endif
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
new file mode 100644
index 0000000..978c110
--- /dev/null
+++ b/media/jni/android_media_AmrInputStream.cpp
@@ -0,0 +1,184 @@
+/*
+**
+** 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 "AmrInputStream"
+#include "utils/Log.h"
+
+#include <media/mediarecorder.h>
+#include <stdio.h>
+#include <assert.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utils/threads.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "gsmamr_encoder_wrapper.h"
+
+
+// ----------------------------------------------------------------------------
+
+using namespace android;
+
+// Corresponds to max bit rate of 12.2 kbps.
+static const int aMaxOutputBufferSize = 32;
+
+static const int SAMPLES_PER_FRAME = 8000 * 20 / 1000;
+
+
+//
+// helper function to throw an exception
+//
+static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) {
+ if (jclass cls = env->FindClass(ex)) {
+ char msg[1000];
+ sprintf(msg, fmt, data);
+ env->ThrowNew(cls, msg);
+ env->DeleteLocalRef(cls);
+ }
+}
+
+static jint android_media_AmrInputStream_GsmAmrEncoderNew
+ (JNIEnv *env, jclass clazz) {
+ CPvGsmAmrEncoder* gae = new CPvGsmAmrEncoder();
+ if (gae == NULL) {
+ throwException(env, "java/lang/IllegalStateException",
+ "new CPvGsmAmrEncoder() failed", 0);
+ }
+ return (jint)gae;
+}
+
+static void android_media_AmrInputStream_GsmAmrEncoderInitialize
+ (JNIEnv *env, jclass clazz, jint gae) {
+ // set input parameters
+ TEncodeProperties encodeProps;
+ encodeProps.iInBitsPerSample = 16;
+ encodeProps.iInSamplingRate = 8000;
+ encodeProps.iInClockRate = 1000;
+ encodeProps.iInNumChannels = 1;
+ encodeProps.iInInterleaveMode = TEncodeProperties::EINTERLEAVE_LR;
+ encodeProps.iMode = CPvGsmAmrEncoder::GSM_AMR_12_2;
+ encodeProps.iBitStreamFormatIf2 = false;
+ encodeProps.iAudioObjectType = 0;
+ encodeProps.iOutSamplingRate = encodeProps.iInSamplingRate;
+ encodeProps.iOutNumChannels = encodeProps.iInNumChannels;
+ encodeProps.iOutClockRate = encodeProps.iInClockRate;
+
+ if (int rtn = ((CPvGsmAmrEncoder*)gae)->
+ InitializeEncoder(aMaxOutputBufferSize, &encodeProps)) {
+ throwException(env, "java/lang/IllegalArgumentException",
+ "CPvGsmAmrEncoder::InitializeEncoder failed %d", rtn);
+ }
+}
+
+static jint android_media_AmrInputStream_GsmAmrEncoderEncode
+ (JNIEnv *env, jclass clazz,
+ jint gae, jbyteArray pcm, jint pcmOffset, jbyteArray amr, jint amrOffset) {
+
+ // set up input stream
+ jbyte inBuf[SAMPLES_PER_FRAME*2];
+ TInputAudioStream in;
+ in.iSampleBuffer = (uint8*)inBuf;
+ env->GetByteArrayRegion(pcm, pcmOffset, sizeof(inBuf), inBuf);
+ in.iSampleLength = sizeof(inBuf);
+ in.iMode = CPvGsmAmrEncoder::GSM_AMR_12_2;
+ in.iStartTime = 0;
+ in.iStopTime = 0;
+
+ // set up output stream
+ jbyte outBuf[aMaxOutputBufferSize];
+ int32 sampleFrameSize[1] = { 0 };
+ TOutputAudioStream out;
+ out.iBitStreamBuffer = (uint8*)outBuf;
+ out.iNumSampleFrames = 0;
+ out.iSampleFrameSize = sampleFrameSize;
+ out.iStartTime = 0;
+ out.iStopTime = 0;
+
+ // encode
+ if (int rtn = ((CPvGsmAmrEncoder*)gae)->Encode(in, out)) {
+ throwException(env, "java/io/IOException", "CPvGsmAmrEncoder::Encode failed %d", rtn);
+ return -1;
+ }
+
+ // validate one-frame assumption
+ if (out.iNumSampleFrames != 1) {
+ throwException(env, "java/io/IOException",
+ "CPvGsmAmrEncoder::Encode more than one frame returned %d", out.iNumSampleFrames);
+ return 0;
+ }
+
+ // copy result
+ int length = out.iSampleFrameSize[0];
+
+ // The 1st byte of PV AMR frames are WMF (Wireless Multimedia Forum)
+ // bitpacked, i.e.;
+ // [P(4) + FT(4)]. Q=1 for good frame, P=padding bit, 0
+ // Here we are converting the header to be as specified in Section 5.3 of
+ // RFC 3267 (AMR storage format) i.e.
+ // [P(1) + FT(4) + Q(1) + P(2)].
+ if (length > 0) {
+ outBuf[0] = (outBuf[0] << 3) | 0x4;
+ }
+
+ env->SetByteArrayRegion(amr, amrOffset, length, outBuf);
+
+ return length;
+}
+
+static void android_media_AmrInputStream_GsmAmrEncoderCleanup
+ (JNIEnv *env, jclass clazz, jint gae) {
+ if (int rtn = ((CPvGsmAmrEncoder*)gae)->CleanupEncoder()) {
+ throwException(env, "java/lang/IllegalStateException",
+ "CPvGsmAmrEncoder::CleanupEncoder failed %d", rtn);
+ }
+}
+
+static void android_media_AmrInputStream_GsmAmrEncoderDelete
+ (JNIEnv *env, jclass clazz, jint gae) {
+ delete (CPvGsmAmrEncoder*)gae;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"GsmAmrEncoderNew", "()I", (void*)android_media_AmrInputStream_GsmAmrEncoderNew},
+ {"GsmAmrEncoderInitialize", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize},
+ {"GsmAmrEncoderEncode", "(I[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode},
+ {"GsmAmrEncoderCleanup", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderCleanup},
+ {"GsmAmrEncoderDelete", "(I)V", (void*)android_media_AmrInputStream_GsmAmrEncoderDelete},
+};
+
+
+int register_android_media_AmrInputStream(JNIEnv *env)
+{
+ const char* const kClassPathName = "android/media/AmrInputStream";
+ jclass clazz;
+
+ clazz = env->FindClass(kClassPathName);
+ if (clazz == NULL) {
+ LOGE("Can't find %s", kClassPathName);
+ return -1;
+ }
+
+ return AndroidRuntime::registerNativeMethods(env,
+ kClassPathName, gMethods, NELEM(gMethods));
+}
+
+
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index ff58fba..5b0ecb8 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -15,23 +15,31 @@
** limitations under the License.
*/
-#ifdef LOG_TAG
-#undef LOG_TAG
-#define LOG_TAG "MediaMetadataRetriever"
-#endif
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaMetadataRetrieverJNI"
#include <assert.h>
#include <utils/Log.h>
#include <utils/threads.h>
#include <graphics/SkBitmap.h>
#include <media/mediametadataretriever.h>
+#include <private/media/VideoFrame.h>
+
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+
using namespace android;
-static const char* const kClassPathName = "android/media/MediaMetadataRetriever";
+struct fields_t {
+ jfieldID context;
+ jclass bitmapClazz;
+ jmethodID bitmapConstructor;
+};
+
+static fields_t fields;
+static Mutex sLock;
static void process_media_retriever_call(JNIEnv *env, status_t opStatus, const char* exception, const char *message)
{
@@ -50,13 +58,29 @@ static void process_media_retriever_call(JNIEnv *env, status_t opStatus, const c
}
}
-static void android_media_MediaMetadataRetriever_setMode(JNIEnv *env, jobject thiz, jint mode)
+static MediaMetadataRetriever* getRetriever(JNIEnv* env, jobject thiz)
{
- MediaMetadataRetriever::setMode(mode);
+ // No lock is needed, since it is called internally by other methods that are protected
+ MediaMetadataRetriever* retriever = (MediaMetadataRetriever*) env->GetIntField(thiz, fields.context);
+ return retriever;
+}
+
+static void setRetriever(JNIEnv* env, jobject thiz, int retriever)
+{
+ // No lock is needed, since it is called internally by other methods that are protected
+ MediaMetadataRetriever *old = (MediaMetadataRetriever*) env->GetIntField(thiz, fields.context);
+ env->SetIntField(thiz, fields.context, retriever);
}
static void android_media_MediaMetadataRetriever_setDataSource(JNIEnv *env, jobject thiz, jstring path)
{
+ LOGV("setDataSource");
+ Mutex::Autolock lock(sLock);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+ return;
+ }
if (!path) {
jniThrowException(env, "java/lang/IllegalArgumentException", "Null pointer");
return;
@@ -73,85 +97,195 @@ static void android_media_MediaMetadataRetriever_setDataSource(JNIEnv *env, jobj
return;
}
- process_media_retriever_call(env, MediaMetadataRetriever::setDataSource(pathStr), "java/lang/RuntimeException", "setDataSource failed");
+ process_media_retriever_call(env, retriever->setDataSource(pathStr), "java/lang/RuntimeException", "setDataSource failed");
env->ReleaseStringUTFChars(path, pathStr);
}
-static jobject android_media_MediaMetadataRetriever_extractMetadata(JNIEnv *env, jobject thiz, jint keyCode)
+static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
- const char* value = MediaMetadataRetriever::extractMetadata(keyCode);
- if (!value) {
- LOGV("extractMetadata: Metadata is not found");
- return NULL;
+ LOGV("setDataSource");
+ Mutex::Autolock lock(sLock);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+ return;
}
- LOGV("extractMetadata: value (%s) for keyCode(%d)", value, keyCode);
- return env->NewStringUTF(value);
+ if (!fileDescriptor) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+ int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ if (offset < 0 || length < 0 || fd < 0) {
+ if (offset < 0) {
+ LOGE("negative offset (%lld)", offset);
+ }
+ if (length < 0) {
+ LOGE("negative length (%lld)", length);
+ }
+ if (fd < 0) {
+ LOGE("invalid file descriptor");
+ }
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+ process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed");
+}
+
+static void android_media_MediaMetadataRetriever_setMode(JNIEnv *env, jobject thiz, jint mode)
+{
+ LOGV("setMode");
+ Mutex::Autolock lock(sLock);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+ return;
+ }
+ process_media_retriever_call(env, retriever->setMode(mode), "java/lang/RuntimeException", "setMode failed");
+}
+
+static int android_media_MediaMetadataRetriever_getMode(JNIEnv *env, jobject thiz)
+{
+ LOGV("getMode");
+ Mutex::Autolock lock(sLock);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+ return -1; // Error
+ }
+ int mode = -1;
+ retriever->getMode(&mode);
+ return mode;
}
static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jobject thiz)
{
- // Call native MediaMetadataRetriever::captureFrame method
- SkBitmap *bitmap = MediaMetadataRetriever::captureFrame();
- if (!bitmap) {
+ LOGV("captureFrame");
+ Mutex::Autolock lock(sLock);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return NULL;
}
- // Create the bitmap by calling into Java!
- jclass bitmapClazz = env->FindClass("android/graphics/Bitmap");
- if (!bitmapClazz) {
- LOGE("captureFrame: Bitmap class is not found");
+ // Call native method to retrieve a video frame
+ VideoFrame *videoFrame = NULL;
+ sp<IMemory> frameMemory = retriever->captureFrame();
+ if (frameMemory != 0) { // cast the shared structure to a VideoFrame object
+ videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
+ }
+ if (videoFrame == NULL) {
+ LOGE("captureFrame: videoFrame is a NULL pointer");
return NULL;
}
- jmethodID constructor = env->GetMethodID(bitmapClazz, "<init>", "(IZ[B)V");
- if (!constructor) {
- LOGE("captureFrame: Bitmap constructor is not found");
+
+ // Create a SkBitmap to hold the pixels
+ SkBitmap *bitmap = new SkBitmap();
+ if (bitmap == NULL) {
+ LOGE("captureFrame: cannot instantiate a SkBitmap object.");
+ return NULL;
+ }
+ bitmap->setConfig(SkBitmap::kRGB_565_Config, videoFrame->mDisplayWidth, videoFrame->mDisplayHeight);
+ if (!bitmap->allocPixels()) {
+ delete bitmap;
+ LOGE("failed to allocate pixel buffer");
return NULL;
}
- return env->NewObject(bitmapClazz, constructor, (int) bitmap, true, NULL);
+ memcpy((uint8_t*)bitmap->getPixels(), (uint8_t*)videoFrame + sizeof(VideoFrame), videoFrame->mSize);
+
+ // Since internally SkBitmap uses reference count to manage the reference to
+ // its pixels, it is important that the pixels (along with SkBitmap) be
+ // available after creating the Bitmap is returned to Java app.
+ return env->NewObject(fields.bitmapClazz, fields.bitmapConstructor, (int) bitmap, true, NULL);
}
static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *env, jobject thiz)
{
- MediaAlbumArt* mediaAlbumArt = MediaMetadataRetriever::extractAlbumArt();
- if (!mediaAlbumArt) {
+ LOGV("extractAlbumArt");
+ Mutex::Autolock lock(sLock);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+ return NULL;
+ }
+ MediaAlbumArt* mediaAlbumArt = NULL;
+ sp<IMemory> albumArtMemory = retriever->extractAlbumArt();
+ if (albumArtMemory != 0) { // cast the shared structure to a MediaAlbumArt object
+ mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer());
+ }
+ if (mediaAlbumArt == NULL) {
LOGE("extractAlbumArt: Call to extractAlbumArt failed.");
return NULL;
}
- unsigned int len = mediaAlbumArt->getLength();
- char* data = mediaAlbumArt->getData();
+ unsigned int len = mediaAlbumArt->mSize;
+ char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt);
jbyteArray array = env->NewByteArray(len);
if (!array) { // OutOfMemoryError exception has already been thrown.
LOGE("extractAlbumArt: OutOfMemoryError is thrown.");
} else {
jbyte* bytes = env->GetByteArrayElements(array, NULL);
- memcpy(bytes, data, len);
- env->ReleaseByteArrayElements(array, bytes, 0);
+ if (bytes != NULL) {
+ memcpy(bytes, data, len);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+ }
}
- delete []data;
- delete mediaAlbumArt;
+
+ // No need to delete mediaAlbumArt here
return array;
}
+static jobject android_media_MediaMetadataRetriever_extractMetadata(JNIEnv *env, jobject thiz, jint keyCode)
+{
+ LOGV("extractMetadata");
+ Mutex::Autolock lock(sLock);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
+ return NULL;
+ }
+ const char* value = retriever->extractMetadata(keyCode);
+ if (!value) {
+ LOGV("extractMetadata: Metadata is not found");
+ return NULL;
+ }
+ LOGV("extractMetadata: value (%s) for keyCode(%d)", value, keyCode);
+ return env->NewStringUTF(value);
+}
+
static void android_media_MediaMetadataRetriever_release(JNIEnv *env, jobject thiz)
{
- MediaMetadataRetriever::release();
+ LOGV("release");
+ Mutex::Autolock lock(sLock);
+ MediaMetadataRetriever* retriever = getRetriever(env, thiz);
+ delete retriever;
+ setRetriever(env, thiz, 0);
}
static void android_media_MediaMetadataRetriever_native_finalize(JNIEnv *env, jobject thiz)
{
- MediaMetadataRetriever::release();
+ LOGV("native_finalize");
+
+ // No lock is needed, since android_media_MediaMetadataRetriever_release() is protected
+ android_media_MediaMetadataRetriever_release(env, thiz);
}
static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz)
{
- MediaMetadataRetriever::create();
+ LOGV("native_setup");
+ MediaMetadataRetriever* retriever = new MediaMetadataRetriever();
+ if (retriever == 0) {
+ jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ return;
+ }
+ setRetriever(env, thiz, (int)retriever);
}
// JNI mapping between Java methods and native methods
static JNINativeMethod nativeMethods[] = {
- {"setMode", "(I)V", (void *)android_media_MediaMetadataRetriever_setMode},
{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource},
+ {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
+ {"setMode", "(I)V", (void *)android_media_MediaMetadataRetriever_setMode},
+ {"getMode", "()I", (void *)android_media_MediaMetadataRetriever_getMode},
{"captureFrame", "()Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_captureFrame},
{"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
{"extractAlbumArt", "()[B", (void *)android_media_MediaMetadataRetriever_extractAlbumArt},
@@ -163,12 +297,31 @@ static JNINativeMethod nativeMethods[] = {
// Register native mehtods with Android runtime environment
int register_android_media_MediaMetadataRetriever(JNIEnv *env)
{
+ static const char* const kClassPathName = "android/media/MediaMetadataRetriever";
jclass clazz = env->FindClass(kClassPathName);
if (clazz == NULL) {
LOGE("Can't find class: %s", kClassPathName);
return -1;
}
+ fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
+ if (fields.context == NULL) {
+ LOGE("Can't find MediaMetadataRetriever.mNativeContext");
+ return -1;
+ }
+
+ fields.bitmapClazz = env->FindClass("android/graphics/Bitmap");
+ if (fields.bitmapClazz == NULL) {
+ LOGE("Bitmap class is not found");
+ return -1;
+ }
+
+ fields.bitmapConstructor = env->GetMethodID(fields.bitmapClazz, "<init>", "(IZ[B)V");
+ if (fields.bitmapConstructor == NULL) {
+ LOGE("Bitmap constructor is not found");
+ return -1;
+ }
+
return AndroidRuntime::registerNativeMethods
(env, kClassPathName, nativeMethods, NELEM(nativeMethods));
}
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index f9f3646..8083882 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -375,6 +375,17 @@ android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping
process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
}
+static jboolean
+android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL ) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+ return mp->isLooping();
+}
+
static void
android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume)
{
@@ -450,6 +461,7 @@ static JNINativeMethod gMethods[] = {
{"_reset", "()V", (void *)android_media_MediaPlayer_reset},
{"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
+ {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
{"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
{"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
@@ -506,6 +518,7 @@ static int register_android_media_MediaPlayer(JNIEnv *env)
extern int register_android_media_MediaRecorder(JNIEnv *env);
extern int register_android_media_MediaScanner(JNIEnv *env);
extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
+extern int register_android_media_AmrInputStream(JNIEnv *env);
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
@@ -538,6 +551,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
goto bail;
}
+ if (register_android_media_AmrInputStream(env) < 0) {
+ LOGE("ERROR: AmrInputStream native registration failed\n");
+ goto bail;
+ }
+
/* success -- return valid version number */
result = JNI_VERSION_1_4;
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index f7adf4e..2810a9c 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -1,23 +1,26 @@
-/* //device/libs/media_jni/android_media_MediaRecorder.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 "MediaRecorder"
-#include "utils/Log.h"
-
+/*
+ * 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 "MediaRecorderJNI"
+#include <utils/Log.h>
+
+#include <ui/SurfaceComposerClient.h>
+#include <ui/ICameraService.h>
+#include <ui/Camera.h>
#include <media/mediarecorder.h>
#include <stdio.h>
#include <assert.h>
@@ -37,6 +40,9 @@ using namespace android;
// ----------------------------------------------------------------------------
+// helper function to extract a native Camera object from a Camera Java object
+extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz);
+
struct fields_t {
jfieldID context;
jfieldID surface;
@@ -49,12 +55,14 @@ static fields_t fields;
static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
{
+ LOGV("get_surface");
Surface* const p = (Surface*)env->GetIntField(clazz, fields.surface_native);
return sp<Surface>(p);
}
static void process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message)
{
+ LOGV("process_media_recorder_call");
if (opStatus == (status_t)INVALID_OPERATION) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
} else if (opStatus != (status_t)OK) {
@@ -63,48 +71,82 @@ static void process_media_recorder_call(JNIEnv *env, status_t opStatus, const ch
return;
}
+static void android_media_MediaRecorder_setCamera(JNIEnv* env, jobject thiz, jobject camera)
+{
+ sp<Camera> c = get_native_camera(env, camera);
+ MediaRecorder *mr = (MediaRecorder*)env->GetIntField(thiz, fields.context);
+ process_media_recorder_call(env, mr->setCamera(c->remote()),
+ "java/lang/RuntimeException", "setCamera failed.");
+}
+
static void
android_media_MediaRecorder_setVideoSource(JNIEnv *env, jobject thiz, jint vs)
{
+ LOGV("setVideoSource(%d)", vs);
+ if (vs < VIDEO_SOURCE_DEFAULT || vs > VIDEO_SOURCE_CAMERA) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video source");
+ return;
+ }
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
- process_media_recorder_call(env, mr->setVideoSource((video_source)vs), "java/lang/RuntimeException", "setVideoSource failed.");
+ process_media_recorder_call(env, mr->setVideoSource(vs), "java/lang/RuntimeException", "setVideoSource failed.");
}
static void
android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as)
{
+ LOGV("setAudioSource(%d)", as);
+ if (as < AUDIO_SOURCE_DEFAULT || as > AUDIO_SOURCE_MIC) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio source");
+ return;
+ }
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
- process_media_recorder_call(env, mr->setAudioSource((audio_source)as), "java/lang/RuntimeException", "setAudioSource failed.");
+ process_media_recorder_call(env, mr->setAudioSource(as), "java/lang/RuntimeException", "setAudioSource failed.");
}
static void
android_media_MediaRecorder_setOutputFormat(JNIEnv *env, jobject thiz, jint of)
{
+ LOGV("setOutputFormat(%d)", of);
+ if (of < OUTPUT_FORMAT_DEFAULT || of >= OUTPUT_FORMAT_LIST_END) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid output format");
+ return;
+ }
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
- process_media_recorder_call(env, mr->setOutputFormat((output_format)of), "java/lang/RuntimeException", "setOutputFormat failed.");
+ process_media_recorder_call(env, mr->setOutputFormat(of), "java/lang/RuntimeException", "setOutputFormat failed.");
}
static void
android_media_MediaRecorder_setVideoEncoder(JNIEnv *env, jobject thiz, jint ve)
{
+ LOGV("setVideoEncoder(%d)", ve);
+ if (ve < VIDEO_ENCODER_DEFAULT || ve > VIDEO_ENCODER_MPEG_4_SP) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video encoder");
+ return;
+ }
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
- process_media_recorder_call(env, mr->setVideoEncoder((video_encoder)ve), "java/lang/RuntimeException", "setVideoEncoder failed.");
+ process_media_recorder_call(env, mr->setVideoEncoder(ve), "java/lang/RuntimeException", "setVideoEncoder failed.");
}
static void
android_media_MediaRecorder_setAudioEncoder(JNIEnv *env, jobject thiz, jint ae)
{
+ LOGV("setAudioEncoder(%d)", ae);
+ if (ae < AUDIO_ENCODER_DEFAULT || ae > AUDIO_ENCODER_AMR_NB) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio encoder");
+ return;
+ }
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
- process_media_recorder_call(env, mr->setAudioEncoder((audio_encoder)ae), "java/lang/RuntimeException", "setAudioEncoder failed.");
+ process_media_recorder_call(env, mr->setAudioEncoder(ae), "java/lang/RuntimeException", "setAudioEncoder failed.");
}
static void
android_media_MediaRecorder_setOutputFile(JNIEnv *env, jobject thiz, jstring path)
{
+ LOGV("setOutputFile");
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
if (path == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Path is a NULL pointer");
return;
}
const char *pathStr = env->GetStringUTFChars(path, NULL);
@@ -113,7 +155,7 @@ android_media_MediaRecorder_setOutputFile(JNIEnv *env, jobject thiz, jstring pat
return;
}
status_t opStatus = mr->setOutputFile(pathStr);
-
+
// Make sure that local ref is released before a potential exception
env->ReleaseStringUTFChars(path, pathStr);
process_media_recorder_call(env, opStatus, "java/lang/RuntimeException", "setOutputFile failed.");
@@ -122,13 +164,24 @@ android_media_MediaRecorder_setOutputFile(JNIEnv *env, jobject thiz, jstring pat
static void
android_media_MediaRecorder_setVideoSize(JNIEnv *env, jobject thiz, jint width, jint height)
{
+ LOGV("setVideoSize(%d, %d)", width, height);
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
+
+ if (width <= 0 || height <= 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "invalid video size");
+ return;
+ }
process_media_recorder_call(env, mr->setVideoSize(width, height), "java/lang/RuntimeException", "setVideoSize failed.");
}
static void
android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint rate)
{
+ LOGV("setVideoFrameRate(%d)", rate);
+ if (rate <= 0 || rate > MEDIA_RECORDER_MAX_FRAME_RATE) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "invalid frame rate");
+ return;
+ }
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
process_media_recorder_call(env, mr->setVideoFrameRate(rate), "java/lang/RuntimeException", "setVideoFrameRate failed.");
}
@@ -136,13 +189,13 @@ android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint ra
static void
android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
{
+ LOGV("prepare");
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
jobject surface = env->GetObjectField(thiz, fields.surface);
if (surface != NULL) {
const sp<Surface>& native_surface = get_surface(env, surface);
- LOGI("prepare: surface=%p (id=%d)",
- native_surface.get(), native_surface->ID());
+ LOGI("prepare: surface=%p (id=%d)", native_surface.get(), native_surface->ID());
process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed.");
}
process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed.");
@@ -151,6 +204,7 @@ android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
static int
android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv *env, jobject thiz)
{
+ LOGV("getMaxAmplitude");
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
int result = 0;
process_media_recorder_call(env, mr->getMaxAmplitude(&result), "java/lang/RuntimeException", "getMaxAmplitude failed.");
@@ -160,6 +214,7 @@ android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv *env, jobject thiz)
static void
android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
{
+ LOGV("start");
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");
}
@@ -167,6 +222,7 @@ android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
static void
android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)
{
+ LOGV("stop");
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
process_media_recorder_call(env, mr->stop(), "java/lang/RuntimeException", "stop failed.");
}
@@ -174,6 +230,7 @@ android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)
static void
android_media_MediaRecorder_reset(JNIEnv *env, jobject thiz)
{
+ LOGV("reset");
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
process_media_recorder_call(env, mr->reset(), "java/lang/RuntimeException", "reset failed.");
}
@@ -181,6 +238,7 @@ android_media_MediaRecorder_reset(JNIEnv *env, jobject thiz)
static void
android_media_MediaRecorder_release(JNIEnv *env, jobject thiz)
{
+ LOGV("release");
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
env->SetIntField(thiz, fields.context, 0);
delete mr;
@@ -189,32 +247,28 @@ android_media_MediaRecorder_release(JNIEnv *env, jobject thiz)
static void
android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz)
{
+ LOGV("setup");
MediaRecorder *mr = new MediaRecorder();
- if (mr == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
- return;
+ if (mr->initCheck() == NO_ERROR) {
+ env->SetIntField(thiz, fields.context, (int)mr);
+ } else {
+ delete mr;
+ jniThrowException(env, "java/lang/IOException", "Unable to initialize camera");
}
-
- process_media_recorder_call(env, mr->init(), "java/lang/RuntimeException", "init failed.");
- env->SetIntField(thiz, fields.context, (int)mr);
}
static void
android_media_MediaRecorder_native_finalize(JNIEnv *env, jobject thiz)
{
+ LOGV("finalize");
MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
-
- //printf("##### android_media_MediaRecorder_native_finalize: ctx=0x%p\n", ctx);
-
- if (mr == 0)
- return;
-
delete mr;
}
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
+ {"setCamera", "(Landroid/hardware/Camera;)V",(void *)android_media_MediaRecorder_setCamera},
{"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource},
{"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource},
{"setOutputFormat", "(I)V", (void *)android_media_MediaRecorder_setOutputFormat},
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 76202d3..8764a70 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -189,6 +189,25 @@ android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path,
}
}
+static void
+android_media_MediaScanner_setLocale(JNIEnv *env, jobject thiz, jstring locale)
+{
+ MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context);
+
+ if (locale == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+ const char *localeStr = env->GetStringUTFChars(locale, NULL);
+ if (localeStr == NULL) { // Out of memory
+ jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+ return;
+ }
+ mp->setLocale(localeStr);
+
+ env->ReleaseStringUTFChars(locale, localeStr);
+}
+
static jbyteArray
android_media_MediaScanner_extractAlbumArt(JNIEnv *env, jobject thiz, jobject fileDescriptor)
{
@@ -254,6 +273,7 @@ static JNINativeMethod gMethods[] = {
(void *)android_media_MediaScanner_processDirectory},
{"processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
(void *)android_media_MediaScanner_processFile},
+ {"setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale},
{"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt},
{"native_setup", "()V", (void *)android_media_MediaScanner_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize},
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 8ad73d7..7872a8d 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -15,9 +15,11 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "SoundPoolRestartThread"
+#define LOG_TAG "SoundPool"
#include <utils/Log.h>
+//#define USE_SHARED_MEM_BUFFER
+
// XXX needed for timing latency
#include <utils/Timers.h>
@@ -32,40 +34,80 @@ namespace android
{
int kDefaultBufferCount = 4;
-uint32_t kMaxSampleRate = 44100;
+uint32_t kMaxSampleRate = 48000;
+uint32_t kDefaultSampleRate = 44100;
+uint32_t kDefaultFrameCount = 1200;
+
+SoundPool::SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int srcQuality)
+{
+ LOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d",
+ maxChannels, streamType, srcQuality);
-// handles restarting channels that have been stolen
-class SoundPoolRestartThread
+ if (maxChannels > 32) {
+ LOGW("App requested %d channels, capped at 32", maxChannels);
+ maxChannels = 32;
+ }
+
+ mQuit = false;
+ mSoundPoolRef = soundPoolRef;
+ mDecodeThread = 0;
+ mMaxChannels = maxChannels;
+ mStreamType = streamType;
+ mSrcQuality = srcQuality;
+ mAllocated = 0;
+ mNextSampleID = 0;
+ mNextChannelID = 0;
+
+ mChannelPool = new SoundChannel[maxChannels];
+ for (int i = 0; i < maxChannels; ++i) {
+ mChannelPool[i].init(this);
+ mChannels.push_back(&mChannelPool[i]);
+ }
+
+ if (AudioSystem::getOutputFrameCount(&mFrameCount) != NO_ERROR) {
+ mFrameCount = kDefaultFrameCount;
+ }
+ if (AudioSystem::getOutputSamplingRate(&mSampleRate) != NO_ERROR) {
+ mSampleRate = kDefaultSampleRate;
+ }
+
+ // start decode thread
+ startThreads();
+}
+
+SoundPool::~SoundPool()
{
-public:
- SoundPoolRestartThread() : mQuit(false) { createThread(beginThread, this); }
- void addToRestartList(SoundChannel* channel);
- void quit();
+ LOGV("SoundPool destructor");
+ mDecodeThread->quit();
+ quit();
-private:
- static int beginThread(void* arg);
- int run();
+ Mutex::Autolock lock(&mLock);
+ mChannels.clear();
+ if (mChannelPool)
+ delete [] mChannelPool;
- Mutex mLock;
- Condition mCondition;
- List<SoundChannel*> mRestart;
- bool mQuit;
-};
+ // clean up samples
+ LOGV("clear samples");
+ mSamples.clear();
-void SoundPoolRestartThread::addToRestartList(SoundChannel* channel)
+ if (mDecodeThread)
+ delete mDecodeThread;
+}
+
+void SoundPool::addToRestartList(SoundChannel* channel)
{
Mutex::Autolock lock(&mLock);
mRestart.push_back(channel);
mCondition.signal();
}
-int SoundPoolRestartThread::beginThread(void* arg)
+int SoundPool::beginThread(void* arg)
{
- SoundPoolRestartThread* thread = (SoundPoolRestartThread*)arg;
- return thread->run();
+ SoundPool* p = (SoundPool*)arg;
+ return p->run();
}
-int SoundPoolRestartThread::run()
+int SoundPool::run()
{
mLock.lock();
while (!mQuit) {
@@ -79,21 +121,7 @@ int SoundPoolRestartThread::run()
List<SoundChannel*>::iterator iter = mRestart.begin();
channel = *iter;
mRestart.erase(iter);
- if (channel) {
- SoundEvent* next = channel->nextEvent();
- if (next) {
- LOGV("Starting stolen channel %d -> %d", channel->channelID(), next->mChannelID);
- channel->play(next->mSample, next->mChannelID, next->mLeftVolume,
- next->mRightVolume, next->mPriority, next->mLoop,
- next->mRate);
- }
- else {
- LOGW("stolen channel has no event");
- }
- }
- else {
- LOGW("no stolen channel to process");
- }
+ if (channel) channel->nextEvent();
if (mQuit) break;
}
}
@@ -105,64 +133,22 @@ int SoundPoolRestartThread::run()
return 0;
}
-void SoundPoolRestartThread::quit()
+void SoundPool::quit()
{
mLock.lock();
mQuit = true;
mCondition.signal();
mCondition.wait(mLock);
LOGV("return from quit");
-}
-
-#undef LOG_TAG
-#define LOG_TAG "SoundPool"
-
-SoundPool::SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int srcQuality) :
- mSoundPoolRef(soundPoolRef), mRestartThread(NULL), mDecodeThread(NULL),
- mChannelPool(NULL), mMaxChannels(maxChannels), mStreamType(streamType),
- mSrcQuality(srcQuality), mAllocated(0), mNextSampleID(0), mNextChannelID(0)
-{
- LOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d",
- maxChannels, streamType, srcQuality);
-
- mChannelPool = new SoundChannel[maxChannels];
- for (int i = 0; i < maxChannels; ++i) {
- mChannelPool[i].init(this);
- mChannels.push_back(&mChannelPool[i]);
- }
-
- // start decode thread
- startThreads();
-}
-
-SoundPool::~SoundPool()
-{
- LOGV("SoundPool destructor");
- mDecodeThread->quit();
- mRestartThread->quit();
-
- Mutex::Autolock lock(&mLock);
- mChannels.clear();
- if (mChannelPool)
- delete [] mChannelPool;
-
- // clean up samples
- LOGV("clear samples");
- mSamples.clear();
-
- if (mDecodeThread)
- delete mDecodeThread;
- if (mRestartThread)
- delete mRestartThread;
+ mLock.unlock();
}
bool SoundPool::startThreads()
{
+ createThread(beginThread, this);
if (mDecodeThread == NULL)
mDecodeThread = new SoundPoolThread(this);
- if (mRestartThread == NULL)
- mRestartThread = new SoundPoolRestartThread();
- return (mDecodeThread && mRestartThread);
+ return mDecodeThread != NULL;
}
SoundChannel* SoundPool::findChannel(int channelID)
@@ -178,7 +164,7 @@ SoundChannel* SoundPool::findChannel(int channelID)
SoundChannel* SoundPool::findNextChannel(int channelID)
{
for (int i = 0; i < mMaxChannels; ++i) {
- if (mChannelPool[i].nextEvent()->mChannelID == channelID) {
+ if (mChannelPool[i].nextChannelID() == channelID) {
return &mChannelPool[i];
}
}
@@ -225,44 +211,37 @@ int SoundPool::play(int sampleID, float leftVolume, float rightVolume,
{
LOGV("sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
sampleID, leftVolume, rightVolume, priority, loop, rate);
- Mutex::Autolock lock(&mLock);
+ sp<Sample> sample;
+ SoundChannel* channel;
+ int channelID;
+
+ // scope for lock
+ {
+ Mutex::Autolock lock(&mLock);
+
+ // is sample ready?
+ sample = findSample(sampleID);
+ if ((sample == 0) || (sample->state() != Sample::READY)) {
+ LOGW(" sample %d not READY", sampleID);
+ return 0;
+ }
- // is sample ready?
- sp<Sample> sample = findSample(sampleID);
- if ((sample == 0) || (sample->state() != Sample::READY)) {
- LOGW(" sample %d not READY", sampleID);
- return 0;
- }
+ dump();
- dump();
+ // allocate a channel
+ channel = allocateChannel(priority);
- // allocate a channel
- SoundChannel* channel = allocateChannel(priority);
+ // no channel allocated - return 0
+ if (!channel) {
+ LOGV("No channel allocated");
+ return 0;
+ }
- // no channel allocated - return 0
- if (!channel) {
- LOGV("No channel allocated");
- return 0;
+ channelID = ++mNextChannelID;
}
- int channelID = ++mNextChannelID;
LOGV("channel state = %d", channel->state());
-
- // idle: start playback
- if (channel->state() == SoundChannel::IDLE) {
- LOGV("idle channel - starting playback");
- channel->play(sample, channelID, leftVolume, rightVolume, priority,
- loop, rate);
- }
-
- // stolen: stop, save event data, and let service thread restart it
- else {
- LOGV("channel %d stolen - event queued for channel %d", channel->channelID(), channelID);
- channel->stop();
- channel->setNextEvent(new SoundEvent(sample, channelID, leftVolume,
- rightVolume, priority, loop, rate));
- }
-
+ channel->play(sample, channelID, leftVolume, rightVolume, priority, loop, rate);
return channelID;
}
@@ -295,12 +274,12 @@ SoundChannel* SoundPool::allocateChannel(int priority)
}
// move a channel from its current position to the front of the list
-void SoundPool::moveToFront(List<SoundChannel*>& list, SoundChannel* channel)
+void SoundPool::moveToFront(SoundChannel* channel)
{
- for (List<SoundChannel*>::iterator iter = list.begin(); iter != list.end(); ++iter) {
+ for (List<SoundChannel*>::iterator iter = mChannels.begin(); iter != mChannels.end(); ++iter) {
if (*iter == channel) {
- list.erase(iter);
- list.push_front(channel);
+ mChannels.erase(iter);
+ mChannels.push_front(channel);
break;
}
}
@@ -342,7 +321,6 @@ void SoundPool::stop(int channelID)
void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume)
{
- LOGV("setVolume(%d, %f, %f)", channelID, leftVolume, rightVolume);
Mutex::Autolock lock(&mLock);
SoundChannel* channel = findChannel(channelID);
if (channel) {
@@ -380,21 +358,21 @@ void SoundPool::setRate(int channelID, float rate)
}
}
+// call with lock held
void SoundPool::done(SoundChannel* channel)
{
LOGV("done(%d)", channel->channelID());
// if "stolen", play next event
- SoundEvent* next = channel->nextEvent();
- if (next) {
+ if (channel->nextChannelID() != 0) {
LOGV("add to restart list");
- mRestartThread->addToRestartList(channel);
+ addToRestartList(channel);
}
// return to idle state
else {
LOGV("move to front");
- moveToFront(mChannels, channel);
+ moveToFront(channel);
}
}
@@ -405,6 +383,7 @@ void SoundPool::dump()
}
}
+
Sample::Sample(int sampleID, const char* url)
{
init();
@@ -447,39 +426,17 @@ Sample::~Sample()
delete mUrl;
}
-// TODO: Remove after debug is complete
-#if 0
-static void _dumpBuffer(void* buffer, size_t bufferSize, size_t dumpSize=10, bool zeroCheck=true)
-{
- int16_t* p = static_cast<int16_t*>(buffer);
- if (zeroCheck) {
- for (size_t i = 0; i < bufferSize / 2; i++) {
- if (*p != 0) {
- goto Dump;
- }
- }
- LOGV("Sample data is all zeroes");
- return;
- }
-
-Dump:
- LOGV("Sample Data");
- while (--dumpSize) {
- LOGV(" %04x", *p++);
- }
-}
-#endif
-
void Sample::doLoad()
{
uint32_t sampleRate;
int numChannels;
+ int format;
sp<IMemory> p;
LOGV("Start decode");
if (mUrl) {
- p = MediaPlayer::decode(mUrl, &sampleRate, &numChannels);
+ p = MediaPlayer::decode(mUrl, &sampleRate, &numChannels, &format);
} else {
- p = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels);
+ p = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels, &format);
LOGV("close(%d)", mFd);
::close(mFd);
mFd = -1;
@@ -509,150 +466,195 @@ void Sample::doLoad()
mSize = p->size();
mSampleRate = sampleRate;
mNumChannels = numChannels;
+ mFormat = format;
mState = READY;
}
+
void SoundChannel::init(SoundPool* soundPool)
{
mSoundPool = soundPool;
}
-void SoundChannel::deleteTrack() {
- LOGV("delete track");
- delete mAudioTrack;
- mAudioTrack = 0;
- mState = IDLE;
- return;
-}
-
-void SoundChannel::play(const sp<Sample>& sample, int channelID, float leftVolume,
+void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftVolume,
float rightVolume, int priority, int loop, float rate)
{
- Mutex::Autolock lock(&mLock);
- mSample = sample;
- mChannelID = channelID;
- mPriority = priority;
- mLoop = loop;
- doPlay(leftVolume, rightVolume, rate);
-}
+ AudioTrack* oldTrack;
-// must call with mutex held
-void SoundChannel::doPlay(float leftVolume, float rightVolume, float rate)
-{
- LOGV("SoundChannel::doPlay: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
- mSample->sampleID(), mChannelID, leftVolume, rightVolume, mPriority, mLoop, rate);
- deleteTrack();
- mNumChannels = mSample->numChannels();
- clearNextEvent();
- mPos = 0;
+ LOGV("play: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f",
+ sample->sampleID(), nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+
+ // if not idle, this voice is being stolen
+ if (mState != IDLE) {
+ LOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
+ stop_l();
+ mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
+#ifdef USE_SHARED_MEM_BUFFER
+ mSoundPool->done(this);
+#endif
+ return;
+ }
// initialize track
- uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
- LOGV("play: channelID=%d, sampleRate=%d\n", mChannelID, sampleRate); // create track
+ int numChannels = sample->numChannels();
+ uint32_t sampleRate = uint32_t(float(sample->sampleRate()) * rate + 0.5);
+ uint32_t bufferFrames = (mSoundPool->mFrameCount * sampleRate) / mSoundPool->mSampleRate;
+ uint32_t frameCount = 0;
- mAudioTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, AudioSystem::PCM_16_BIT,
- mSample->numChannels(), kDefaultBufferCount, 0, callback, this);
- if (mAudioTrack->initCheck() != NO_ERROR) {
+ if (loop) {
+ frameCount = sample->size()/numChannels/((sample->format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t));
+ }
+
+ // Ensure minimum audio buffer size in case of short looped sample
+ if(frameCount < kDefaultBufferCount * bufferFrames) {
+ frameCount = kDefaultBufferCount * bufferFrames;
+ }
+
+ AudioTrack* newTrack;
+#ifdef USE_SHARED_MEM_BUFFER
+ newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(),
+ numChannels, sample->getIMemory(), 0, callback, this);
+#else
+ newTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, sample->format(),
+ numChannels, frameCount, 0, callback, this, bufferFrames);
+#endif
+ if (newTrack->initCheck() != NO_ERROR) {
LOGE("Error creating AudioTrack");
- deleteTrack();
+ delete newTrack;
return;
}
- mLeftVolume = leftVolume;
- mRightVolume = rightVolume;
- mAudioTrack->setVolume(leftVolume, rightVolume);
+ LOGV("setVolume %p", newTrack);
+ newTrack->setVolume(leftVolume, rightVolume);
+ newTrack->setLoop(0, frameCount, loop);
+
+ {
+ Mutex::Autolock lock(&mLock);
+ oldTrack = mAudioTrack;
+ mAudioTrack = newTrack;
+ mPos = 0;
+ mSample = sample;
+ mChannelID = nextChannelID;
+ mPriority = priority;
+ mLoop = loop;
+ mLeftVolume = leftVolume;
+ mRightVolume = rightVolume;
+ mNumChannels = numChannels;
+ mRate = rate;
+ clearNextEvent();
+ mState = PLAYING;
+ mAudioTrack->start();
+ mAudioBufferSize = newTrack->frameCount()*newTrack->frameSize();
+ }
+
+ LOGV("delete oldTrack %p", oldTrack);
+ delete oldTrack;
+}
+
+void SoundChannel::nextEvent()
+{
+ sp<Sample> sample;
+ int nextChannelID;
+ float leftVolume;
+ float rightVolume;
+ int priority;
+ int loop;
+ float rate;
- // start playback
- mState = PLAYING;
- LOGV("play: start track");
- mAudioTrack->start();
+ // check for valid event
+ {
+ Mutex::Autolock lock(&mLock);
+ nextChannelID = mNextEvent.channelID();
+ if (nextChannelID == 0) {
+ LOGV("stolen channel has no event");
+ return;
+ }
+
+ sample = mNextEvent.sample();
+ leftVolume = mNextEvent.leftVolume();
+ rightVolume = mNextEvent.rightVolume();
+ priority = mNextEvent.priority();
+ loop = mNextEvent.loop();
+ rate = mNextEvent.rate();
+ }
+
+ LOGV("Starting stolen channel %d -> %d", channelID(), nextChannelID);
+ play(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
}
-void SoundChannel::callback(void* user, const AudioTrack::Buffer& b)
+void SoundChannel::callback(int event, void* user, void *info)
{
SoundChannel* channel = static_cast<SoundChannel*>(user);
- channel->process(b);
+ channel->process(event, info);
}
-void SoundChannel::process(const AudioTrack::Buffer& b)
+void SoundChannel::process(int event, void *info)
{
//LOGV("process(%d)", mChannelID);
- bool more = true;
sp<Sample> sample = mSample;
- // check for stop state
- if (sample != 0) {
-
- // fill buffer
- uint8_t* q = (uint8_t*) b.i8;
- uint8_t* p = sample->data() + mPos;
- size_t count = sample->size() - mPos;
- if (count > b.size) {
- //LOGV("fill: q=%p, p=%p, mPos=%u, b.size=%u", q, p, mPos, b.size);
- memcpy(q, p, b.size);
- mPos += b.size;
- }
+ LOGV("SoundChannel::process event %d", event);
+
+ if (event == AudioTrack::EVENT_MORE_DATA) {
+ AudioTrack::Buffer* b = static_cast<AudioTrack::Buffer *>(info);
+
+ // check for stop state
+ if (b->size == 0) return;
+
+ if (sample != 0) {
+ // fill buffer
+ uint8_t* q = (uint8_t*) b->i8;
+ size_t count = 0;
- // not enough samples to fill buffer
- else {
- //LOGV("partial: q=%p, p=%p, mPos=%u, count=%u", q, p, mPos, count);
- memcpy(q, p, count);
- size_t left = b.size - count;
- q += count;
-
- // loop sample
- while (left && mLoop) {
- if (mLoop > 0) {
- mLoop--;
+ if (mPos < (int)sample->size()) {
+ uint8_t* p = sample->data() + mPos;
+ count = sample->size() - mPos;
+ if (count > b->size) {
+ count = b->size;
}
- count = left > sample->size() ? sample->size() : left;
- //LOGV("loop: q=%p, p=%p, count=%u, mLoop=%d", p, q, count, mLoop);
- memcpy(q, sample->data(), count);
- q += count;
- mPos = count;
- left -= count;
-
- // done filling buffer?
- if ((mLoop == 0) && (count == sample->size())) {
- more = false;
+ memcpy(q, p, count);
+ LOGV("fill: q=%p, p=%p, mPos=%u, b->size=%u, count=%d", q, p, mPos, b->size, count);
+ } else if (mPos < mAudioBufferSize) {
+ count = mAudioBufferSize - mPos;
+ if (count > b->size) {
+ count = b->size;
}
+ memset(q, 0, count);
+ LOGV("fill extra: q=%p, mPos=%u, b->size=%u, count=%d", q, mPos, b->size, count);
}
- // end of sample: zero-fill and stop track
- if (left) {
- //LOGV("zero-fill: q=%p, left=%u", q, left);
- memset(q, 0, left);
- more = false;
- }
+ mPos += count;
+ b->size = count;
+ //LOGV("buffer=%p, [0]=%d", b->i16, b->i16[0]);
}
-
- //LOGV("buffer=%p, [0]=%d", b.i16, b.i16[0]);
+ } else if (event == AudioTrack::EVENT_UNDERRUN) {
+ LOGV("stopping track");
+ stop();
+ } else if (event == AudioTrack::EVENT_LOOP_END) {
+ LOGV("End loop: %d", *(int *)info);
}
+}
- // clean up
- Mutex::Autolock lock(&mLock);
- if (!more || (mState == STOPPING) || (mState == PAUSED)) {
- LOGV("stopping track");
+
+// call with lock held
+void SoundChannel::stop_l()
+{
+ if (mState != IDLE) {
+ setVolume_l(0, 0);
+ LOGV("stop");
mAudioTrack->stop();
- if (more && (mState == PAUSED)) {
- LOGV("volume to zero");
- mAudioTrack->setVolume(0,0);
- } else {
- mSample.clear();
- mState = IDLE;
- mPriority = IDLE_PRIORITY;
- mSoundPool->done(this);
- }
+ mSample.clear();
+ mState = IDLE;
+ mPriority = IDLE_PRIORITY;
}
}
void SoundChannel::stop()
{
- Mutex::Autolock lock(&mLock);
- if (mState != IDLE) {
- setVolume(0, 0);
- LOGV("stop");
- mState = STOPPING;
+ {
+ Mutex::Autolock lock(&mLock);
+ stop_l();
}
+ mSoundPool->done(this);
}
//FIXME: Pause is a little broken right now
@@ -662,6 +664,7 @@ void SoundChannel::pause()
if (mState == PLAYING) {
LOGV("pause track");
mState = PAUSED;
+ mAudioTrack->pause();
}
}
@@ -671,25 +674,43 @@ void SoundChannel::resume()
if (mState == PAUSED) {
LOGV("resume track");
mState = PLAYING;
- mAudioTrack->setVolume(mLeftVolume, mRightVolume);
mAudioTrack->start();
}
}
void SoundChannel::setRate(float rate)
{
- uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
- mAudioTrack->setSampleRate(sampleRate);
+ Mutex::Autolock lock(&mLock);
+ if (mAudioTrack != 0 && mSample.get() != 0) {
+ uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5);
+ mAudioTrack->setSampleRate(sampleRate);
+ mRate = rate;
+ }
}
-void SoundChannel::setVolume(float leftVolume, float rightVolume)
+// call with lock held
+void SoundChannel::setVolume_l(float leftVolume, float rightVolume)
{
- Mutex::Autolock lock(&mLock);
mLeftVolume = leftVolume;
mRightVolume = rightVolume;
if (mAudioTrack != 0) mAudioTrack->setVolume(leftVolume, rightVolume);
}
+void SoundChannel::setVolume(float leftVolume, float rightVolume)
+{
+ Mutex::Autolock lock(&mLock);
+ setVolume_l(leftVolume, rightVolume);
+}
+
+void SoundChannel::setLoop(int loop)
+{
+ Mutex::Autolock lock(&mLock);
+ if (mAudioTrack != 0 && mSample.get() != 0) {
+ mAudioTrack->setLoop(0, mSample->size()/mNumChannels/((mSample->format() == AudioSystem::PCM_16_BIT) ? sizeof(int16_t) : sizeof(uint8_t)), loop);
+ mLoop = loop;
+ }
+}
+
SoundChannel::~SoundChannel()
{
LOGV("SoundChannel destructor");
@@ -702,28 +723,23 @@ SoundChannel::~SoundChannel()
mSample.clear();
}
-// always call with lock held
-void SoundChannel::clearNextEvent()
-{
- if (mNextEvent) {
- mNextEvent->mSample.clear();
- delete mNextEvent;
- mNextEvent = NULL;
- }
-}
-
-void SoundChannel::setNextEvent(SoundEvent* nextEvent)
-{
- Mutex::Autolock lock(&mLock);
- clearNextEvent();
- mNextEvent = nextEvent;
-}
-
void SoundChannel::dump()
{
LOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d",
mState, mChannelID, mNumChannels, mPos, mPriority, mLoop);
}
+void SoundEvent::set(const sp<Sample>& sample, int channelID, float leftVolume,
+ float rightVolume, int priority, int loop, float rate)
+{
+ mSample =sample;
+ mChannelID = channelID;
+ mLeftVolume = leftVolume;
+ mRightVolume = rightVolume;
+ mPriority = priority;
+ mLoop = loop;
+ mRate =rate;
+}
+
} // end namespace android
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index ccd724a..d02ae8b 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -32,7 +32,6 @@ static const int IDLE_PRIORITY = -1;
// forward declarations
class SoundEvent;
-class SoundPoolRestartThread;
class SoundPoolThread;
class SoundPool;
@@ -59,15 +58,17 @@ public:
int sampleID() { return mSampleID; }
int numChannels() { return mNumChannels; }
int sampleRate() { return mSampleRate; }
+ int format() { return mFormat; }
size_t size() { return mSize; }
int state() { return mState; }
uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
void doLoad();
void startLoad() { mState = LOADING; }
+ sp<IMemory> getIMemory() { return mData; }
// hack
- void init(int numChannels, int sampleRate, size_t size, sp<IMemory> data ) {
- mNumChannels = numChannels; mSampleRate = sampleRate; mSize = size; mData = data; }
+ void init(int numChannels, int sampleRate, int format, size_t size, sp<IMemory> data ) {
+ mNumChannels = numChannels; mSampleRate = sampleRate; mFormat = format; mSize = size; mData = data; }
private:
void init();
@@ -78,6 +79,7 @@ private:
uint16_t mSampleRate;
uint8_t mState : 3;
uint8_t mNumChannels : 2;
+ uint8_t mFormat : 2;
int mFd;
int64_t mOffset;
int64_t mLength;
@@ -89,11 +91,20 @@ private:
class SoundEvent
{
public:
- SoundEvent(const sp<Sample>& sample, int channelID, float leftVolume,
- float rightVolume, int priority, int loop, float rate) :
- mSample(sample), mChannelID(channelID), mLeftVolume(leftVolume),
- mRightVolume(rightVolume), mPriority(priority), mLoop(loop),
- mRate(rate) {}
+ SoundEvent() : mChannelID(0), mLeftVolume(0), mRightVolume(0),
+ mPriority(IDLE_PRIORITY), mLoop(0), mRate(0) {}
+ void set(const sp<Sample>& sample, int channelID, float leftVolume,
+ float rightVolume, int priority, int loop, float rate);
+ sp<Sample> sample() { return mSample; }
+ int channelID() { return mChannelID; }
+ float leftVolume() { return mLeftVolume; }
+ float rightVolume() { return mRightVolume; }
+ int priority() { return mPriority; }
+ int loop() { return mLoop; }
+ float rate() { return mRate; }
+ void clear() { mChannelID = 0; mSample.clear(); }
+
+protected:
sp<Sample> mSample;
int mChannelID;
float mLeftVolume;
@@ -104,50 +115,42 @@ public:
};
// for channels aka AudioTracks
-class SoundChannel {
+class SoundChannel : public SoundEvent {
public:
enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING };
- SoundChannel() : mAudioTrack(0), mNextEvent(0), mChannelID(0), mState(IDLE),
- mNumChannels(1), mPos(0), mPriority(IDLE_PRIORITY), mLoop(0) {}
+ SoundChannel() : mAudioTrack(0), mState(IDLE), mNumChannels(1), mPos(0) {}
~SoundChannel();
void init(SoundPool* soundPool);
- void deleteTrack();
void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume,
int priority, int loop, float rate);
- void doPlay(float leftVolume, float rightVolume, float rate);
+ void setVolume_l(float leftVolume, float rightVolume);
void setVolume(float leftVolume, float rightVolume);
+ void stop_l();
void stop();
void pause();
void resume();
void setRate(float rate);
- int channelID() { return mChannelID; }
int state() { return mState; }
- int priority() { return mPriority; }
void setPriority(int priority) { mPriority = priority; }
- void setLoop(int loop) { mLoop = loop; }
+ void setLoop(int loop);
int numChannels() { return mNumChannels; }
- SoundEvent* nextEvent() { return mNextEvent; }
- void clearNextEvent();
- void setNextEvent(SoundEvent* nextEvent);
+ void clearNextEvent() { mNextEvent.clear(); }
+ void nextEvent();
+ int nextChannelID() { return mNextEvent.channelID(); }
void dump();
private:
- static void callback(void* user, const AudioTrack::Buffer& info);
- void process(const AudioTrack::Buffer& b);
+ static void callback(int event, void* user, void *info);
+ void process(int event, void *info);
SoundPool* mSoundPool;
AudioTrack* mAudioTrack;
- sp<Sample> mSample;
- SoundEvent* mNextEvent;
+ SoundEvent mNextEvent;
Mutex mLock;
- int mChannelID;
int mState;
int mNumChannels;
int mPos;
- int mPriority;
- int mLoop;
- float mLeftVolume;
- float mRightVolume;
+ int mAudioBufferSize;
};
// application object for managing a pool of sounds
@@ -189,15 +192,22 @@ private:
SoundChannel* findChannel (int channelID);
SoundChannel* findNextChannel (int channelID);
SoundChannel* allocateChannel(int priority);
- void moveToFront(List<SoundChannel*>& list, SoundChannel* channel);
+ void moveToFront(SoundChannel* channel);
void dump();
+ // restart thread
+ void addToRestartList(SoundChannel* channel);
+ static int beginThread(void* arg);
+ int run();
+ void quit();
+
jobject mSoundPoolRef;
Mutex mLock;
- SoundPoolRestartThread* mRestartThread;
+ Condition mCondition;
SoundPoolThread* mDecodeThread;
SoundChannel* mChannelPool;
List<SoundChannel*> mChannels;
+ List<SoundChannel*> mRestart;
DefaultKeyedVector< int, sp<Sample> > mSamples;
int mMaxChannels;
int mStreamType;
@@ -205,6 +215,9 @@ private:
int mAllocated;
int mNextSampleID;
int mNextChannelID;
+ int mFrameCount;
+ int mSampleRate;
+ bool mQuit;
};
} // end namespace android