[pulseaudio-discuss] Setting the volume via API has no effect

Hugo Osvaldo Barrera hugo at barrera.io
Wed Aug 20 05:37:17 PDT 2014


Hi,

First of all, sorry for the rather long and verbose email, but I'd like to be
as specific as possible.

I'm trying to write my own volume control application, and first of all,
started fiddling with the pulseaudio api (with a threaded main loop).

I've gotten the sinks, the volume, etc, but when I _set_ a volume, it has no
effect. The API reports success, but pavucontrol reveals that it has not
changes (also, if I set it to 0%, I can still hear stuff like vlc, etc).

The code is a bit long, but pretty clear. Build with:

  clang -Wall pulse.c -o pulse `pkg-config --cflags --libs libpulse-simple`

Here's the code in question:

#include <stdio.h>
#include <pulse/introspect.h>
#include <pulse/context.h>
#include <pulse/thread-mainloop.h>
#include <pulse/error.h>
#include <unistd.h>
#include <stdlib.h>

int sink_count = 0;
// FIXME: list that can handle more than 5
pa_sink_info sinks[5];

void vol_success(pa_context *c, int success, void *userdata) {
    int i = *(int*) userdata;
    printf("Card %d, success: %d.\n", i, success);
    free(userdata);
}

void sinks_callback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) {
  if (!eol) {
      printf("Got sink %d (mute: %d, vol: %.2fdB): %s - %s.\n", i->index, i->mute,
             pa_sw_volume_to_dB(i->volume.values[0]), i->description, i->name);
      sinks[sink_count++] = *i;
  }
  else {
      printf("Got all the sinks! :D\n\n");
      pa_volume_t volume = PA_VOLUME_NORM;

      for (int i = 0; i < sink_count; i++) {
          // Copy this value because we might alter it before the other thread consumes it.
          int *idx = malloc(sizeof(int)); *idx = i;
          pa_cvolume vols = sinks[i].volume;
          pa_cvolume_set(&vols, vols.channels, volume);

          printf("Volume being set to %d (%.2fdB) on card %d (%d channels), (was %.2fdB)\n",
                 volume, pa_sw_volume_to_dB(volume), *idx, vols.channels,
                 pa_sw_volume_to_dB(sinks[i].volume.values[0]));

          pa_operation* o = pa_context_set_sink_input_volume(c, *idx, &vols, vol_success, idx);
          if (!o) {
              printf("\nError setting volume for sink: %s\n", pa_strerror(pa_context_errno(c)));
              exit(-15);
          }
          pa_operation_unref(o);
      }
  }
}

void context_state_callback(pa_context* c, void* userdata) {
    pa_operation* o;
    switch (pa_context_get_state(c)) {
        case PA_CONTEXT_UNCONNECTED:
        case PA_CONTEXT_CONNECTING:
        case PA_CONTEXT_AUTHORIZING:
        case PA_CONTEXT_SETTING_NAME:
            printf(". "); fflush(NULL);
            break;
        case PA_CONTEXT_READY:
            printf("SUCCESS!\n\n");
            o = pa_context_get_sink_info_list(c, sinks_callback, NULL);
            if (!o) {
                printf("Error getting sinks: %s\n", pa_strerror(pa_context_errno(c)));
                exit(-13);
            }
            pa_operation_unref(o);
            break;
        case PA_CONTEXT_FAILED:
            printf("The connection failed or was disconnected.\n");
            exit(-11);
        case PA_CONTEXT_TERMINATED:
            printf("The connection was terminated cleanly.\n");
            exit(-12);
        default:
            printf("Unexpected context state.\n");
    }
}

int main(void) {
    // create loop
    pa_threaded_mainloop* loop = pa_threaded_mainloop_new();
    if (!loop) {
        printf("Failed to create main loop.\n");
        exit(-1);
    }

    // start loop
    if (pa_threaded_mainloop_start(loop)) {
        printf("Failed to start main loop.\n");
        exit(-2);
    }

    // get the api
    pa_mainloop_api* api = pa_threaded_mainloop_get_api(loop);
    if (!api) {
        printf("Failed to get api.\n");
        exit(-3);
    }

    // get a context
    pa_context *c = pa_context_new(api, "volctl3");
    if (!c) {
        printf("Failed to get context.\n");
        exit(-4);
    }

    // set a callback for context state changes
    pa_context_set_state_callback(c, context_state_callback, NULL);

    pa_threaded_mainloop_lock(loop);

    // connect
    printf("About to connect: ");
    if (pa_context_connect(c, NULL, PA_CONTEXT_NOFLAGS, NULL)) {
        printf("FAILED!\n");
        exit(-5);
    }

    pa_threaded_mainloop_unlock(loop);

    // Sleep to keep the thread alive. Note that an actuall app would do stuff
    // here.
    sleep(15);

    return 0;
}

// END OF CODE

Am I going something wrong, or have I hit a bug?

Thanks,

-- 
Hugo Osvaldo Barrera
A: Because we read from top to bottom, left to right.
Q: Why should I start my reply below the quoted text?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/pulseaudio-discuss/attachments/20140820/045ddfd3/attachment.sig>


More information about the pulseaudio-discuss mailing list