嘉应学院毕业论文(设计)
桢的形式存放,即首先记录完桢1的左声道样本和右声道样本(假设为立体声格式),再开始桢2的记录。而在非交错模式下,首先记录的是一个周期内所有桢的左声道样本,再记录右声道样本,数据是以连续通道的方式存储。不过多数情况下,我们只需要使用交错模式就可以了。
明白了各参数含义及关系后,我们开始设置参数: void CWavPlayer::set_pcm_params() {
switch(bit_per_sample/8) {
case 1:snd_pcm_hw_params_set_format(handle, hw_params, SND_PCM_FORMAT_U8);
break ;
//设置采样位数
snd_pcm_hw_params_t *hw_params; snd_pcm_hw_params_malloc(&hw_params);
snd_pcm_hw_params_any(handle, hw_params); //设备初始化 snd_pcm_hw_params_set_access(handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED);
//设置为交错模式
case 2:snd_pcm_hw_params_set_format(handle, hw_params,
SND_PCM_FORMAT_S16_LE);
break ;
case 3:snd_pcm_hw_params_set_format(handle, hw_params,
SND_PCM_FORMAT_S24_LE);
}
snd_pcm_hw_params_set_channels(handle, hw_params, channels); //设置通道数 int dir = 0;
snd_pcm_hw_params_set_rate_near(handle, hw_params, &sample_rate, &dir); //设置采样率
uint32_t buffer_time, period_time;
if (snd_pcm_hw_params_get_buffer_time_max(hw_params, &buffer_time, 0) < 0) {
break ;
17
嘉应学院毕业论文(设计)
}
std::cerr << \exit(1);
if (buffer_time > 500000) buffer_time = 500000; period_time = buffer_time / 4;
if (snd_pcm_hw_params_set_buffer_time_near(handle, hw_params, &buffer_time,
0) < 0) {
if (snd_pcm_hw_params_set_period_time_near(handle, hw_params, &period_time, }
std::cerr << \exit(1);
0) < 0) { }
3.设置好参数后便可以开始录音了,录音过程实际上就是从音频设备中读取数据信息并保存。
void CWavPlayer::alsa_record(char *sendBuffer)
snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir); snd_pcm_format_t format;
snd_pcm_hw_params_get_format(hw_params, &format); bit_per_sample = snd_pcm_format_physical_width(format); bit_per_frame = bit_per_sample * channels;
//计算帧大小
//获取采样位数
snd_pcm_hw_params(handle, hw_params); }
std::cerr << \exit(1);
chunk_byte = (uint32_t)period_size * bit_per_frame / 8; //计算周期长度 snd_pcm_hw_params_free(hw_params);
18
嘉应学院毕业论文(设计)
{
int r = 0;
size_t count = period_size; size_t result = 0;
while (count > 0) {
r = snd_pcm_readi(handle, sendBuffer, count); //把采集到的音频数据放
到sendBuffer缓冲区里,通过RTP封装然后发送
if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {
std::cerr << \
std::endl;
}
else if (r == -EPIPE) { }
else if (r == -ESTRPIPE) { }
else if (r < 0) {
std::cout << \std::cout << \std::cerr << \snd_pcm_prepare(handle); snd_pcm_wait(handle, 1000);
std::endl;
}
exit(-1);
19
嘉应学院毕业论文(设计)
} }
if (r > 0) { }
result += r; count -= r;
sendBuffer += r * bit_per_frame / 8;
4.同样的原理,我们再添加一个播放函数,当接收到音频数据时,向音频设备写入数据,这个函数在class COrtpClient中: void COrtpClient::play_wav(char *pBuffer) {
int rc = 0;
snd_pcm_t *handle = player.get_handle();
snd_pcm_uframes_t period_size = player.get_period_size();
//将pBuffer接收到得音频数据写入音频设备
while((rc = snd_pcm_writei(handle, pBuffer, period_size)) < 0) {
std::cout << \if (rc == -EPIPE)
{
usleep(200000);
/* EPIPE means underrun */ //perror(\
snd_pcm_prepare(handle);
}
else if (rc < 0) {
perror(\ }
20
exit(1);
嘉应学院毕业论文(设计)
}
}
4.2.3 音量调整相关操作
初始化麦克风及本机音量调节器相关代码: void CWavPlayer::set_pcm_mixer() {
snd_mixer_t *mixer; snd_mixer_elem_t *elem; long minVolume, maxVolume; int result;
if ((result = snd_mixer_open(&mixer, 0)) < 0) { }
if ((result = snd_mixer_attach(mixer, \ { }
if ((result = snd_mixer_selem_register(mixer, NULL, NULL)) < 0) { }
std::cerr << \mixer = NULL;
std::cerr << \snd_mixer_close(mixer); mixer = NULL;
std::cerr << \snd_mixer_close(mixer); mixer = NULL;
21
嘉应学院毕业论文(设计)
if ((result = snd_mixer_load(mixer)) < 0) { }
for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem))
{
if (snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE && std::cerr << \snd_mixer_close(mixer); mixer = NULL;
snd_mixer_selem_is_active(elem))
{
snd_mixer_selem_get_playback_volume_range(elem, &minVolume,
&maxVolume);
snd_mixer_selem_get_capture_volume_range(elem, &minVolume,
snd_mixer_selem_set_playback_switch_all(elem, 1);
snd_mixer_selem_set_playback_volume_all(elem, maxVolume);
&maxVolume);
} }
}
snd_mixer_selem_set_capture_switch_all(elem, 1);
snd_mixer_selem_set_capture_volume_all(elem, maxVolume);
22