一个语音通话断续的问题分析


在语音通话过程中,没有规律的卡顿。分析过程包括:

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

请先登录后发表评论
  • 最新评论
  • 总共0条评论