From db528b1a7467e6b090ab5276d1d1787f9226601a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Grisez?= Date: Mon, 6 Oct 2014 15:07:47 +0200 Subject: [PATCH] Add the LinphonePlayer Java interface --- build/android/Android.mk | 3 +- build/android/liblinphone_tester.mk | 3 +- coreapi/linphonecore_jni.cc | 93 +++++++++++++++++++ .../org/linphone/core/LinphoneCore.java | 12 +++ .../org/linphone/core/LinphonePlayer.java | 83 +++++++++++++++++ .../org/linphone/core/LinphoneCoreImpl.java | 16 ++++ .../org/linphone/core/LinphonePlayerImpl.java | 52 +++++++++++ tester/player_tester.c | 20 +++- 8 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 java/common/org/linphone/core/LinphonePlayer.java create mode 100644 java/impl/org/linphone/core/LinphonePlayerImpl.java diff --git a/build/android/Android.mk b/build/android/Android.mk index f972bfe14..1edc91fac 100755 --- a/build/android/Android.mk +++ b/build/android/Android.mk @@ -68,7 +68,8 @@ LOCAL_SRC_FILES := \ quality_reporting.c \ call_log.c \ call_params.c \ - player.c + player.c \ + fileplayer.c ifndef LIBLINPHONE_VERSION LIBLINPHONE_VERSION = "Devel" diff --git a/build/android/liblinphone_tester.mk b/build/android/liblinphone_tester.mk index a6a2ab5f5..b23a381bd 100644 --- a/build/android/liblinphone_tester.mk +++ b/build/android/liblinphone_tester.mk @@ -14,7 +14,8 @@ common_SRC_FILES := \ tester.c \ remote_provisioning_tester.c \ quality_reporting_tester.c \ - transport_tester.c + transport_tester.c \ + player_tester.c common_C_INCLUDES += \ $(LOCAL_PATH) \ diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index bcdf0fdf0..2b8fce197 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -5208,3 +5208,96 @@ JNIEXPORT jstring JNICALL Java_org_linphone_core_ErrorInfoImpl_getDetails(JNIEnv } #endif +/* Linphone Player */ +class LinphonePlayerData { +public: + LinphonePlayerData(jobject listener, jobject jLinphonePlayer) : + mListener(listener), + mJLinphonePlayer(jLinphonePlayer) {} + + jobject mListener; + jobject mJLinphonePlayer; + + static jmethodID endOfFileMethodID; + + static void init(JNIEnv *env) { + jclass listenerClass = env->FindClass("org/linphone/core/LinphonePlayer#Listener"); + endOfFileMethodID = env->GetMethodID(listenerClass, "endOfFile", "(Lorg/linphone/core/LinphonePlayer;)V"); + } +}; + +jmethodID LinphonePlayerData::endOfFileMethodID = NULL; + +static void _eof_callback(LinphonePlayer *player, void *user_data) { + JNIEnv *env; + LinphonePlayerData *player_data = (LinphonePlayerData *)user_data; + jvm->AttachCurrentThread(&env, NULL); + if(LinphonePlayerData::endOfFileMethodID == NULL) { + LinphonePlayerData::init(env); + } + env->CallVoidMethod(player_data->mListener, LinphonePlayerData::endOfFileMethodID, player_data->mJLinphonePlayer); + jvm->DetachCurrentThread(); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphonePlayer_open(JNIEnv *env, jobject jPlayer, jlong ptr, jstring filename, jobject listener) { + LinphonePlayerData *data = NULL; + LinphonePlayerEofCallback cb = NULL; + if(listener) { + listener = env->NewGlobalRef(listener); + jPlayer = env->NewGlobalRef(jPlayer); + data = new LinphonePlayerData(listener, jPlayer); + cb = _eof_callback; + } + if(linphone_player_open((LinphonePlayer *)ptr, env->GetStringUTFChars(filename, NULL), cb, &data) == -1) { + if(data) { + delete data; + env->DeleteGlobalRef(listener); + env->DeleteGlobalRef(jPlayer); + } + return -1; + } + return 0; +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphonePlayer_start(JNIEnv *env, jobject jobj, jlong ptr) { + return (jint)linphone_player_start((LinphonePlayer *)ptr); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphonePlayer_pause(JNIEnv *env, jobject jobj, jlong ptr) { + return (jint)linphone_player_pause((LinphonePlayer *)ptr); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphonePlayer_seek(JNIEnv *env, jobject jobj, jlong ptr, jint timeMs) { + return (jint)linphone_player_seek((LinphonePlayer *)ptr, timeMs); +} + +JNIEXPORT jint JNICALL Java_org_linphone_core_LinphonePlayer_getState(JNIEnv *env, jobject jobj, jlong ptr) { + return (jint)linphone_player_get_state((LinphonePlayer *)ptr); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphonePlayer_close(JNIEnv *env, jobject playerPtr, jlong ptr) { + LinphonePlayer *player = (LinphonePlayer *)ptr; + if(player->user_data) { + LinphonePlayerData *data = (LinphonePlayerData *)player->user_data; + env->DeleteGlobalRef(data->mListener); + env->DeleteGlobalRef(data->mJLinphonePlayer); + delete data; + player->user_data = NULL; + } + linphone_player_close(player); +} + +JNIEXPORT jlong JNICALL Java_org_linphone_core_LinphoneCore_createPlayer(JNIEnv *env, jobject jobj, jlong ptr) { + return (jlong)linphone_core_create_file_player((LinphoneCore *)ptr, NULL, NULL); +} + +JNIEXPORT void JNICALL Java_org_linphone_core_LinphoneCore_destroyPlayer(JNIEnv *env, jobject jobj, jlong playerPtr) { + LinphonePlayer *player = (LinphonePlayer *)playerPtr; + if(player->user_data) { + LinphonePlayerData *data = (LinphonePlayerData *)player->user_data; + env->DeleteGlobalRef(data->mListener); + env->DeleteGlobalRef(data->mJLinphonePlayer); + delete data; + } + linphone_file_player_destroy(player); +} diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 3a9e1d86d..26b721675 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -1781,4 +1781,16 @@ public interface LinphoneCore { * @return the serverUrl */ public String getFileTransferServer(); + + /** + * Create a media player + * @return An object that implement LinphonePlayer + */ + public LinphonePlayer createPlayer(); + + /** + * Destroy a player + * @param player Player to destroy + */ + public void destroyPlayer(LinphonePlayer player); } diff --git a/java/common/org/linphone/core/LinphonePlayer.java b/java/common/org/linphone/core/LinphonePlayer.java new file mode 100644 index 000000000..c38340af1 --- /dev/null +++ b/java/common/org/linphone/core/LinphonePlayer.java @@ -0,0 +1,83 @@ +/** + * Interface to manipulate different media players of Linphone + */ +package org.linphone.core; + +/** + * @author François Grisez + * + */ +public interface LinphonePlayer { + /** + * States that the player can be + * @author François Grisez + * + */ + public enum State { + closed, /**< No file is open */ + paused, /**< A file is open and playback is not running */ + playing; /**< A file is open and playback is running */ + + public static State fromValue(int value) { + if(value == 0) { + return closed; + } else if(value == 1) { + return paused; + } else if(value == 2) { + return playing; + } else { + return null; + } + } + }; + + /** + * Listener for Linphone players + * @author François Grisez + * + */ + public interface Listener { + /** + * Method called when a player reaches the end of a file + * @param player The player which called the method + */ + public void endOfFile(LinphonePlayer player); + } + + /** + * Open a file + * @param filename Name of the file to open + * @return 0 on success, -1 on failure + */ + public int open(final String filename, Listener listener); + + /** + * Start playback + * @return 0 on success, -1 on failure + */ + public int start(); + + /** + * Get playback paused + * @return 0 on success, -1 on failure + */ + public int pause(); + + /** + * Go to a specific position in the timeline + * @param timeMs Time in milliseconds + * @return 0 on success, -1 on failure + */ + public int seek(int timeMs); + + /** + * Get the state of the player + * @return See State enumeration + */ + public State getState(); + + /** + * Close a file + */ + public void close(); +} diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 0c53735fc..8bd3f0d7e 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -1279,4 +1279,20 @@ class LinphoneCoreImpl implements LinphoneCore { return getFileTransferServer(nativePtr); } + private native long createPlayer(long nativePtr); + @Override + public synchronized LinphonePlayer createPlayer() { + long player = createPlayer(nativePtr); + if(player != 0) { + return new LinphonePlayerImpl(createPlayer(nativePtr)); + } else { + return null; + } + } + + private native void destroyPlayer(long playerPtr); + @Override + public synchronized void destroyPlayer(LinphonePlayer player) { + + } } diff --git a/java/impl/org/linphone/core/LinphonePlayerImpl.java b/java/impl/org/linphone/core/LinphonePlayerImpl.java new file mode 100644 index 000000000..a6c5cb2e5 --- /dev/null +++ b/java/impl/org/linphone/core/LinphonePlayerImpl.java @@ -0,0 +1,52 @@ +/** + * + */ +package org.linphone.core; + +/** + * @author François Grisez + * + */ +public class LinphonePlayerImpl implements LinphonePlayer { + private long nativePtr = 0; + + LinphonePlayerImpl(long nativePtr) { + this.nativePtr = nativePtr; + } + + private native int open(long nativePtr, final String filename, Listener listener, LinphonePlayer player); + @Override + public synchronized int open(final String filename, Listener listener) { + return open(nativePtr, filename, listener, this); + } + + private native int start(long nativePtr); + @Override + public synchronized int start() { + return start(nativePtr); + } + + private native int pause(long nativePtr); + @Override + public synchronized int pause() { + return pause(nativePtr); + } + + private native int seek(long nativePtr, int timeMs); + @Override + public synchronized int seek(int timeMs) { + return seek(nativePtr, timeMs); + } + + private native int getState(long nativePtr); + @Override + public synchronized State getState() { + return LinphonePlayer.State.fromValue(getState(nativePtr)); + } + + private native void close(long nativePtr); + @Override + public synchronized void close() { + close(nativePtr); + } +} diff --git a/tester/player_tester.c b/tester/player_tester.c index 59e648340..57a57da60 100644 --- a/tester/player_tester.c +++ b/tester/player_tester.c @@ -1,5 +1,23 @@ #include "liblinphone_tester.h" +static const char *_get_default_video_renderer(void){ +#ifdef WIN32 + return "MSDrawDibDisplay"; +#elif defined(ANDROID) + return "MSAndroidDisplay"; +#elif __APPLE__ && !defined(__ios) + return "MSOSXGLDisplay"; +#elif defined (HAVE_XV) + return "MSX11Video"; +#elif defined(HAVE_GL) + return "MSGLXVideo"; +#elif defined(__ios) + return "IOSDisplay"; +#else + return "MSVideoOut"; +#endif +} + static bool_t wait_for_eof(bool_t *eof, int *time,int time_refresh, int timeout) { while(*time < timeout && !*eof) { usleep(time_refresh * 1000U); @@ -23,7 +41,7 @@ static void play_file(const char *filename, bool_t unsupported_format) { CU_ASSERT_PTR_NOT_NULL(lc_manager); if(lc_manager == NULL) return; - player = linphone_core_create_file_player(lc_manager->lc, ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()), video_stream_get_default_video_renderer()); + player = linphone_core_create_file_player(lc_manager->lc, ms_snd_card_manager_get_default_card(ms_snd_card_manager_get()), _get_default_video_renderer()); CU_ASSERT_PTR_NOT_NULL(player); if(player == NULL) goto fail;