Speex for Android

在Android开发中,需要录音并发送到对方设备上。这时问题来了,手机常会是GPRS、3G等方式上网,所以节省流量是非常关键的,使用Speex来压缩音频文件,可以将音频压文件小数倍。

1.去Speex官网下载最新Speex源码

2.创建一个新的应用(我创建的应用名为Audio),并创建一个jni目录($project/jni)。

3.把speex源码目录下的libspeex和include目录及其子目录文件全部拷贝到$project/jni目录下($project/jni/libspeex
and $project/jni/include)。

4.在jni目录下新增Android.mk文件,编辑内容如下

[plain] view
plain
copy

  1. LOCAL_PATH :=
    $(call my-dir)
  2. include
    $(CLEAR_VARS)
  3. LOCAL_MODULE   
    := libspeex

  4. LOCAL_CFLAGS
    = -DFIXED_POINT -DUSE_KISS_FFT -DEXPORT="" -UHAVE_CONFIG_H

  5. LOCAL_C_INCLUDES
    := $(LOCAL_PATH)/include
  6. LOCAL_SRC_FILES
    :=  \

  7. ./speex_jni.cpp
    \

  8. ./libspeex/bits.c
    \

  9. ./libspeex/buffer.c
    \

  10. ./libspeex/cb_search.c
    \

  11. ./libspeex/exc_10_16_table.c
    \

  12. ./libspeex/exc_10_32_table.c
    \

  13. ./libspeex/exc_20_32_table.c
    \

  14. ./libspeex/exc_5_256_table.c
    \

  15. ./libspeex/exc_5_64_table.c
    \

  16. ./libspeex/exc_8_128_table.c
    \

  17. ./libspeex/fftwrap.c
    \

  18. ./libspeex/filterbank.c
    \

  19. ./libspeex/filters.c
    \

  20. ./libspeex/gain_table.c
    \

  21. ./libspeex/gain_table_lbr.c
    \

  22. ./libspeex/hexc_10_32_table.c
    \

  23. ./libspeex/hexc_table.c
    \

  24. ./libspeex/high_lsp_tables.c
    \

  25. ./libspeex/jitter.c
    \

  26. ./libspeex/kiss_fft.c
    \

  27. ./libspeex/kiss_fftr.c
    \

  28. ./libspeex/lpc.c
    \

  29. ./libspeex/lsp.c
    \

  30. ./libspeex/lsp_tables_nb.c
    \

  31. ./libspeex/ltp.c
    \

  32. ./libspeex/mdf.c
    \

  33. ./libspeex/modes.c
    \

  34. ./libspeex/modes_wb.c
    \

  35. ./libspeex/nb_celp.c
    \

  36. ./libspeex/preprocess.c
    \

  37. ./libspeex/quant_lsp.c
    \

  38. ./libspeex/resample.c
    \

  39. ./libspeex/sb_celp.c
    \

  40. ./libspeex/scal.c
    \

  41. ./libspeex/smallft.c
    \

  42. ./libspeex/speex.c
    \

  43. ./libspeex/speex_callbacks.c
    \

  44. ./libspeex/speex_header.c
    \

  45. ./libspeex/stereo.c
    \

  46. ./libspeex/vbr.c
    \

  47. ./libspeex/vq.c
    \

  48. ./libspeex/window.c
  49. include
    $(BUILD_SHARED_LIBRARY)

5.在jni目录下新增Application.mk文件,编辑内容如下

[plain] view
plain
copy

  1. APP_ABI :=
    armeabi armeabi-v7a

6.在$project/jni/include/speex/目录下新增speex_config_types.h文件,编辑内容如下

[cpp] view
plain
copy

  1. #ifndef __SPEEX_TYPES_H__

  2. #define __SPEEX_TYPES_H__

  3. typedefshort
    spx_int16_t;

  4. typedef
    unsigned short
    spx_uint16_t;

  5. typedefint
    spx_int32_t;

  6. typedef
    unsigned int
    spx_uint32_t;

  7. #endif

7.创建JNI包装类speex_jni.cpp,用来调用Speex中的C代码函数,编辑内容如下

[cpp] view
plain
copy

  1. #include <jni.h>
  2. #include <string.h>

  3. #include <unistd.h>
  4. #include <speex/speex.h>
  5. staticint
    codec_open = 0;
  6. staticint
    dec_frame_size;

  7. staticint
    enc_frame_size;
  8. static
    SpeexBits ebits, dbits;

  9. void
    *enc_state;

  10. void
    *dec_state;
  11. static
    JavaVM *gJavaVM;
  12. extern"C"

  13. JNIEXPORT
    jint JNICALL Java_com_audio_Speex_open

  14. (JNIEnv *env, jobject obj, jint compression) {

  15. int
    tmp;
  16. if
    (codec_open++ != 0)

  17. return
    (jint)0;
  18. speex_bits_init(&ebits);

  19. speex_bits_init(&dbits);
  20. enc_state = speex_encoder_init(&speex_nb_mode);

  21. dec_state = speex_decoder_init(&speex_nb_mode);

  22. tmp = compression;

  23. speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp);

  24. speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &enc_frame_size);

  25. speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &dec_frame_size);
  26. return
    (jint)0;

  27. }
  28. extern"C"

  29. JNIEXPORT
    jint Java_com_audio_Speex_encode

  30. (JNIEnv *env, jobject obj, jshortArray lin, jint offset, jbyteArray encoded,
    jint size) {
  31. jshort buffer[enc_frame_size];

  32. jbyte output_buffer[enc_frame_size];

  33. int
    nsamples = (size-1)/enc_frame_size + 1;

  34. int
    i, tot_bytes = 0;
  35. if
    (!codec_open)

  36. return
    0;
  37. speex_bits_reset(&ebits);
  38. for
    (i = 0; i < nsamples; i++) {

  39. env->GetShortArrayRegion(lin, offset + i*enc_frame_size, enc_frame_size,
    buffer);

  40. speex_encode_int(enc_state, buffer, &ebits);

  41. }

  42. //env->GetShortArrayRegion(lin, offset, enc_frame_size,
    buffer);

  43. //speex_encode_int(enc_state, buffer, &ebits);
  44. tot_bytes = speex_bits_write(&ebits, (char
    *)output_buffer,

  45. enc_frame_size);

  46. env->SetByteArrayRegion(encoded, 0, tot_bytes,

  47. output_buffer);
  48. return
    (jint)tot_bytes;

  49. }
  50. extern"C"

  51. JNIEXPORT
    jint JNICALL Java_com_audio_Speex_decode

  52. (JNIEnv *env, jobject obj, jbyteArray encoded, jshortArray lin, jint size)
    {
  53. jbyte buffer[dec_frame_size];

  54. jshort output_buffer[dec_frame_size];

  55. jsize encoded_length = size;
  56. if
    (!codec_open)

  57. return
    0;
  58. env->GetByteArrayRegion(encoded, 0, encoded_length, buffer);

  59. speex_bits_read_from(&dbits, (char
    *)buffer, encoded_length);

  60. speex_decode_int(dec_state, &dbits, output_buffer);

  61. env->SetShortArrayRegion(lin, 0, dec_frame_size,

  62. output_buffer);
  63. return
    (jint)dec_frame_size;

  64. }
  65. extern"C"

  66. JNIEXPORT
    jint JNICALL Java_com_audio_getFrameSize

  67. (JNIEnv *env, jobject obj) {
  68. if
    (!codec_open)

  69. return
    0;

  70. return
    (jint)enc_frame_size;
  71. }
  72. extern"C"

  73. JNIEXPORT
    void
    JNICALL Java_com_audio_Speex_close

  74. (JNIEnv *env, jobject obj) {
  75. if
    (--codec_open != 0)

  76. return;
  77. speex_bits_destroy(&ebits);

  78. speex_bits_destroy(&dbits);

  79. speex_decoder_destroy(dec_state);

  80. speex_encoder_destroy(enc_state);

  81. }

8.在Java层创建Speex工具类,内容如下

[java] view
plain
copy

  1. package
    com.audio;
  2. class
    Speex  {
  3. /* quality

  4. * 1 : 4kbps (very noticeable
    artifacts, usually intelligible)

  5. * 2 : 6kbps (very noticeable
    artifacts, good intelligibility)

  6. * 4 : 8kbps (noticeable artifacts
    sometimes)

  7. * 6 : 11kpbs (artifacts usually only
    noticeable with headphones)

  8. * 8 : 15kbps (artifacts not usually
    noticeable)

  9. */

  10. privatestaticfinalint
    DEFAULT_COMPRESSION = 8;
  11. Speex() {

  12. }
  13. publicvoid
    init() {

  14. load();

  15. open(DEFAULT_COMPRESSION);

  16. }
  17. privatevoid
    load() {

  18. try
    {

  19. System.loadLibrary("speex");

  20. } catch
    (Throwable e) {

  21. e.printStackTrace();

  22. }
  23. }
  24. publicnativeint
    open(int
    compression);

  25. publicnativeint
    getFrameSize();

  26. publicnativeint
    decode(byte
    encoded[], short
    lin[], int
    size);

  27. publicnativeint
    encode(short
    lin[], int
    offset, byte
    encoded[], int
    size);

  28. publicnativevoid
    close();
  29. }

9.打开cygwin工具,切换到项目目录(我项目是在F:\workspace\Audio),输入$NDK/ndk-build

cygwin工具的安装与配置,可以看这篇文章——使用NDK与环境搭建

会在项目中生成libs目录和libspeex.so文件,这就是Speex类中System.loadLibrary("speex");代码引用的,系统会根据操作系统由"speex"找到对应的动态库libspeex.so,Windows下是.dll文件,linux下是.so文件。

当前,我的项目结构如下图

Speex for Android,布布扣,bubuko.com

时间: 2024-10-03 22:25:21

Speex for Android的相关文章

speex编解码在android上实现

以前在应用中使用到了Speex编解码,近来总结了一下Speex在android上的实现.Speex是一套主要针对语音的开源免费,无专利保护的音频压缩格式.Speex工程着力于通过提供一个可以替代高性能语音编解码来降低语音应用输入门槛 .另外,相对于其它编解码,Speex也很适合网络应用,在网络应用上有着自己独特的优势.同时,Speex还是GNU工程的一部分,在改版的BSD协议中得到了很好的支持.Speex是基于CELP并且专门为码率在2-44kbps的语音压缩而设计的.Speex源码是基于c语音

转: ios与android语音互通方案,类微信

Ios实现amr编解码 Feb 5th, 2012 介绍 学习ios第一个练手功能就是给已有产品加上语音通信功能,能够互通ios与android.这里给出自己的一些心得,希望能给他人一些参考. 资料搜集与参考 类似产品使用的技术 talkbox Android版用的是ilbc的第三方编解码库,在iPhone上用的是caf 微信 Android版估计是amr估计转码的是交给腾讯强大的服务器了. 米聊 Android版和Iphone版用的都是speex 目前支持的开源第三方库也就只有 ilbc和sp

录音功能实现

http://hhuai.github.com/blog/2012/02/05/ios-and-andorid-voice/ 介绍 学习ios第一个练手功能就是给已有产品加上语音通信功能,能够互通ios与android.这里给出自己的一些心得,希望能给他人一些参考. 资料搜集与参考 类似产品使用的技术 talkbox Android版用的是ilbc的第三方编解码库,在iPhone上用的是caf 微信 Android版估计是amr估计转码的是交给腾讯强大的服务器了. 米聊 Android版和Iph

Android 与 iOS 下 Speex的使用

首先,在现在这个微信的时代,做一个IMapp,绝对不能少了语音通讯这个功能,如果没有了语音通讯功能我相信在当下已经不能算是一个IM了. 由于前段时间在忙碌一个新的项目,导致这个模块已经耽误了一个月了.终于在今天另一个项目上线之后我从新开始这个模块的研究. 在研究开始之前,我首先去市场下载了几个目前比较流行IM,然后通过强大的反编译和文件查找能力,发现即使是陌陌这个app ,他们的语音传输都是没有经过比较大的压缩的(MEWOW同样地没没有经过较大的压缩),但微信则是通过自身强大的算法,对音频文件进

Android 开发:开源库Speex支持arm64的动态库文件

随着处理器制造工艺的不断进步,和Android系统的不断发展,最近出了arm64-v8a的架构,由于项目中用到了speex的第三方语音编解码的动态库,其他架构的处理器暂不用说,一切正常,唯独到arm64-v8a这里出问题了,在Android5.0 arm64位的手机上使用语音会报错,关于其他架构的.so文件编译不再赘述,网上都有资料.废话少说,直接上步骤: 1.下载android-ndk-r10e-windows-x86_64并解压,这个支持arm64 -v8a的编译,之前的版本都不行,我之前用

Android中使用speex将PCM录音格式转Wav格式

Android中使用speex将PCM录音格式转Wav格式 2013-09-17 17:24:00|  分类: android |  标签:android  speex  wav  |举报|字号 订阅 下载LOFTER客户端 1>     平台支持录音格式情况 Android Cocos2d-x 2>     我的代码 Android下使用speex保存录音格式wav 参考: 1.       PCM录音数据转Wav格式(java版) 使用该文章发现,保存的wav格式声音有些失真,也许是我写文

Speex 同时适用于 Ios 与 Android 【代码篇 二】

书接上一回. 前文提到如何利用协议编码好音频pcm数据,使其在解码的时候可以用于ios系统与Android系统. 现在是解码部分,解码部分主要是获取到.spx文件的全部字节,然后根据前文的协议,先获取到.spx的头信息,在头信息中获取到音频的相关参数,然后初始化播放器,再把每一帧解码出来进行播放. 关于协议部分,可以有很多种协议方式,可以沿用speex_header.h定义的方式也可以,我选择了最方便的一种. 以下几个参数特别说明一下,因为直接关系到解码的成败. 比特率:160 比特率为160,

Android系统源代码目录结构 “Android源代码”“目录结构”

在讲述Android源码编译的三个步骤之前,将先介绍Android源码目录结构,以便读者理清Android编译系统核心代码在Android源代码的位置. Android源代码顶层目录结构如下所示: ├──abi #应用二进制接口,不同的操作系统,应用二进制接口不同,因此linux上的二进制可执行文件在windows上无法执行 ├──android #存放了一些xml文件,用于描述工程路径及其对应的远程仓库地址,repo工具将使用这些信息同步代码 ├──bionic #bionic C库,Andr

Android 实现能够暂停的录音功能

转载请注明出处:http://blog.csdn.net/yegongheng/article/details/40624267 好久没更新博客了,着实有点惭愧,以后不管工作是忙是闲都得坚持更新博客,持之以恒地做下去! 正式进入主题,今天我分享一个在工作中过程中遇到的一个技术难点以及我解决该难点的方案,该问题困扰了我许久,通过不断地研究和翻阅资料,终于在满足工作需求的情况下将该问题解决,希望我的经验能够对读者有所帮助.我们知道Android ApI提供了MediaRecorder和AudioRe