http://blog.csdn.net/chenfeng0104/article/details/7088138
在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文件,编辑内容如下

  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文件,编辑内容如下

  1. APP_ABI := armeabi armeabi-v7a

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

  1. #ifndef __SPEEX_TYPES_H__
  2. #define __SPEEX_TYPES_H__
  3. typedef short spx_int16_t;
  4. typedef unsigned short spx_uint16_t;
  5. typedef int spx_int32_t;
  6. typedef unsigned int spx_uint32_t;
  7. #endif

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

  1. #include <jni.h>
  2. #include <string.h>
  3. #include <unistd.h>
  4. #include <speex/speex.h>
  5. static int codec_open = 0;
  6. static int dec_frame_size;
  7. static int 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工具类,内容如下

  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. private static final int DEFAULT_COMPRESSION = 8;
  11. Speex() {
  12. }
  13. public void init() {
  14. load();
  15. open(DEFAULT_COMPRESSION);
  16. }
  17. private void load() {
  18. try {
  19. System.loadLibrary("speex");
  20. } catch (Throwable e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. public native int open(int compression);
  25. public native int getFrameSize();
  26. public native int decode(byte encoded[], short lin[], int size);
  27. public native int encode(short lin[], int offset, byte encoded[], int size);
  28. public native void 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的更多相关文章

  1. speex编解码在android上实现

    以前在应用中使用到了Speex编解码,近来总结了一下Speex在android上的实现.Speex是一套主要针对语音的开源免费,无专利保护的音频压缩格式.Speex工程着力于通过提供一个可以替代高性能 ...

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

    Android中使用speex将PCM录音格式转Wav格式 2013-09-17 17:24:00|  分类: android |  标签:android  speex  wav  |举报|字号 订阅 ...

  3. Android - 基于 Speex 的高度封装语音库,0 耦合使用

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  4. Android 基于 Speex 的高度封装语音库,0 耦合,没三方jar包

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

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

    随着处理器制造工艺的不断进步,和Android系统的不断发展,最近出了arm64-v8a的架构,由于项目中用到了speex的第三方语音编解码的动态库,其他架构的处理器暂不用说,一切正常,唯独到arm6 ...

  6. Android 5.0 到 Android 6.0 + 的深坑之一 之 .so 动态库的适配

    (原创:http://www.cnblogs.com/linguanh) 目录: 前序 一,问题描述 二,为何会如此"无情"? 三,目前存在该问题的知名SDK 四,解决方案,1 对 ...

  7. Android源码目录结构详解(转载)

    转自:http://blog.csdn.net/xiangjai/article/details/9012387 在学习Android的过程中,学习写应用还好,一开始不用管太多代码,直接调用函数就可以 ...

  8. android源码的目录结构

    android源码的目录结构 [以下网络摘抄] |-- Makefile ! l/ a5 n% S% @- `0 d# z# a$ P4 V3 o7 R|-- bionic              ...

  9. Android 4.0 源代码结构

    Android源码的第一级目录结构   Android/abi (abi相关代码.ABI:application binary interface,应用程序二进制接口)   Android/bioni ...

随机推荐

  1. phpStorm连接mysql

    小结:牛逼的IDE

  2. HDU 1494 跑跑卡丁车

    很无爱的一道题. 题解都看得一知半解的. acm之家的题解,留着以后慢慢体会: 把这题转化为背包模型,每个%20能量算一个单位,最多有15个,如果大于5个有一个加速卡,如果大于10个有2个加速卡,如果 ...

  3. VB6 仿.netWinfrom控件 Anchor属性类

    vb6中控件没有anchor与dock属性,窗体变大后原来要在resize中调整控件的move属性,否则就面目全非了.网上找到一些调整控件大小的代码,发现并不太适合自己,于是按照思路自己做了一个类似a ...

  4. 20160201.CCPP体系详解(0011天)

    内容概要:C语言基本数据类型及运算题库(含答案) 第二章 基本数据类型及运算 一.选择题 1. 若以下选项中的变量已正确定义,则正确的赋值语句是[C]. A) x1=26.8%3; B) 1+2=x2 ...

  5. dede 5.7进后台卡死解决办法

    注释后台文件dede/templets/index_body.htm(大概在第18行) <script type="text/javascript"> function ...

  6. linux上改变mysql数据文件的位置

    用软连接改变了/var/lib/mysql的位置,并设置好mysql.mysql的权限,但是发现还是不能启动. 发现/var/log/mysqld.log 150308 16:16:02 [Warni ...

  7. AIX 第2章 指令记录

    root@db:/#mount  node       mounted        mounted over    vfs       date        options     ------- ...

  8. js获取当前url信息

    window.location 属性 描述 hash 设置或获取 href 属性中在井号"#"后面的分段. host 设置或获取 location 或 URL 的 hostname ...

  9. 【模版消息】C#推送微信模版消息(Senparc.Weixin.MP.dll)

    定义的模版内容: {{first.DATA}} 商品名称:{{product.DATA}} 商品价格:{{price.DATA}} 购买时间:{{time.DATA}} {{remark.DATA}} ...

  10. web.xml文件的作用

    每个javaEE工程中都有web.xml文件,那么它的作用是什么呢?它是每个web.xml工程都必须的吗? 一个web中可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的. ...