Skip to content
Snippets Groups Projects
Select Git revision
  • 4ae14570e9c4bef67b6a1f3961afc2c7fd0043bf
  • devel default
  • master
  • fo
  • jirka/typing
  • fo-base
  • mj/submit-images
  • jk/issue-96
  • jk/issue-196
  • honza/add-contestant
  • honza/mr7
  • honza/mrf
  • honza/mrd
  • honza/mra
  • honza/mr6
  • honza/submit-images
  • honza/kolo-vs-soutez
  • jh-stress-test-wip
  • shorten-schools
19 results

org_contest_task.html

Blame
  • osd-alsa.c 5.31 KiB
    /*
     *	A Simple ALSA Volume Control via OSD
     *
     *	(c) 2012 Martin Mares <mj@ucw.cz>
     */
    
    #undef DEBUG
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <getopt.h>
    #include <alsa/asoundlib.h>
    
    #include "util.h"
    #include "osd.h"
    
    static char *alsa_device = "default";
    static char *mixer_control = "Master";
    static int adjust_by;
    static int want_mute = -1;
    
    static snd_mixer_t *mixer;
    static snd_mixer_elem_t *elem;
    
    static void init_mixer(void)
    {
      int err;
    
      if (err = snd_mixer_open(&mixer, 0))
        die("snd_mixer_open failed: error %d", err);
    
      if (err = snd_mixer_attach(mixer, alsa_device))
        die("snd_mixer_attach failed: error %d", err);
    
      if (err = snd_mixer_selem_register(mixer, NULL, NULL))
        die("snd_mixer_selem_register failed: error %d", err);
    
      if (err = snd_mixer_load(mixer))
        die("snd_mixer_load: error %d", err);
    
      for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem))
        {
          const char *name = snd_mixer_selem_get_name(elem);
          int index = snd_mixer_selem_get_index(elem);
          if (!strcmp(name, mixer_control) || index)
    	{
    	  if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE)
    	    die("Unable to handle non-simple mixer controls");
    	  if (!snd_mixer_selem_is_active(elem))
    	    die("Selected mixer control is not active");
    	  DBG("Found mixer control %s[%d]\n", name, index);
    	  return;
    	}
        }
    
      die("Unable to find mixer control %s", mixer_control);
    }
    
    static int get_mute(void)
    {
      int mute_on = 0, mute_off = 0;
    
      if (snd_mixer_selem_has_playback_switch(elem))
        {
          for (snd_mixer_selem_channel_id_t ch=0; ch < SND_MIXER_SCHN_LAST; ch++)
    	{
    	  int val;
    	  if (!snd_mixer_selem_get_playback_switch(elem, ch, &val))
    	    {
    	      if (val)
    		mute_off++;
    	      else
    		mute_on++;
    	    }
    	}
        }
      DBG("Mute: on=%d off=%d\n", mute_on, mute_off);
      return !!mute_on;
    }
    
    static long get_volume(long *pmin, long *pmax)
    {
      long min, max, curr=0;
      if (!snd_mixer_selem_has_playback_volume(elem) ||
          snd_mixer_selem_get_playback_volume_range(elem, &min, &max))
        {
          *pmin = *pmax = 0;
          return 0;
        }
    
      for (snd_mixer_selem_channel_id_t ch=0; ch < SND_MIXER_SCHN_LAST; ch++)
        {
          long val;
          if (!snd_mixer_selem_get_playback_volume(elem, ch, &val))
    	{
    	  if (val > curr)
    	    curr = val;
    	}
        }
    
      DBG("Volume: min=%ld max=%ld curr=%ld\n", min, max, curr);
      *pmin = min;
      *pmax = max;
      return curr;
    }
    
    static int vol_to_perc(long curr, long min, long max)
    {
      return (100LL * (curr-min) + (max-min)/2) / (max-min);
    }
    
    static long perc_to_vol(int perc, long min, long max)
    {
      return ((long long) perc * (max-min) + 50) / 100;
    }
    
    static void show_mixer(void)
    {
      long min, max;
      long curr = get_volume(&min, &max);
      int muted = get_mute();
    
      struct osd_msg *msg = osd_new_msg();
      osd_add_line(msg, "min-duration", "0");
      char buf[256];
      snprintf(buf, sizeof(buf), "%s volume", mixer_control);
      osd_add_line(msg, NULL, buf);
      if (muted)
        osd_add_line(msg, NULL, "[mute]");
      else if (min < max)
        {
          snprintf(buf, sizeof(buf), "%d", vol_to_perc(curr, min, max));
          osd_add_line(msg, "slider", buf);
        }
      osd_send(msg);
    }
    
    
    static void set_mute(void)
    {
      if (want_mute < 0)
        return;
    
      if (want_mute == 2)
        want_mute = !get_mute();
    
      if (snd_mixer_selem_has_playback_switch(elem))
        {
          for (snd_mixer_selem_channel_id_t ch=0; ch < SND_MIXER_SCHN_LAST; ch++)
    	snd_mixer_selem_set_playback_switch(elem, ch, !want_mute);
        }
    }
    
    static void set_volume(void)
    {
      if (!adjust_by)
        return;
    
      long min, max;
      long curr = get_volume(&min, &max);
      int perc = vol_to_perc(curr, min, max);
    
      DBG("Volume: have %d %ld\n", perc, curr);
      perc += adjust_by;
      if (perc < 0)
        perc = 0;
      if (perc > 100)
        perc = 100;
      curr = perc_to_vol(perc, min, max);
      curr = min + (((long long) perc * (max-min) + 50) / 100);
      DBG("Volume: want %d %ld\n", perc, curr);
    
      for (snd_mixer_selem_channel_id_t ch=0; ch < SND_MIXER_SCHN_LAST; ch++)
        snd_mixer_selem_set_playback_volume(elem, ch, curr);
    }
    
    static void NONRET
    usage(void)
    {
      fprintf(stderr, "\
    Usage: osd-alsa <options>\n\
    \n\
    Options:\n\
    -a, --adjust=<percent>	Adjust the control by a given amount\n\
    -D, --device=<name>	ALSA device (default: `default')\n\
    -m, --mixer=<name>	Name of mixer control (default: `Master')\n\
    -0, --mute		Mute the control\n\
    -t, --toggle		Mute/unmute the control\n\
    -1, --unmute		Unmute the control\n\
    ");
      exit(1);
    }
    
    static const char short_opts[] = "01a:c:D:t";
    
    static const struct option long_opts[] = {
      { "adjust",		required_argument,	NULL,	'a' },
      { "device",		required_argument,	NULL,	'D' },
      { "mixer",		required_argument,	NULL,	'm' },
      { "mute",		no_argument,		NULL,	'0' },
      { "toggle",		no_argument,		NULL,	't' },
      { "unmute",		no_argument,		NULL,	'1' },
      { NULL,		0,			NULL,	0   },
    };
    
    int main(int argc, char **argv)
    {
      int opt;
      while ((opt = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0)
        switch (opt)
          {
          case '0':
    	want_mute = 1;
    	break;
          case '1':
    	want_mute = 0;
    	break;
          case 'a':
    	adjust_by = atoi(optarg);
    	break;
          case 'D':
    	alsa_device = optarg;
    	break;
          case 'm':
    	mixer_control = optarg;
    	break;
          case 't':
    	want_mute = 2;
    	break;
          default:
    	usage();
          }
      if (optind < argc)
        usage();
    
      init_mixer();
      osd_init();
      set_mute();
      set_volume();
      show_mixer();
      return 0;
    }