1.粤嵌开发板(客户端),采集音频,发往服务器进行语音识别。2Ubuntu(服务器),从客户端获取音频,进行识别,返回对应识别结果 实现过程以及代码(Linux)
时间: 2024-04-01 16:30:47 浏览: 309
实现过程:
客户端:
1. 首先需要安装alsa库和录音工具arecord。
2. 通过arecord录制音频,并将其转换为PCM格式。
3. 使用socket将PCM格式的音频数据发送到服务器。
客户端代码示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <alsa/asoundlib.h>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8888
#define BUF_SIZE 4096
int main()
{
int sockfd;
struct sockaddr_in server_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(1);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("connect");
exit(1);
}
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
int size;
/* 打开PCM设备 */
if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0) < 0) {
perror("snd_pcm_open");
exit(1);
}
/* 分配硬件参数对象 */
if (snd_pcm_hw_params_malloc(¶ms) < 0) {
perror("snd_pcm_hw_params_malloc");
exit(1);
}
/* 初始化硬件参数对象 */
if (snd_pcm_hw_params_any(handle, params) < 0) {
perror("snd_pcm_hw_params_any");
exit(1);
}
/* 设置访问类型为交错模式 */
if (snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
perror("snd_pcm_hw_params_set_access");
exit(1);
}
/* 设置数据格式为S16_LE */
if (snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE) < 0) {
perror("snd_pcm_hw_params_set_format");
exit(1);
}
/* 设置采样率为16000Hz */
val = 16000;
if (snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir) < 0) {
perror("snd_pcm_hw_params_set_rate_near");
exit(1);
}
/* 设置通道数为1 */
if (snd_pcm_hw_params_set_channels(handle, params, 1) < 0) {
perror("snd_pcm_hw_params_set_channels");
exit(1);
}
/* 设置传输周期长度为32 */
frames = 32;
if (snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir) < 0) {
perror("snd_pcm_hw_params_set_period_size_near");
exit(1);
}
/* 将硬件参数设置到PCM设备中 */
if (snd_pcm_hw_params(handle, params) < 0) {
perror("snd_pcm_hw_params");
exit(1);
}
/* 释放硬件参数对象 */
snd_pcm_hw_params_free(params);
/* 分配缓冲区 */
size = frames * 2;
buffer = (char *)malloc(size);
/* 录制音频并发送到服务器 */
while (1) {
/* 录制音频 */
if (snd_pcm_readi(handle, buffer, frames) != frames) {
perror("snd_pcm_readi");
break;
}
/* 发送音频数据到服务器 */
if (send(sockfd, buffer, size, 0) == -1) {
perror("send");
break;
}
}
/* 释放缓冲区 */
free(buffer);
/* 关闭PCM设备 */
snd_pcm_close(handle);
/* 关闭socket */
close(sockfd);
return 0;
}
```
服务器端:
1. 首先需要安装ffmpeg库和语音识别软件Sphinx。
2. 通过socket接收客户端发送过来的PCM格式的音频数据。
3. 使用ffmpeg将PCM格式的音频数据转换为wav格式。
4. 使用Sphinx进行语音识别,并返回识别结果。
服务器端代码示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <ffmpeg/avformat.h>
#include <sphinxbase/err.h>
#include <pocketsphinx.h>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8888
#define BUF_SIZE 4096
const char *config =
"default\n"
"{\n"
" -hmm /usr/local/share/pocketsphinx/model/en-us/en-us\n"
" -lm /usr/local/share/pocketsphinx/model/en-us/en-us.lm.bin\n"
" -dict /usr/local/share/pocketsphinx/model/en-us/cmudict-en-us.dict\n"
"}\n";
int main()
{
int sockfd, connfd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_addr_len;
char buffer[BUF_SIZE];
int size;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
exit(1);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
exit(1);
}
if (listen(sockfd, 5) == -1) {
perror("listen");
exit(1);
}
client_addr_len = sizeof(client_addr);
connfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
if (connfd == -1) {
perror("accept");
exit(1);
}
AVFormatContext *fmt_ctx = NULL;
AVCodecContext *dec_ctx = NULL;
AVCodec *dec = NULL;
AVPacket pkt;
AVFrame *frame = NULL;
char *pcm_buffer = NULL;
/* 注册所有的解码器 */
av_register_all();
/* 打开输入文件 */
if (avformat_open_input(&fmt_ctx, "pipe:", NULL, NULL) < 0) {
perror("avformat_open_input");
exit(1);
}
/* 查找音频流 */
if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
perror("avformat_find_stream_info");
exit(1);
}
/* 找到第一个音频流 */
int audio_stream_index = -1;
for (int i = 0; i < fmt_ctx->nb_streams; i++) {
if (fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_stream_index = i;
break;
}
}
if (audio_stream_index == -1) {
fprintf(stderr, "No audio stream found.\n");
exit(1);
}
/* 获取音频解码器 */
dec = avcodec_find_decoder(fmt_ctx->streams[audio_stream_index]->codecpar->codec_id);
if (!dec) {
fprintf(stderr, "Failed to find codec.\n");
exit(1);
}
/* 分配解码器上下文 */
dec_ctx = avcodec_alloc_context3(dec);
if (!dec_ctx) {
fprintf(stderr, "Failed to allocate codec context.\n");
exit(1);
}
/* 将流参数拷贝到解码器上下文中 */
if (avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[audio_stream_index]->codecpar) < 0) {
fprintf(stderr, "Failed to copy codec parameters to decoder context.\n");
exit(1);
}
/* 打开解码器 */
if (avcodec_open2(dec_ctx, dec, NULL) < 0) {
fprintf(stderr, "Failed to open codec.\n");
exit(1);
}
/* 分配音频帧 */
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Failed to allocate frame.\n");
exit(1);
}
/* 分配PCM缓冲区 */
pcm_buffer = (char *)malloc(BUF_SIZE);
/* 初始化语音识别器 */
ps_decoder_t *ps = ps_init(cmd_ln_parse_string_r(NULL, config, TRUE, FALSE), NULL);
if (!ps) {
fprintf(stderr, "Failed to initialize pocketsphinx.\n");
exit(1);
}
/* 开始识别 */
ps_start_utt(ps);
/* 从socket接收音频数据并进行识别 */
while ((size = recv(connfd, buffer, BUF_SIZE, 0)) > 0) {
/* 发送音频数据到解码器 */
av_init_packet(&pkt);
pkt.data = (unsigned char *)buffer;
pkt.size = size;
if (avcodec_send_packet(dec_ctx, &pkt) < 0) {
fprintf(stderr, "Error sending packet for decoding.\n");
exit(1);
}
/* 接收解码后的音频数据 */
while (avcodec_receive_frame(dec_ctx, frame) == 0) {
/* 将解码后的音频数据保存为PCM格式 */
int pcm_size = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1);
memcpy(pcm_buffer, frame->data[0], pcm_size);
/* 发送PCM格式的音频数据到语音识别器 */
ps_process_raw(ps, pcm_buffer, pcm_size, 0, 0);
/* 如果检测到语音终止,则输出识别结果 */
if (ps_get_in_speech(ps)) {
printf("%s\n", ps_get_hyp(ps, NULL));
}
}
}
/* 结束识别 */
ps_end_utt(ps);
/* 释放语音识别器 */
ps_free(ps);
/* 释放PCM缓冲区 */
free(pcm_buffer);
/* 释放音频帧 */
av_frame_free(&frame);
/* 关闭解码器 */
avcodec_close(dec_ctx);
/* 关闭输入文件 */
avformat_close_input(&fmt_ctx);
/* 关闭socket */
close(connfd);
close(sockfd);
return 0;
}
```
说明:
该示例代码使用alsa库和录音工具arecord实现了客户端采集音频数据,并将其发送到服务器进行语音识别。服务器端使用ffmpeg库将PCM格式的音频数据转换为wav格式,然后使用语音识别软件Sphinx进行语音识别,并返回识别结果。
阅读全文