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. Machine Learning for hackers读书笔记(八)PCA:构建股票市场指数

    library('ggplot2') prices <- read.csv('G:\\dataguru\\ML_for_Hackers\\ML_for_Hackers-master\\08-PC ...

  2. HDU 3951 (博弈) Coin Game

    先考虑两种简单的情况: 如果先手能一次把硬币拿完,即 k >= n ,那么先手胜 如果每次只能拿一个硬币, 即 k = 1 ,那么如果有奇数个硬币先手胜,如果有偶数个硬币后手胜. 剩下的情况就是 ...

  3. 51nod1394 差和问题

    我只会用线段树写...不喜欢树状数组..其实跑的也不算慢?然后各种*的时候忘了longlong一直WA...药丸! 而且我不怎么会用map离散化...那么就sort+unique #include&l ...

  4. HDU1495 非常可乐

    解题思路:简单的宽搜,见代码: #include<cstdio> #include<cstring> #include<algorithm> #include< ...

  5. 【英语】Bingo口语笔记(21) - 表达“请客吃饭”

  6. YouTrack Changing Database Location for EXE Distribution(windows service)

    If you have installed YouTrack from EXE Distribution, then the best way to change the database locat ...

  7. vm虚拟机挂载usb

    首先得保证能在VM里看到usb设备,如图

  8. centos 安装mysql 登录进提示 Access denied for user 'root'@'localhost' (using password: NO)

    # service mysqld stop # mysqld_safe --user=mysql --skip-grant-tables --skip-networking & # mysql ...

  9. hdu 1429(bfs+状态压缩)

    题意:容易理解,但要注意的地方是:如果魔王回来的时候刚好走到出口或还未到出口都算逃亡失败.因为这里我贡献了一次wa. 分析:仔细阅读题目之后,会发现最多的钥匙数量为10把,所以把这个作为题目的突破口, ...

  10. EhCache 分布式缓存/缓存集群

    开发环境: System:Windows JavaEE Server:tomcat5.0.2.8.tomcat6 JavaSDK: jdk6+ IDE:eclipse.MyEclipse 6.6 开发 ...