背景
产品喝大了,说开发一个聊天界面,功能参照微信即可。
这是应了那句话:新人一开口,便知有没有~~真是风趣幽默。
问题分析
其实仔细看微信的聊天面板,功能拆分出来,主要有以下几点:
(1)emoji表情,自定义表情等等。这里可以归类为“表情”tab。
(2)语音交互,音频录制播放压缩。
(3)媒体交互,选择图片,视频,文件等等。
核心就是上面的内容,锦上添花的功能就不再叙述了。
实现效果
开发环境
win10
jdk8+
as2024+
本文内容
本文将会讲解安卓原生进行音频录制,并且压缩生成mp3的核心流程。
音频录制
对于音频录制,安卓原生应该是支持两种方式,一种是MediaRecorder,一种是AudioRecord。第一种就不再提及了,封装度比较高,网上很多教程。
本文主要讲解的是第二种,AudioRecord录制音频,生成pcm文件,通过lamb音频压缩把文件转换为mp3。
(1)初始化录制参数
双声道,44100赫兹频录,麦克风,这些都是常规参数,正常初始化AudioRecorder对象即可。
接着调用AudioRecorder对象 startRecording方法,指定开始录音。通过read方法,读取录制内容,然后通过流的方式,写出到文件,核心代码如下:
int bufferReadResult = audioRecorder.read(buffer, 0, mBufferSizeInBytes);
if (bufferReadResult == -1) {
bufferReadResult = 0;
}
mDataOutputStream.write(buffer, 0, bufferReadResult);
上述思路,就完成了音频的录制了,得到的一个产物就是xxxx.pcm。然后我们要对这个pcm进行压缩,这里选用的是Lamb进行音频压缩。
C核心代码如下:
/**
* 音频文件转换为mp3
* bit -- 44100
* channel -- 2
* */
extern "C"
JNIEXPORT void JNICALL
Java_com_north_light_liblame_LameUtils_convertToMp3(JNIEnv *env, jobject obj, jstring orgFile,
jstring jmp3,jint bit ,jint channel) {
char *corgFile = Jstring2CStr(env, orgFile);
char *cmp3 = Jstring2CStr(env, jmp3);
LOGI("org = %s", corgFile);
LOGI("mp3 = %s", cmp3);
//1.打开文件
FILE *forgFile = fopen(corgFile, "rb");
FILE *forgFileCount = fopen(corgFile, "rb");
FILE *fmp3 = fopen(cmp3, "wb");
short int wav_buffer[8192 * 2];
unsigned char mp3_buffer[8192];
//1.初始化lame的编码器
lame_t lame = lame_init();
//2. 设置lame mp3编码的采样率
lame_set_in_samplerate(lame, bit);
lame_set_num_channels(lame, channel);
// 3. 设置MP3的编码方式
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
LOGI("lame init finish");
long read;
long write; //代表读了多少个次 和写了多少次
long total = 0; // 当前读的wav文件的byte数目
do {
read = fread(wav_buffer, sizeof(short int) * 2, 8192, forgFile);
total += read * sizeof(short int) * 2;
fseek(forgFileCount, 0, SEEK_END);
long length = ftell(forgFileCount);
rewind(forgFileCount);
LOGI("converting ....%d", total);
publishJavaProgress(env, obj, total, length, jmp3);
// 调用java代码 完成进度条的更新
if (read != 0) {
write = lame_encode_buffer_interleaved(lame, wav_buffer, read, mp3_buffer, 8192);
//把转化后的mp3数据写到文件里
fwrite(mp3_buffer, sizeof(unsigned char), write, fmp3);
}
if (read == 0) {
lame_encode_flush(lame, mp3_buffer, 8192);
}
} while (read != 0);
LOGI("convert finish");
lame_close(lame);
fclose(forgFile);
fclose(forgFileCount);
fclose(fmp3);
}
其中,部分引用,是用lamb提供的库
官网地址:https://lame.sourceforge.io/download.php
下载集成到项目中即可。至于项目中,ndk如何配置,这里就不一一详述了,我直接贴一下我的cmakelists.txt文件吧。
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
#指定cmake的最小版本号
cmake_minimum_required(VERSION 3.4.1)
#定义项目名称,可以不定义
#project(demo)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#设置so库的输出路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs/${ANDROID_ABI})
#设置编译类型
#add_executable(demo demo.cpp) # 生成可执行文件
#生成动态共享库
add_library( # 设置编译成so库的名称
lame-lib
# 生成动态库或共享库,此处如果SHARED改为STATIC,其含义是生成静态库
SHARED
# 提供一个需要编译的源文件的相对路径(),native-lib.cpp就是需要编译的源文件
native-lib-lamb.cpp
lame/bitstream.c
lame/encoder.c
lame/fft.c
lame/gain_analysis.c
lame/id3tag.c
lame/lame.c
lame/mpglib_interface.c
lame/newmdct.c
lame/presets.c
lame/psymodel.c
lame/quantize.c
lame/quantize_pvt.c
lame/reservoir.c
lame/set_get.c
lame/tables.c
lame/takehiro.c
lame/util.c
lame/vbrquantize.c
lame/VbrTag.c
lame/version.c
)
#明确指定编译时需要编译哪些源文件
#add_library(demo demo.cpp test.cpp util.cpp)
#aux_source_directory(dir VAR) 发现一个目录下所有的源代码文件并将列表存储在一个变量中。
#例如:aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
#add_library(demo ${SRC_LIST})
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
#查找到指定的预编译库,并将它的路径存储在变量中
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
#设置target需要链接的库
target_link_libraries( # Specifies the target library.目标库
lame-lib
# Links the target library to the log library 目标库需要链接的库,log-lib是上面find_library指定的变量名
# included in the NDK.
${log-lib})
目录结构如下:
其中,lame目录,就是存放刚刚从官网下载的c代码。
LameUtils就是jni文件编写给java层使用的。
至此,你已经有了大概的思路,还有下载官方代码库的初步了解,录制音频,压缩音频核心方法的认识,那么,文章这里就结束了,如需源码,文末有下载方式。
注意点
注意录制文件格式保存,文中是pcm,其他格式可能会引起问题。如wav。
源码
源码获取方式,关注回复: 安卓录音插件源码
即可获得: