安卓使用speex开源库

Speex是一套主要针对语音的开源免费,无专利保护的音频压缩格式。
Speex工程着力于通过提供一个可以替代高性能语音编解码来降低语音应用输入门槛 。
另外,相对于其它编解码器,Speex也很适合网络应用,在网络应用上有着自己独特的优势。
同时,Speex还是GNU工程的一部分,在改版的BSD协议中得到了很好的支持。
它完全是C语言实现的,所以它具有很好的移植性。所以在Android当中具有很好的使用性。
可以在它的官网上下载需要的源码来操作。

安卓一直speex需要以下几个配置:

1.NDK配置
百度搜索ndk配置就ok。
最后能够在cmd成功执行ndk-build说明设置成功了
大概提示几行
F:\UDPSDK\sample_bak\sample_0821_audiook\sample_0820_videook\sample>ndk-build
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
D:\SDK\ndk-bundle\build\\..\build\core\build-local.mk:151: *** Android NDK: Aborting    .  Stop.

2.Speex库编译
2.1 去官网下载开源speex库(直接百度搜索speex库,官网下载的库有问题,少文件编译会报错,具体未提供文件原因未知)
2.2 在工程下创建一个jni目录
2.3 把speex源码目录下的libspeex和include目录及其子目录文件拷贝到jni目录下
2.4 在jni目录下中创建Android.mk和Application.mk
内容如下:

LOCAL_PATH := $(call my-dir)

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 \

#创建static静态库,动态库为BUILD_SHARED_LIBRARY
include $(BUILD_STATIC_LIBRARY)  

Application.mk内容如下:
APP_ABI := armeabi armeabi-v7a    

2.5 在jni/include/speex/目录下的speex_config_types.h.xx文件的xx后缀去掉,编辑内容如下 :

#ifndef __SPEEX_TYPES_H__    
#define __SPEEX_TYPES_H__    
pedef short spx_int16_t;    
typedef unsigned short spx_uint16_t;    
typedef int spx_int32_t;    
typedef unsigned int spx_uint32_t;    
#endif 

2.6 打开安卓下的terminal cd进入到jni目录下编译,输入ndk-build。
 

C:\Users\DELL\Desktop\sample_0820_videook\sample\app\src\main\jni>ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-16.
Android NDK: WARNING: APP_PLATFORM android-16 is higher than android:minSdkVersion 1 in C:/Users/DELL/Desktop/sample_0820_videook/sample/app/src/main/AndroidManifest.xml. NDK binaries will *not* be compatible with devices older than android-16. See https://android.googlesource.com/platform/ndk/+/master/d
ocs/user/common_problems.md for more information.
[armeabi-v7a] Compile thumb  : speex <= fftwrap.c
[armeabi-v7a] Compile thumb  : speex <= filterbank.c
[armeabi-v7a] Compile thumb  : speex <= filters.c
[armeabi-v7a] Compile thumb  : speex <= gain_table.c
[armeabi-v7a] Compile thumb  : speex <= gain_table_lbr.c
[armeabi-v7a] Compile thumb  : speex <= hexc_10_32_table.c
[armeabi-v7a] Compile thumb  : speex <= hexc_table.c
[armeabi-v7a] Compile thumb  : speex <= high_lsp_tables.c
[armeabi-v7a] Compile thumb  : speex <= jitter.c
[armeabi-v7a] Compile thumb  : speex <= kiss_fft.c
[armeabi-v7a] Compile thumb  : speex <= kiss_fftr.c
[armeabi-v7a] Compile thumb  : speex <= lpc.c
[armeabi-v7a] Compile thumb  : speex <= lsp.c
[armeabi-v7a] Compile thumb  : speex <= lsp_tables_nb.c
[armeabi-v7a] Compile thumb  : speex <= ltp.c
[armeabi-v7a] Compile thumb  : speex <= mdf.c
[armeabi-v7a] Compile thumb  : speex <= modes.c
[armeabi-v7a] Compile thumb  : speex <= modes_wb.c
[armeabi-v7a] Compile thumb  : speex <= nb_celp.c
[armeabi-v7a] Compile thumb  : speex <= preprocess.c
[armeabi-v7a] Compile thumb  : speex <= quant_lsp.c
[armeabi-v7a] Compile thumb  : speex <= resample.c
[armeabi-v7a] Compile thumb  : speex <= sb_celp.c
[armeabi-v7a] Compile thumb  : speex <= scal.c
[armeabi-v7a] Compile thumb  : speex <= smallft.c
[armeabi-v7a] Compile thumb  : speex <= speex.c
[armeabi-v7a] Compile thumb  : speex <= speex_callbacks.c
[armeabi-v7a] Compile thumb  : speex <= speex_header.c
[armeabi-v7a] Compile thumb  : speex <= stereo.c
[armeabi-v7a] Compile thumb  : speex <= vbr.c
[armeabi-v7a] Compile thumb  : speex <= vq.c
[armeabi-v7a] Compile thumb  : speex <= window.c
[armeabi-v7a] StaticLibrary  : libspeex.a

应该就成功了。
但是我在编译的时候之前用的官方下的库会提示buffffer.c 和.h文件没有

然后在Application.mk中可能会提示错误

C:\Users\DELL\Desktop\sample_0820_videook\sample\app\src\main\jni>ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-16.
Android NDK: WARNING: APP_PLATFORM android-16 is higher than android:minSdkVersion 1 in C:/Users/DELL/Desktop/sample_0820_videook/sample/app/src/main/AndroidManifest.xml. NDK binaries will *not* be compatible with devices older than a
ndroid-16. See https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md for more information.
Android NDK: The armeabi ABI is no longer supported. Use armeabi-v7a.
Android NDK: NDK Application 'local' targets unknown ABI(s): armeabi
Android NDK: Please fix the APP_ABI definition in C:/Users/DELL/Desktop/sample_0820_videook/sample/app/src/main/jni/Application.mk
D:/SDK/ndk-bundle/build//../build/core/setup-app.mk:79: *** Android NDK: Aborting    .  Stop.

大概意思如下:
armeabi和armeabi-v7a是表示cpu的类型,我们知道一般的手机或平板都是用arm的cpu(mips的就悲催的被忽视了),
不同的cpu的特性不一样,armeabi就是针对普通的或旧的arm cpu,armeabi-v7a是针对有浮点运算或高级扩展功能的arm cpu。

armeabi默认选项,
支持基于 ARM* v5TE 的设备
支持软浮点运算(不支持硬件辅助的浮点计算)
支持所有 ARM* 设备
armeabi-v7a
支持基于 ARM* v7 的设备
支持硬件 FPU 指令
支持硬件浮点运算
不同手机由于cpu的不同,使用不同的驱动。
ABI:指应用基于哪种指令集来进行编译,ABI总共有四种,分别是armeabi、armeabi-v7a、mips、x86,它们都是表示cpu的类型。

我的是去掉armeabi,就可以成功了
文件位置是app\src\main\obj\local\armeabi-v7a\libspeex.a

3.libSpeex.a的使用
将libSpeex.a拷贝到需要的工程目录中,然后将libSpeex下的.h文件和include中的.h文件全部拷贝到jni目录中,
然后编写自己的Speex Native文件,可以是C或者C++的

Speex 编码流程
1、定义一个SpeexBits类型变量bits和一个Speex编码器状态变量enc_state。
2、调用speex_bits_init(&bits)初始化bits。
3、调用speex_encoder_init(&speex_nb_mode)来初始化enc_state。其中speex_nb_mode是SpeexMode类型的变量,表示的是窄带模式。还有speex_wb_mode表示宽带模式、speex_uwb_mode表示超宽带模式。
4、调用函数int speex_encoder_ ctl(void *state, int request, void *ptr)来设定编码器的参数,其中参数state表示编码器的状态;参数request表示要定义的参数类型,如SPEEX_ GET_ FRAME_SIZE表示设置帧大小,SPEEX_ SET_QUALITY表示量化大小,这决定了编码的质量;参数ptr表示要设定的值。
    可通过speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &frame_size) 和speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &quality)来设定编码器的参数。
5、初始化完毕后,对每一帧声音作如下处理:调用函数speex_bits_reset(&bits)再次设定SpeexBits,然后调用函数speex_encode(enc_state, input_frame, &bits),参数bits中保存编码后的数据流。
6、编码结束后,调用函数speex_bits_destroy (&bits), speex_encoder_destroy (enc_state)来


解码流程:
1、 定义一个SpeexBits类型变量bits和一个Speex编码状态变量enc_state。
2、 调用speex_bits_init(&bits)初始化bits。
3、 调用speex_decoder_init (&speex_nb_mode)来初始化enc_state。
4、 调用函数speex_decoder_ctl (void *state, int request, void *ptr)来设定编码器的参数。
5、 调用函数 speex_decode(void *state, SpeexBits *bits, float *out)对参数bits中的音频数据进行解编码,参数out中保存解码后的数据流。
6、 调用函数speex_bits_destroy(&bits), speex_ decoder_ destroy (void *state)来关闭和销毁SpeexBits和解码器。


我没有使用speex编解码,我是使用g711编解码,在录取到pcm裸码的时候消噪声然后直接用jni传到c++中编码发出去,

也试过拿到pcm数据的时候直接传到c++中再消噪声回声之后g711编码之后发送出去,我现在用的是后者,就直接不需要使用

.a库了,直接调用头文件就ok,比较方便。效果一样的。

 这是我使用的speex写的native层:

public class Speex {

	private static final String tag = "[Speex]";

	/* quality
	 * 1 : 4kbps (very noticeable artifacts, usually intelligible)
	 * 2 : 6kbps (very noticeable artifacts, good intelligibility)
	 * 4 : 8kbps (noticeable artifacts sometimes)
	 * 6 : 11kpbs (artifacts usually only noticeable with headphones)
	 * 8 : 15kbps (artifacts not usually noticeable)
	 */
	private static final int DEFAULT_COMPRESSION = 4;

	static {
		try {
			System.loadLibrary("libspeex");
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	public Speex() {
	}
	//编码解码
	public native int open(int compression);
	public native int getFrameSize();
	public native int decode(byte encoded[], short lin[], int size);
	public native int encode(short lin[], int offset, byte encoded[], int size);
	public native int close();

	//回声消除
	public native int InitAudioAEC(int frame_size,int filter_length,int sampling_rate);
	public native int AudioAECProc(byte[] recordArray,byte[] playArray,byte[] szOutArray);
	public native int ExitSpeexDsp();

    //噪声消除
    public native int CancelNoiseInit(int frame_size, int sample_rate);
    public native int CancelNoisePreprocess(byte[] buffer);
    public native int CancelNoiseDestroy();
}

这是回调函数:

    public native void inputvoicestream(byte[] audio_stream,int audio_stream_len);

意思就是在安卓中处理了之后再回调给c++发送出去。

差不多流程就是这样。

发布了37 篇原创文章 · 获赞 16 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/double_lee3/article/details/100518019