絕大多數的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