在语音通话过程中,没有规律的卡顿。分析过程包括:
1、网络抓包分析,没有丢包。
2、从MIC进来音频文件,AEC回音消除处理后的wav文件,编码、发送,怀疑回音消除算法影响卡顿。
通过写wav文件对比发现,回音消除算法并没有特别明显的卡顿,但会消掉部分音频。
3、播放端的流程包括,接收RTP,解码,然后扔个ALSA播放。
播放端ALSA声卡偶尔会有underrun的错误,参考表示给声卡喂数据慢了, 导致播放断续。
修改方法:
将音频编码协议从OPUS修改为PCMU,验证播放不卡顿。
问题原因确认:
这个嵌入式linux平台的cpu负载比较高,导致音频播放的解码线程得不到CPU调度,ALSA声卡出现饥饿现象,产生的播放卡顿。
WAV文件读写方法:
下面的读写方法,只用调用两个方法就可以生成一个wav文件。
1、写文件:
inner_file_write_before_encode(采样率,buf,buf_size);
2、录音结束,写文件头
write_header_to_file(文件长度);
代码:
//save 2 file #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> #include <stdint.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> static int init_file(char *filePath); static int file_open(const char *filename, int flags); static int file_read(int fd, unsigned char *buf, int size); static int file_write(int fd, const unsigned char *buf, int size); static int64_t file_seek(int fd, int64_t pos, int whence); static int file_close(int fd); #define DEBUG_LOCAL_FILE 1 static int g_fd_encode = -1; static int g_fd_decode = -1; long total_decoded_data_len = 0; long total_recorded_data_len = 0; //static char* save_pcm_before_encoded_file = "/mnt/UDISK/app/aac_before_encoded.wav"; //static char* save_pcm_after_decoded_file = "/mnt/UDISK/app/aac_after_decoded.wav"; static char save_pcm_before_encoded_file[1024] = {0}; static char save_pcm_after_decoded_file[1024] = {0}; static char* tmp_save_pcm_before_encoded_file = "/mnt/UDISK/app/audio/aac_before_encoded"; static char* tmp_save_pcm_after_decoded_file = "/mnt/UDISK/app/audio/aac_after_encoded"; static char* postfix = ".wav"; static char* aacpostfix = ".aac"; #define SAMPLE_RATE_VALUE 16000 static uint8_t get_use_save_for_test(){ return 1; } void write_header_to_file(int sample_frame_size){ if (g_fd_decode != -1){ file_close(g_fd_decode); g_fd_decode = -1; } if (g_fd_encode != -1){ file_close(g_fd_encode); g_fd_encode = -1; } int fd_header = file_open(save_pcm_before_encoded_file, O_WRONLY); if (fd_header != -1){ //int64_t seek = file_seek(fd_header, (int64_t)0, SEEK_END);//SEEK_SET:0 SEEK_CUR:1 SEEK_END:2 //printf("i seek:%d", seek); //seek = file_seek(fd_header, (int64_t)0, SEEK_SET);//SEEK_SET:0 SEEK_CUR:1 SEEK_END:2 //printf("ii seek:%d", seek); write_header(fd_header, total_recorded_data_len, total_recorded_data_len + 44, SAMPLE_RATE_VALUE, 1, sample_frame_size); file_close(fd_header); } fd_header = file_open(save_pcm_after_decoded_file, O_WRONLY); if (fd_header != -1){ //int64_t seek = file_seek(fd_header, (int64_t)0, SEEK_END);//SEEK_SET:0 SEEK_CUR:1 SEEK_END:2 //printf("iii seek:%d", seek); //seek = file_seek(fd_header, (int64_t)0, SEEK_SET);//SEEK_SET:0 SEEK_CUR:1 SEEK_END:2 // printf("iv seek:%d", seek); write_header(fd_header, total_decoded_data_len, total_decoded_data_len + 44, SAMPLE_RATE_VALUE, 1, sample_frame_size); file_close(fd_header); } } typedef unsigned char byte; /* 8000*1*16/8 channel*samplerate* per_samples_bytes/8 channel:1 samplerate:8000 per_samples_bytes:2*8 16bit pcm byteRate:160 */ void write_header(int fd, long totalAudioLen, long totalDataLen, int longSampleRate, int channels, int byteRate){ unsigned char header[44]; header[0] = 'R'; // RIFF/WAVE header header[1] = 'I'; header[2] = 'F'; header[3] = 'F'; header[4] = (byte) (totalDataLen & 0xff); header[5] = (byte) ((totalDataLen >> 8) & 0xff); header[6] = (byte) ((totalDataLen >> 16) & 0xff); header[7] = (byte) ((totalDataLen >> 24) & 0xff); header[8] = 'W'; header[9] = 'A'; header[10] = 'V'; header[11] = 'E'; header[12] = 'f'; // 'fmt ' chunk header[13] = 'm'; header[14] = 't'; header[15] = ' '; header[16] = 16; // 4 bytes: size of 'fmt ' chunk header[17] = 0; header[18] = 0; header[19] = 0; header[20] = 1; // format = 1 header[21] = 0; header[22] = (byte) channels; header[23] = 0; header[24] = (byte) (longSampleRate & 0xff); header[25] = (byte) ((longSampleRate >> 8) & 0xff); header[26] = (byte) ((longSampleRate >> 16) & 0xff); header[27] = (byte) ((longSampleRate >> 24) & 0xff); header[28] = (byte) (byteRate & 0xff); header[29] = (byte) ((byteRate >> 8) & 0xff); header[30] = (byte) ((byteRate >> 16) & 0xff); header[31] = (byte) ((byteRate >> 24) & 0xff); header[32] = (byte) (2 * 16 / 8); // block align header[33] = 0; header[34] = 16; // bits per sample header[35] = 0; header[36] = 'd'; header[37] = 'a'; header[38] = 't'; header[39] = 'a'; header[40] = (byte) (totalAudioLen & 0xff); header[41] = (byte) ((totalAudioLen >> 8) & 0xff); header[42] = (byte) ((totalAudioLen >> 16) & 0xff); header[43] = (byte) ((totalAudioLen >> 24) & 0xff); file_write(fd, header, 44); } int inner_file_write_after_decode(int sample_frame_size, const unsigned char *buf, int size){ if (!get_use_save_for_test()){ //no need do anything. return -1; } static int dcount = 0; if (g_fd_decode == -1){ //char after_file[1024] = { 0 }; sprintf(save_pcm_after_decoded_file, "%s%d%s", tmp_save_pcm_after_decoded_file, dcount++, aacpostfix); printf("inner_file_write_after_decode,size:%d save_pcm_after_decoded_file:%s", size, save_pcm_after_decoded_file); g_fd_decode = init_file(save_pcm_after_decoded_file); total_decoded_data_len = 0; write_header(g_fd_decode, total_decoded_data_len, total_decoded_data_len + 44, SAMPLE_RATE_VALUE, 1, sample_frame_size); return -1; } file_write(g_fd_decode, buf, size); printf("inner_file_write_after_decode,write size:%d", size); total_decoded_data_len+= size; } int inner_file_write_before_encode(int sample_frame_size, const unsigned char *buf, int size){ if (!get_use_save_for_test()){ //no need do anything. return -1; } static int ecount = 0; if (g_fd_encode == -1){ //char before_file[1024] = { 0 }; sprintf(save_pcm_before_encoded_file, "%s%d%s", tmp_save_pcm_before_encoded_file, ecount++, postfix); printf("inner_file_write_before_encode, save_pcm_before_encoded_file:%s", save_pcm_before_encoded_file); g_fd_encode = init_file(save_pcm_before_encoded_file); total_recorded_data_len = 0; write_header(g_fd_decode, total_decoded_data_len, total_decoded_data_len + 44, SAMPLE_RATE_VALUE, 1, sample_frame_size); return -1; } file_write(g_fd_encode, buf, size); total_recorded_data_len+= size; } static int init_file(char *filePath){ char* filename = filePath; remove(filename); mkdir("/mnt/UDISK/app/", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); mkdir("/mnt/UDISK/app/audio", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); int fd = file_open(filename, O_CREAT | O_WRONLY | O_APPEND); if (fd == -1){ return -1; } return fd ; } /**/ static int file_open(const char *filename, int flags) { int fd; fd = open(filename, flags, 0666); if (fd == -1) return -1; return fd; } static int file_read(int fd, unsigned char *buf, int size) { return read(fd, buf, size); } static int file_write(int fd, const unsigned char *buf, int size) { return write(fd, buf, size); } static int64_t file_seek(int fd, int64_t pos, int whence) { return lseek(fd, pos, whence); } static int file_close(int fd) { return close(fd); }
-------------------广告线---------------
项目、合作,欢迎勾搭,邮箱:promall@qq.com
本文为呱牛笔记原创文章,转载无需和我联系,但请注明来自呱牛笔记 ,it3q.com