MediaSync: add MediaSync JAVA API
Bug: 19666434
Change-Id: Iab6941f6d81cb95a3b86be14b239287acb0d0eee
diff --git a/media/jni/android_media_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp
new file mode 100644
index 0000000..f31b511
--- /dev/null
+++ b/media/jni/android_media_MediaSync.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2015, 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 "MediaSync-JNI"
+#include <utils/Log.h>
+
+#include "android_media_MediaSync.h"
+
+#include "android_media_AudioTrack.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_view_Surface.h"
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <gui/Surface.h>
+
+#include <media/AudioTrack.h>
+#include <media/stagefright/MediaSync.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+
+#include <nativehelper/ScopedLocalRef.h>
+
+namespace android {
+
+struct fields_t {
+ jfieldID context;
+};
+
+static fields_t gFields;
+
+////////////////////////////////////////////////////////////////////////////////
+
+JMediaSync::JMediaSync() {
+ mSync = MediaSync::create();
+}
+
+JMediaSync::~JMediaSync() {
+}
+
+status_t JMediaSync::configureSurface(const sp<IGraphicBufferProducer> &bufferProducer) {
+ return mSync->configureSurface(bufferProducer);
+}
+
+status_t JMediaSync::configureAudioTrack(
+ const sp<AudioTrack> &audioTrack,
+ int32_t nativeSampleRateInHz) {
+ return mSync->configureAudioTrack(audioTrack, nativeSampleRateInHz);
+}
+
+status_t JMediaSync::createInputSurface(
+ sp<IGraphicBufferProducer>* bufferProducer) {
+ return mSync->createInputSurface(bufferProducer);
+}
+
+void JMediaSync::setPlaybackRate(float rate) {
+ mSync->setPlaybackRate(rate);
+}
+
+status_t JMediaSync::updateQueuedAudioData(
+ int sizeInBytes, int64_t presentationTimeUs) {
+ return mSync->updateQueuedAudioData(sizeInBytes, presentationTimeUs);
+}
+
+} // namespace android
+
+////////////////////////////////////////////////////////////////////////////////
+
+using namespace android;
+
+static sp<JMediaSync> setMediaSync(JNIEnv *env, jobject thiz, const sp<JMediaSync> &sync) {
+ sp<JMediaSync> old = (JMediaSync *)env->GetLongField(thiz, gFields.context);
+ if (sync != NULL) {
+ sync->incStrong(thiz);
+ }
+ if (old != NULL) {
+ old->decStrong(thiz);
+ }
+
+ env->SetLongField(thiz, gFields.context, (jlong)sync.get());
+
+ return old;
+}
+
+static sp<JMediaSync> getMediaSync(JNIEnv *env, jobject thiz) {
+ return (JMediaSync *)env->GetLongField(thiz, gFields.context);
+}
+
+static void android_media_MediaSync_release(JNIEnv *env, jobject thiz) {
+ setMediaSync(env, thiz, NULL);
+}
+
+static void throwExceptionAsNecessary(
+ JNIEnv *env, status_t err, const char *msg = NULL) {
+ switch (err) {
+ case INVALID_OPERATION:
+ jniThrowException(env, "java/lang/IllegalStateException", msg);
+ break;
+
+ case BAD_VALUE:
+ jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void android_media_MediaSync_native_configureSurface(
+ JNIEnv *env, jobject thiz, jobject jsurface) {
+ ALOGV("android_media_MediaSync_configureSurface");
+
+ sp<JMediaSync> sync = getMediaSync(env, thiz);
+ if (sync == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ sp<IGraphicBufferProducer> bufferProducer;
+ if (jsurface != NULL) {
+ sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
+ if (surface != NULL) {
+ bufferProducer = surface->getIGraphicBufferProducer();
+ } else {
+ throwExceptionAsNecessary(env, BAD_VALUE, "The surface has been released");
+ return;
+ }
+ }
+
+ status_t err = sync->configureSurface(bufferProducer);
+
+ if (err == INVALID_OPERATION) {
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, "Surface has already been configured");
+ } if (err != NO_ERROR) {
+ AString msg("Failed to connect to surface with error ");
+ msg.append(err);
+ throwExceptionAsNecessary(env, BAD_VALUE, msg.c_str());
+ }
+}
+
+static void android_media_MediaSync_native_configureAudioTrack(
+ JNIEnv *env, jobject thiz, jobject jaudioTrack, jint nativeSampleRateInHz) {
+ ALOGV("android_media_MediaSync_configureAudioTrack");
+
+ sp<JMediaSync> sync = getMediaSync(env, thiz);
+ if (sync == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ sp<AudioTrack> audioTrack;
+ if (jaudioTrack != NULL) {
+ audioTrack = android_media_AudioTrack_getAudioTrack(env, jaudioTrack);
+ if (audioTrack == NULL) {
+ throwExceptionAsNecessary(env, BAD_VALUE, "The audio track has been released");
+ return;
+ }
+ }
+
+ status_t err = sync->configureAudioTrack(audioTrack, nativeSampleRateInHz);
+
+ if (err == INVALID_OPERATION) {
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, "Audio track has already been configured");
+ } if (err != NO_ERROR) {
+ AString msg("Failed to configure audio track with error ");
+ msg.append(err);
+ throwExceptionAsNecessary(env, BAD_VALUE, msg.c_str());
+ }
+}
+
+static jobject android_media_MediaSync_createInputSurface(
+ JNIEnv* env, jobject thiz) {
+ ALOGV("android_media_MediaSync_createInputSurface");
+
+ sp<JMediaSync> sync = getMediaSync(env, thiz);
+ if (sync == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return NULL;
+ }
+
+ // Tell the MediaSync that we want to use a Surface as input.
+ sp<IGraphicBufferProducer> bufferProducer;
+ status_t err = sync->createInputSurface(&bufferProducer);
+ if (err != NO_ERROR) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return NULL;
+ }
+
+ // Wrap the IGBP in a Java-language Surface.
+ return android_view_Surface_createFromIGraphicBufferProducer(env,
+ bufferProducer);
+}
+
+static void android_media_MediaSync_native_updateQueuedAudioData(
+ JNIEnv *env, jobject thiz, jint sizeInBytes, jlong presentationTimeUs) {
+ sp<JMediaSync> sync = getMediaSync(env, thiz);
+ if (sync == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ status_t err = sync->updateQueuedAudioData(sizeInBytes, presentationTimeUs);
+ if (err != NO_ERROR) {
+ throwExceptionAsNecessary(env, err);
+ return;
+ }
+}
+
+static void android_media_MediaSync_native_init(JNIEnv *env) {
+ ScopedLocalRef<jclass> clazz(env, env->FindClass("android/media/MediaSync"));
+ CHECK(clazz.get() != NULL);
+
+ gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
+ CHECK(gFields.context != NULL);
+}
+
+static void android_media_MediaSync_native_setup(JNIEnv *env, jobject thiz) {
+ sp<JMediaSync> sync = new JMediaSync();
+
+ setMediaSync(env, thiz, sync);
+}
+
+static void android_media_MediaSync_native_setPlaybackRate(
+ JNIEnv *env, jobject thiz, jfloat rate) {
+ sp<JMediaSync> sync = getMediaSync(env, thiz);
+ if (sync == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ sync->setPlaybackRate(rate);
+}
+
+static void android_media_MediaSync_native_finalize(JNIEnv *env, jobject thiz) {
+ android_media_MediaSync_release(env, thiz);
+}
+
+static JNINativeMethod gMethods[] = {
+ { "native_configureSurface",
+ "(Landroid/view/Surface;)V",
+ (void *)android_media_MediaSync_native_configureSurface },
+
+ { "native_configureAudioTrack",
+ "(Landroid/media/AudioTrack;I)V",
+ (void *)android_media_MediaSync_native_configureAudioTrack },
+
+ { "createInputSurface", "()Landroid/view/Surface;",
+ (void *)android_media_MediaSync_createInputSurface },
+
+ { "native_updateQueuedAudioData",
+ "(IJ)V",
+ (void *)android_media_MediaSync_native_updateQueuedAudioData },
+
+ { "native_init", "()V", (void *)android_media_MediaSync_native_init },
+
+ { "native_setup", "()V", (void *)android_media_MediaSync_native_setup },
+
+ { "native_release", "()V", (void *)android_media_MediaSync_release },
+
+ { "native_setPlaybackRate", "(F)V", (void *)android_media_MediaSync_native_setPlaybackRate },
+
+ { "native_finalize", "()V", (void *)android_media_MediaSync_native_finalize },
+};
+
+int register_android_media_MediaSync(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(
+ env, "android/media/MediaSync", gMethods, NELEM(gMethods));
+}