androidandroid-ndkjava-native-interfacevoice-recordingspeex

Compile echo cancellation using NDK in Android


My problem is how to cancel echo using jni in android between two devices. I tried to use the code in this link Speex echo cancellation configuration but it didn't work to me! in this code

#include <jni.h>
#include "speex/speex_echo.h"
#include "speex/speex_preprocess.h"

SpeexEchoState *st;
SpeexPreprocessState *den;

JNIEXPORT void JNICALL Java_speex_EchoCanceller_open
  (JNIEnv *env, jobject jObj, jint jSampleRate, jint jBufSize, jint jTotalSize)
{
     //init
     int sampleRate=jSampleRate;
     st = speex_echo_state_init(jBufSize, jTotalSize);
     den = speex_preprocess_state_init(jBufSize, sampleRate);
     speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &sampleRate);
     speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st);
}

JNIEXPORT jshortArray JNICALL Java_speex_EchoCanceller_process
  (JNIEnv * env, jobject jObj, jshortArray input_frame, jshortArray echo_frame)
{
  //create native shorts from java shorts
  jshort *native_input_frame = (*env)->GetShortArrayElements(env, input_frame, NULL);
  jshort *native_echo_frame = (*env)->GetShortArrayElements(env, echo_frame, NULL);

  //allocate memory for output data
  jint length = (*env)->GetArrayLength(env, input_frame);
  jshortArray temp = (*env)->NewShortArray(env, length);
  jshort *native_output_frame = (*env)->GetShortArrayElements(env, temp, 0);

  //call echo cancellation
  speex_echo_cancellation(st, native_input_frame, native_echo_frame, native_output_frame);
  //preprocess output frame
  speex_preprocess_run(den, native_output_frame);

  //convert native output to java layer output
  jshortArray output_shorts = (*env)->NewShortArray(env, length);
  (*env)->SetShortArrayRegion(env, output_shorts, 0, length, native_output_frame);

  //cleanup and return
  (*env)->ReleaseShortArrayElements(env, input_frame, native_input_frame, 0);
  (*env)->ReleaseShortArrayElements(env, echo_frame, native_echo_frame, 0);
  (*env)->ReleaseShortArrayElements(env, temp, native_output_frame, 0);

  return output_shorts;   
}

JNIEXPORT void JNICALL Java_speex_EchoCanceller_close
  (JNIEnv *env, jobject jObj)
{
     //close
     speex_echo_state_destroy(st);
     speex_preprocess_state_destroy(den);
}

And the Android.mk is

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := SendAudio2
LOCAL_SRC_FILES := speex.c


include $(BUILD_SHARED_LIBRARY)

When I build my project i get error

/home/Develop/AndroidNDK/android-ndk-r9d/ndk-build all 
Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml    
[armeabi] Compile thumb  : SendAudio2 <= speex.c
[armeabi] SharedLibrary  : libSendAudio2.so
/home/Develop/AndroidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/SendAudio2/speex.o: in function Java_speex_EchoCanceller_open:jni/speex.c:15: error: undefined reference to 'speex_echo_state_init'
/home/Develop/AndroidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/SendAudio2/speex.o: in function Java_speex_EchoCanceller_open:jni/speex.c:16: error: undefined reference to 'speex_preprocess_state_init'
/home/Develop/AndroidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/SendAudio2/speex.o: in function Java_speex_EchoCanceller_open:jni/speex.c:17: error: undefined reference to 'speex_echo_ctl'
/home/Develop/AndroidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/SendAudio2/speex.o: in function Java_speex_EchoCanceller_open:jni/speex.c:18: error: undefined reference to 'speex_preprocess_ctl'
/home/Develop/AndroidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/SendAudio2/speex.o: in function Java_speex_EchoCanceller_process:jni/speex.c:34: error: undefined reference to 'speex_echo_cancellation'
/home/Develop/AndroidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/SendAudio2/speex.o: in function Java_speex_EchoCanceller_process:jni/speex.c:36: error: undefined reference to 'speex_preprocess_run'
/home/Develop/AndroidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/SendAudio2/speex.o: in function Java_speex_EchoCanceller_close:jni/speex.c:54: error: undefined reference to 'speex_echo_state_destroy'
/home/Develop/AndroidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/SendAudio2/speex.o: in function Java_speex_EchoCanceller_close:jni/speex.c:55: error: undefined reference to 'speex_preprocess_state_destroy'
collect2: ld returned 1 exit status
make: *** [obj/local/armeabi/libSendAudio2.so] Error 1

How can i resolve this? thanks!!


Solution

  • Your Android.mk should also build and link libspeex.so, maybe like this:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE    := SendAudio2
    LOCAL_SRC_FILES := speex.c
    LOCAL_SHARED_LIBRARIES := speex
    
    include $(BUILD_SHARED_LIBRARY)
    
    LOCAL_PATH := d:/ext/speeks
    include $(CLEAR_VARS)
    
    LOCAL_MODULE    := libspeex
    LOCAL_CFLAGS = -DFIXED_POINT -DUSE_KISS_FFT -DEXPORT="" -UHAVE_CONFIG_H
    LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
    
    LOCAL_SRC_FILES :=  \
    ./libspeex/bits.c \
    ./libspeex/buffer.c \
    ./libspeex/cb_search.c \
    ./libspeex/exc_10_16_table.c \
    ./libspeex/exc_10_32_table.c \
    ./libspeex/exc_20_32_table.c \
    ./libspeex/exc_5_256_table.c \
    ./libspeex/exc_5_64_table.c \
    ./libspeex/exc_8_128_table.c \
    ./libspeex/fftwrap.c \
    ./libspeex/filterbank.c \
    ./libspeex/filters.c \
    ./libspeex/gain_table.c \
    ./libspeex/gain_table_lbr.c \
    ./libspeex/hexc_10_32_table.c \
    ./libspeex/hexc_table.c \
    ./libspeex/high_lsp_tables.c \
    ./libspeex/jitter.c \
    ./libspeex/kiss_fft.c \
    ./libspeex/kiss_fftr.c \
    ./libspeex/lpc.c \
    ./libspeex/lsp.c \
    ./libspeex/lsp_tables_nb.c \
    ./libspeex/ltp.c \
    ./libspeex/mdf.c \
    ./libspeex/modes.c \
    ./libspeex/modes_wb.c \
    ./libspeex/nb_celp.c \
    ./libspeex/preprocess.c \
    ./libspeex/quant_lsp.c \
    ./libspeex/resample.c \
    ./libspeex/sb_celp.c \
    ./libspeex/scal.c \
    ./libspeex/smallft.c \
    ./libspeex/speex.c \
    ./libspeex/speex_callbacks.c \
    ./libspeex/speex_header.c \
    ./libspeex/stereo.c \
    ./libspeex/vbr.c \
    ./libspeex/vq.c \
    ./libspeex/window.c \
    ./libogg/bitwise.c \
    ./libogg/framing.c
    
    include $(BUILD_SHARED_LIBRARY)
    

    To compile libspeex, you may need some adjustments, see http://developer.samsung.com/android/technical-docs/Porting-and-Using-the-Speex-Library-in-Android-with-JNI.