第17章Linux OSS 音频设备驱动之二

2.mixer 编程

    声卡上的混音器由多个混音通道(channel)组成,声卡上的混音器可以通过驱动程序提供的设备文件/dev/mixer 进行编程。对混音器的操作一般通过 ioctl()系统调用来完成,所有控制命令都以 SOUND_MIXER

或者 MIXER 开头,表 17.1 列出常用的混音器控制命令。


    对声卡的输入增益和输出增益调节是混音器的一个主要作用,目前大部分声卡采用的是8 位或者 16 位的增益控制器,声卡驱动程序将它们转换成百分比的形式,无论是输入增益还是输出增益,其取值范围都是从 0~100。

(1)SOUND_MIXER_READ 宏

混音器编程时,使用 SOUND_MIXER_READ 宏读取混音通道的增益大小,如下代码可获得麦克风的输入增益:

ioctl(fd, SOUND_MIXER_READ(SOUND_MIXER_MIC), &vol);

对于只有一个混音通道的单声道设备,返回的增益大小保存在低位字节中。对于支持多个混音通道的双声道设备,返回的增益大小包括两个部分,分别代表左、右两个声道的值,其中低位字节保存左声道的音量,高位字节保存右声道的音量。下面的代码从返回值中依次提取左右声道的增益大小:

int left, right;
left = vol & 0xff;

right = (vol & 0xff00) >> 8;

(2)SOUND_MIXER_WRITE 宏

通过 SOUND_MIXER_WRITE 宏来设置混音通道的增益大小,下面的语句用来设置麦克风的输入增益:

vol = (right << 8) + left;

ioctl(fd, SOUND_MIXER_WRITE(SOUND_MIXER_MIC), &vol);

(3)查询 MIXER 信息

    声卡驱动程序提供多个 ioctl()系统调用来获得混音器的信息,通常返回一个整型的位掩码,其中每一位分别代表一个特定的混音通道,如果相应的位为 1,说明与之对应的混音通道是可用的。

    通过 SOUND_MIXER_READ_DEVMASK返回的位掩码查询出能够被声卡支持的每一个混音通道,通过 SOUND_MIXER_READ_RECMAS 返回的位掩码可以查询出能够被当作录音源的每一个通道。如下代码可用来检查 CD 输入是否是一个有效的混音通道:

ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask);
if (devmask & SOUND_MIXER_CD)

    printf("The CD input is supported");

如下代码用来检查 CD 输入是否是一个有效的录音源:

ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask);
if (recmask & SOUND_MIXER_CD)
    printf("The CD input can be a recording source");

    大多数声卡提供多个录音源,通过 SOUND_MIXER_READ_RECSRC 可以查询出当前正在使用的录音源,同一时刻可使用两个或两个以上的录音源,具体由声卡硬件本身决定。使用 SOUND_MIXER_WRITE_RECSRC 来设置声卡当前使用的录音源,如下代码将 CD输入作为声卡的录音源使用。

devmask = SOUND_MIXER_CD;

ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &devmask);

    此外,所有的混音通道都有单声道和双声道的区别,如果需要知道哪些混音通道提供对立体声的支持,通过 SOUND_MIXER_READ_STEREODEVS 来获得。

    代码清单 17.4 的程序实现利用/dev/mixer 接口对混音器进行编程的过程,该程序可对各种混音通道的增益进行调节。

代码清单 17.4 OSS mixer 接口应用编程

/* 用来存储所有可用混音设备的名称 */
 const char *sound_device_names[] = SOUND_DEVICE_NAMES;
 int fd; /* 混音设备所对应的文件描述符 */
 int devmask, stereodevs; /* 混音器信息对应的 bit 掩码 */
 char *name;
 /* 显示命令的使用方法及所有可用的混音设备 */
 void usage()
 {
     int i;
     fprintf(stderr, "usage: %s <device> <left-gain%%> <right-gain%%>\n"
         "%s <device> <gain%%>\n\n""Where <device> is one of:\n", name, name);
     for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
            if ((1 << i) &devmask)

            /* 只显示有效的混音设备 */

            fprintf(stderr, "%s ", sound_device_names[i]);

     fprintf(stderr, "\n");
     exit(1);
}

int main(int argc, char *argv[])

 {

        int left, right, level; /* 增益设置 */

        int status; /* 系统调用的返回值 */

        int device; /* 选用的混音设备 */

        char *dev; /* 混音设备的名称 */
        int i;
        name = argv[0];
        /* 以只读方式打开混音设备 */

        fd = open("/dev/mixer", O_RDONLY);

        if (fd == - 1) {
            perror("unable to open /dev/mixer");
            exit(1);

        }

        /* 获得所需要的信息 */
        status = ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask);
        if(status == - 1)
                perror("SOUND_MIXER_READ_DEVMASK ioctl failed");

        status = ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs);

         if (status == - 1)

                perror("SOUND_MIXER_READ_STEREODEVS ioctl failed");
        /* 检查用户输入 */
        if (argc != 3 && argc != 4)
              usage();
        /* 保存用户输入的混音器名称 */
        dev = argv[1];

        /* 确定即将用到的混音设备 */

        for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
             if (((1 << i) &devmask) && !strcmp(dev, sound_device_names[i]))
                 break;
             if (i == SOUND_MIXER_NRDEVICES) {
                     /* 没有找到匹配项 */
                     fprintf(stderr, "%s is not a valid mixer device\n", dev);
                     usage();
             }

        /* 查找到有效的混音设备 */
         device = i;
         /* 获取增益值 */
         if (argc == 4) {
             /* 左、右声道均给定 */
             left = atoi(argv[2]);
             right = atoi(argv[3]);
         } else {
             /* 左、右声道设为相等 */
             left = atoi(argv[2]);
             right = atoi(argv[2]);
         }

         /* 对非立体声设备给出警告信息 */

        if ((left != right) && !((1 << i) &stereodevs))
             fprintf(stderr, "warning: %s is not a stereo device\n", dev);

        /* 将两个声道的值合到同一变量中 */
        level = (right << 8) + left;

        /* 设置增益 */
         status = ioctl(fd, MIXER_WRITE(device), &level);
         if (status == - 1) {
             perror("MIXER_WRITE ioctl failed");
             exit(1);
         }
         /* 获得从驱动返回的左右声道的增益 */
        left = level &0xff;
        right = (level &0xff00) >> 8;
         /* 显示实际设置的增益 */
        fprintf(stderr, "%s gain set to %d%% / %d%%\n", dev, left, right);
        /* 关闭混音设备 */
        close(fd);
        return 0;

 }

总结:

        编译上述程序为可执行文件 mixer,执行./mixer <device> <left-gain%> <right-gain%>或./mixer
<device> <gain%>可设置增益,device 可以是 vol、pcm、speaker、line、mic、cd、igain、line1、
phin、video。


猜你喜欢

转载自blog.csdn.net/xiezhi123456/article/details/80719324
oss