コード例 #1
0
ファイル: alsa.c プロジェクト: MichaelMcDonnell/wine
/**************************************************************************
 * 			ALSA_CheckSetVolume		[internal]
 *
 *  Helper function for Alsa volume queries.  This tries to simplify
 * the process of managing the volume.  All parameters are optional
 * (pass NULL to ignore or not use).
 *  Return values are MMSYSERR_NOERROR on success, or !0 on failure;
 * error codes are normalized into the possible documented return
 * values from waveOutGetVolume.
 */
int ALSA_CheckSetVolume(snd_hctl_t *hctl, int *out_left, int *out_right,
            int *out_min, int *out_max, int *out_step,
            int *new_left, int *new_right)
{
    int rc = MMSYSERR_NOERROR;
    int value_count = 0;
    snd_hctl_elem_t *           elem = NULL;
    snd_ctl_elem_info_t *       eleminfop = NULL;
    snd_ctl_elem_value_t *      elemvaluep = NULL;
    snd_ctl_elem_id_t *         elemidp = NULL;
    const char *names[] = {"PCM Playback Volume", "Line Playback Volume", NULL};
    const char **name;


#define EXIT_ON_ERROR(f,txt,exitcode) do \
{ \
    int err; \
    if ( (err = (f) ) < 0) \
    { \
	ERR(txt " failed: %s\n", snd_strerror(err)); \
        rc = exitcode; \
        goto out; \
    } \
} while(0)

    if (! hctl)
        return MMSYSERR_NOTSUPPORTED;

    /* Allocate areas to return information about the volume */
    EXIT_ON_ERROR(snd_ctl_elem_id_malloc(&elemidp), "snd_ctl_elem_id_malloc", MMSYSERR_NOMEM);
    EXIT_ON_ERROR(snd_ctl_elem_value_malloc (&elemvaluep), "snd_ctl_elem_value_malloc", MMSYSERR_NOMEM);
    EXIT_ON_ERROR(snd_ctl_elem_info_malloc (&eleminfop), "snd_ctl_elem_info_malloc", MMSYSERR_NOMEM);
    snd_ctl_elem_id_clear(elemidp);
    snd_ctl_elem_value_clear(elemvaluep);
    snd_ctl_elem_info_clear(eleminfop);

    /* Setup and find an element id that exactly matches the characteristic we want
    ** FIXME:  It is probably short sighted to hard code and fixate on PCM Playback Volume */

    for( name = names; *name; name++ )
    {
	snd_ctl_elem_id_set_name(elemidp, *name);
	snd_ctl_elem_id_set_interface(elemidp, SND_CTL_ELEM_IFACE_MIXER);
	elem = snd_hctl_find_elem(hctl, elemidp);
	if (elem)
	{
	    /* Read and return volume information */
	    EXIT_ON_ERROR(snd_hctl_elem_info(elem, eleminfop), "snd_hctl_elem_info", MMSYSERR_NOTSUPPORTED);
	    value_count = snd_ctl_elem_info_get_count(eleminfop);
	    if (out_min || out_max || out_step)
	    {
		if (!snd_ctl_elem_info_is_readable(eleminfop))
		{
		    ERR("snd_ctl_elem_info_is_readable returned false; cannot return info\n");
		    rc = MMSYSERR_NOTSUPPORTED;
		    goto out;
		}

		if (out_min)
		    *out_min = snd_ctl_elem_info_get_min(eleminfop);

		if (out_max)
		    *out_max = snd_ctl_elem_info_get_max(eleminfop);

		if (out_step)
		    *out_step = snd_ctl_elem_info_get_step(eleminfop);
	    }

	    if (out_left || out_right)
	    {
		EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED);

		if (out_left)
		    *out_left = snd_ctl_elem_value_get_integer(elemvaluep, 0);

		if (out_right)
		{
		    if (value_count == 1)
			*out_right = snd_ctl_elem_value_get_integer(elemvaluep, 0);
		    else if (value_count == 2)
			*out_right = snd_ctl_elem_value_get_integer(elemvaluep, 1);
		    else
		    {
			ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while getting volume info\n", value_count);
			rc = -1;
			goto out;
		    }
		}
	    }

	    /* Set the volume */
	    if (new_left || new_right)
	    {
		EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED);
		if (new_left)
		    snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_left);
		if (new_right)
		{
		    if (value_count == 1)
			snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_right);
		    else if (value_count == 2)
			snd_ctl_elem_value_set_integer(elemvaluep, 1, *new_right);
		    else
		    {
			ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while setting volume info\n", value_count);
			rc = -1;
			goto out;
		    }
		}

		EXIT_ON_ERROR(snd_hctl_elem_write(elem, elemvaluep), "snd_hctl_elem_write", MMSYSERR_NOTSUPPORTED);
	    }

	    break;
	}
    }

    if( !*name )
    {
        ERR("Could not find '{PCM,Line} Playback Volume' element\n");
        rc = MMSYSERR_NOTSUPPORTED;
    }


#undef EXIT_ON_ERROR

out:

    if (elemvaluep)
        snd_ctl_elem_value_free(elemvaluep);
    if (eleminfop)
        snd_ctl_elem_info_free(eleminfop);
    if (elemidp)
        snd_ctl_elem_id_free(elemidp);

    return rc;
}
コード例 #2
0
ファイル: volume.c プロジェクト: baskerville/sutils
int main(int argc, char *argv[])
{
    char *format = FORMAT;
    char *device = DEVICE;
    char *volume_control = VOLUME_CONTROL;
    char *mute_control = MUTE_CONTROL;
    int interval = INTERVAL;
    bool snoop = false;

    int opt;
    while ((opt = getopt(argc, argv, "hsf:i:d:v:m:")) != -1) {
        switch (opt) {
            case 'h':
                printf("volume [-h|-s|-f FORMAT|-i INTERVAL|-d DEVICE|-v VOLUME_CONTROL|-m MUTE_CONTROL]\n");
                exit(EXIT_SUCCESS);
                break;
            case 's':
                snoop = true;
                break;
            case 'f':
                format = optarg;
                break;
            case 'd':
                device = optarg;
                break;
            case 'i':
                interval = atoi(optarg);
                break;
            case 'v':
                volume_control = optarg;
                break;
            case 'm':
                mute_control = optarg;
                break;
        }
    }

    int exit_code;

    snd_hctl_t *hctl;
    snd_ctl_elem_id_t *volume_id;
    snd_ctl_elem_id_t *mute_id;
    snd_ctl_elem_value_t *volume_ctl;
    snd_ctl_elem_value_t *mute_ctl;
    snd_ctl_elem_info_t *volume_info;
    snd_hctl_elem_t *volume_elem;
    snd_hctl_elem_t *mute_elem;
    int vol_max, vol_min;

    if (snd_hctl_open(&hctl, device, 0) || snd_hctl_load(hctl)) {
        return EXIT_FAILURE;
    }

    snd_ctl_elem_id_malloc(&volume_id);
    snd_ctl_elem_id_malloc(&mute_id);
    snd_ctl_elem_value_malloc(&volume_ctl);
    snd_ctl_elem_value_malloc(&mute_ctl);
    snd_ctl_elem_info_malloc(&volume_info);

    snd_ctl_elem_id_set_interface(volume_id, SND_CTL_ELEM_IFACE_MIXER);
    snd_ctl_elem_id_set_interface(mute_id, SND_CTL_ELEM_IFACE_MIXER);
    snd_ctl_elem_id_set_name(volume_id, volume_control);
    snd_ctl_elem_id_set_name(mute_id, mute_control);

    snd_ctl_elem_value_set_id(volume_ctl, volume_id);
    snd_ctl_elem_value_set_id(mute_ctl, mute_id);
    volume_elem = snd_hctl_find_elem(hctl, volume_id);
    mute_elem = snd_hctl_find_elem(hctl, mute_id);

    snd_ctl_elem_info_set_id(volume_info, volume_id);
    snd_hctl_elem_info(volume_elem, volume_info);
    vol_min = (int)snd_ctl_elem_info_get_min(volume_info);
    vol_max = (int)snd_ctl_elem_info_get_max(volume_info);

    if (volume_elem == NULL || mute_elem == NULL) {
        snd_hctl_close(hctl);
        return EXIT_FAILURE;
    }

    struct sigaction action = {.sa_handler = &sig_handler};
    sigaction(SIGUSR1, &action, NULL);

    if (snoop)
        for (;;) {
            if (update) {
                update = false;
                continue;
            }

            if ((exit_code = put_infos(vol_min, vol_max, volume_elem, mute_elem,
                volume_ctl, mute_ctl, format)) == EXIT_FAILURE)
                break;

            sleep(interval);
        }
    else
        exit_code = put_infos(vol_min, vol_max, volume_elem, mute_elem,
            volume_ctl, mute_ctl, format);

    snd_hctl_close(hctl);
    snd_ctl_elem_id_free(volume_id);
    snd_ctl_elem_id_free(mute_id);
    snd_ctl_elem_value_free(volume_ctl);
    snd_ctl_elem_value_free(mute_ctl);
    snd_ctl_elem_info_free(volume_info);
    return exit_code;
}
コード例 #3
0
ファイル: alsaspdifsink.c プロジェクト: JJCG/gst-plugins-bad
/* Try and find an IEC958 PCM device and mixer on card 0 and open it
 * This function is only used on older ALSA installs that don't have the
 * correct iec958 alias stuff set up, and relies on there being only
 * one IEC958 PCM device (relies IEC958 in the device name) and one IEC958
 * mixer control for doing the settings.
 */
static int
alsaspdifsink_find_pcm_device (AlsaSPDIFSink * sink)
{
  int err = -1, dev, idx, count;
  const gchar *ctl_name = "hw:0";
  const gchar *spdif_name = SND_CTL_NAME_IEC958 ("", PLAYBACK, NONE);
  int card = sink->card;
  gchar pcm_name[24];
  snd_pcm_t *pcm = NULL;
  snd_ctl_t *ctl = NULL;
  snd_ctl_card_info_t *info = NULL;
  snd_ctl_elem_list_t *clist = NULL;
  snd_ctl_elem_id_t *cid = NULL;
  snd_pcm_info_t *pinfo = NULL;

  GST_WARNING ("Opening IEC958 named device failed. Trying to autodetect");

  if ((err = snd_ctl_open (&ctl, ctl_name, card)) < 0)
    return err;

  snd_ctl_card_info_malloc (&info);
  snd_pcm_info_malloc (&pinfo);

  /* Find a mixer for IEC958 settings */
  snd_ctl_elem_list_malloc (&clist);
  if ((err = snd_ctl_elem_list (ctl, clist)) < 0)
    goto beach;

  if ((err =
          snd_ctl_elem_list_alloc_space (clist,
              snd_ctl_elem_list_get_count (clist))) < 0)
    goto beach;
  if ((err = snd_ctl_elem_list (ctl, clist)) < 0)
    goto beach;

  count = snd_ctl_elem_list_get_used (clist);
  for (idx = 0; idx < count; idx++) {
    if (strstr (snd_ctl_elem_list_get_name (clist, idx), spdif_name) != NULL)
      break;
  }
  if (idx == count) {
    /* No SPDIF mixer availble */
    err = 0;
    goto beach;
  }
  snd_ctl_elem_id_malloc (&cid);
  snd_ctl_elem_list_get_id (clist, idx, cid);

  /* Now find a PCM device for IEC 958 */
  if ((err = snd_ctl_card_info (ctl, info)) < 0)
    goto beach;
  dev = -1;
  do {
    if (snd_ctl_pcm_next_device (ctl, &dev) < 0)
      goto beach;
    if (dev < 0)
      break;                    /* No more devices */

    /* Filter for playback devices */
    snd_pcm_info_set_device (pinfo, dev);
    snd_pcm_info_set_subdevice (pinfo, 0);
    snd_pcm_info_set_stream (pinfo, SND_PCM_STREAM_PLAYBACK);
    if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0) {
      if (err != -ENOENT)
        goto beach;             /* Genuine error */

      /* Device has no playback streams */
      continue;
    }
    if (strstr (snd_pcm_info_get_name (pinfo), "IEC958") == NULL)
      continue;                 /* Not the device we are looking for */

    count = snd_pcm_info_get_subdevices_count (pinfo);
    GST_LOG_OBJECT (sink, "Device %d has %d subdevices\n", dev,
        snd_pcm_info_get_subdevices_count (pinfo));
    for (idx = 0; idx < count; idx++) {
      snd_pcm_info_set_subdevice (pinfo, idx);

      if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0)
        goto beach;

      g_assert (snd_pcm_info_get_stream (pinfo) == SND_PCM_STREAM_PLAYBACK);

      GST_LOG_OBJECT (sink, "Found playback stream on dev %d sub-d %d\n", dev,
          idx);

      /* Found a suitable PCM device, let's open it */
      g_snprintf (pcm_name, 24, "hw:%d,%d", card, dev);
      if ((err =
              snd_pcm_open (&(pcm), pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
        goto beach;

      break;
    }
  } while (pcm == NULL);

  if (pcm != NULL) {
    snd_ctl_elem_value_t *cval;
    snd_aes_iec958_t iec958;

    /* Have a PCM device and a mixer, set things up */
    snd_ctl_elem_value_malloc (&cval);
    snd_ctl_elem_value_set_id (cval, cid);
    snd_ctl_elem_value_get_iec958 (cval, &iec958);
    iec958.status[0] = IEC958_AES0_NONAUDIO;
    iec958.status[1] = IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER;
    iec958.status[2] = 0;
    iec958.status[3] = IEC958_AES3_CON_FS_48000;
    snd_ctl_elem_value_set_iec958 (cval, &iec958);
    snd_ctl_elem_value_free (cval);

    sink->pcm = pcm;
    pcm = NULL;
    err = 0;
  }

beach:
  if (pcm)
    snd_pcm_close (pcm);
  if (clist)
    snd_ctl_elem_list_clear (clist);
  if (ctl)
    snd_ctl_close (ctl);
  if (clist)
    snd_ctl_elem_list_free (clist);
  if (cid)
    snd_ctl_elem_id_free (cid);
  if (info)
    snd_ctl_card_info_free (info);
  if (pinfo)
    snd_pcm_info_free (pinfo);
  return err;
}