【问题标题】:Get master sound volume in C in Linux在 Linux 中用 C 语言获取主音量
【发布时间】:2011-12-01 05:44:50
【问题描述】:

我正在尝试检索(可能稍后设置)Linux 中的主音量。我正在使用 PulseAudio,但理想情况下它也适用于 ALSA。

我发现this 关于如何设置音量的帖子非常有用,并且从中我能够推断出 snd_mixer_selem_get_playback_volume() 的存在以检索当前设置。但是在我的系统上,这似乎给了我错误的读数 - 混音器程序显示 100%,最高约为 66%。

如果我打开 pavucontrol,我可以看到这个输出设备的音量与我从这里得到的读数相匹配,所以我认为它给了我硬件音量设置,而不是我想要的全局主音量。

【问题讨论】:

    标签: c linux api audio alsa


    【解决方案1】:

    用gcc audio_volume.c -o audio_volume -lasound 编译下面的代码,或者用gcc audio_volume.c -o audio_volume_oss -DOSSCONTROL 编译。 OSS版本写的很粗糙,没有给出精确的结果。将音量设置为 100 会在我的系统中设置 97% 的音量。 ALSA 版本适用于我和 openSUSE 中的 PulseAudio。需要一些清理和爱,但我希望它是你需要的,我允许在 WTFPL license 上使用它。

    #include <unistd.h>
    #include <fcntl.h>
    
    #ifdef OSSCONTROL
    #define MIXER_DEV "/dev/dsp"
    
    #include <sys/soundcard.h>
    #include <sys/ioctl.h>
    #include <stdio.h>
    #else
    #include <alsa/asoundlib.h>
    #endif
    
    
    typedef enum {
        AUDIO_VOLUME_SET,
        AUDIO_VOLUME_GET,
    } audio_volume_action;
    
    /*
      Drawbacks. Sets volume on both channels but gets volume on one. Can be easily adapted.
     */
    int audio_volume(audio_volume_action action, long* outvol)
    {
    #ifdef OSSCONTROL
        int ret = 0;
        int fd, devs;
    
        if ((fd = open(MIXER_DEV, O_WRONLY)) > 0)
        {
            if(action == AUDIO_VOLUME_SET) {
                if(*outvol < 0 || *outvol > 100)
                    return -2;
                *outvol = (*outvol << 8) | *outvol;
                ioctl(fd, SOUND_MIXER_WRITE_VOLUME, outvol);
            }
            else if(action == AUDIO_VOLUME_GET) {
                ioctl(fd, SOUND_MIXER_READ_VOLUME, outvol);
                *outvol = *outvol & 0xff;
            }
            close(fd);
            return 0;
        }
        return -1;;
    #else
        snd_mixer_t* handle;
        snd_mixer_elem_t* elem;
        snd_mixer_selem_id_t* sid;
    
        static const char* mix_name = "Master";
        static const char* card = "default";
        static int mix_index = 0;
    
        long pmin, pmax;
        long get_vol, set_vol;
        float f_multi;
    
        snd_mixer_selem_id_alloca(&sid);
    
        //sets simple-mixer index and name
        snd_mixer_selem_id_set_index(sid, mix_index);
        snd_mixer_selem_id_set_name(sid, mix_name);
    
            if ((snd_mixer_open(&handle, 0)) < 0)
            return -1;
        if ((snd_mixer_attach(handle, card)) < 0) {
            snd_mixer_close(handle);
            return -2;
        }
        if ((snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
            snd_mixer_close(handle);
            return -3;
        }
        ret = snd_mixer_load(handle);
        if (ret < 0) {
            snd_mixer_close(handle);
            return -4;
        }
        elem = snd_mixer_find_selem(handle, sid);
        if (!elem) {
            snd_mixer_close(handle);
            return -5;
        }
    
        long minv, maxv;
    
        snd_mixer_selem_get_playback_volume_range (elem, &minv, &maxv);
        fprintf(stderr, "Volume range <%i,%i>\n", minv, maxv);
    
        if(action == AUDIO_VOLUME_GET) {
            if(snd_mixer_selem_get_playback_volume(elem, 0, outvol) < 0) {
                snd_mixer_close(handle);
                return -6;
            }
    
            fprintf(stderr, "Get volume %i with status %i\n", *outvol, ret);
            /* make the value bound to 100 */
            *outvol -= minv;
            maxv -= minv;
            minv = 0;
            *outvol = 100 * (*outvol) / maxv; // make the value bound from 0 to 100
        }
        else if(action == AUDIO_VOLUME_SET) {
            if(*outvol < 0 || *outvol > VOLUME_BOUND) // out of bounds
                return -7;
            *outvol = (*outvol * (maxv - minv) / (100-1)) + minv;
    
            if(snd_mixer_selem_set_playback_volume(elem, 0, *outvol) < 0) {
                snd_mixer_close(handle);
                return -8;
            }
            if(snd_mixer_selem_set_playback_volume(elem, 1, *outvol) < 0) {
                snd_mixer_close(handle);
                return -9;
            }
            fprintf(stderr, "Set volume %i with status %i\n", *outvol, ret);
        }
    
        snd_mixer_close(handle);
        return 0;
    #endif
        }
    
    int main(void)
    {
        long vol = -1;
        printf("Ret %i\n", audio_volume(AUDIO_VOLUME_GET, &vol));
        printf("Master volume is %i\n", vol);
    
        vol = 100;
        printf("Ret %i\n", audio_volume(AUDIO_VOLUME_SET, &vol));
    
        return 0;
    }
    

    【讨论】:

    • 除了额外的错误检查之外,这似乎与我链接的代码做同样的事情。
    • 嗯,这对我有用,很抱歉它不适合你。我不使用更高级的 PulseAudio 功能。我认为 PulseAudio 允许在内部增加超过 100% 的音量(将样本乘以 >1),所以也许你应该看看 PulseAudio API 来控制音量?
    • RushPL 如何分别改变左右声道的音量。我曾尝试分别为 0 和 1 调用“snd_mixer_selem_set_playback_volume”,但更改了整个主音量。
    • 任何 PulseAudio 示例来改变左右声道音量变化?
    • 所以您知道,在任何 Stack Exchange 站点上发布的任何和所有代码都会根据他们选择的许可自动获得许可,而不是您的许可。显然,您可以重新许可它,但 Stack Exchange 上的特定来源随该许可一起提供。
    猜你喜欢
    • 2011-02-01
    • 2014-12-22
    • 1970-01-01
    • 2011-03-02
    • 2018-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-14
    相关资源
    最近更新 更多