📄 sound_mixplay.c.svn-base
字号:
#include <stdio.h>#include <fcntl.h>#include <pthread.h>#include <assert.h>#include <sys/soundcard.h>#include <stdlib.h>#include "sound_mixplay_pub.h"#include "player_pub.h"#include <esd.h>extern player_t *player_p;#define SAMPLESIZE 16#define DSP_SPEED 11025#define MONO_STEREO 1 // 1 单声道, 2 立体声static void mix_data(struct pcm_block *bp,struct pcm_block *p);// 混音并播放void snd_mixplay_do(void) { int sound_fd = -1; //声音设备的文件句柄 struct pcm_block buf; struct channel ch; struct pcm_block *bp = &buf; struct pcm_block *p; struct pcm_block *oldp; int states; int max_pos;#if 1 int rate = DSP_SPEED; int bits = ESD_BITS16, channels = ESD_MONO; int mode = ESD_STREAM, func = ESD_PLAY ; char *host = "127.0.0.1:18000"; char *name = NULL; esd_format_t format = 0; sound_fd = esd_open_sound("127.0.0.1:18000"); format = bits | channels | mode | func; sound_fd = esd_play_stream_fallback( format, rate, host, name );#else int tmp; int sample_size = SAMPLESIZE; int dsp_speed = DSP_SPEED; ch.sample_size = SAMPLESIZE; ch.dsp_speed = DSP_SPEED; ch.mono_stereo = MONO_STEREO; buf.channel_p = &ch; // 打开 dsp 文件 sound_fd = open("/dev/dsp", O_WRONLY, 0); assert(sound_fd != -1); // 设置采样长度 tmp = sample_size; ioctl(sound_fd, SNDCTL_DSP_SAMPLESIZE, &sample_size); assert(tmp == sample_size); // 设置采样速率 tmp = ioctl(sound_fd, SNDCTL_DSP_SPEED, &dsp_speed); assert(tmp != -1);#endif while(1) { states = pthread_mutex_lock(&player_p->pcm_block_mutex); assert(states == 0); p = player_p->pcm_block_head.downchannel_p; memset(&buf,0,sizeof(struct pcm_block)); // 遍历所有 Channel. // p 指向当前 Channel 的当前块. bp 指向播放缓冲区. bp->pos = 0; bp->length = BUF_LENGTH; max_pos = 0; while ( p != NULL ) { // 如果缓冲区读满,则转下一通道 if (bp->pos == bp->length) { p = p->downchannel_p; bp->pos = 0; continue; }; // 如果当前块读完,并且下一块不为空,则当前块置为当前 Channel 的下一块 // ,并释放当前块. if (( p->pos == p->length) && ( p->next_p != NULL)) { oldp = p; // 从双向链表中摘出去 if (p->upchannel_p != NULL) { p->upchannel_p->downchannel_p = p->next_p; }; if (p->downchannel_p != NULL) { p->downchannel_p->upchannel_p = p->next_p; }; p->next_p->upchannel_p = p->upchannel_p; p->next_p->downchannel_p = p->downchannel_p; p->next_p->channel_p = p->channel_p; // Channel 指针传递下去 p = p->next_p; free(oldp); continue; }; // 如果当前 channel 已读完 if (( p->pos == p->length) && ( p->next_p == NULL)) { if (p->channel_p->type == STREAM_CHANNEL) { // 转下一通道 p = p->downchannel_p; continue; } else { // 如果 channel 不是 mp3 stream 型,则取消当前通道,并转下一通道 oldp = p; if (p->upchannel_p != NULL) { p->upchannel_p->downchannel_p = p->downchannel_p; }; if (p->downchannel_p != NULL) { p->downchannel_p->upchannel_p = p->upchannel_p; }; p = p->downchannel_p; bp->pos = 0; // channel 释放时,同时释放附属的 channel 结构体. if (oldp->channel_p != NULL) { free(oldp->channel_p); }; free(oldp); continue; }; }; // 取一个采样到缓冲区 mix_data(bp,p); if (bp->pos > max_pos) { max_pos = bp->pos; }; }; states = pthread_mutex_unlock(&player_p->pcm_block_mutex); assert(states == 0); // 如果遍历所有 channel 无收获,说明已无数据,休息 0.2s. if (max_pos > 0) { // 将播放缓冲区的内容送入声音设备 states = write(sound_fd,(bp->data),max_pos); assert(states >= 0); } else { usleep(2000); } };}staticvoid mix_data(struct pcm_block *bp,struct pcm_block *p) { int32_t s1,s2; int8_t conv; int i; //确定转换方案 conv = 0; if ((p->channel_p->dsp_speed == DSP_SPEED) && ((p->channel_p->mono_stereo / MONO_STEREO) == 2) && ( p->channel_p->sample_size = 16)) { conv = 2; }; if (((p->channel_p->dsp_speed / DSP_SPEED) == 2) && (p->channel_p->mono_stereo == MONO_STEREO) && ( p->channel_p->sample_size = 16)) { conv = 2; }; if ((p->channel_p->dsp_speed == DSP_SPEED) && (p->channel_p->mono_stereo == MONO_STEREO) && ( p->channel_p->sample_size = 16)) { conv = 3; }; if (((p->channel_p->dsp_speed / DSP_SPEED) == 4) && (p->channel_p->mono_stereo == MONO_STEREO) && ( p->channel_p->sample_size = 16)) { conv = 5; }; if (((p->channel_p->dsp_speed / DSP_SPEED) == 4) && ((p->channel_p->mono_stereo / MONO_STEREO) == 2) && ( p->channel_p->sample_size = 16)) { conv = 6; }; if (((p->channel_p->dsp_speed / DSP_SPEED) == 2) && ((p->channel_p->mono_stereo / MONO_STEREO) == 2) && ( p->channel_p->sample_size = 16)) { conv = 5; }; //转换 switch(conv) { case 2: // 16 bit -> 16bit : 双声道->单声道 : 同速率 // 16 bit -> 16bit : 同声道 : 降一倍速率 while ((p->pos < p->length) && (bp->pos < bp->length)) { s1 = *((SI16*)(p->data + p->pos)); p->pos = p->pos + 2; assert(p->pos < p->length); s2 = *((SI16*)(p->data + p->pos)); p->pos = p->pos + 2; assert(p->pos <= p->length); *((SI16*)(bp->data + bp->pos)) = *((SI16*)(bp->data + bp->pos)) + (s1+s2)/2/4; bp->pos = bp->pos + 2; }; break; case 3: // 16 bit -> 16bit : 同声道 : 同速率 while ((p->pos < p->length) && (bp->pos < bp->length)) { *((SI16*)(bp->data + bp->pos)) = *((SI16*)(bp->data + bp->pos)) + *((SI16*)(p->data + p->pos))/4 ; bp->pos = bp->pos + 2; p->pos = p->pos + 2; }; break; case 4: // 8 bit -> 8 bit : 同声道 : 同速率 *((SI8*)(bp->data + bp->pos)) = *((SI8*)(bp->data + bp->pos)) + *((SI8*)(p->data + p->pos))/4; bp->pos = bp->pos + 1; p->pos = p->pos + 1; break; case 5: while ((p->pos < p->length) && (bp->pos < bp->length)) { s1 = 0; for (i=0;i<4;i++) { if (!i) { s1=*((SI16*)(p->data + p->pos)); } s1 += *((SI16*)(p->data + p->pos +i*2)); } *((SI16*)(bp->data + bp->pos)) += (s1/16); bp->pos = bp->pos + 2; p->pos = p->pos + 8; } break; case 6: while ((p->pos < p->length) && (bp->pos < bp->length)) { s1 = 0; s2 = 0; for (i=0;i<4;i++) { if (!i) { s1=*((SI16*)(p->data + p->pos)); } s1 += *((SI16*)(p->data + p->pos +i*2)); } for (i=0;i<4;i++) { if (!i) { s2=*((SI16*)(p->data + p->pos + 8)); } s2 += *((SI16*)(p->data + p->pos +i*2 +8)); } *((SI16*)(bp->data + bp->pos)) += (((s1/16)+(s1/16))/2); bp->pos = bp->pos + 2; p->pos = p->pos + 16; } break; default: assert(0); };}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -