- WebRTC app - C# / Xamarin - Part #1 - Building platform native webrtc library
- WebRTC app - C# / Xamarin - Part #2 - Attempt #1 - failure to using a JNI .so file directly from C# / Mono
- WebRTC app - C# / Xamarin - Part #2 - Attempt #2 - success using a JNI .so file from C# / Mono
- WebRTC app - C# / Xamarin - (C# - JNI - C/C++) - Summary and GitHub repository
In my previous posting WebRTC app - C# / Xamarin - Part #1 - Building platform native webrtc library I have showed how to build a native library that we need to use to build a WebRTC app on Xamarin / Mono.Droid.
In this posting I will take you through my struggles, subsequent failure and the next posting finally success on how to actually use this JNI native library from Mono.Android.
I started a new solution in Visual Studio 2013 and added new Android Application project. Then according to Xamarin: Using Native Libraries.
I needed to add my .so file to the location
<project>\lib\armeabi-v7a\libwebrtc-video-demo-jni.so.
The next step that I tried was to start using DllImport statements.
using System; using System.Runtime.InteropServices; using Android.Content; using Android.Util; using Encoding = System.Text.Encoding; namespace WebRtc { public class ViEAndroidJavaAPI { ... // API Native [DllImport("libwebrtc-video-demo-jni.so")] private static extern bool NativeInit(Context context); // Video Engine API // Initialization and Termination functions [DllImport("libwebrtc-video-demo-jni.so")] public static extern int GetVideoEngine(); [DllImport("libwebrtc-video-demo-jni.so")] public static extern int Init(bool enableTrace); [DllImport("libwebrtc-video-demo-jni.so")] public static extern int Terminate(); ...
Trying to run my project yielded some EntryPointNotFoundException in the error log. After a bit of Google-ing I found that the method names as seen from Mono are not as you expect instead they contain the full package/class path.
Using the following command on the Ubuntu build machine
~/WebRTCDemo/trunk/webrtc/video_engine/test/android/libs/armeabi-v7a$ arm-linux-androideabi-nm -D libwebrtc-video-demo-jni.soyielded the following output
00015358 T JNI_OnLoad 00015be4 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_AddRemoteRenderer 00016e3c T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_CreateChannel 00015f14 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_EnableNACK 00015f58 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_EnablePLI 00015e04 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetCameraOrientation 00015acc T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetCodecs 000153d4 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine 000154cc T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Init 000153d0 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_NativeInit 00015c30 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_RemoveRemoteRenderer 00015fb0 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_SetCallback 00015ea8 T Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_SetExternalMediaCodecDecoderRenderer ...So changing my code to the following made the EntryPointNotFoundException go away
using System; using System.Runtime.InteropServices; using Android.Content; using Android.Util; using Encoding = System.Text.Encoding; namespace WebRtc { public class ViEAndroidJavaAPI { ... // API Native [DllImport("libwebrtc-video-demo-jni.so")] private static extern bool Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_NativeInit(Context context); // Video Engine API // Initialization and Termination functions [DllImport("libwebrtc-video-demo-jni.so")] public static extern int Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_GetVideoEngine(); [DllImport("libwebrtc-video-demo-jni.so")] public static extern int Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Init(bool enableTrace); [DllImport("libwebrtc-video-demo-jni.so")] public static extern int Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_Terminate(); ...Now I was faced with another exception which seemed much nastier.
UNHANDLED EXCEPTION: System.Runtime.InteropServices.MarshalDirectiveException: Type Java.Lang.Object which is passed to unmanaged code must have a StructLayout attribute.
12-21 19:29:04.298 I/MonoDroid(15226): UNHANDLED EXCEPTION: System.Runtime.InteropServices.MarshalDirectiveException: Type Java.Lang.Object which is passed to unmanaged code must have a StructLayout attribute. 12-21 19:29:04.298 I/MonoDroid(15226): at (wrapper managed-to-native) WebRtc.ViEAndroidJavaAPI.Java_org_webrtc_videoengineapp_ViEAndroidJavaAPI_NativeInit (Android.Content.Context) 12-21 19:29:04.298 I/MonoDroid(15226): at WebRtc.ViEAndroidJavaAPI..ctor (Android.Content.Context) [0x00033] in XXX\WebRtc.Mono.Droid\ViEAndroidJavaAPI.cs:30 12-21 19:29:04.298 I/MonoDroid(15226): at WebRtc.Mono.Droid.WebRTCDemo.startMain () [0x0004b] in XXX\WebRtc.Mono.Droid\WebRTCDemo.cs:533 12-21 19:29:04.298 I/MonoDroid(15226): at WebRtc.Mono.Droid.WebRTCDemo.OnCreate (Android.OS.Bundle) [0x0028e] in XXX\WebRtc.Mono.Droid\WebRTCDemo.cs:313 12-21 19:29:04.298 I/MonoDroid(15226): at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) [0x00011] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.1-branch/d23a19bf/source/monodroid/src/Mono.Android/platforms/android-17/src/generated/Android.App.Activity.cs:2119 12-21 19:29:04.298 I/MonoDroid(15226): at (wrapper dynamic-method) object.705dc6ba-9c58-4bcd-a8a2-f12584a9175f (intptr,intptr,intptr)
Finally after digging I found this posting Native library integration which basically state
you cannot sanely use P/Invoke to invoke the native method. You must instead use JNI to invoke the Java-side native method.Basically because this is Java native C/C++ interface we are to invoke, you cannot do this like normal non JNI wrapped C/C++ methods.
This is pushing me in a direction that I initially hoped I could avoid (mainly due to my limited knowledge in the area), JNI.
Later: I did some (quite a bit) reading, namely I found these links useful:
Interop with Native Libraries
Java Integration Overview
Working With JNI
In the next posting in this series I manage to invoke the native methods.
No comments:
Post a Comment