void AudioDriverPulseAudio::detect_channels(bool capture) {

	pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map);

	String device = capture ? capture_device_name : device_name;
	if (device == "Default") {
		// Get the default output device name
		pa_status = 0;
		pa_operation *pa_op = pa_context_get_server_info(pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)this);
		if (pa_op) {
			while (pa_status == 0) {
				int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
				if (ret < 0) {
					ERR_PRINT("pa_mainloop_iterate error");
				}
			}

			pa_operation_unref(pa_op);
		} else {
			ERR_PRINT("pa_context_get_server_info error");
		}
	}

	char dev[1024];
	if (device == "Default") {
		strcpy(dev, capture ? capture_default_device.utf8().get_data() : default_device.utf8().get_data());
	} else {
		strcpy(dev, device.utf8().get_data());
	}

	// Now using the device name get the amount of channels
	pa_status = 0;
	pa_operation *pa_op;
	if (capture) {
		pa_op = pa_context_get_source_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_source_info_cb, (void *)this);
	} else {
		pa_op = pa_context_get_sink_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this);
	}

	if (pa_op) {
		while (pa_status == 0) {
			int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
			if (ret < 0) {
				ERR_PRINT("pa_mainloop_iterate error");
			}
		}

		pa_operation_unref(pa_op);
	} else {
		if (capture) {
			ERR_PRINT("pa_context_get_source_info_by_name error");
		} else {
			ERR_PRINT("pa_context_get_sink_info_by_name error");
		}
	}
}
Exemple #2
0
static void toggle_mic_mute(pa_context *c)
{
	pa_operation *o;

	o = pa_context_get_source_info_by_name(c, "@DEFAULT_SOURCE@",
					       source_toggle_mute_callback,
					       NULL);
	if (!o) {
		fprintf(stderr, "Operation failed: %s\n",
			pa_strerror(pa_context_errno(c)));
		return;
	}
	pa_operation_unref(o);
}
Exemple #3
0
static gchar *
gst_pulsesrc_device_description (GstPulseSrc * pulsesrc)
{
  pa_operation *o = NULL;
  gchar *t;

  if (!pulsesrc->mainloop)
    goto no_mainloop;

  pa_threaded_mainloop_lock (pulsesrc->mainloop);

  if (!(o = pa_context_get_source_info_by_name (pulsesrc->context,
              pulsesrc->device, gst_pulsesrc_source_info_cb, pulsesrc))) {

    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
        ("pa_stream_get_source_info() failed: %s",
            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
    goto unlock;
  }

  while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {

    if (gst_pulsesrc_is_dead (pulsesrc, FALSE))
      goto unlock;

    pa_threaded_mainloop_wait (pulsesrc->mainloop);
  }

unlock:

  if (o)
    pa_operation_unref (o);

  t = g_strdup (pulsesrc->device_description);

  pa_threaded_mainloop_unlock (pulsesrc->mainloop);

  return t;

no_mainloop:
  {
    GST_DEBUG_OBJECT (pulsesrc, "have no mainloop");
    return NULL;
  }
}
int_fast32_t pulse_get_source_info(pa_source_info_cb_t cb, const char *name,
	void *userdata)
{
	if (pulse_context_ready() < 0)
		return -1;

	pulse_lock();

	pa_operation *op = pa_context_get_source_info_by_name(
		pulse_context, name, cb, userdata);
	while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
		pulse_wait();
	pa_operation_unref(op);

	pulse_unlock();

	return 0;
}
Exemple #5
0
static int pulse_update_volume(snd_ctl_pulse_t * ctl)
{
	int err;
	pa_operation *o;

	assert(ctl);

	if (!ctl->p)
		return -EBADFD;

	err = pulse_check_connection(ctl->p);
	if (err < 0)
		return err;

	o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->sink,
					     sink_info_cb, ctl);
	if (o) {
		err = pulse_wait_operation(ctl->p, o);
		pa_operation_unref(o);
	} else
		err = -EIO;

	if (err < 0)
		return err;

	o = pa_context_get_source_info_by_name(ctl->p->context,
					       ctl->source, source_info_cb,
					       ctl);
	if (o) {
		err = pulse_wait_operation(ctl->p, o);
		pa_operation_unref(o);
	} else
		err = -EIO;

	if (err < 0)
		return err;

	return 0;
}
Exemple #6
0
static void event_cb(pa_context * c, pa_subscription_event_type_t t,
		     uint32_t index, void *userdata)
{
	snd_ctl_pulse_t *ctl = (snd_ctl_pulse_t *) userdata;
	pa_operation *o;

	assert(ctl);

	if (!ctl->p || !ctl->p->mainloop || !ctl->p->context)
		return;

	o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->sink,
					     sink_info_cb, ctl);

	if (o)
		pa_operation_unref(o);

	o = pa_context_get_source_info_by_name(ctl->p->context,
					       ctl->source, source_info_cb,
					       ctl);

	if (o)
		pa_operation_unref(o);
}
Exemple #7
0
static void probe_devices(ALboolean capture)
{
    pa_threaded_mainloop *loop;

    if(capture == AL_FALSE)
        allDevNameMap = malloc(sizeof(DevMap) * 1);
    else
        allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);

    if((loop=pa_threaded_mainloop_new()) &&
       pa_threaded_mainloop_start(loop) >= 0)
    {
        pa_context *context;

        pa_threaded_mainloop_lock(loop);
        context = connect_context(loop, AL_FALSE);
        if(context)
        {
            pa_operation *o;

            if(capture == AL_FALSE)
            {
                pa_stream_flags_t flags;
                pa_sample_spec spec;
                pa_stream *stream;

                flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
                        PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;

                spec.format = PA_SAMPLE_S16NE;
                spec.rate = 44100;
                spec.channels = 2;

                stream = connect_playback_stream(NULL, loop, context, flags,
                                                 NULL, &spec, NULL);
                if(stream)
                {
                    o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), sink_device_callback, loop);
                    WAIT_FOR_OPERATION(o, loop);

                    pa_stream_disconnect(stream);
                    pa_stream_unref(stream);
                    stream = NULL;
                }

                o = pa_context_get_sink_info_list(context, sink_device_callback, loop);
            }
            else
            {
                pa_stream_flags_t flags;
                pa_sample_spec spec;
                pa_stream *stream;

                flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
                        PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE;

                spec.format = PA_SAMPLE_S16NE;
                spec.rate = 44100;
                spec.channels = 1;

                stream = connect_record_stream(NULL, loop, context, flags,
                                               NULL, &spec, NULL);
                if(stream)
                {
                    o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), source_device_callback, loop);
                    WAIT_FOR_OPERATION(o, loop);

                    pa_stream_disconnect(stream);
                    pa_stream_unref(stream);
                    stream = NULL;
                }

                o = pa_context_get_source_info_list(context, source_device_callback, loop);
            }
            WAIT_FOR_OPERATION(o, loop);

            pa_context_disconnect(context);
            pa_context_unref(context);
        }
        pa_threaded_mainloop_unlock(loop);
        pa_threaded_mainloop_stop(loop);
    }
    if(loop)
        pa_threaded_mainloop_free(loop);
}
Exemple #8
0
static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name)
{
    const char *pulse_name = NULL;
    pa_stream_flags_t flags = 0;
    pa_channel_map chanmap;
    pulse_data *data;
    pa_operation *o;
    ALuint samples;

    if(device_name)
    {
        ALuint i;

        if(!allCaptureDevNameMap)
            probe_devices(AL_TRUE);

        for(i = 0;i < numCaptureDevNames;i++)
        {
            if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0)
            {
                pulse_name = allCaptureDevNameMap[i].device_name;
                break;
            }
        }
        if(i == numCaptureDevNames)
            return ALC_INVALID_VALUE;
    }

    if(pulse_open(device) == ALC_FALSE)
        return ALC_INVALID_VALUE;

    data = device->ExtraData;
    pa_threaded_mainloop_lock(data->loop);

    data->spec.rate = device->Frequency;
    data->spec.channels = ChannelsFromDevFmt(device->FmtChans);

    switch(device->FmtType)
    {
        case DevFmtUByte:
            data->spec.format = PA_SAMPLE_U8;
            break;
        case DevFmtShort:
            data->spec.format = PA_SAMPLE_S16NE;
            break;
        case DevFmtInt:
            data->spec.format = PA_SAMPLE_S32NE;
            break;
        case DevFmtFloat:
            data->spec.format = PA_SAMPLE_FLOAT32NE;
            break;
        case DevFmtByte:
        case DevFmtUShort:
        case DevFmtUInt:
            ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
            pa_threaded_mainloop_unlock(data->loop);
            goto fail;
    }

    if(pa_sample_spec_valid(&data->spec) == 0)
    {
        ERR("Invalid sample format\n");
        pa_threaded_mainloop_unlock(data->loop);
        goto fail;
    }

    if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
    {
        ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels);
        pa_threaded_mainloop_unlock(data->loop);
        goto fail;
    }

    samples = device->UpdateSize * device->NumUpdates;
    samples = maxu(samples, 100 * device->Frequency / 1000);

    data->attr.minreq = -1;
    data->attr.prebuf = -1;
    data->attr.maxlength = samples * pa_frame_size(&data->spec);
    data->attr.tlength = -1;
    data->attr.fragsize = minu(samples, 50*device->Frequency/1000) *
                          pa_frame_size(&data->spec);

    flags |= PA_STREAM_DONT_MOVE;
    flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
    data->stream = connect_record_stream(pulse_name, data->loop, data->context,
                                         flags, &data->attr, &data->spec,
                                         &chanmap);
    if(!data->stream)
    {
        pa_threaded_mainloop_unlock(data->loop);
        goto fail;
    }
    pa_stream_set_state_callback(data->stream, stream_state_callback2, device);

    data->device_name = strdup(pa_stream_get_device_name(data->stream));
    o = pa_context_get_source_info_by_name(data->context, data->device_name,
                                           source_name_callback, device);
    WAIT_FOR_OPERATION(o, data->loop);

    pa_threaded_mainloop_unlock(data->loop);
    return ALC_NO_ERROR;

fail:
    pulse_close(device);
    return ALC_INVALID_VALUE;
}
static gboolean
gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c)
{
  int e;
  gchar *name = gst_pulse_client_name ();
  pa_operation *o = NULL;

  g_assert (c);

  c->mainloop = pa_threaded_mainloop_new ();
  g_assert (c->mainloop);

  e = pa_threaded_mainloop_start (c->mainloop);
  g_assert (e == 0);

  pa_threaded_mainloop_lock (c->mainloop);

  if (!(c->context =
          pa_context_new (pa_threaded_mainloop_get_api (c->mainloop), name))) {
    GST_WARNING_OBJECT (c->object, "Failed to create context");
    goto unlock_and_fail;
  }

  pa_context_set_state_callback (c->context,
      gst_pulsemixer_ctrl_context_state_cb, c);
  pa_context_set_subscribe_callback (c->context,
      gst_pulsemixer_ctrl_subscribe_cb, c);

  if (pa_context_connect (c->context, c->server, 0, NULL) < 0) {
    GST_WARNING_OBJECT (c->object, "Failed to connect context: %s",
        pa_strerror (pa_context_errno (c->context)));
    goto unlock_and_fail;
  }

  /* Wait until the context is ready */
  pa_threaded_mainloop_wait (c->mainloop);

  if (pa_context_get_state (c->context) != PA_CONTEXT_READY) {
    GST_WARNING_OBJECT (c->object, "Failed to connect context: %s",
        pa_strerror (pa_context_errno (c->context)));
    goto unlock_and_fail;
  }

  /* Subscribe to events */

  if (!(o =
          pa_context_subscribe (c->context,
              PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE,
              gst_pulsemixer_ctrl_success_cb, c))) {
    GST_WARNING_OBJECT (c->object, "Failed to subscribe to events: %s",
        pa_strerror (pa_context_errno (c->context)));
    goto unlock_and_fail;
  }

  c->operation_success = 0;
  while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
    pa_threaded_mainloop_wait (c->mainloop);
    CHECK_DEAD_GOTO (c, unlock_and_fail);
  }

  if (!c->operation_success) {
    GST_WARNING_OBJECT (c->object, "Failed to subscribe to events: %s",
        pa_strerror (pa_context_errno (c->context)));
    goto unlock_and_fail;
  }
  pa_operation_unref (o);
  o = NULL;

  /* Get sink info */

  if (c->type == GST_PULSEMIXER_UNKNOWN || c->type == GST_PULSEMIXER_SINK) {
    if (!(o =
            pa_context_get_sink_info_by_name (c->context, c->device,
                gst_pulsemixer_ctrl_sink_info_cb, c))) {
      GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s",
          pa_strerror (pa_context_errno (c->context)));
      goto unlock_and_fail;
    }

    c->operation_success = 0;
    while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
      pa_threaded_mainloop_wait (c->mainloop);
      CHECK_DEAD_GOTO (c, unlock_and_fail);
    }

    pa_operation_unref (o);
    o = NULL;

    if (!c->operation_success && (c->type == GST_PULSEMIXER_SINK
            || pa_context_errno (c->context) != PA_ERR_NOENTITY)) {
      GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s",
          pa_strerror (pa_context_errno (c->context)));
      goto unlock_and_fail;
    }
  }

  if (c->type == GST_PULSEMIXER_UNKNOWN || c->type == GST_PULSEMIXER_SOURCE) {
    if (!(o =
            pa_context_get_source_info_by_name (c->context, c->device,
                gst_pulsemixer_ctrl_source_info_cb, c))) {
      GST_WARNING_OBJECT (c->object, "Failed to get source info: %s",
          pa_strerror (pa_context_errno (c->context)));
      goto unlock_and_fail;
    }

    c->operation_success = 0;
    while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
      pa_threaded_mainloop_wait (c->mainloop);
      CHECK_DEAD_GOTO (c, unlock_and_fail);
    }

    pa_operation_unref (o);
    o = NULL;

    if (!c->operation_success) {
      GST_WARNING_OBJECT (c->object, "Failed to get source info: %s",
          pa_strerror (pa_context_errno (c->context)));
      goto unlock_and_fail;
    }
  }

  g_assert (c->type != GST_PULSEMIXER_UNKNOWN);

  c->track = gst_pulsemixer_track_new (c);
  c->tracklist = g_list_append (c->tracklist, c->track);

  pa_threaded_mainloop_unlock (c->mainloop);
  g_free (name);

  return TRUE;

unlock_and_fail:

  if (o)
    pa_operation_unref (o);

  if (c->mainloop)
    pa_threaded_mainloop_unlock (c->mainloop);

  g_free (name);

  return FALSE;
}
Exemple #10
0
int force_volume(char* source_name, pa_volume_t desired_volume) {
    // Create a mainloop
    pa_mainloop* pa_ml = pa_mainloop_new();
    pa_mainloop_api* pa_mlapi = pa_mainloop_get_api(pa_ml);

    // Establish PA context
    pa_context* pa_ctx = pa_context_new(pa_mlapi, "uneven");
    pa_context_connect(pa_ctx, NULL, 0, NULL);

    // Set up PA state callback
    int pa_state = 0;
    pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_state);

    // Set up event subscription
    int state = 0;
    pa_context_set_subscribe_callback(pa_ctx, source_state_cb, &state);

    // Prepare loop variables
    pa_operation* pending_op = NULL;
    pa_cvolume current_volume = {0, {0}};
    int do_update;
    int i;

    // Iterate PA mainloop until we're done or the context enters an error state
    while (done == -1 && pa_state != 2) {
        pa_mainloop_iterate(pa_ml, 1, NULL);

        // Can't do anything unless PA is ready
        if (pa_state == 1) {
            // Wait for any pending operation to complete
            if (!pending_op || (pending_op && pa_operation_get_state(pending_op) == PA_OPERATION_DONE)) {
                if (pending_op) {
                    pa_operation_unref(pending_op);
                    pending_op = NULL;
                }
                switch (state) {
                    case 0:
                        // Subscribe to source events
                        pending_op = pa_context_subscribe(pa_ctx, PA_SUBSCRIPTION_MASK_SOURCE, NULL, NULL);

                        state = 2;
                        break;
                    case 1:
                        // Idle
                        break;
                    case 2:
                        // Source change detected, retrive volume information
                        pending_op = pa_context_get_source_info_by_name(pa_ctx, source_name, get_volume_cb, &current_volume);

                        state++;
                        break;
                    case 3:
                        // Check channel volumes and reset if required
                        do_update = 0;
                        for (i = 0; i < current_volume.channels; i++) {
                            if (current_volume.values[i] != desired_volume) {
                                do_update = 1;
                                current_volume.values[i] = desired_volume;
                            }
                        }

                        if (do_update) {
                            pending_op = pa_context_set_source_volume_by_name(pa_ctx, source_name, &current_volume, NULL, NULL);
                        }

                        state = 1;
                        break;
                    default:
                        fprintf(stderr, "in state %d\n", state);
                        done = 2;
                }
            }
        }
    }

    // Clean up
    pa_context_disconnect(pa_ctx);
    pa_context_unref(pa_ctx);
    pa_mainloop_free(pa_ml);

    return done;
}