Exemple #1
0
void list_mixers(const char *output_device) {
	int err;
	snd_mixer_t *handle;
	snd_mixer_selem_id_t *sid;
	snd_mixer_elem_t *elem;
	char *ctl = ctl4device(output_device);
	snd_mixer_selem_id_alloca(&sid);

	LOG_INFO("listing mixers for: %s", output_device);

	if ((err = snd_mixer_open(&handle, 0)) < 0) {
		LOG_ERROR("open error: %s", snd_strerror(err));
		return;
	}
	if ((err = snd_mixer_attach(handle, ctl)) < 0) {
		LOG_ERROR("attach error: %s", snd_strerror(err));
		snd_mixer_close(handle);
		free(ctl);
		return;
	}
	free(ctl);
	if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
		LOG_ERROR("register error: %s", snd_strerror(err));
		snd_mixer_close(handle);
		return;
	}
	if ((err = snd_mixer_load(handle)) < 0) {
		LOG_ERROR("load error: %s", snd_strerror(err));
		snd_mixer_close(handle);
		return;
	}

	printf("Volume controls for %s\n", output_device);
	for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) {
		if (snd_mixer_selem_has_playback_volume(elem)) {
			snd_mixer_selem_get_id(elem, sid);
			printf("   %s", snd_mixer_selem_id_get_name(sid));
			if (snd_mixer_selem_id_get_index(sid)) {
				printf(",%d", snd_mixer_selem_id_get_index(sid));
			}
			printf("\n");
		}
	}
	printf("\n");

	snd_mixer_close(handle);
}
Exemple #2
0
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
    struct priv *p = ao->priv;
    snd_mixer_t *handle = NULL;
    switch (cmd) {
    case AOCONTROL_GET_MUTE:
    case AOCONTROL_SET_MUTE:
    case AOCONTROL_GET_VOLUME:
    case AOCONTROL_SET_VOLUME:
    {
        int err;
        snd_mixer_elem_t *elem;
        snd_mixer_selem_id_t *sid;

        long pmin, pmax;
        long get_vol, set_vol;
        float f_multi;

        if (!af_fmt_is_pcm(ao->format))
            return CONTROL_FALSE;

        snd_mixer_selem_id_alloca(&sid);

        snd_mixer_selem_id_set_index(sid, p->cfg_mixer_index);
        snd_mixer_selem_id_set_name(sid, p->cfg_mixer_name);

        err = snd_mixer_open(&handle, 0);
        CHECK_ALSA_ERROR("Mixer open error");

        err = snd_mixer_attach(handle, p->cfg_mixer_device);
        CHECK_ALSA_ERROR("Mixer attach error");

        err = snd_mixer_selem_register(handle, NULL, NULL);
        CHECK_ALSA_ERROR("Mixer register error");

        err = snd_mixer_load(handle);
        CHECK_ALSA_ERROR("Mixer load error");

        elem = snd_mixer_find_selem(handle, sid);
        if (!elem) {
            MP_VERBOSE(ao, "Unable to find simple control '%s',%i.\n",
                       snd_mixer_selem_id_get_name(sid),
                       snd_mixer_selem_id_get_index(sid));
            goto alsa_error;
        }

        snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
        f_multi = (100 / (float)(pmax - pmin));

        switch (cmd) {
        case AOCONTROL_SET_VOLUME: {
            ao_control_vol_t *vol = arg;
            set_vol = vol->left / f_multi + pmin + 0.5;

            err = snd_mixer_selem_set_playback_volume
                    (elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol);
            CHECK_ALSA_ERROR("Error setting left channel");
            MP_DBG(ao, "left=%li, ", set_vol);

            set_vol = vol->right / f_multi + pmin + 0.5;

            err = snd_mixer_selem_set_playback_volume
                    (elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol);
            CHECK_ALSA_ERROR("Error setting right channel");
            MP_DBG(ao, "right=%li, pmin=%li, pmax=%li, mult=%f\n",
                   set_vol, pmin, pmax, f_multi);
            break;
        }
        case AOCONTROL_GET_VOLUME: {
            ao_control_vol_t *vol = arg;
            snd_mixer_selem_get_playback_volume
                (elem, SND_MIXER_SCHN_FRONT_LEFT, &get_vol);
            vol->left = (get_vol - pmin) * f_multi;
            snd_mixer_selem_get_playback_volume
                (elem, SND_MIXER_SCHN_FRONT_RIGHT, &get_vol);
            vol->right = (get_vol - pmin) * f_multi;
            MP_DBG(ao, "left=%f, right=%f\n", vol->left, vol->right);
            break;
        }
        case AOCONTROL_SET_MUTE: {
            bool *mute = arg;
            if (!snd_mixer_selem_has_playback_switch(elem))
                goto alsa_error;
            if (!snd_mixer_selem_has_playback_switch_joined(elem)) {
                snd_mixer_selem_set_playback_switch
                    (elem, SND_MIXER_SCHN_FRONT_RIGHT, !*mute);
            }
            snd_mixer_selem_set_playback_switch
                (elem, SND_MIXER_SCHN_FRONT_LEFT, !*mute);
            break;
        }
        case AOCONTROL_GET_MUTE: {
            bool *mute = arg;
            if (!snd_mixer_selem_has_playback_switch(elem))
                goto alsa_error;
            int tmp = 1;
            snd_mixer_selem_get_playback_switch
                (elem, SND_MIXER_SCHN_FRONT_LEFT, &tmp);
            *mute = !tmp;
            if (!snd_mixer_selem_has_playback_switch_joined(elem)) {
                snd_mixer_selem_get_playback_switch
                    (elem, SND_MIXER_SCHN_FRONT_RIGHT, &tmp);
                *mute &= !tmp;
            }
            break;
        }
        }
        snd_mixer_close(handle);
        return CONTROL_OK;
    }

    } //end switch
    return CONTROL_UNKNOWN;

alsa_error:
    if (handle)
        snd_mixer_close(handle);
    return CONTROL_ERROR;
}
Exemple #3
0
static int open_mixer(PxDev *dev, int card, int playback)
{
   snd_mixer_elem_t *elem;
   char name[256];
   int err;
   int i;

   sprintf(name, "hw:%d", card);

   dev->card = card;
   dev->handle = NULL;

   do {
      err = snd_mixer_open(&dev->handle, 0);
      if (err < 0) {
         break;
      }

      err = snd_mixer_attach(dev->handle, name);
      if (err < 0) {
         break;
      }

      err = snd_mixer_selem_register(dev->handle, NULL, NULL);
      if (err < 0) {
         break;
      }

      err = snd_mixer_load(dev->handle);
      if (err < 0) {
         break;
      }

      for (elem = snd_mixer_first_elem(dev->handle);
           elem != NULL;
           elem = snd_mixer_elem_next(elem))
      {
         if (!playback) {
            if (!snd_mixer_selem_has_capture_volume(elem) &&
                !snd_mixer_selem_has_capture_switch(elem) &&
                !snd_mixer_selem_has_common_volume(elem)) {
               continue;
            }
         }
         else {
            if (!snd_mixer_selem_has_playback_volume(elem) &&
                !snd_mixer_selem_has_playback_switch(elem) &&
                !snd_mixer_selem_has_common_volume(elem)) {
               continue;
            }
         }
         dev->numselems++;
      }

      dev->selems = calloc(dev->numselems, sizeof(PxSelem));
      if (dev->selems == NULL) {
         break;
      }

      i = 0;
      for (elem = snd_mixer_first_elem(dev->handle);
           elem != NULL;
           elem = snd_mixer_elem_next(elem))
      {
         if (!playback) {
            if (!snd_mixer_selem_has_capture_volume(elem) &&
                !snd_mixer_selem_has_capture_switch(elem) &&
                !snd_mixer_selem_has_common_volume(elem)) {
               continue;
            }
         }
         else {
            if (!snd_mixer_selem_has_playback_volume(elem) &&
                !snd_mixer_selem_has_playback_switch(elem) &&
                !snd_mixer_selem_has_common_volume(elem)) {
               continue;
            }
         }
               
         if (snd_mixer_selem_id_malloc(&dev->selems[i].sid) < 0) {
            break;
         }

         snd_mixer_selem_get_id(elem, dev->selems[i].sid);
         dev->selems[i].elem = elem;

         snprintf(name,
                  sizeof(name),
                  "%s:%d",
                  snd_mixer_selem_id_get_name(dev->selems[i].sid),
                  snd_mixer_selem_id_get_index(dev->selems[i].sid));

         dev->selems[i].name = strdup(name);
         if (!dev->selems[i].name) {
            break;
         }
         i++;
      }

      if (i == dev->numselems) {
         return TRUE;
      }

   } while (FALSE);

   if (dev->selems) {
      for (i = 0; i < dev->numselems; i++) {
         if (dev->selems[i].sid) {
            snd_mixer_selem_id_free(dev->selems[i].sid);
         }
         if (dev->selems[i].name) {
            free(dev->selems[i].name);
         }
      }
      free(dev->selems);
      dev->selems = NULL;
   }

   if (dev->handle) {
      snd_mixer_close(dev->handle);
      dev->handle = NULL;
   }

   return FALSE;
}
Exemple #4
0
/* to set/get/query special features/parameters */
static int control(int cmd, void *arg)
{
  switch(cmd) {
  case AOCONTROL_QUERY_FORMAT:
    return CONTROL_TRUE;
  case AOCONTROL_GET_VOLUME:
  case AOCONTROL_SET_VOLUME:
    {
      ao_control_vol_t *vol = (ao_control_vol_t *)arg;

      int err;
      snd_mixer_t *handle;
      snd_mixer_elem_t *elem;
      snd_mixer_selem_id_t *sid;

      char *mix_name = "PCM";
      char *card = "default";
      int mix_index = 0;

      long pmin, pmax;
      long get_vol, set_vol;
      float f_multi;

      if(AF_FORMAT_IS_IEC61937(ao_data.format))
	return CONTROL_TRUE;

      if(mixer_channel) {
	 char *test_mix_index;

	 mix_name = strdup(mixer_channel);
	 if ((test_mix_index = strchr(mix_name, ','))){
		*test_mix_index = 0;
		test_mix_index++;
		mix_index = strtol(test_mix_index, &test_mix_index, 0);

		if (*test_mix_index){
		  mp_msg(MSGT_AO,MSGL_ERR,
		    MSGTR_AO_ALSA_InvalidMixerIndexDefaultingToZero);
		  mix_index = 0 ;
		}
	 }
      }
      if(mixer_device) card = mixer_device;

      //allocate simple id
      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 (mixer_channel) {
	free(mix_name);
	mix_name = NULL;
      }

      if ((err = snd_mixer_open(&handle, 0)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerOpenError, snd_strerror(err));
	return CONTROL_ERROR;
      }

      if ((err = snd_mixer_attach(handle, card)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerAttachError,
	       card, snd_strerror(err));
	snd_mixer_close(handle);
	return CONTROL_ERROR;
      }

      if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerRegisterError, snd_strerror(err));
	snd_mixer_close(handle);
	return CONTROL_ERROR;
      }
      err = snd_mixer_load(handle);
      if (err < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerLoadError, snd_strerror(err));
	snd_mixer_close(handle);
	return CONTROL_ERROR;
      }

      elem = snd_mixer_find_selem(handle, sid);
      if (!elem) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToFindSimpleControl,
	       snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
	snd_mixer_close(handle);
	return CONTROL_ERROR;
	}

      snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
      f_multi = (100 / (float)(pmax - pmin));

      if (cmd == AOCONTROL_SET_VOLUME) {

	set_vol = vol->left / f_multi + pmin + 0.5;

	//setting channels
	if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol)) < 0) {
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingLeftChannel,
		 snd_strerror(err));
	  snd_mixer_close(handle);
	  return CONTROL_ERROR;
	}
	mp_msg(MSGT_AO,MSGL_DBG2,"left=%li, ", set_vol);

	set_vol = vol->right / f_multi + pmin + 0.5;

	if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol)) < 0) {
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingRightChannel,
		 snd_strerror(err));
	  snd_mixer_close(handle);
	  return CONTROL_ERROR;
	}
	mp_msg(MSGT_AO,MSGL_DBG2,"right=%li, pmin=%li, pmax=%li, mult=%f\n",
	       set_vol, pmin, pmax, f_multi);

	if (snd_mixer_selem_has_playback_switch(elem)) {
	  int lmute = (vol->left == 0.0);
	  int rmute = (vol->right == 0.0);
	  if (snd_mixer_selem_has_playback_switch_joined(elem)) {
	    lmute = rmute = lmute && rmute;
	  } else {
	    snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, !rmute);
	  }
	  snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, !lmute);
	}
      }
      else {
	snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &get_vol);
	vol->left = (get_vol - pmin) * f_multi;
	snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &get_vol);
	vol->right = (get_vol - pmin) * f_multi;

	mp_msg(MSGT_AO,MSGL_DBG2,"left=%f, right=%f\n",vol->left,vol->right);
      }
      snd_mixer_close(handle);
      return CONTROL_OK;
    }

  } //end switch
  return CONTROL_UNKNOWN;
}
Exemple #5
0
bool AlsaMixer::SetVolumePercent( const char* channel, int value )
{
	LOG( Logger::LOG_DEBUG, "AlsaMixer::SetVolume( %s, %d )", channel, value);
	bool success = false;
	snd_mixer_elem_t *elem;
	snd_mixer_selem_id_t *sid;
	snd_mixer_selem_id_alloca(&sid);

	snd_mixer_selem_id_set_index( sid, 0);
	snd_mixer_selem_id_set_name( sid, channel);
	elem = snd_mixer_find_selem(_handle, sid);
	if (!elem) {
		LOG( Logger::LOG_ERROR, "Unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
		goto end;
	}
	if( snd_mixer_selem_has_playback_volume(elem) )
	{
		long min, max;
		if( snd_mixer_selem_get_playback_volume_range(elem, &min, &max) < 0 )
		{
			LOG( Logger::LOG_ERROR, "Unable to get playback volume range for control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
			goto end;
		}
		int volume = ((max - min) * value) / 100 + min;
		for (int chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			if (snd_mixer_selem_set_playback_volume(elem, (snd_mixer_selem_channel_id_t)chn, volume ) >= 0)
			{
				success = true;
			}
		}
	}else if( snd_mixer_selem_has_capture_volume(elem) )
	{
		long min, max;
		if( snd_mixer_selem_get_capture_volume_range(elem, &min, &max) < 0 )
		{
			LOG( Logger::LOG_ERROR, "Unable to get capture volume range for control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
			goto end;
		}
		int volume = ((max - min) * value) / 100 + min;
		for (int chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			if (snd_mixer_selem_set_capture_volume(elem, (snd_mixer_selem_channel_id_t)chn, volume ) >= 0)
			{
				success = true;
			}
		}
	}
	if( !success )
	{
		LOG( Logger::LOG_ERROR, "Error setting control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
	}
 end:
	return success;
}
Exemple #6
0
bool AlsaMixer::GetChannelSwitch( const char* channel, bool* on )
{
	bool success = false;
	snd_mixer_elem_t *elem;
	snd_mixer_selem_id_t *sid;
	snd_mixer_selem_id_alloca(&sid);

	snd_mixer_selem_id_set_index( sid, 0);
	snd_mixer_selem_id_set_name( sid, channel);
	elem = snd_mixer_find_selem(_handle, sid);
	if (!elem) {
		LOG( Logger::LOG_ERROR, "Unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
		goto end;
	}

	if( snd_mixer_selem_has_playback_switch(elem) )
	{
		for (int chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			int value;
			if (snd_mixer_selem_get_playback_switch(elem, (snd_mixer_selem_channel_id_t)chn, &value) >= 0)
			{
				*on = value != 0; 
				success = true;
				break;
			}
		}
	}else if( snd_mixer_selem_has_capture_switch(elem) )
	{
		for (int chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			int value;
			if (snd_mixer_selem_get_capture_switch(elem, (snd_mixer_selem_channel_id_t)chn, &value ) >= 0)
			{
				*on = value != 0; 
				success = true;
				break;
			}
		}
	}
	if( !success )
	{
		LOG( Logger::LOG_ERROR, "Error getting control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
	}
 end:
	return success;
}
static void alsa_volume_mixer(double volume)
{
	snd_mixer_t* handle;
	snd_mixer_elem_t* elem;
	snd_mixer_selem_id_t* sid;
	unsigned c;
	long pmin, pmax;
	long v;
	int r;

	snd_mixer_selem_id_alloca(&sid);

	log_std(("sound:alsa: soundb_alsa_volume(volume:%g)\n", (double)volume));

	snd_mixer_selem_id_set_name(sid, "Master");

	r = snd_mixer_open(&handle, 0);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Mixer open error: %s\n", snd_strerror(r)));
		goto err;
	}

	r = snd_mixer_attach(handle, alsa_option.mixer_buffer);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Mixer attach error: %s\n", snd_strerror(r)));
		goto err_close;
	}

	if ((r = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
		log_std(("ERROR:sound:alsa: Mixer register error: %s\n", snd_strerror(r)));
		goto err_close;
	}

	r = snd_mixer_load(handle);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Mixer load error: %s\n", snd_strerror(r)));
		goto err_close;
	}

	elem = snd_mixer_find_selem(handle, sid);
	if (!elem) {
		log_std(("ERROR:sound:alsa: Unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)));
		goto err_close;
	}

	if (volume > 0) {
		if (snd_mixer_selem_has_playback_switch(elem)) {
			log_std(("sound:alsa: enable playback\n"));
			for(c=0;c<=SND_MIXER_SCHN_LAST;++c) {
				snd_mixer_selem_set_playback_switch(elem, c, 1);
			}
		} else {
			log_std(("sound:alsa: skip enable playback\n"));
		}

		if (snd_mixer_selem_has_playback_volume(elem)) {
			log_std(("sound:alsa: set playback volume\n"));

			snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);

			v = pmin + (pmax - pmin) * volume + 0.5;
			if (v < pmin)
				v = pmin;
			if (v > pmax)
				v = pmax;

			log_std(("sound:alsa: min:%d, max:%d, set:%d\n", (int)pmin, (int)pmax, (int)v));

			for(c=0;c<=SND_MIXER_SCHN_LAST;++c) {
				snd_mixer_selem_set_playback_volume(elem, c, v);
			}
		} else {
			log_std(("sound:alsa: skip set playback volume\n"));
		}
	} else {
		if (snd_mixer_selem_has_playback_switch(elem)) {
			log_std(("sound:alsa: disable playback\n"));
			for(c=0;c<=SND_MIXER_SCHN_LAST;++c) {
				snd_mixer_selem_set_playback_switch(elem, c, 0);
			}
		} else {
			log_std(("sound:alsa: skip disable playback\n"));
		}
	}

	snd_mixer_close(handle);

	return;

err_close:
	snd_mixer_close(handle);
err:
	return;
}