非常简单地……用esd播放PCM音频数据
Thursday, February 8, 2007 9:39:59 AM
esd本身提供了wav文件播放、sample播放和stream播放等相关的函数,可以在/usr/include/esd.h中看到所有的函数原型已经少得可怜的说明文字。下面要说的就是用它的stream播放功能来实现PCM音频数据流的播放。
首先程序要有#include <esd.h>,链接时也要加上-lesd开关。
获取esd服务器信息的方法:
gint efd; esd_server_info_t *info; efd = esd_open_sound (NULL); //NULL表示本机的esd if (efd == -1) return; info = esd_get_server_info(efd); if (info) esd_print_server_info(info); esd_close(efd);
esd_server_info_t结构的成员可要在esd.h中看到,也就版本、数据格式、采样率三个信息。
数据格式的低4(0x000F)位标明数据是8位还是16位,0x00F0位标明是单声道还是立体声。在esd.h中定义了:
#define ESD_BITS8 ( 0x0000 ) #define ESD_BITS16 ( 0x0001 ) #define ESD_MONO ( 0x0010 ) #define ESD_STEREO ( 0x0020 )
即format == 0x0021时,表示server的输出数据是16位有符号数,双声道。
嗯,播放音频流可以不用调用esd_open_sound(),用esd_play_stream_fallback()打开一个player,获取对应的file descriptor,对这个fd进行write()操作就可以了。打开一个player的代码:
gint player; //player is a FD player = esd_play_stream_fallback(ESD_BITS16 | ESD_STEREO, 44100, NULL, "dummy"); if (player == -1) return;
第一个参数指明了程序使用的pcm音频数据的格式为signed int16,立体声(即一个数据为左声道一个数据为右声道地交替),第二个参数44100为采样率。如果pcm数据是单声道,或者采样率不是44100,就要对参数做相应的修改。pcm数据的这些格式参数可以在wav文件的文件头里提取出来。第三个参数用于指定esd server,NULL表示local,第四个参数为player设置一个名称标示。
然后就是打开pcm数据文件并向player写数据:
gint fd, rlen;
gchar buf[2048];
fd_set rfds;
if ((fd = open("081.raw", O_RDONLY))<0){
g_error("failed to open input file\n");
return;
}
do {
FD_ZERO(&rfds);
FD_SET(player, &rfds);
rlen = read (fd, buf, 530 );
if (select(player + 1, NULL, &rfds, NULL, NULL) < 0) {
perror("select");
break;
}
if (FD_ISSET(player, &rfds) ){
write(player, buf, rlen);
}
} while (rlen > 0);
esd_close(player);
close (fd);
可以看到,跟前面说的socket操作类似,也是使用select检查fd是否可以写,当可以写的时候就把读到的数据写到player中,从而实现音频播放。因此如果fd是一个socket连接,就可以实现把网络上收到的音频流数据播放出来。同样,如果是蓝牙的sco音频连接,就可以把蓝牙耳机的mic收到的声音播放出来。
另外,可以参考一下xmms源码中的Output/esd目录,这是一个很好的esd音频输出范例。








Unregistered user # Friday, March 2, 2007 8:54:20 AM
Returner # Friday, March 2, 2007 9:18:00 AM
参考:
http://www.china-askpro.com/msg48/qa81.shtml
http://topic.csdn.net/t/20030709/22/2010011.html
没错我是中大的:)
Unregistered user # Saturday, March 3, 2007 9:02:50 AM
Unregistered user # Sunday, March 4, 2007 8:00:18 AM
Returner # Tuesday, March 6, 2007 2:44:59 AM
Unregistered user # Tuesday, March 6, 2007 8:44:09 AM
Returner # Tuesday, March 6, 2007 9:24:22 AM
基本上,你能读写的最小单位是字节而不是位。也就是说你一次只能至少读写8个位(即一个字节)而不是一个位
另外,不要拘泥于16进制和10进制的问题了,本质上它们都是以2进制的方式存储的,不同数制之间的转换关系也可以在很多编程教科书的基础章节中查到。例如你读入的是11110000(二进制),表示成16进制就是0xF0,表示成10进制就是240
Unregistered user # Wednesday, March 7, 2007 7:25:06 AM