diff --git a/meson.build b/meson.build index b56ae6e8..8a076775 100644 --- a/meson.build +++ b/meson.build @@ -108,6 +108,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [ 'src/api-impl-jni/graphics/android_graphics_drawable_DrawableContainer.c', 'src/api-impl-jni/location/android_location_LocationManager.c', 'src/api-impl-jni/media/android_media_MediaCodec.c', + 'src/api-impl-jni/media/android_media_MediaPlayer.c', 'src/api-impl-jni/media/android_media_session_MediaSession.c', 'src/api-impl-jni/net/android_net_ConnectivityManager.c', 'src/api-impl-jni/os/android_os_Process.c', diff --git a/src/api-impl-jni/generated_headers/android_media_MediaPlayer.h b/src/api-impl-jni/generated_headers/android_media_MediaPlayer.h new file mode 100644 index 00000000..12a17c80 --- /dev/null +++ b/src/api-impl-jni/generated_headers/android_media_MediaPlayer.h @@ -0,0 +1,45 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class android_media_MediaPlayer */ + +#ifndef _Included_android_media_MediaPlayer +#define _Included_android_media_MediaPlayer +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: android_media_MediaPlayer + * Method: native_prepare + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_media_MediaPlayer_native_1prepare + (JNIEnv *, jclass, jlong); + +/* + * Class: android_media_MediaPlayer + * Method: native_setDataSource + * Signature: (Ljava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_android_media_MediaPlayer_native_1setDataSource + (JNIEnv *, jobject, jstring); + +/* + * Class: android_media_MediaPlayer + * Method: native_setOnCompletionListener + * Signature: (JLandroid/media/MediaPlayer/OnCompletionListener;)V + */ +JNIEXPORT void JNICALL Java_android_media_MediaPlayer_native_1setOnCompletionListener + (JNIEnv *, jclass, jlong, jobject); + +/* + * Class: android_media_MediaPlayer + * Method: native_start + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_android_media_MediaPlayer_native_1start + (JNIEnv *, jclass, jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/api-impl-jni/media/android_media_MediaPlayer.c b/src/api-impl-jni/media/android_media_MediaPlayer.c new file mode 100644 index 00000000..a905f8c9 --- /dev/null +++ b/src/api-impl-jni/media/android_media_MediaPlayer.c @@ -0,0 +1,58 @@ +#include + +#include "../defines.h" +#include "../util.h" +#include "../generated_headers/android_media_MediaPlayer.h" + +static void on_prepared(GtkMediaStream *media_stream) +{ + // play once muted to ensure file is fully loaded + gtk_media_stream_set_muted(media_stream, true); + gtk_media_stream_play(media_stream); +} + +JNIEXPORT jlong JNICALL Java_android_media_MediaPlayer_native_1setDataSource(JNIEnv *env, jobject this, jstring path_jstr) +{ + const char *path = _CSTRING(path_jstr); + + GtkMediaStream *media_stream = gtk_media_file_new_for_filename(path); + + g_object_set_data(G_OBJECT(media_stream), "media_player", _REF(this)); + g_signal_connect(media_stream, "notify::prepared", G_CALLBACK(on_prepared), NULL); + return _INTPTR(media_stream); +} + +static void on_ended(GtkMediaStream *media_stream, GParamSpec *pspec, jobject listener) +{ + JNIEnv *env = get_jni_env(); + + jmethodID onCompletion = _METHOD(_CLASS(listener), "onCompletion", "(Landroid/media/MediaPlayer;)V"); + (*env)->CallVoidMethod(env, listener, onCompletion, g_object_get_data(G_OBJECT(media_stream), "media_player")); +} + +JNIEXPORT void JNICALL Java_android_media_MediaPlayer_native_1setOnCompletionListener(JNIEnv *env, jclass this, jlong media_stream_ptr, jobject listener) +{ + GtkMediaStream *media_stream = _PTR(media_stream_ptr); + + g_signal_connect(media_stream, "notify::ended", G_CALLBACK(on_ended), _REF(listener)); +} + +JNIEXPORT void JNICALL Java_android_media_MediaPlayer_native_1prepare(JNIEnv *env, jclass this, jlong media_stream_ptr) +{ + GtkMediaStream *media_stream = _PTR(media_stream_ptr); + + if(!gtk_media_stream_is_prepared(media_stream)) { + /* HACK: GtkMediaStream doesn't support synchronous initialization */ + gtk_media_stream_stream_prepared(media_stream, true, true, false, 0); + } +} + + +JNIEXPORT void JNICALL Java_android_media_MediaPlayer_native_1start(JNIEnv *env, jclass this, jlong media_stream_ptr) +{ + GtkMediaStream *media_stream = _PTR(media_stream_ptr); + + gtk_media_stream_set_muted(media_stream, false); + gtk_media_stream_set_volume(media_stream, 1.0); + gtk_media_stream_play(media_stream); +} diff --git a/src/api-impl/android/media/MediaPlayer.java b/src/api-impl/android/media/MediaPlayer.java index 29d84e08..b886420f 100644 --- a/src/api-impl/android/media/MediaPlayer.java +++ b/src/api-impl/android/media/MediaPlayer.java @@ -4,7 +4,10 @@ import android.content.Context; import java.io.FileDescriptor; public class MediaPlayer { + private long gtk_media_stream; + public interface OnCompletionListener { + void onCompletion(MediaPlayer media_player); } public interface OnErrorListener { } @@ -23,19 +26,44 @@ public class MediaPlayer { public static MediaPlayer create(Context context, int dummy) { return new MediaPlayer(); } - public void setDataSource(FileDescriptor src, long dummy, long dummy2) {} + public void setDataSource(FileDescriptor src, long offset, long length) {} + + public void setDataSource(String path) { + gtk_media_stream = native_setDataSource(path); + } + public void setLooping(boolean dummy) {} - public void setOnCompletionListener(MediaPlayer.OnCompletionListener dummy) {} + + public void setOnCompletionListener(MediaPlayer.OnCompletionListener listener) { + native_setOnCompletionListener(gtk_media_stream, listener); + } + public void setOnErrorListener(MediaPlayer.OnErrorListener dummy) {} public void setOnPreparedListener(MediaPlayer.OnPreparedListener dummy) {} public void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener dummy) {} public void setOnInfoListener(MediaPlayer.OnInfoListener dummy) {} public void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener dummy) {} public void setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener dummy) {} + public void setAudioAttributes(AudioAttributes attributes) {} public void setAudioStreamType(int dummy) {} - public void start() {} + + public void start() { + native_start(gtk_media_stream); + } + + public void stop() {} public void pause() {} + + public void prepare() { + native_prepare(gtk_media_stream); + } + public void prepareAsync() {} public void reset() {} public void release() {} + + public static native void native_prepare(long gtk_media_stream); + public native long native_setDataSource(String path); + public static native void native_setOnCompletionListener(long gtk_media_stream, MediaPlayer.OnCompletionListener listener); + public static native void native_start(long gtk_media_stream); }