绝大多数的ios录音实现方案中都是首先录制成pcm源码,然后在对文件进行转码和压缩,然后再上传到服务端上。Pcm文件只要加一个14字节的头,就是wav文件。常用的压缩格式有很多。例如:mp3,amr,speex,speex+ogg等等。但是具体压缩成什么格式要考虑几个方面:1.压缩比,2.压缩算法实现的难度,3.转码压缩需要的时间,4.平台的通用性(ios和android)等等。综合了以上一点,我们选择了压缩成amr文件然后上传(在实际的工程中我们也曾经使用过speex+ogg的格式,他的压缩比很大,但是很多语音识别的服务商不提供对他的支持,后来也就不用了)。
Amr的一个优势就是android原生就支持,但是amr的转码相关的功能直到Android4.X才有相关的API支持。Amr压缩后的大小不到pcm的1/10,转码后的清晰程度也基本能符合要求。(但是amr有wb和nb两种形式,nb压缩比例太大,不适合来做语音识别的素材,必须是wb才行。)微信的录音用的也是amr格式,只是对文件头等信息自己稍微做了一些修改而已。
确定是用amr,现在的问题就是如何将pcm转换为amr-wb。Android系统开放的源代码中直接就有相关的c代码。现在有开源的工程来实现这个转换,opencore-amr和opencore-amrwb。opencore-amr主要实现了pcm和arm-nb的相互转换,和arm-wb的解码过程。opencore-amrwb提供了一个将pcm文件转化为arm-nb的接口。所以如果只需要录音和转码为arm-wb格式的话,我们只需要opencore-amrwb即可(下载地址https://sourceforge.net/projects/opencore-amr/files/?source=navbar)。
编译的过程参考了很多网上的例子,但是在xcode8下编译成.ad的库一直没有成功,所以进行了一些修改,成功的编译成功并在工程中使用,具体如下:
#!/bin/sh
set -xe
VERSION="0.1.3"
LIBSRCNAME="vo-amrwbenc"
CURRENTPATH=`pwd`
#解压源代码
mkdir -p"${CURRENTPATH}/src"
tar zxvf${LIBSRCNAME}-${VERSION}.tar.gz -C "${CURRENTPATH}/src"
cd"${CURRENTPATH}/src/${LIBSRCNAME}-${VERSION}"
#设置环境变量并创建lib-ios文件夹,后续生成的.a类库都会放在这个文件夹里边
DEST="${CURRENTPATH}/lib-ios"
mkdir -p"${DEST}"
#编译的类型
ARCHS="armv7armv7s arm64 i386 x86_64"
#生成的类库名称
LIBS="libvo-amrwbenc.a"
#开始编译类库
for arch in$ARCHS; do
case $arch inarm*)
IOSV="-miphoneos-version-min=7.0"
if [ $arch =="arm64" ]
then
IOSV="-miphoneos-version-min=7.0"
fi
echo"Building for iOS $arch ****************"
#编译$arch环境的类库(amr类型类型)
SDKROOT="$(xcrun--sdk iphoneos --show-sdk-path)"
CC="$(xcrun--sdk iphoneos -f clang)"
CXX="$(xcrun--sdk iphoneos -f clang++)"
CPP="$(xcrun-sdk iphonesimulator -f clang++)"
CFLAGS="-isysroot$SDKROOT -arch $arch $IOSV -isystem $SDKROOT/usr/include -fembed-bitcode"
CXXFLAGS=$CFLAGS
CPPFLAGS=$CFLAGS
export CC CXXCFLAGS CXXFLAGS CPPFLAGS
./configure \
--host=arm-apple-darwin\
--prefix=$DEST \
--disable-shared--enable-static
;;
*)
IOSV="-mios-simulator-version-min=7.0"
echo"Building for iOS $arch*****************"
if [ $arch =="i386" ]
then
HOST="i386-apple-darwin"
fi
if [ $arch =="arm64" ]
then
HOST="x86_64-apple-darwin"
fi
#编译$arch环境的类库(其他类型类型)
SDKROOT=`xcodebuild-version -sdk iphonesimulator Path`
CC="$(xcrun-sdk iphoneos -f clang)"
CXX="$(xcrun-sdk iphonesimulator -f clang++)"
CPP="$(xcrun-sdk iphonesimulator -f clang++)"
CFLAGS="-isysroot$SDKROOT -arch $arch $IOSV -isystem $SDKROOT/usr/include -fembed-bitcode"
CXXFLAGS=$CFLAGS
CPPFLAGS=$CFLAGS
export CC CXXCFLAGS CXXFLAGS CPPFLAGS
./configure \
--prefix=$DEST \
--host=$HOST \
--disable-shared
;;
esac
make >/dev/null
makeinstall#将编译成功的可执行文件安装到指定目录中
make clean#清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件。
#清除多余的文件
for i in $LIBS;do
mv $DEST/lib/$i$DEST/lib/$i.$arch
done
done
#制作通用静态库
#http://blog.csdn.net/cuiweijie3/article/details/8671240
for i in $LIBS;do
input=""
for arch in$ARCHS; do
input="$input$DEST/lib/$i.$arch"
done
lipo -create-output $DEST/lib/$i $input
done