Split out documentation into subfolders.
[platform/upstream/gstreamer.git] / markdown / tutorials / android / a-running-pipeline.md
1 # Android tutorial 2: A running pipeline
2
3 ### Goal
4
5 ![screenshot]
6
7 The tutorials seen in the [Basic](tutorials/basic/index.md) and
8 [Playback](tutorials/playback/index.md) sections are intended for Desktop
9 platforms and, therefore, their main thread is allowed to block (using
10 `gst_bus_pop_filtered()`) or relinquish control to a GLib main loop. On
11 Android this would lead to the application being tagged as
12 non-responsive and probably closed.
13
14 This tutorial shows how to overcome this problem. In particular, we will
15 learn:
16
17   - How to move the native code to its own thread
18   - How to allow threads created from C code to communicate with Java
19   - How to access Java code from C
20   - How to allocate a `CustomData` structure from C and have Java host
21     it
22
23 ### Introduction
24
25 When using a Graphical User Interface (UI), if the application waits for
26 GStreamer calls to complete the user experience will suffer. The usual
27 approach, with the [GTK+ toolkit](http://www.gtk.org) for example, is to
28 relinquish control to a GLib `GMainLoop` and let it control the events
29 coming from the UI or GStreamer.
30
31 This approach can be very cumbersome when GStreamer and the Android UI
32 communicate through the JNI interface, so we take a cleaner route: We
33 use a GLib main loop, and move it to its own thread, so it does not
34 block the application. This simplifies the GStreamer-Android
35 integration, and we only need to worry about a few inter-process
36 synchronization bits, which are detailed in this tutorial.
37
38 Additionally, this tutorial shows how to obtain, from any thread, the
39 [JNI Environment
40 pointer](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/design.html#wp16696)
41 required to make JNI calls. This is necessary, for example, to call Java
42 code from callbacks in threads spawned deep within GStreamer, which
43 never received this pointer directly.
44
45 Finally, this tutorial explains how to call Java methods from native C
46 code, which involves locating the desired method’s ID in the class.
47 These IDs never change, so they are cached as global variables in the C
48 code and obtained in the static initializer of the class.
49
50 The code below builds a pipeline with an `audiotestsrc` and an
51 `autoaudiosink` (it plays an audible tone). Two buttons in the UI allow
52 setting the pipeline to PLAYING or PAUSED. A TextView in the UI shows
53 messages sent from the C code (for errors and state changes).
54
55 ### A pipeline on Android \[Java code\]
56
57 **src/org/freedesktop/gstreamer/tutorials/tutorial\_2/Tutorial2.java**
58
59 ``` java
60 package org.freedesktop.gstreamer.tutorials.tutorial_2;
61
62 import android.app.Activity;
63 import android.os.Bundle;
64 import android.util.Log;
65 import android.view.View;
66 import android.view.View.OnClickListener;
67 import android.widget.ImageButton;
68 import android.widget.TextView;
69 import android.widget.Toast;
70
71 import org.freedesktop.gstreamer.GStreamer;
72
73 public class Tutorial2 extends Activity {
74     private native void nativeInit();     // Initialize native code, build pipeline, etc
75     private native void nativeFinalize(); // Destroy pipeline and shutdown native code
76     private native void nativePlay();     // Set pipeline to PLAYING
77     private native void nativePause();    // Set pipeline to PAUSED
78     private static native boolean nativeClassInit(); // Initialize native class: cache Method IDs for callbacks
79     private long native_custom_data;      // Native code will use this to keep private data
80
81     private boolean is_playing_desired;   // Whether the user asked to go to PLAYING
82
83     // Called when the activity is first created.
84     @Override
85     public void onCreate(Bundle savedInstanceState)
86     {
87         super.onCreate(savedInstanceState);
88
89         // Initialize GStreamer and warn if it fails
90         try {
91             GStreamer.init(this);
92         } catch (Exception e) {
93             Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
94             finish();
95             return;
96         }
97
98         setContentView(R.layout.main);
99
100         ImageButton play = (ImageButton) this.findViewById(R.id.button_play);
101         play.setOnClickListener(new OnClickListener() {
102             public void onClick(View v) {
103                 is_playing_desired = true;
104                 nativePlay();
105             }
106         });
107
108         ImageButton pause = (ImageButton) this.findViewById(R.id.button_stop);
109         pause.setOnClickListener(new OnClickListener() {
110             public void onClick(View v) {
111                 is_playing_desired = false;
112                 nativePause();
113             }
114         });
115
116         if (savedInstanceState != null) {
117             is_playing_desired = savedInstanceState.getBoolean("playing");
118             Log.i ("GStreamer", "Activity created. Saved state is playing:" + is_playing_desired);
119         } else {
120             is_playing_desired = false;
121             Log.i ("GStreamer", "Activity created. There is no saved state, playing: false");
122         }
123
124         // Start with disabled buttons, until native code is initialized
125         this.findViewById(R.id.button_play).setEnabled(false);
126         this.findViewById(R.id.button_stop).setEnabled(false);
127
128         nativeInit();
129     }
130
131     protected void onSaveInstanceState (Bundle outState) {
132         Log.d ("GStreamer", "Saving state, playing:" + is_playing_desired);
133         outState.putBoolean("playing", is_playing_desired);
134     }
135
136     protected void onDestroy() {
137         nativeFinalize();
138         super.onDestroy();
139     }
140
141     // Called from native code. This sets the content of the TextView from the UI thread.
142     private void setMessage(final String message) {
143         final TextView tv = (TextView) this.findViewById(R.id.textview_message);
144         runOnUiThread (new Runnable() {
145           public void run() {
146             tv.setText(message);
147           }
148         });
149     }
150
151     // Called from native code. Native code calls this once it has created its pipeline and
152     // the main loop is running, so it is ready to accept commands.
153     private void onGStreamerInitialized () {
154         Log.i ("GStreamer", "Gst initialized. Restoring state, playing:" + is_playing_desired);
155         // Restore previous playing state
156         if (is_playing_desired) {
157             nativePlay();
158         } else {
159             nativePause();
160         }
161
162         // Re-enable buttons, now that GStreamer is initialized
163         final Activity activity = this;
164         runOnUiThread(new Runnable() {
165             public void run() {
166                 activity.findViewById(R.id.button_play).setEnabled(true);
167                 activity.findViewById(R.id.button_stop).setEnabled(true);
168             }
169         });
170     }
171
172     static {
173         System.loadLibrary("gstreamer_android");
174         System.loadLibrary("tutorial-2");
175         nativeClassInit();
176     }
177
178 }
179 ```
180
181 As usual, the first bit that gets executed is the static initializer of
182 the class:
183
184 ``` java
185 static {
186     System.loadLibrary("gstreamer_android");
187     System.loadLibrary("tutorial-2");
188     nativeClassInit();
189 }
190 ```
191
192 As explained in the previous tutorial, the two native libraries are
193 loaded and their `JNI_OnLoad()` methods are executed. Here, we also call
194 the native method `nativeClassInit()`, previously declared with the
195 `native` keyword in line 19. We will later see what its purpose is
196
197 In the `onCreate()` method GStreamer is initialized as in the previous
198 tutorial with `GStreamer.init(this)`, and then the layout is inflated
199 and listeners are setup for the two UI buttons:
200
201 ``` java
202 ImageButton play = (ImageButton) this.findViewById(R.id.button_play);
203 play.setOnClickListener(new OnClickListener() {
204     public void onClick(View v) {
205         is_playing_desired = true;
206         nativePlay();
207     }
208 });
209 ImageButton pause = (ImageButton) this.findViewById(R.id.button_stop);
210 pause.setOnClickListener(new OnClickListener() {
211     public void onClick(View v) {
212         is_playing_desired = false;
213         nativePause();
214     }
215 });
216 ```
217
218 Each button instructs the native code to set the pipeline to the desired
219 state, and also remembers this state in the
220 `is_playing_desired` variable.  This is required so, when the
221 application is restarted (for example, due to an orientation change), it
222 can set the pipeline again to the desired state. This approach is easier
223 and safer than tracking the actual pipeline state, because orientation
224 changes can happen before the pipeline has moved to the desired state,
225 for example.
226
227 ``` java
228 if (savedInstanceState != null) {
229     is_playing_desired = savedInstanceState.getBoolean("playing");
230     Log.i ("GStreamer", "Activity created. Saved state is playing:" + is_playing_desired);
231 } else {
232     is_playing_desired = false;
233     Log.i ("GStreamer", "Activity created. There is no saved state, playing: false");
234 }
235 ```
236
237 Restore the previous playing state (if any) from `savedInstanceState`.
238 We will first build the GStreamer pipeline (below) and only when the
239 native code reports itself as initialized we will use
240 `is_playing_desired`.
241
242 ``` java
243 nativeInit();
244 ```
245
246 As will be shown in the C code, `nativeInit()` creates a dedicated
247 thread, a GStreamer pipeline, a GLib main loop, and, right before
248 calling `g_main_loop_run()` and going to sleep, it warns the Java code
249 that the native code is initialized and ready to accept commands.
250
251 This finishes the `onCreate()` method and the Java initialization. The
252 UI buttons are disabled, so nothing will happen until native code is
253 ready and `onGStreamerInitialized()` is called:
254
255 ``` java
256 private void onGStreamerInitialized () {
257     Log.i ("GStreamer", "Gst initialized. Restoring state, playing:" + is_playing_desired);
258 ```
259
260 This is called by the native code when its main loop is finally running.
261 We first retrieve the desired playing state from `is_playing_desired`,
262 and then set that state:
263
264 ``` java
265 // Restore previous playing state
266 if (is_playing_desired) {
267     nativePlay();
268 } else {
269     nativePause();
270 }
271 ```
272
273 Here comes the first caveat, when re-enabling the UI buttons:
274
275 ``` java
276 // Re-enable buttons, now that GStreamer is initialized
277 final Activity activity = this;
278 runOnUiThread(new Runnable() {
279     public void run() {
280         activity.findViewById(R.id.button_play).setEnabled(true);
281         activity.findViewById(R.id.button_stop).setEnabled(true);
282     }
283 });
284 ```
285
286 This method is being called from the thread that the native code created
287 to run its main loop, and is not allowed to issue UI-altering commands:
288 Only the UI thread can do that. The solution is easy though: Android
289 Activities have a handy
290 [runOnUiThread()](http://developer.android.com/reference/android/app/Activity.html#runOnUiThread\(java.lang.Runnable\))
291 method which lets bits of code to be executed from the correct thread. A
292 [Runnable](http://developer.android.com/reference/java/lang/Runnable.html)
293 instance has to be constructed and any parameter can be passed either by
294 sub-classing
295 [Runnable](http://developer.android.com/reference/java/lang/Runnable.html)
296 and adding a dedicated constructor, or by using the `final` modifier, as
297 shown in the above snippet.
298
299 The same problem exists when the native code wants to output a string in
300 our TextView using the `setMessage()` method: it has to be done from the
301 UI thread. The solution is the same:
302
303 ``` java
304 private void setMessage(final String message) {
305     final TextView tv = (TextView) this.findViewById(R.id.textview_message);
306     runOnUiThread (new Runnable() {
307       public void run() {
308       tv.setText(message);
309     }
310   });
311 }
312 ```
313
314 Finally, a few remaining bits:
315
316 ``` java
317 protected void onSaveInstanceState (Bundle outState) {
318     Log.d ("GStreamer", "Saving state, playing:" + is_playing_desired);
319     outState.putBoolean("playing", is_playing_desired);
320 }
321 ```
322
323 This method stores the currently desired playing state when Android is
324 about to shut us down, so next time it restarts (after an orientation
325 change, for example), it can restore the same state.
326
327 ``` java
328 protected void onDestroy() {
329     nativeFinalize();
330     super.onDestroy();
331 }
332 ```
333
334 And this is called before Android destroys our application. We call the
335 `nativeFinalize()`method to exit the main loop, destroy its thread and
336 all allocated resources.
337
338 This concludes the UI part of the tutorial.
339
340 ### A pipeline on Android \[C code\]
341
342 **jni/tutorial-2.c**
343
344 ``` c
345 #include <string.h>
346 #include <jni.h>
347 #include <android/log.h>
348 #include <gst/gst.h>
349 #include <pthread.h>
350
351 GST_DEBUG_CATEGORY_STATIC (debug_category);
352 #define GST_CAT_DEFAULT debug_category
353
354 /*
355  * These macros provide a way to store the native pointer to CustomData, which might be 32 or 64 bits, into
356  * a jlong, which is always 64 bits, without warnings.
357  */
358 #if GLIB_SIZEOF_VOID_P == 8
359 ## define GET_CUSTOM_DATA(env, thiz, fieldID) (CustomData *)(*env)->GetLongField (env, thiz, fieldID)
360 ## define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)data)
361 #else
362 ## define GET_CUSTOM_DATA(env, thiz, fieldID) (CustomData *)(jint)(*env)->GetLongField (env, thiz, fieldID)
363 ## define SET_CUSTOM_DATA(env, thiz, fieldID, data) (*env)->SetLongField (env, thiz, fieldID, (jlong)(jint)data)
364 #endif
365
366 /* Structure to contain all our information, so we can pass it to callbacks */
367 typedef struct _CustomData {
368   jobject app;           /* Application instance, used to call its methods. A global reference is kept. */
369   GstElement *pipeline;  /* The running pipeline */
370   GMainContext *context; /* GLib context used to run the main loop */
371   GMainLoop *main_loop;  /* GLib main loop */
372   gboolean initialized;  /* To avoid informing the UI multiple times about the initialization */
373 } CustomData;
374
375 /* These global variables cache values which are not changing during execution */
376 static pthread_t gst_app_thread;
377 static pthread_key_t current_jni_env;
378 static JavaVM *java_vm;
379 static jfieldID custom_data_field_id;
380 static jmethodID set_message_method_id;
381 static jmethodID on_gstreamer_initialized_method_id;
382
383 /*
384  * Private methods
385  */
386
387 /* Register this thread with the VM */
388 static JNIEnv *attach_current_thread (void) {
389   JNIEnv *env;
390   JavaVMAttachArgs args;
391
392   GST_DEBUG ("Attaching thread %p", g_thread_self ());
393   args.version = JNI_VERSION_1_4;
394   args.name = NULL;
395   args.group = NULL;
396
397   if ((*java_vm)->AttachCurrentThread (java_vm, &env, &args) < 0) {
398     GST_ERROR ("Failed to attach current thread");
399     return NULL;
400   }
401
402   return env;
403 }
404
405 /* Unregister this thread from the VM */
406 static void detach_current_thread (void *env) {
407   GST_DEBUG ("Detaching thread %p", g_thread_self ());
408   (*java_vm)->DetachCurrentThread (java_vm);
409 }
410
411 /* Retrieve the JNI environment for this thread */
412 static JNIEnv *get_jni_env (void) {
413   JNIEnv *env;
414
415   if ((env = pthread_getspecific (current_jni_env)) == NULL) {
416     env = attach_current_thread ();
417     pthread_setspecific (current_jni_env, env);
418   }
419
420   return env;
421 }
422
423 /* Change the content of the UI's TextView */
424 static void set_ui_message (const gchar *message, CustomData *data) {
425   JNIEnv *env = get_jni_env ();
426   GST_DEBUG ("Setting message to: %s", message);
427   jstring jmessage = (*env)->NewStringUTF(env, message);
428   (*env)->CallVoidMethod (env, data->app, set_message_method_id, jmessage);
429   if ((*env)->ExceptionCheck (env)) {
430     GST_ERROR ("Failed to call Java method");
431     (*env)->ExceptionClear (env);
432   }
433   (*env)->DeleteLocalRef (env, jmessage);
434 }
435
436 /* Retrieve errors from the bus and show them on the UI */
437 static void error_cb (GstBus *bus, GstMessage *msg, CustomData *data) {
438   GError *err;
439   gchar *debug_info;
440   gchar *message_string;
441
442   gst_message_parse_error (msg, &err, &debug_info);
443   message_string = g_strdup_printf ("Error received from element %s: %s", GST_OBJECT_NAME (msg->src), err->message);
444   g_clear_error (&err);
445   g_free (debug_info);
446   set_ui_message (message_string, data);
447   g_free (message_string);
448   gst_element_set_state (data->pipeline, GST_STATE_NULL);
449 }
450
451 /* Notify UI about pipeline state changes */
452 static void state_changed_cb (GstBus *bus, GstMessage *msg, CustomData *data) {
453   GstState old_state, new_state, pending_state;
454   gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
455   /* Only pay attention to messages coming from the pipeline, not its children */
456   if (GST_MESSAGE_SRC (msg) == GST_OBJECT (data->pipeline)) {
457     gchar *message = g_strdup_printf("State changed to %s", gst_element_state_get_name(new_state));
458     set_ui_message(message, data);
459     g_free (message);
460   }
461 }
462
463 /* Check if all conditions are met to report GStreamer as initialized.
464  * These conditions will change depending on the application */
465 static void check_initialization_complete (CustomData *data) {
466   JNIEnv *env = get_jni_env ();
467   if (!data->initialized && data->main_loop) {
468     GST_DEBUG ("Initialization complete, notifying application. main_loop:%p", data->main_loop);
469     (*env)->CallVoidMethod (env, data->app, on_gstreamer_initialized_method_id);
470     if ((*env)->ExceptionCheck (env)) {
471       GST_ERROR ("Failed to call Java method");
472       (*env)->ExceptionClear (env);
473     }
474     data->initialized = TRUE;
475   }
476 }
477
478 /* Main method for the native code. This is executed on its own thread. */
479 static void *app_function (void *userdata) {
480   JavaVMAttachArgs args;
481   GstBus *bus;
482   CustomData *data = (CustomData *)userdata;
483   GSource *bus_source;
484   GError *error = NULL;
485
486   GST_DEBUG ("Creating pipeline in CustomData at %p", data);
487
488   /* Create our own GLib Main Context and make it the default one */
489   data->context = g_main_context_new ();
490   g_main_context_push_thread_default(data->context);
491
492   /* Build pipeline */
493   data->pipeline = gst_parse_launch("audiotestsrc ! audioconvert ! audioresample ! autoaudiosink", &error);
494   if (error) {
495     gchar *message = g_strdup_printf("Unable to build pipeline: %s", error->message);
496     g_clear_error (&error);
497     set_ui_message(message, data);
498     g_free (message);
499     return NULL;
500   }
501
502   /* Instruct the bus to emit signals for each received message, and connect to the interesting signals */
503   bus = gst_element_get_bus (data->pipeline);
504   bus_source = gst_bus_create_watch (bus);
505   g_source_set_callback (bus_source, (GSourceFunc) gst_bus_async_signal_func, NULL, NULL);
506   g_source_attach (bus_source, data->context);
507   g_source_unref (bus_source);
508   g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, data);
509   g_signal_connect (G_OBJECT (bus), "message::state-changed", (GCallback)state_changed_cb, data);
510   gst_object_unref (bus);
511
512   /* Create a GLib Main Loop and set it to run */
513   GST_DEBUG ("Entering main loop... (CustomData:%p)", data);
514   data->main_loop = g_main_loop_new (data->context, FALSE);
515   check_initialization_complete (data);
516   g_main_loop_run (data->main_loop);
517   GST_DEBUG ("Exited main loop");
518   g_main_loop_unref (data->main_loop);
519   data->main_loop = NULL;
520
521   /* Free resources */
522   g_main_context_pop_thread_default(data->context);
523   g_main_context_unref (data->context);
524   gst_element_set_state (data->pipeline, GST_STATE_NULL);
525   gst_object_unref (data->pipeline);
526
527   return NULL;
528 }
529
530 /*
531  * Java Bindings
532  */
533
534 /* Instruct the native code to create its internal data structure, pipeline and thread */
535 static void gst_native_init (JNIEnv* env, jobject thiz) {
536   CustomData *data = g_new0 (CustomData, 1);
537   SET_CUSTOM_DATA (env, thiz, custom_data_field_id, data);
538   GST_DEBUG_CATEGORY_INIT (debug_category, "tutorial-2", 0, "Android tutorial 2");
539   gst_debug_set_threshold_for_name("tutorial-2", GST_LEVEL_DEBUG);
540   GST_DEBUG ("Created CustomData at %p", data);
541   data->app = (*env)->NewGlobalRef (env, thiz);
542   GST_DEBUG ("Created GlobalRef for app object at %p", data->app);
543   pthread_create (&gst_app_thread, NULL, &app_function, data);
544 }
545
546 /* Quit the main loop, remove the native thread and free resources */
547 static void gst_native_finalize (JNIEnv* env, jobject thiz) {
548   CustomData *data = GET_CUSTOM_DATA (env, thiz, custom_data_field_id);
549   if (!data) return;
550   GST_DEBUG ("Quitting main loop...");
551   g_main_loop_quit (data->main_loop);
552   GST_DEBUG ("Waiting for thread to finish...");
553   pthread_join (gst_app_thread, NULL);
554   GST_DEBUG ("Deleting GlobalRef for app object at %p", data->app);
555   (*env)->DeleteGlobalRef (env, data->app);
556   GST_DEBUG ("Freeing CustomData at %p", data);
557   g_free (data);
558   SET_CUSTOM_DATA (env, thiz, custom_data_field_id, NULL);
559   GST_DEBUG ("Done finalizing");
560 }
561
562 /* Set pipeline to PLAYING state */
563 static void gst_native_play (JNIEnv* env, jobject thiz) {
564   CustomData *data = GET_CUSTOM_DATA (env, thiz, custom_data_field_id);
565   if (!data) return;
566   GST_DEBUG ("Setting state to PLAYING");
567   gst_element_set_state (data->pipeline, GST_STATE_PLAYING);
568 }
569
570 /* Set pipeline to PAUSED state */
571 static void gst_native_pause (JNIEnv* env, jobject thiz) {
572   CustomData *data = GET_CUSTOM_DATA (env, thiz, custom_data_field_id);
573   if (!data) return;
574   GST_DEBUG ("Setting state to PAUSED");
575   gst_element_set_state (data->pipeline, GST_STATE_PAUSED);
576 }
577
578 /* Static class initializer: retrieve method and field IDs */
579 static jboolean gst_native_class_init (JNIEnv* env, jclass klass) {
580   custom_data_field_id = (*env)->GetFieldID (env, klass, "native_custom_data", "J");
581   set_message_method_id = (*env)->GetMethodID (env, klass, "setMessage", "(Ljava/lang/String;)V");
582   on_gstreamer_initialized_method_id = (*env)->GetMethodID (env, klass, "onGStreamerInitialized", "()V");
583
584   if (!custom_data_field_id || !set_message_method_id || !on_gstreamer_initialized_method_id) {
585     /* We emit this message through the Android log instead of the GStreamer log because the later
586      * has not been initialized yet.
587      */
588     __android_log_print (ANDROID_LOG_ERROR, "tutorial-2", "The calling class does not implement all necessary interface methods");
589     return JNI_FALSE;
590   }
591   return JNI_TRUE;
592 }
593
594 /* List of implemented native methods */
595 static JNINativeMethod native_methods[] = {
596   { "nativeInit", "()V", (void *) gst_native_init},
597   { "nativeFinalize", "()V", (void *) gst_native_finalize},
598   { "nativePlay", "()V", (void *) gst_native_play},
599   { "nativePause", "()V", (void *) gst_native_pause},
600   { "nativeClassInit", "()Z", (void *) gst_native_class_init}
601 };
602
603 /* Library initializer */
604 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
605   JNIEnv *env = NULL;
606
607   java_vm = vm;
608
609   if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
610     __android_log_print (ANDROID_LOG_ERROR, "tutorial-2", "Could not retrieve JNIEnv");
611     return 0;
612   }
613   jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/tutorials/tutorial_2/Tutorial2");
614   (*env)->RegisterNatives (env, klass, native_methods, G_N_ELEMENTS(native_methods));
615
616   pthread_key_create (&current_jni_env, detach_current_thread);
617
618   return JNI_VERSION_1_4;
619 }
620 ```
621
622 Let’s start with the `CustomData` structure. We have seen it in most of
623 the basic tutorials, and it is used to hold all our information in one
624 place, so we can easily pass it around to
625 callbacks:
626
627 ``` c
628 /* Structure to contain all our information, so we can pass it to callbacks */
629 typedef struct _CustomData {
630   jobject app;           /* Application instance, used to call its methods. A global reference is kept. */
631   GstElement *pipeline;  /* The running pipeline */
632   GMainContext *context; /* GLib context used to run the main loop */
633   GMainLoop *main_loop;  /* GLib main loop */
634   gboolean initialized;  /* To avoid informing the UI multiple times about the initialization */
635 } CustomData;
636 ```
637
638 We will see the meaning of each member as we go. What is interesting now
639 is that `CustomData` belongs to the application, so a pointer is kept in
640 the Tutorial2 Java class in the `private long
641 native_custom_data` attribute. Java only holds this pointer for us; it
642 is completely handled in C code.
643
644 From C, this pointer can be set and retrieved with the
645 [SetLongField()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#wp16613)
646 and
647 [GetLongField()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#wp16572)
648 JNI functions, but two convenience macros have been defined,
649 `SET_CUSTOM_DATA` and `GET_CUSTOM_DATA`. These macros are handy because
650 the `long` type used in Java is always 64 bits wide, but the pointer
651 used in C can be either 32 or 64 bits wide. The macros take care of the
652 conversion without warnings.
653
654 ``` c
655 /* Library initializer */
656 jint JNI_OnLoad(JavaVM *vm, void *reserved) {
657   JNIEnv *env = NULL;
658
659   java_vm = vm;
660
661   if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
662     __android_log_print (ANDROID_LOG_ERROR, "tutorial-2", "Could not retrieve JNIEnv");
663     return 0;
664   }
665   jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/tutorials/tutorial_2/Tutorial2");
666   (*env)->RegisterNatives (env, klass, native_methods, G_N_ELEMENTS(native_methods));
667
668   pthread_key_create (&current_jni_env, detach_current_thread);
669
670   return JNI_VERSION_1_4;
671 }
672 ```
673
674 The `JNI_OnLoad` function is almost the same as the previous tutorial.
675 It registers the list of native methods (which is longer in this
676 tutorial). It also
677 uses [pthread\_key\_create()](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_key_create.html)
678 to be able to store per-thread information, which is crucial to properly
679 manage the JNI Environment, as shown later.
680
681 ``` c
682 /* Static class initializer: retrieve method and field IDs */
683 static jboolean gst_native_class_init (JNIEnv* env, jclass klass) {
684   custom_data_field_id = (*env)->GetFieldID (env, klass, "native_custom_data", "J");
685   set_message_method_id = (*env)->GetMethodID (env, klass, "setMessage", "(Ljava/lang/String;)V");
686   on_gstreamer_initialized_method_id = (*env)->GetMethodID (env, klass, "onGStreamerInitialized", "()V");
687
688   if (!custom_data_field_id || !set_message_method_id || !on_gstreamer_initialized_method_id) {
689     /* We emit this message through the Android log instead of the GStreamer log because the later
690      * has not been initialized yet.
691      */
692     __android_log_print (ANDROID_LOG_ERROR, "tutorial-2", "The calling class does not implement all necessary interface methods");
693     return JNI_FALSE;
694   }
695   return JNI_TRUE;
696 }
697 ```
698
699 This method is called from the static initializer of the Java class,
700 which is passed as a parameter (since this is called from a static
701 method, it receives a class object instead of an instance object). In
702 order for C code to be able to call a Java method, it needs to know the
703 method’s
704 [MethodID](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp1064).
705 This ID is obtained from the method’s name and signature and can be
706 cached. The purpose of the `gst_native_class_init()` function is to
707 obtain the IDs of all the methods and fields that the C code will need.
708 If some ID cannot be retrieved, the calling Java class does not offer
709 the expected interface and execution should halt (which is not currently
710 done for simplicity).
711
712 Let’s review now the first native method which can be directly called
713 from Java:
714
715 #### `gst_native_init()` (`nativeInit()` from Java)
716
717 This method is called at the end of Java's `onCreate()`.
718
719 ``` c
720 static void gst_native_init (JNIEnv* env, jobject thiz) {
721   CustomData *data = g_new0 (CustomData, 1);
722   SET_CUSTOM_DATA (env, thiz, custom_data_field_id, data);
723 ```
724
725 It first allocates memory for the `CustomData` structure and passes the
726 pointer to the Java class with `SET_CUSTOM_DATA`, so it is remembered.
727
728 ``` c
729 data->app = (*env)->NewGlobalRef (env, thiz);
730 ```
731
732 A pointer to the application class (the `Tutorial2` class) is also kept
733 in `CustomData` (a [Global
734 Reference](http://developer.android.com/guide/practices/jni.html#local_and_global_references)
735 is used) so its methods can be called later.
736
737 ``` c
738 pthread_create (&gst_app_thread, NULL, &app_function, data);
739 ```
740
741 Finally, a thread is created and it starts running the
742 `app_function()` method.
743
744 ####  `app_function()`
745
746 ``` c
747 /* Main method for the native code. This is executed on its own thread. */
748 static void *app_function (void *userdata) {
749   JavaVMAttachArgs args;
750   GstBus *bus;
751   CustomData *data = (CustomData *)userdata;
752   GSource *bus_source;
753   GError *error = NULL;
754
755   GST_DEBUG ("Creating pipeline in CustomData at %p", data);
756
757   /* Create our own GLib Main Context and make it the default one */
758   data->context = g_main_context_new ();
759   g_main_context_push_thread_default(data->context);
760 ```
761
762 It first creates a GLib context so all `GSource` are kept in the same
763 place. This also helps cleaning after GSources created by other
764 libraries which might not have been properly disposed of. A new context
765 is created with `g_main_context_new()` and then it is made the default
766 one for the thread with
767 `g_main_context_push_thread_default()`.
768
769 ``` c
770 data->pipeline = gst_parse_launch("audiotestsrc ! audioconvert ! audioresample ! autoaudiosink", &error);
771 if (error) {
772   gchar *message = g_strdup_printf("Unable to build pipeline: %s", error->message);
773   g_clear_error (&error);
774   set_ui_message(message, data);
775   g_free (message);
776   return NULL;
777 }
778 ```
779
780 It then creates a pipeline the easy way, with `gst-parse-launch()`. In
781 this case, it is simply an `audiotestsrc` (which produces a continuous
782 tone) and an `autoaudiosink`, with accompanying adapter elements.
783
784 ``` c
785 bus = gst_element_get_bus (data->pipeline);
786 bus_source = gst_bus_create_watch (bus);
787 g_source_set_callback (bus_source, (GSourceFunc) gst_bus_async_signal_func, NULL, NULL);
788 g_source_attach (bus_source, data->context);
789 g_source_unref (bus_source);
790 g_signal_connect (G_OBJECT (bus), "message::error", (GCallback)error_cb, data);
791 g_signal_connect (G_OBJECT (bus), "message::state-changed", (GCallback)state_changed_cb, data);
792 gst_object_unref (bus);
793 ```
794
795 These lines create a bus signal watch and connect to some interesting
796 signals, just like we have been doing in the basic tutorials. The
797 creation of the watch is done step by step instead of using
798 `gst_bus_add_signal_watch()` to exemplify how to use a custom GLib
799 context.
800
801 ``` c
802 GST_DEBUG ("Entering main loop... (CustomData:%p)", data);
803 data->main_loop = g_main_loop_new (data->context, FALSE);
804 check_initialization_complete (data);
805 g_main_loop_run (data->main_loop);
806 GST_DEBUG ("Exited main loop");
807 g_main_loop_unref (data->main_loop);
808 data->main_loop = NULL;
809 ```
810
811 Finally, the main loop is created and set to run. When it exits (because
812 somebody else calls `g_main_loop_quit()`) the main loop is disposed of.
813 Before entering the main loop, though,
814 `check_initialization_complete()` is called. This method checks if all
815 conditions are met to consider the native code “ready” to accept
816 commands. Since having a running main loop is one of the conditions,
817 `check_initialization_complete()` is called here. This method is
818 reviewed below.
819
820 Once the main loop has quit, all resources are freed in lines 178 to
821 181.
822
823 #### `check_initialization_complete()`
824
825 ``` c
826 static void check_initialization_complete (CustomData *data) {
827   JNIEnv *env = get_jni_env ();
828   if (!data->initialized && data->main_loop) {
829     GST_DEBUG ("Initialization complete, notifying application. main_loop:%p", data->main_loop);
830     (*env)->CallVoidMethod (env, data->app, on_gstreamer_initialized_method_id);
831     if ((*env)->ExceptionCheck (env)) {
832       GST_ERROR ("Failed to call Java method");
833       (*env)->ExceptionClear (env);
834     }
835     data->initialized = TRUE;
836   }
837 }
838 ```
839
840 This method does not do much in this tutorial, but it will also be used
841 in the next ones, with progressively more complex functionality. Its
842 purpose is to check if the native code is ready to accept commands, and,
843 if so, notify the UI code.
844
845 In tutorial 2, the only conditions are 1) the code is not already
846 initialized and 2) the main loop is running. If these two are met, the
847 Java `onGStreamerInitialized()` method is called via the
848 [CallVoidMethod()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#wp4256)
849 JNI call.
850
851 Here comes a tricky bit. JNI calls require a JNI Environment, **which is
852 different for every thread**. C methods called from Java receive a
853 `JNIEnv` pointer as a parameter, but this is not the situation with
854 `check_initialization_complete()`. Here, we are in a thread which has
855 never been called from Java, so we have no `JNIEnv`. We need to use the
856 `JavaVM` pointer (passed to us in the `JNI_OnLoad()` method, and shared
857 among all threads) to attach this thread to the Java Virtual Machine and
858 obtain a `JNIEnv`. This `JNIEnv` is stored in the [Thread-Local
859 Storage](http://en.wikipedia.org/wiki/Thread-local_storage) (TLS) using
860 the pthread key we created in `JNI_OnLoad()`, so we do not need to
861 attach the thread anymore.
862
863 This behavior is implemented in the `get_jni_env()` method, used for
864 example in `check_initialization_complete()` as we have just seen. Let’s
865 see how it works, step by step:
866
867 #### `get_jni_env()`
868
869 ``` c
870 static JNIEnv *get_jni_env (void) {
871   JNIEnv *env;
872   if ((env = pthread_getspecific (current_jni_env)) == NULL) {
873     env = attach_current_thread ();
874     pthread_setspecific (current_jni_env, env);
875   }
876   return env;
877 }
878 ```
879
880 It first retrieves the current `JNIEnv` from the TLS using
881 [pthread\_getspecific()](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getspecific.html)
882 and the key we obtained from
883 [pthread\_key\_create()](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_key_create.html).
884 If it returns NULL, we never attached this thread, so we do now with
885 `attach_current_thread()` and then store the new `JNIEnv` into the TLS
886 with
887 [pthread\_setspecific()](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setspecific.html).
888
889 #### `attach_current_thread()`
890
891 This method is simply a convenience wrapper around
892 [AttachCurrentThread()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html#attach_current_thread)
893 to deal with its parameters.
894
895 #### `detach_current_thread()`
896
897 This method is called by the pthreads library when a TLS key is deleted,
898 meaning that the thread is about to be destroyed. We simply detach the
899 thread from the JavaVM with
900 [DetachCurrentThread()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html#detach_current_thread).
901
902 Let's now review the rest of the native methods accessible from Java:
903
904 #### `gst_native_finalize()` (`nativeFinalize()` from Java)
905
906 ``` c
907 static void gst_native_finalize (JNIEnv* env, jobject thiz) {
908   CustomData *data = GET_CUSTOM_DATA (env, thiz, custom_data_field_id);
909   if (!data) return;
910   GST_DEBUG ("Quitting main loop...");
911   g_main_loop_quit (data->main_loop);
912   GST_DEBUG ("Waiting for thread to finish...");
913   pthread_join (gst_app_thread, NULL);
914   GST_DEBUG ("Deleting GlobalRef for app object at %p", data->app);
915   (*env)->DeleteGlobalRef (env, data->app);
916   GST_DEBUG ("Freeing CustomData at %p", data);
917   g_free (data);
918   SET_CUSTOM_DATA (env, thiz, custom_data_field_id, NULL);
919   GST_DEBUG ("Done finalizing");
920 }
921 ```
922
923 This method is called from Java in `onDestroy()`, when the activity is
924 about to be destroyed. Here, we:
925
926   - Instruct the GLib main loop to quit with `g_main_loop_quit()`. This
927     call returns immediately, and the main loop will terminate at its
928     earliest convenience.
929   - Wait for the thread to finish with
930     [pthread\_join()](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html).
931     This call blocks until the `app_function()` method returns, meaning
932     that the main loop has exited, and the thread has been destroyed.
933   - Dispose of the global reference we kept for the Java application
934     class (`Tutorial2`) in `CustomData`.
935   - Free `CustomData` and set the Java pointer inside the
936     `Tutorial2` class to NULL with
937 `SET_CUSTOM_DATA()`.
938
939 #### `gst_native_play` and `gst_native_pause()` (`nativePlay` and `nativePause()` from Java)
940
941 These two simple methods retrieve `CustomData` from the passed-in object
942 with `GET_CUSTOM_DATA()` and set the pipeline found inside `CustomData`
943 to the desired state, returning immediately.
944
945 Finally, let’s see how the GStreamer callbacks are handled:
946
947 #### `error_cb` and `state_changed_cb`
948
949 This tutorial does not do much in these callbacks. They simply parse the
950 error or state changed message and display a message in the UI using the
951 `set_ui_message()` method:
952
953 #### `set_ui_message()`
954
955 ``` c
956 static void set_ui_message (const gchar *message, CustomData *data) {
957   JNIEnv *env = get_jni_env ();
958   GST_DEBUG ("Setting message to: %s", message);
959   jstring jmessage = (*env)->NewStringUTF(env, message);
960   (*env)->CallVoidMethod (env, data->app, set_message_method_id, jmessage);
961   if ((*env)->ExceptionCheck (env)) {
962     GST_ERROR ("Failed to call Java method");
963     (*env)->ExceptionClear (env);
964   }
965   (*env)->DeleteLocalRef (env, jmessage);
966 }
967 ```
968
969
970
971 This is the other method (besides `check_initialization_complete()`)
972 that needs to call a Java function from a thread which never received an
973 `JNIEnv` pointer directly. Notice how all the complexities of attaching
974 the thread to the JavaVM and storing the JNI environment in the TLS are
975 hidden in the simple call to `get_jni_env()`.
976
977 The desired message (received in
978 [ASCII](http://en.wikipedia.org/wiki/ASCII), or modified
979 [UTF8](http://en.wikipedia.org/wiki/Modified_UTF-8#Modified_UTF-8)), is
980 converted to [UTF16](http://en.wikipedia.org/wiki/UTF-16) as required by
981 Java using the
982 [NewStringUTF()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#wp17220)
983 JNI call.
984
985 The `setMessage()` Java method is called via the JNI
986 [CallVoidMethod()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#wp4256)
987 using the global reference to the class we are keeping in
988 `CustomData` (`data->app`) and the `set_message_method_id` we cached in
989 `gst_native_class_init()`.
990
991 We check for exceptions with the JNI
992 [ExceptionCheck()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#exception_check)
993 method and free the UTF16 message with
994 [DeleteLocalRef()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html#DeleteLocalRef).
995
996 ### A pipeline on Android \[Android.mk\]
997
998 **jni/Android.mk**
999
1000 ``` ruby
1001 LOCAL_PATH := $(call my-dir)
1002
1003 include $(CLEAR_VARS)
1004
1005 LOCAL_MODULE    := tutorial-2
1006 LOCAL_SRC_FILES := tutorial-2.c
1007 LOCAL_SHARED_LIBRARIES := gstreamer_android
1008 LOCAL_LDLIBS := -llog
1009 include $(BUILD_SHARED_LIBRARY)
1010
1011 ifndef GSTREAMER_ROOT
1012 ifndef GSTREAMER_ROOT_ANDROID
1013 $(error GSTREAMER_ROOT_ANDROID is not defined!)
1014 endif
1015 GSTREAMER_ROOT        := $(GSTREAMER_ROOT_ANDROID)
1016 endif
1017 GSTREAMER_NDK_BUILD_PATH  := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/
1018 include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk
1019 GSTREAMER_PLUGINS         := $(GSTREAMER_PLUGINS_CORE) $(GSTREAMER_PLUGINS_SYS)
1020 include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk
1021 ```
1022
1023 Notice how the required `GSTREAMER_PLUGINS` are now
1024 `$(GSTREAMER_PLUGINS_CORE)` (For the test source and converter elements)
1025 and `$(GSTREAMER_PLUGINS_SYS)` (for the audio sink).
1026
1027 And this is it\! This has been a rather long tutorial, but we covered a
1028 lot of territory. Building on top of this one, the following ones are
1029 shorter and focus only on the new topics.
1030
1031 ### Conclusion
1032
1033 This tutorial has shown:
1034
1035   - How to manage multiple threads from C code and have them interact
1036     with java.
1037   - How to access Java code from any C thread
1038     using [AttachCurrentThread()](http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html#attach_current_thread).
1039   - How to allocate a CustomData structure from C and have Java host it,
1040     so it is available to all threads.
1041
1042 Most of the methods introduced in this tutorial, like `get_jni_env()`,
1043 `check_initialization_complete()`, `app_function()` and the API methods
1044 `gst_native_init()`, `gst_native_finalize()` and
1045 `gst_native_class_init()` will continue to be used in the following
1046 tutorials with minimal modifications, so better get used to them\!
1047
1048 As usual, it has been a pleasure having you here, and see you soon\!
1049
1050   [screenshot]: images/tutorials/android-a-running-pipeline-screenshot.png