Makefile needed for compiling the Opus Codec for Android - android-ndk

I am trying to compile the opus audio codec (http://www.opus-codec.org/downloads/) for use in an Android application. I am using Android NDK (release 6) to compile my libraries. Up to now, the native C libraries that I had to compile for my application has been pretty straightforward and I have been able to base my Android.mk files in jni mostly on tutorials or other examples. However, the compilation of Opus looks to be somewhat more complex. The tar.gz archive contains a solution file for compiling the libraries for Windows and it also contains some Makefiles for a standard Unix implementation, but translating these into an Android.mk makefile for use by the Android NDK is a bit of a challenge.
I have searched, but have been unable to find an online version for the Android makefile to compile libopus. Can someone perhaps link me to such a makefile? Alternatively, I might be missing something simpler? Is it perhaps possible to use Automake or some kind of converter to maybe generate the Android.mk file for me from the unix makefile that is already included in the tar.gz?

The following is the Android.mk makefile that eventually worked for me. I hope this can help someone else too in future. Do take note that in the unix makefile included in the Opus Archive, the decision of whether to use the fixed or float silk sources is defined as an "ifdef" whereas here I am using "fixed". (To use "float" would be simple - simply update the paths "silk/fixed" to point to "silk/float" and update the CFLAGS.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
MY_MODULE_DIR := opus
LOCAL_MODULE := $(MY_MODULE_DIR)
LOCAL_SRC_FILES := \
$(subst $(ROOT_DIR)/$(MY_MODULE_DIR)/,,$(wildcard $(ROOT_DIR)/$(MY_MODULE_DIR)/src/*.c*)) \
$(subst $(ROOT_DIR)/$(MY_MODULE_DIR)/,,$(wildcard $(ROOT_DIR)/$(MY_MODULE_DIR)/celt/*.c*)) \
$(subst $(ROOT_DIR)/$(MY_MODULE_DIR)/,,$(wildcard $(ROOT_DIR)/$(MY_MODULE_DIR)/silk/*.c*)) \
$(subst $(ROOT_DIR)/$(MY_MODULE_DIR)/,,$(wildcard $(ROOT_DIR)/$(MY_MODULE_DIR)/silk/fixed/*.c*))
LOCAL_LDLIBS := -lm -llog
LOCAL_C_INCLUDES := \
$(ROOT_DIR)/$(MY_MODULE_DIR)/include \
$(ROOT_DIR)/$(MY_MODULE_DIR)/silk \
$(ROOT_DIR)/$(MY_MODULE_DIR)/silk/fixed \
$(ROOT_DIR)/$(MY_MODULE_DIR)/celt
LOCAL_CFLAGS := -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -O3 -fno-math-errno
LOCAL_CPPFLAGS := -DBSD=1
LOCAL_CPPFLAGS += -ffast-math -O3 -funroll-loops
include $(BUILD_STATIC_LIBRARY)

IMPORTANT EDIT
The images might not be up to date but the work has been tested on below versions:
opus-1.1
opus-1.1.2
An updated version (works for opus-1.1.2 ) of #praneetloke's solution. A kind of different approach with some extras.
First of all below is my structure to use (I intended to use more libraries, so I put opus in its own sub-folder. )
Secondly I have a root Android.mk file and one another inside the folder opus-1.1.2 .
Here is the root Android.mk file:
LOCAL_PATH := $(call my-dir)
OPUS_DIR := opus-1.1.2
include $(OPUS_DIR)/Android.mk
include $(CLEAR_VARS)
LOCAL_MODULE := codec
LOCAL_SRC_FILES := Opus_jni.cpp
LOCAL_CFLAGS := -DNULL=0
LOCAL_LDLIBS := -lm -llog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(OPUS_DIR)/include
LOCAL_SHARED_LIBRARIES := opus
include $(BUILD_SHARED_LIBRARY)
Android.mk file inside the opus-1.1.2 folder is below:
#Backing up previous LOCAL_PATH so it does not screw with the root Android.mk file
LOCAL_PATH_OLD := $(LOCAL_PATH)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#include the .mk files
include $(LOCAL_PATH)/celt_sources.mk
include $(LOCAL_PATH)/silk_sources.mk
include $(LOCAL_PATH)/opus_sources.mk
LOCAL_MODULE := opus
#fixed point sources
SILK_SOURCES += $(SILK_SOURCES_FIXED)
#ARM build
CELT_SOURCES += $(CELT_SOURCES_ARM)
SILK_SOURCES += $(SILK_SOURCES_ARM)
LOCAL_SRC_FILES := \
$(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES)
LOCAL_LDLIBS := -lm -llog
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/silk \
$(LOCAL_PATH)/silk/fixed \
$(LOCAL_PATH)/celt
LOCAL_CFLAGS := -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT=1 -DDISABLE_FLOAT_API -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -DAVOID_TABLES
LOCAL_CFLAGS += -w -std=gnu99 -O3 -fno-strict-aliasing -fprefetch-loop-arrays -fno-math-errno
LOCAL_CPPFLAGS := -DBSD=1
LOCAL_CPPFLAGS += -ffast-math -O3 -funroll-loops
include $(BUILD_SHARED_LIBRARY)
#Putting previous LOCAL_PATH back here
LOCAL_PATH := $(LOCAL_PATH_OLD)
This is how it looks like inside opus-1.1.2 folder:
The only touch to the original sources is addition of an Android.mk file. Nothing removed.
This way I can use and update opus just like a separate library.
Here is the extras for those who wants to compile and use opus in android; Wrapper source, partially:
#include <jni.h>
#include <android/log.h>
#include <opus.h>
/* Header for class net_abcdefgh_opustrial_codec_Opus */
#ifndef _Included_net_abcdefgh_opustrial_codec_Opus
#define _Included_net_abcdefgh_opustrial_codec_Opus
#define TAG "Opus_JNI"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , TAG,__VA_ARGS__)
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_net_abcdefgh_opustrial_codec_Opus_open
(JNIEnv *env, jobject thiz){
...
return error;
}
JNIEXPORT jint JNICALL Java_net_abcdefgh_opustrial_codec_Opus_decode
(JNIEnv * env, jobject thiz, jbyteArray jencoded, jint jencodedOffset, jint jencodedLength, jbyteArray jpcm, jint jpcmOffset, jint jframeSize) {
...
return decodedSize;
}
JNIEXPORT jint JNICALL Java_net_abcdefgh_opustrial_codec_Opus_encode
(JNIEnv * env, jobject thiz, jbyteArray jpcm, jint jpcmOffset, jint jpcmLength, jbyteArray jencoded, jint jencodedOffset) {
...
return encodedSize;
}
JNIEXPORT void JNICALL Java_net_abcdefgh_opustrial_codec_Opus_close
(JNIEnv *env, jobject thiz){
...
}
#ifdef __cplusplus
}
#endif
#endif
Application.mk file (optional)
APP_ABI := all # mips, armeabi, armeabi-v7a, x86 etc. builds

Thanks to #Stanley, I was able to create a shared library successfully by tweaking his solution a bit. I don't know yet if there is an advantage of having a static library vs. a shared library. All I know is I need a shared library for the JNI wrapper. This is what I have. Note the compiler flags for fixed point. Without those the compilation will fail for fixed point mode.
First copy the celt_sources.mk, silk_sources.mk and opus_sources.mk from the opus source tarball to your jni directory. Bringing these files into your Android.mk file will add different variables which you can use to include source files based on the type of the build. This is what the opus build process does as well.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#include the .mk files
include celt_sources.mk
include silk_sources.mk
include opus_sources.mk
MY_MODULE_DIR := opus
LOCAL_MODULE := $(MY_MODULE_DIR)
#fixed point sources
SILK_SOURCES += $(SILK_SOURCES_FIXED)
#ARM build
CELT_SOURCES += $(CELT_SOURCES_ARM)
SILK_SOURCES += $(SILK_SOURCES_ARM)
LOCAL_SRC_FILES := \
$(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES)
LOCAL_LDLIBS := -lm -llog
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/silk \
$(LOCAL_PATH)/silk/fixed \
$(LOCAL_PATH)/celt
LOCAL_CFLAGS := -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT=1 -DDISABLE_FLOAT_API -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -O3 -fno-math-errno
LOCAL_CPPFLAGS := -DBSD=1
LOCAL_CPPFLAGS += -ffast-math -O3 -funroll-loops
#build a shared library not a static one like in Stanley's solution
include $(BUILD_SHARED_LIBRARY)
Here's my project structure for the opus library.

EDIT: Just use the accepted answer's solution above, the original link is dead plus it's basically the same as the accepted answer at the time I answered.
Here is one, maybe a little outdated (it used opus 0.9.14):
https://github.com/haxar/mangler/blob/master/android/jni/Android.mk
You're to write some JNI wrappers after getting the library to compile, though...

Related

Linking against included platform lib and headers with Android Studio and custom makefile

I've managed to get Android Studio setup to link against a custom library in jniLibs and compile a shim with it. But, I can't figure out how to link against EGL.
C++ Shim
#include <jni.h>
#include <android/log.h>
#include <EGL/egl.h>
extern "C" {
// Code and stuff
} // End extern
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := faceblaster-engine
LOCAL_SRC_FILES := ../jniLibs/$(TARGET_ARCH_ABI)/libfaceblaster-engine.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := faceblaster
LOCAL_SRC_FILES := gl-tests.cpp
LOCAL_SHARED_LIBRARIES := faceblaster-engine libEGL
include $(BUILD_SHARED_LIBRARY)
I get the following error:
fatal error: EGL/egl.h: No such file or directory
My guess is that it's assuming that EGL/egl.h should also be in app/src/main/jni, and throws the error because it's obviously not in that directory.
However, it does find android/log.h, so it must have some idea of where these are, but it fails out when it's time to grab EGL. Anyone have thoughts on why EGL is not being pulled in?
Thanks in advance for any help!
Turns out, you need a thing called Application.mk in the same directory as Android.mk to define targets and stuff. I just added this to that file, and everything worked as expected:
APP_ABI := armeabi
APP_PLATFORM := android-15

Warning : Overriding commands for target Android Makefile

I've got an issue building my C++ code using NDK r9d, since I try to compile C files using C++ compiler (G++) I've got this warnings :
C:/Android/ndk/build/core/build-binary.mk:393: warning: overriding commands for target
C:/Android/ndk/build/core/build-binary.mk:391: warning: ignoring old commands for target
Before I didn't need to compile with C++ 11 and my C files was compiled with GCC, I had no problems, but since I had LOCAL_CPP_EXTENSION := .cpp .c, this warnings appears (only for C files).
I found that someone else had the same problem (Overriding commands for target Android Makefile) but didn't get any answer.
Here is my files :
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
MY_INC_PATH := ../../..
LOCAL_MODULE := test
LOCAL_CFLAGS := -Werror
LOCAL_CPPFLAGS := -std=c++11
LOCAL_LDLIBS := -ldl -llog -lGLESv1_CM
LOCAL_C_INCLUDES := \
$(MY_INC_PATH)
MY_SRC_PATH := ../../../..
LOCAL_CPP_EXTENSION := .cpp .c
LOCAL_SRC_FILES := \
$(MY_SRC_PATH)/XXX.c \
$(MY_SRC_PATH)/YYY.cpp \
$(MY_SRC_PATH)/ZZZ.cpp
include $(BUILD_SHARED_LIBRARY)
I use NDK r9d and compile with G++ 4.8 and C++ 11 activated. Thanks for your help.
As of r9d, NDK does not provide methods to unassociate .c files from C compiler. You can redefine $$(TARGET_CC), and also set LOCAL_CFLAGS += -std=c++11, and not set LOCAL_CPP_EXTENSION to include .c, but that would be a hack, anyways. So if you cannot rename the files, and do not want to hack your NDK, the cleanest solution would be to simply ignore the warning.

Android link many static libraries into shared library

i have 4 static libraries libavcodec.a libavutil.a libswscale.a libx264.a
I want to link it with libmytest.so
I tried below Android.mk script
LOCAL_PATH := $(call my-dir)
INITIAL_PATH := $(LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE := mytest
LOCAL_SRC_FILES := mytest.c
LOCAL_LDLIBS += -llog
LOCAL_WHOLE_STATIC_LIBRARIES := libavutil libavcodec libswscale libx264
include $(BUILD_SHARED_LIBRARY)
mytest.c calls many functions from those libraries. The 4 libraries are placed inside PROJECTPATH\jni\.
But i get undefined reference to all functions from those libraries.
I tried giving LOCAL_ALLOW_UNDEFINED_SYMBOLS := truewhich allowed me to create shared library, but when i launch the app, i get
01-22 07:15:15.650: E/AndroidRuntime(9655): Caused by: java.lang.UnsatisfiedLinkError: Cannot load library: reloc_library[1285]: 1868 cannot locate 'avcodec_register_all'...
01-22 07:15:15.650: E/AndroidRuntime(9655): at java.lang.Runtime.loadLibrary(Runtime.java:370)
01-22 07:15:15.650: E/AndroidRuntime(9655): at java.lang.System.loadLibrary(System.java:535)
You need to define a PREBUILT_STATIC_LIBRARY for each one of your libraries if you do not build them from source, e.g.
include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := $(LOCAL_PATH)/jni/libavutil.a
include $(PREBUILT_STATIC_LIBRARY)
...
[repeat for other prebuilt libraries].
LOCAL_STATIC_LIBRARIES only understands module names, i.e. names of stuff that have been declared through their own ndk-build module definition. I'm surprised it didn't provide a warning about missing modules though, but it's the most likely explanation corresponding to your problem.

Adding libpng in android ndk project

I've searched a lot of topics about linking libpng to my android ndk project but I've found right answer for my problem and I hope somebody will help me.
This is hierarchy of my project:
jni
different_cpp_files
different_hpp_files
Android.mk
libpng
different_cpp_files
different_hpp_files
Android.mk
Android.mk in libpng folder:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LS_C=$(subst $(1)/,,$(wildcard $(1)/*.c))
LOCAL_MODULE := png
LOCAL_SRC_FILES := \
$(filter-out example.c pngtest.c,$(call LS_C,$(LOCAL_PATH)))
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_LDLIBS := -lz
include $(BUILD_STATIC_LIBRARY)
I suppose that everything is right here..
Android.mk in jni folder:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LS_CPP=$(subst $(1)/,,$(wildcard $(1)/*.cpp))
LOCAL_MODULE := pacman
LOCAL_CFLAGS := -Wno-psabi
LOCAL_SRC_FILES := $(call LS_CPP,$(LOCAL_PATH))
LOCAL_LDLIBS := -landroid -llog -lEGL -lGLESv1_CM -lOpenSLES
LOCAL_STATIC_LIBRARIES := android_native_app_glue png
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
$(call import-module,libpng)
The last line shows that I got libpng like native_app_glue lib(in the directory of android-ndk sources) Now I want to compile libpng from my project. What I need to change in Android.mk file?
i've got another way for you:
Download all files from here and paste it into a new folder anywhere on your system:
https://github.com/julienr/libpng-android
go into the folder and run:
./build.sh
You will get an libpng.a file in [YOUR_FOLDER]/obj/local/armeabi/libpng.a
Copy this file into:
[YOUR_ANDROID_NDK_FOLDER]/platforms/[ALL_FOLDERS_IN_HERE]/arch-arm/usr/lib/
now you can use libpng in all your projects with the simple line:
LOCAL_LDLIBS += -lpng
you only have to include this in your cpp's:
#include <png.h>
Have fun!

Getting Android NDK to work with libspotify

Im trying to use libspotify for an android app but Im having some problems building my c wrapper. Ive created a very small wrapper that only asks libspotify what its version is.
My folder structure looks like this:
jni
|-libs
| |-Android.mk
| |-libspotify.so (symlink)
| |-libspotify.so.12 (symlink)
| |-libspotify.so.12.1.51
|
|-include
| |-libspotify
| |-api.h
|
|-Android.mk
|-spotifywrap.c
/jni/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := libspotify
LOCAL_MODULE := spotifywrap
LOCAL_SRC_FILES := spotifywrap.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
include $(BUILD_SHARED_LIBRARY)
/jni/spotifywrap.c
include <jni.h>
include <libspotify/api.h>
jstring Java_com_example_ndktest_MainActivity_getBuild(JNIEnv * env, jobject this)
{
jstring result = (*env)->NewStringUTF( env, sp_build_id() );
return result;
}
/jni/libs/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libspotify
LOCAL_SRC_FILES := libspotify.so
include $(PREBUILT_SHARED_LIBRARY)
When I run ndk-build I get this:
spotifywrap.c:6: undefined reference to `sp_build_id'
sp_build_id is part of the interface in api.h.
Any ideas on what Im doing wrong?
I have a feeling that your directory structure within the jni subdirectory is what's causing you problems. Try editing your Android.mk build file to add this:
LOCAL_CPPFLAGS = -std=c++0x -D__STDC_INT64__
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
Also, I have a feeling that you'll need to copy libspotify.so to your top-level libs/armeabi directory to link successfully.

Resources