void VolumeControl::init()
{
	//initialize audio mixer interface
#if defined (__APPLE__)
	#error TODO: Not implemented for MacOS yet!!!
#elif defined(__linux__)
	//try to open mixer device
	if (mixerHandle == nullptr)
	{
		snd_mixer_selem_id_alloca(&mixerSelemId);
		//sets simple-mixer index and name
		snd_mixer_selem_id_set_index(mixerSelemId, mixerIndex);
		snd_mixer_selem_id_set_name(mixerSelemId, mixerName);
		//open mixer
		if (snd_mixer_open(&mixerHandle, 0) >= 0)
		{
			LOG(LogDebug) << "VolumeControl::init() - Opened ALSA mixer";
			//ok. attach to defualt card
			if (snd_mixer_attach(mixerHandle, mixerCard) >= 0)
			{
				LOG(LogDebug) << "VolumeControl::init() - Attached to default card";
				//ok. register simple element class
				if (snd_mixer_selem_register(mixerHandle, NULL, NULL) >= 0)
				{
					LOG(LogDebug) << "VolumeControl::init() - Registered simple element class";
					//ok. load registered elements
					if (snd_mixer_load(mixerHandle) >= 0)
					{
						LOG(LogDebug) << "VolumeControl::init() - Loaded mixer elements";
						//ok. find elements now
						mixerElem = snd_mixer_find_selem(mixerHandle, mixerSelemId);
						if (mixerElem != nullptr)
						{
							//wohoo. good to go...
							LOG(LogDebug) << "VolumeControl::init() - Mixer initialized";
						}
						else
						{
							LOG(LogError) << "VolumeControl::init() - Failed to find mixer elements!";
							snd_mixer_close(mixerHandle);
							mixerHandle = nullptr;
						}
					}
					else
					{
						LOG(LogError) << "VolumeControl::init() - Failed to load mixer elements!";
						snd_mixer_close(mixerHandle);
						mixerHandle = nullptr;
					}
				}
				else
				{
					LOG(LogError) << "VolumeControl::init() - Failed to register simple element class!";
					snd_mixer_close(mixerHandle);
					mixerHandle = nullptr;
				}
			}
			else
			{
				LOG(LogError) << "VolumeControl::init() - Failed to attach to default card!";
				snd_mixer_close(mixerHandle);
				mixerHandle = nullptr;
			}
		}
		else
		{
			LOG(LogError) << "VolumeControl::init() - Failed to open ALSA mixer!";
		}
	}
#elif defined(WIN32) || defined(_WIN32)
	//get windows version information
	OSVERSIONINFOEXA osVer = {sizeof(OSVERSIONINFO)};
	::GetVersionExA(reinterpret_cast<LPOSVERSIONINFOA>(&osVer));
	//check windows version
	if(osVer.dwMajorVersion < 6)
	{
		//Windows older than Vista. use mixer API. open default mixer
		if (mixerHandle == nullptr)
		{
			if (mixerOpen(&mixerHandle, 0, NULL, 0, 0) == MMSYSERR_NOERROR)
			{
				//retrieve info on the volume slider control for the "Speaker Out" line
				MIXERLINECONTROLS mixerLineControls;
				mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
				mixerLineControls.dwLineID = 0xFFFF0000; //Id of "Speaker Out" line
				mixerLineControls.cControls = 1;
				//mixerLineControls.dwControlID = 0x00000000; //Id of "Speaker Out" line's volume slider
				mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; //Get volume control
				mixerLineControls.pamxctrl = &mixerControl;
				mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
				if (mixerGetLineControls((HMIXEROBJ)mixerHandle, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
				{
					LOG(LogError) << "VolumeControl::getVolume() - Failed to get mixer volume control!";
					mixerClose(mixerHandle);
					mixerHandle = nullptr;
				}
			}
			else
			{
				LOG(LogError) << "VolumeControl::init() - Failed to open mixer!";
			}
		}
	}
	else 
	{
		//Windows Vista or above. use EndpointVolume API. get device enumerator
		if (endpointVolume == nullptr)
		{
			CoInitialize(nullptr);
			IMMDeviceEnumerator * deviceEnumerator = nullptr;
			CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
			if (deviceEnumerator != nullptr)
			{
				//get default endpoint
				IMMDevice * defaultDevice = nullptr;
				deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
				if (defaultDevice != nullptr)
				{
					//retrieve endpoint volume
					defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, nullptr, (LPVOID *)&endpointVolume);
					if (endpointVolume == nullptr)
					{
						LOG(LogError) << "VolumeControl::init() - Failed to get default audio endpoint volume!";
					}
					//release default device. we don't need it anymore
					defaultDevice->Release();
				}
				else
				{
					LOG(LogError) << "VolumeControl::init() - Failed to get default audio endpoint!";
				}
				//release device enumerator. we don't need it anymore
				deviceEnumerator->Release();
			}
			else
			{
				LOG(LogError) << "VolumeControl::init() - Failed to get audio endpoint enumerator!";
				CoUninitialize();
			}
		}
	}
#endif
}
Exemple #2
0
ALSAMixer::ALSAMixer()
{
    int err;

    initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], "AndroidOut");
    initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], "AndroidIn");

    snd_mixer_selem_id_t *sid;
    snd_mixer_selem_id_alloca(&sid);

    for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {

        if (!mMixer[i]) continue;

        mixer_info_t *info = mixerMasterProp[i].mInfo = new mixer_info_t;

        property_get (mixerMasterProp[i].propName,
                      info->name,
                      mixerMasterProp[i].propDefault);

        for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
             elem;
             elem = snd_mixer_elem_next(elem)) {

            if (!snd_mixer_selem_is_active(elem))
                continue;

            snd_mixer_selem_get_id(elem, sid);

            // Find PCM playback volume control element.
            const char *elementName = snd_mixer_selem_id_get_name(sid);

            if (info->elem == NULL &&
                strcmp(elementName, info->name) == 0 &&
                hasVolume[i] (elem)) {

                info->elem = elem;
                getVolumeRange[i] (elem, &info->min, &info->max);
                info->volume = info->max;
                setVol[i] (elem, info->volume);
                if (i == SND_PCM_STREAM_PLAYBACK &&
                    snd_mixer_selem_has_playback_switch (elem))
                    snd_mixer_selem_set_playback_switch_all (elem, 1);
                break;
            }
        }

        LOGV("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");

        for (int j = 0; mixerProp[j][i].device; j++) {

            mixer_info_t *info = mixerProp[j][i].mInfo = new mixer_info_t;

            property_get (mixerProp[j][i].propName,
                          info->name,
                          mixerProp[j][i].propDefault);

            for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
                 elem;
                 elem = snd_mixer_elem_next(elem)) {

                if (!snd_mixer_selem_is_active(elem))
                    continue;

                snd_mixer_selem_get_id(elem, sid);

                // Find PCM playback volume control element.
                const char *elementName = snd_mixer_selem_id_get_name(sid);

               if (info->elem == NULL &&
                    strcmp(elementName, info->name) == 0 &&
                    hasVolume[i] (elem)) {

                    info->elem = elem;
                    getVolumeRange[i] (elem, &info->min, &info->max);
                    info->volume = info->max;
                    setVol[i] (elem, info->volume);
                    if (i == SND_PCM_STREAM_PLAYBACK &&
                        snd_mixer_selem_has_playback_switch (elem))
                        snd_mixer_selem_set_playback_switch_all (elem, 1);
                    break;
                }
            }
            LOGV("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
        }
    }
    LOGV("mixer initialized.");
}
Exemple #3
0
gboolean show_mixer(GtkWidget *widget, GdkEvent  *event, gpointer user_data)
{

  GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(win), "SIDE Mixer");
  gtk_container_set_border_width(GTK_CONTAINER(win), 10);
  gtk_window_resize(GTK_WINDOW(win), 150, 300);
  GdkScreen *screen = gdk_screen_get_default();

  fwin = win;

  g_timeout_add(100, check_focus, win);

  GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
  GtkWidget *dsc = gtk_label_new("master");

  GtkAdjustment *adj = gtk_adjustment_new(50, 0, 100, 5, 0, 0);
  g_signal_connect(G_OBJECT(adj), "value-changed", G_CALLBACK(set_volume), NULL);
  GtkWidget     *scl = gtk_scale_new(GTK_ORIENTATION_VERTICAL, adj);
  gtk_scale_set_draw_value(GTK_SCALE(scl), FALSE);

  s_mute = gtk_toggle_button_new_with_label("mute");

  g_signal_connect(G_OBJECT(s_mute), "toggled", G_CALLBACK(set_mute), (gpointer) adj);


  gtk_box_pack_end(GTK_BOX(box), s_mute, FALSE, FALSE, 0);


  gtk_container_add(GTK_CONTAINER(box), dsc);
  gtk_box_pack_end(GTK_BOX(box), scl, TRUE, TRUE, 5);


    int x, y;
    gtk_window_get_size(GTK_WINDOW(win), &x, &y);
    gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
    gtk_window_move(GTK_WINDOW(win), gdk_screen_get_width(screen), gdk_screen_get_height(screen) - (y+25));



  gtk_container_add(GTK_CONTAINER(win), box);
  gtk_widget_show_all(win);


  snd_mixer_t *mix;
  snd_mixer_selem_id_t *sid;
  const char *card = "default";
  const char *selem_name = "Master";

  long val, max, min;

  snd_mixer_open(&mix, 0);
  snd_mixer_attach(mix, card);
  snd_mixer_selem_register(mix, NULL, NULL);
  snd_mixer_load(mix);

  snd_mixer_selem_id_alloca(&sid);
  snd_mixer_selem_id_set_index(sid, 0);
  snd_mixer_selem_id_set_name(sid, selem_name);
  snd_mixer_elem_t* elem = snd_mixer_find_selem(mix, sid);

  snd_mixer_selem_get_playback_volume_range(elem, &min, &max);

  snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO  , &val);
  gtk_adjustment_set_value(adj, 100 - (int)  100 * val / max);


  snd_mixer_close(mix);



  return FALSE;
}
Exemple #4
0
static void set_mixer(const char *device, const char *mixer, int mixer_index, bool setmax, float ldB, float rdB) {
	int err;
	long nleft, nright;
	long min, max;
	snd_mixer_t *handle;
	snd_mixer_selem_id_t *sid;
	snd_mixer_elem_t* elem;

	if ((err = snd_mixer_open(&handle, 0)) < 0) {
		LOG_ERROR("open error: %s", snd_strerror(err));
		return;
	}
	if ((err = snd_mixer_attach(handle, device)) < 0) {
		LOG_ERROR("attach error: %s", snd_strerror(err));
		snd_mixer_close(handle);
		return;
	}
	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;
	}

	snd_mixer_selem_id_alloca(&sid);

	snd_mixer_selem_id_set_index(sid, mixer_index);
	snd_mixer_selem_id_set_name(sid, mixer);

	if ((elem = snd_mixer_find_selem(handle, sid)) == NULL) {
		LOG_ERROR("error find selem %s", mixer);
		snd_mixer_close(handle);
		return;
	}

	if (snd_mixer_selem_has_playback_switch(elem)) {
		snd_mixer_selem_set_playback_switch_all(elem, 1); // unmute
	}

	err = snd_mixer_selem_get_playback_dB_range(elem, &min, &max);

	if (err < 0 || max - min < 1000) {
		// unable to get db range or range is less than 10dB - ignore and set using raw values
		if ((err = snd_mixer_selem_get_playback_volume_range(elem, &min, &max)) < 0) {
			LOG_ERROR("unable to get volume raw range");
		} else {
			long lraw, rraw;
			if (setmax) {
				lraw = rraw = max;
			} else {
				lraw = ((ldB > -MINVOL_DB ? MINVOL_DB + floor(ldB) : 0) / MINVOL_DB * (max-min)) + min;
				rraw = ((rdB > -MINVOL_DB ? MINVOL_DB + floor(rdB) : 0) / MINVOL_DB * (max-min)) + min;
			}
			LOG_DEBUG("setting vol raw [%ld..%ld]", min, max);
			if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, lraw)) < 0) {
				LOG_ERROR("error setting left volume: %s", snd_strerror(err));
			}
			if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, rraw)) < 0) {
				LOG_ERROR("error setting right volume: %s", snd_strerror(err));
			}
		}
	} else {
		// set db directly
		LOG_DEBUG("setting vol dB [%ld..%ld]", min, max);
		if (setmax) {
			// set to 0dB if available as this should be max volume for music recored at max pcm values
			if (max >= 0 && min <= 0) {
				ldB = rdB = 0;
			} else {
				ldB = rdB = max;
			}
		}
		if ((err = snd_mixer_selem_set_playback_dB(elem, SND_MIXER_SCHN_FRONT_LEFT, 100 * ldB, 1)) < 0) {
			LOG_ERROR("error setting left volume: %s", snd_strerror(err));
		}
		if ((err = snd_mixer_selem_set_playback_dB(elem, SND_MIXER_SCHN_FRONT_RIGHT, 100 * rdB, 1)) < 0) {
			LOG_ERROR("error setting right volume: %s", snd_strerror(err));
		}
	}

	if ((err = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &nleft)) < 0) {
		LOG_ERROR("error getting left vol: %s", snd_strerror(err));
	}
	if ((err = snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &nright)) < 0) {
		LOG_ERROR("error getting right vol: %s", snd_strerror(err));
	}

	LOG_DEBUG("%s left: %3.1fdB -> %ld right: %3.1fdB -> %ld", mixer, ldB, nleft, rdB, nright);

	snd_mixer_close(handle);
}
Exemple #5
0
/**
 * Initializes the alsa system by getting the cards
 * and channels and setting the io watch for external
 * volume changes.
 *
 * @return 0 on success otherwise negative error code
 */
static int
alsaset(void)
{
    char *card_name;
    char *channel;

    // update list of available cards
    DEBUG_PRINT("Getting available cards...");
    get_cards();
    assert(cards != NULL);

    // get selected card
    assert(active_card == NULL);
    card_name = get_selected_card();
    DEBUG_PRINT("Selected card: %s", card_name);
    if (card_name) {
        active_card = find_card(card_name);
        g_free(card_name);
    }
    // if not available, use the default card
    if (!active_card) {
        DEBUG_PRINT("Using default soundcard");
        active_card = cards->data;
    }
    // If no playable channels, iterate on card list until a valid card is
    // found.
    // In most situations, the first card of the list (which is the
    // Alsa default card) can be opened.
    // However, in some situations the default card may be unavailable.
    // For example, when it's an USB DAC, and it's disconnected.
    if (!active_card->channels) {
        GSList *item;
        DEBUG_PRINT("Card '%s' has no playable channels, iterating on card list",
                    active_card->dev);
        for (item = cards; item; item = item->next) {
            active_card = item->data;
            if (active_card->channels)
                break;
        }
        assert(item != NULL);
    }
    // open card
    DEBUG_PRINT("Opening card '%s'...", active_card->dev);
    smixer_options.device = active_card->dev;
    handle = open_mixer(active_card->dev, &smixer_options, smixer_level);
    assert(handle != NULL);

    // Set the channel
    // We have to handle the fact that the channel name defined
    // in PNMixer configuration is not necessarily valid.
    // For example, this may happen when the default alsa soundcard
    // is modified. The channel names of the new default card may
    // not match the channel names of the previous default card.
    assert(elem == NULL);
    channel = get_selected_channel(active_card->name);
    if (channel) {
        snd_mixer_selem_id_t *sid;
        snd_mixer_selem_id_alloca(&sid);
        snd_mixer_selem_id_set_name(sid, channel);
        elem = snd_mixer_find_selem(handle, sid);
        g_free(channel);
    }
    if (elem == NULL) {
        elem = snd_mixer_first_elem(handle);
    }
    assert(elem != NULL);

    // Set callback
    DEBUG_PRINT("Using channel '%s'", snd_mixer_selem_get_name(elem));
    snd_mixer_elem_set_callback(elem, alsa_cb);

    // set watch for volume changes
    set_io_watch(handle);

    return 0;
}
static int init(int argc, char **argv) {
  const char *str;
  int value;

  int hardware_mixer = 0;

  config.audio_backend_latency_offset = 0;           // this is the default for ALSA
  config.audio_backend_buffer_desired_length = 6615; // default for alsa with a software mixer
  
  

  // get settings from settings file first, allow them to be overridden by command line options

  if (config.cfg != NULL) {
    /* Get the desired buffer size setting. */
    if (config_lookup_int(config.cfg, "alsa.audio_backend_buffer_desired_length_software", &value)) {
      if ((value < 0) || (value > 66150))
        die("Invalid alsa audio backend buffer desired length (software) \"%d\". It should be between 0 and "
            "66150, default is 6615",
            value);
      else {
        config.audio_backend_buffer_desired_length = value;
      }
    }
    
    /* Get the latency offset. */
    if (config_lookup_int(config.cfg, "alsa.audio_backend_latency_offset", &value)) {
      if ((value < -66150) || (value > 66150))
        die("Invalid alsa audio backend buffer latency offset \"%d\". It should be between -66150 and +66150, default is 0",
            value);
      else
        config.audio_backend_latency_offset = value;
    }

    /* Get the Output Device Name. */
    if (config_lookup_string(config.cfg, "alsa.output_device", &str)) {
      alsa_out_dev = (char *)str;
    }


    /* Get the Mixer Type setting. */

    if (config_lookup_string(config.cfg, "alsa.mixer_type", &str)) {
      inform("The alsa mixer_type setting is deprecated and has been ignored. FYI, using the \"mixer_control_name\" setting automatically chooses a hardware mixer.");
    }
    

    /* Get the Mixer Device Name. */
    if (config_lookup_string(config.cfg, "alsa.mixer_device", &str)) {
      alsa_mix_dev = (char *)str;
    }

    /* Get the Mixer Control Name. */
    if (config_lookup_string(config.cfg, "alsa.mixer_control_name", &str)) {
      alsa_mix_ctrl = (char *)str;
      hardware_mixer = 1;
    }
  }

  optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour
  argv--;     // so we shift the arguments to satisfy getopt()
  argc++;
  // some platforms apparently require optreset = 1; - which?
  int opt;
  while ((opt = getopt(argc, argv, "d:t:m:c:i:")) > 0) {
    switch (opt) {
    case 'd':
      alsa_out_dev = optarg;
      break;

    case 't':
      inform("The alsa backend -t option is deprecated and has been ignored. FYI, using the -c option automatically chooses a hardware mixer.");
      break;

    case 'm':
      alsa_mix_dev = optarg;
      break;
    case 'c':
      alsa_mix_ctrl = optarg;
      hardware_mixer = 1;
      break;
    case 'i':
      alsa_mix_index = strtol(optarg, NULL, 10);
      break;
    default:
      help();
      die("Invalid audio option -%c specified", opt);
    }
  }

  if (optind < argc)
    die("Invalid audio argument: %s", argv[optind]);
  
  debug(1,"Output device name is \"%s\".",alsa_out_dev);

  if (!hardware_mixer)
    return 0;

  if (alsa_mix_dev == NULL)
    alsa_mix_dev = alsa_out_dev;

  int ret = 0;
  
  snd_mixer_selem_id_alloca(&alsa_mix_sid);
  snd_mixer_selem_id_set_index(alsa_mix_sid, alsa_mix_index);
  snd_mixer_selem_id_set_name(alsa_mix_sid, alsa_mix_ctrl);

  if ((snd_mixer_open(&alsa_mix_handle, 0)) < 0)
    die("Failed to open mixer");
  debug(1,"Mixer device name is \"%s\".",alsa_mix_dev);
  if ((snd_mixer_attach(alsa_mix_handle, alsa_mix_dev)) < 0)
    die("Failed to attach mixer");
  if ((snd_mixer_selem_register(alsa_mix_handle, NULL, NULL)) < 0)
    die("Failed to register mixer element");

  ret = snd_mixer_load(alsa_mix_handle);
  if (ret < 0)
    die("Failed to load mixer element");
  
  debug(1,"Mixer Control name is \"%s\".",alsa_mix_ctrl);
    
  alsa_mix_elem = snd_mixer_find_selem(alsa_mix_handle, alsa_mix_sid);    
  if (!alsa_mix_elem)
    die("Failed to find mixer element");

 
  if (snd_mixer_selem_get_playback_volume_range(alsa_mix_elem, &alsa_mix_minv, &alsa_mix_maxv) < 0)
    debug(1, "Can't read mixer's [linear] min and max volumes.");
  else {
    if (snd_mixer_selem_get_playback_dB_range (alsa_mix_elem, &alsa_mix_mindb, &alsa_mix_maxdb) == 0) {

      audio_alsa.volume = &volume; // insert the volume function now we know it can do dB stuff
      audio_alsa.parameters = &parameters; // likewise the parameters stuff
      if (alsa_mix_mindb == SND_CTL_TLV_DB_GAIN_MUTE) {
        // Raspberry Pi does this
        debug(1, "Lowest dB value is a mute.");
        if (snd_mixer_selem_ask_playback_vol_dB(alsa_mix_elem, alsa_mix_minv + 1,
                                                &alsa_mix_mindb) == 0)
          debug(1, "Can't get dB value corresponding to a \"volume\" of 1.");
      }
      debug(1, "Hardware mixer has dB volume from %f to %f.", (1.0 * alsa_mix_mindb) / 100.0,
            (1.0 * alsa_mix_maxdb) / 100.0);
      if (config.volume_range_db) {
        long suggested_alsa_min_db = alsa_mix_maxdb - (long)trunc(config.volume_range_db*100);
        if (suggested_alsa_min_db > alsa_mix_mindb)
          alsa_mix_mindb = suggested_alsa_min_db;
        else
          inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,(alsa_mix_maxdb-alsa_mix_mindb)/100.0);
      }else{

        if(config.isset_volume_min_db){
          long suggested_alsa_min_db = (long) trunc(config.volume_min_db * 100);
          if(suggested_alsa_min_db > alsa_mix_mindb){
            alsa_mix_mindb = suggested_alsa_min_db; 
          }
        }

        if(config.isset_volume_max_db){
          long suggested_alsa_max_db = (long) trunc(config.volume_max_db * 100);
          if(suggested_alsa_max_db < alsa_mix_maxdb){
            alsa_mix_maxdb = suggested_alsa_max_db;
          }
        }
        
      }
    } else {
      // use the linear scale and do the db conversion ourselves
      debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have a dB volume scale, so it can't be used.",alsa_mix_ctrl);
      /*
      debug(1, "Min and max volumes are %d and %d.",alsa_mix_minv,alsa_mix_maxv);
      alsa_mix_maxdb = 0;
      if ((alsa_mix_maxv!=0) && (alsa_mix_minv!=0))
        alsa_mix_mindb = -20*100*(log10(alsa_mix_maxv*1.0)-log10(alsa_mix_minv*1.0));
      else if (alsa_mix_maxv!=0)
        alsa_mix_mindb = -20*100*log10(alsa_mix_maxv*1.0);
      audio_alsa.volume = &linear_volume; // insert the linear volume function
      audio_alsa.parameters = &parameters; // likewise the parameters stuff
      debug(1,"Max and min dB calculated are %d and %d.",alsa_mix_maxdb,alsa_mix_mindb);
      */
     }
  }
  if (snd_mixer_selem_has_playback_switch(alsa_mix_elem)) {
    has_mute = 1;
    debug(1, "Has mute ability.");
  }
  return 0;
}
Exemple #7
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;
}
ALSAMixer::ALSAMixer(const char *sndcard)
{
    int err;
    LOGI(" Init ALSAMIXER for SNDCARD : %s",sndcard);

    mixerMasterProp =
        ALSA_PROP(AudioSystem::DEVICE_OUT_ALL, "master", "PCM", "Capture");
        
    mixerProp = {
        ALSA_PROP(AudioSystem::DEVICE_OUT_EARPIECE, "earpiece", "Earpiece", "Capture"),
        ALSA_PROP(AudioSystem::DEVICE_OUT_SPEAKER, "speaker", "Speaker",  ""),
        ALSA_PROP(AudioSystem::DEVICE_OUT_WIRED_HEADSET, "headset", "Headphone", "Capture"),
        ALSA_PROP(AudioSystem::DEVICE_OUT_BLUETOOTH_SCO, "bluetooth.sco", "Bluetooth", "Bluetooth Capture"),
        ALSA_PROP(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP, "bluetooth.a2dp", "Bluetooth A2DP", "Bluetooth A2DP Capture"),
        ALSA_PROP(static_cast<AudioSystem::audio_devices>(0), "", NULL, NULL)
    };

    initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], sndcard);
    initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], sndcard);

    snd_mixer_selem_id_t *sid;
    snd_mixer_selem_id_alloca(&sid);

    for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {

        mixer_info_t *info = mixerMasterProp[i].mInfo = new mixer_info_t;

        property_get (mixerMasterProp[i].propName,
                      info->name,
                      mixerMasterProp[i].propDefault);

        for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
             elem;
             elem = snd_mixer_elem_next(elem)) {

            if (!snd_mixer_selem_is_active(elem))
                continue;

            snd_mixer_selem_get_id(elem, sid);

            // Find PCM playback volume control element.
            const char *elementName = snd_mixer_selem_id_get_name(sid);

            if (info->elem == NULL &&
                strcmp(elementName, info->name) == 0 &&
                hasVolume[i] (elem)) {

                info->elem = elem;
                getVolumeRange[i] (elem, &info->min, &info->max);
                info->volume = info->max;
                setVol[i] (elem, info->volume);
                if (i == SND_PCM_STREAM_PLAYBACK &&
                    snd_mixer_selem_has_playback_switch (elem))
                    snd_mixer_selem_set_playback_switch_all (elem, 1);
                break;
            }
        }

        LOGV("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");

        for (int j = 0; mixerProp[j][i].device; j++) {

            mixer_info_t *info = mixerProp[j][i].mInfo = new mixer_info_t;

            property_get (mixerProp[j][i].propName,
                          info->name,
                          mixerProp[j][i].propDefault);

            for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
                 elem;
                 elem = snd_mixer_elem_next(elem)) {

                if (!snd_mixer_selem_is_active(elem))
                    continue;

                snd_mixer_selem_get_id(elem, sid);

                // Find PCM playback volume control element.
                const char *elementName = snd_mixer_selem_id_get_name(sid);

               if (info->elem == NULL &&
                    strcmp(elementName, info->name) == 0 &&
                    hasVolume[i] (elem)) {

                    info->elem = elem;
                    getVolumeRange[i] (elem, &info->min, &info->max);
                    info->volume = info->max;
                    setVol[i] (elem, info->volume);
                    if (i == SND_PCM_STREAM_PLAYBACK &&
                        snd_mixer_selem_has_playback_switch (elem))
                        snd_mixer_selem_set_playback_switch_all (elem, 1);
                    break;
                }
            }
            LOGV("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
        }
    }
    LOGV("mixer initialized.");
}
Exemple #9
0
static int
setlevels(const char *dev)
{
    snd_mixer_t *handle;
    snd_mixer_selem_id_t *sid;
    snd_mixer_elem_t *elem;
    int err;
    char *mixer_dev, *c;

    /* Basically we just want to turn on Mic capture. */
    if ((err = snd_mixer_open(&handle, 0)) < 0) {
        fprintf(stderr, "Mixer open failed: %s\n", snd_strerror(err));
        return -1;
    }

    mixer_dev = strdup(dev);
    if (strncmp(mixer_dev, "plug", 4) == 0)
        memmove(mixer_dev, mixer_dev + 4, strlen(mixer_dev) - 4 + 1);
    if ((c = strchr(mixer_dev, ',')))
        *c = '\0';
    if ((err = snd_mixer_attach(handle, mixer_dev)) < 0) {
        fprintf(stderr, "Mixer attach to %s failed: %s\n",
                mixer_dev, snd_strerror(err));
        free(mixer_dev);
        snd_mixer_close(handle);
        return -1;
    }
    free(mixer_dev);
    if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
        fprintf(stderr, "Mixer register failed: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return -1;
    }
    if ((err = snd_mixer_load(handle)) < 0) {
        fprintf(stderr, "Mixer load failed: %s\n", snd_strerror(err));
        snd_mixer_close(handle);
        return -1;
    }
    snd_mixer_selem_id_alloca(&sid);
    snd_mixer_selem_id_set_name(sid, "Mic");
    if ((elem = snd_mixer_find_selem(handle, sid)) == NULL) {
        fprintf(stderr, "Warning: Could not find Mic element\n");
    }
    else {
        if ((err = snd_mixer_selem_set_capture_switch_all(elem, 1)) < 0) {
            fprintf(stderr,
                    "Failed to enable microphone capture: %s\n",
                    snd_strerror(err));
            snd_mixer_close(handle);
            return -1;
        }
    }
    snd_mixer_selem_id_set_name(sid, "Capture");
    if ((elem = snd_mixer_find_selem(handle, sid)) == NULL) {
        fprintf(stderr, "Warning: Could not find Capture element\n");
    }
    else {
        if ((err = snd_mixer_selem_set_capture_switch_all(elem, 1)) < 0) {
            fprintf(stderr,
                    "Failed to enable microphone capture: %s\n",
                    snd_strerror(err));
            snd_mixer_close(handle);
            return -1;
        }
    }

    return 0;
}
Exemple #10
0
static int init(int argc, char **argv) {
    int hardware_mixer = 0;

    optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour
    argv--;     // so we shift the arguments to satisfy getopt()
    argc++;
    // some platforms apparently require optreset = 1; - which?
    int opt;
    while ((opt = getopt(argc, argv, "d:t:m:c:i:")) > 0) {
        switch (opt) {
            case 'd':
                alsa_out_dev = optarg;
                break;
            case 't':
                if (strcmp(optarg, "hardware") == 0)
                    hardware_mixer = 1;
                break;
            case 'm':
                alsa_mix_dev = optarg;
                break;
            case 'c':
                alsa_mix_ctrl = optarg;
                break;
            case 'i':
                alsa_mix_index = strtol(optarg, NULL, 10);
                break;
            default:
                help();
                die("Invalid audio option -%c specified", opt);
        }
    }

    if (optind < argc)
        die("Invalid audio argument: %s", argv[optind]);

    if (!hardware_mixer)
        return 0;

    if (alsa_mix_dev == NULL)
        alsa_mix_dev = alsa_out_dev;
    audio_alsa.volume = &volume;

    int ret = 0;
    long alsa_mix_maxv;

    snd_mixer_selem_id_alloca(&alsa_mix_sid);
    snd_mixer_selem_id_set_index(alsa_mix_sid, alsa_mix_index);
    snd_mixer_selem_id_set_name(alsa_mix_sid, alsa_mix_ctrl);

    if ((snd_mixer_open(&alsa_mix_handle, 0)) < 0)
        die ("Failed to open mixer");
    if ((snd_mixer_attach(alsa_mix_handle, alsa_mix_dev)) < 0)
        die ("Failed to attach mixer");
    if ((snd_mixer_selem_register(alsa_mix_handle, NULL, NULL)) < 0)
        die ("Failed to register mixer element");

    ret = snd_mixer_load(alsa_mix_handle);
    if (ret < 0)
        die ("Failed to load mixer element");
    alsa_mix_elem = snd_mixer_find_selem(alsa_mix_handle, alsa_mix_sid);
    if (!alsa_mix_elem)
        die ("Failed to find mixer element");
    snd_mixer_selem_get_playback_volume_range (alsa_mix_elem, &alsa_mix_minv, &alsa_mix_maxv);
    alsa_mix_range = alsa_mix_maxv - alsa_mix_minv;

    return 0;
}
static int
mixer_open(void)
{
  snd_mixer_elem_t *elem;
  snd_mixer_elem_t *master;
  snd_mixer_elem_t *pcm;
  snd_mixer_elem_t *custom;
  snd_mixer_selem_id_t *sid;
  int ret;

  ret = snd_mixer_open(&mixer_hdl, 0);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Failed to open mixer: %s\n", snd_strerror(ret));

      mixer_hdl = NULL;
      return -1;
    }

  ret = snd_mixer_attach(mixer_hdl, card_name);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Failed to attach mixer: %s\n", snd_strerror(ret));

      goto out_close;
    }

  ret = snd_mixer_selem_register(mixer_hdl, NULL, NULL);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Failed to register mixer: %s\n", snd_strerror(ret));

      goto out_detach;
    }

  ret = snd_mixer_load(mixer_hdl);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Failed to load mixer: %s\n", snd_strerror(ret));

      goto out_detach;
    }

  /* Grab interesting elements */
  snd_mixer_selem_id_alloca(&sid);

  pcm = NULL;
  master = NULL;
  custom = NULL;
  for (elem = snd_mixer_first_elem(mixer_hdl); elem; elem = snd_mixer_elem_next(elem))
    {
      snd_mixer_selem_get_id(elem, sid);

      if (mixer_name && (strcmp(snd_mixer_selem_id_get_name(sid), mixer_name) == 0))
	{
	  custom = elem;
	  break;
	}
      else if (strcmp(snd_mixer_selem_id_get_name(sid), "PCM") == 0)
        pcm = elem;
      else if (strcmp(snd_mixer_selem_id_get_name(sid), "Master") == 0)
	master = elem;
    }

  if (mixer_name)
    {
      if (custom)
	vol_elem = custom;
      else
	{
	  DPRINTF(E_LOG, L_LAUDIO, "Failed to open configured mixer element '%s'\n", mixer_name);

	  goto out_detach;
	}
    }
  else if (pcm)
    vol_elem = pcm;
  else if (master)
    vol_elem = master;
  else
    {
      DPRINTF(E_LOG, L_LAUDIO, "Failed to open PCM or Master mixer element\n");

      goto out_detach;
    }

  /* Get min & max volume */
  snd_mixer_selem_get_playback_volume_range(vol_elem, &vol_min, &vol_max);

  return 0;

 out_detach:
  snd_mixer_detach(mixer_hdl, card_name);
 out_close:
  snd_mixer_close(mixer_hdl);
  mixer_hdl = NULL;
  vol_elem = NULL;

  return -1;
}
int indicator_music_init(Indicator *indicator) {
	DBusMessage* msg;
	DBusMessageIter args, element;
	DBusPendingCall* pending;
	char *player;
	int current_type;
	
	if(!dbus.session.connection)
		return -1;
	
	if(!(msg=dbus_message_new_method_call(dbus.interface, dbus.object, dbus.interface, "ListNames")))
		return -1;
	
	if(!dbus_connection_send_with_reply(dbus.session.connection, msg, &pending, -1)) {
		dbus_connection_unref(dbus.session.connection);
		return -1;
	}
	if(!pending) {
		dbus_message_unref(msg);
		dbus_connection_unref(dbus.session.connection);
		return -1;
	}
	dbus_connection_flush(dbus.session.connection);
	dbus_message_unref(msg);
	dbus_pending_call_block(pending);

	if(!(msg=dbus_pending_call_steal_reply(pending))) {
		dbus_connection_unref(dbus.session.connection);
		return -1;
	}
	dbus_pending_call_unref(pending);

	if(!(dbus_message_iter_init(msg, &args)&&dbus_message_iter_get_arg_type(&args)==DBUS_TYPE_ARRAY)) {
		dbus_message_unref(msg);
		dbus_connection_unref(dbus.session.connection);
		return -1;
	}
	
	for(dbus_message_iter_recurse(&args, &element); (current_type=dbus_message_iter_get_arg_type(&element))!=DBUS_TYPE_INVALID; dbus_message_iter_next(&element)) {
		if(current_type!=DBUS_TYPE_STRING)
			continue;
		dbus_message_iter_get_basic(&element, &player);
		if(!strncmp(player, mpris.base, strlen(mpris.base))) {
			mediaplayer_register(player+strlen(mpris.base));
		}
	}
	dbus_message_unref(msg);
	
	dbus_bus_add_match(dbus.session.connection, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", &dbus.session.error);
	dbus_connection_flush(dbus.session.connection);
	if(dbus_error_is_set(&dbus.session.error)) { 
		dbus_connection_unref(dbus.session.connection);
		mediaplayer_deregister_all();
		return -1;
	}
	
	/*init alsa*/
	snd_mixer_selem_id_alloca(&alsa.sid);
	snd_mixer_selem_id_set_index(alsa.sid, alsa.mix_index);
	snd_mixer_selem_id_set_name(alsa.sid, alsa.mix_name);
	
	if((snd_mixer_open(&alsa.handle, 0))<0)
		return -1;
	if((snd_mixer_attach(alsa.handle, alsa.card))<0) {
		snd_mixer_close(alsa.handle);
		return -1;
	}
	if((snd_mixer_selem_register(alsa.handle, NULL, NULL))<0) {
		snd_mixer_close(alsa.handle);
		return -1;
	}
	if(snd_mixer_load(alsa.handle)<0) {
		snd_mixer_close(alsa.handle);
		return -1;
	}
	if(!(alsa.elem=snd_mixer_find_selem(alsa.handle, alsa.sid))) {
		snd_mixer_close(alsa.handle);
		return -1;
	}
	
	snd_mixer_selem_get_playback_volume_range (alsa.elem, &alsa.minv, &alsa.maxv);
	return 0;
}
ALSAMixer::ALSAMixer()
{
    int err;

    initMixer (&mMixer[SND_PCM_STREAM_PLAYBACK], "AndroidOut");
    initMixer (&mMixer[SND_PCM_STREAM_CAPTURE], "AndroidIn");

    snd_mixer_selem_id_t *sid;
    snd_mixer_selem_id_alloca(&sid);

    for (int i = 0; i <= SND_PCM_STREAM_LAST; i++) {

        mixer_info_t *info = mixerMasterProp[i].mInfo = new mixer_info_t;

        property_get (mixerMasterProp[i].propName,
                      info->name,
                      mixerMasterProp[i].propDefault);

        for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
             elem;
             elem = snd_mixer_elem_next(elem)) {

            if (!snd_mixer_selem_is_active(elem))
                continue;

            snd_mixer_selem_get_id(elem, sid);

            // Find PCM playback volume control element.
            const char *elementName = snd_mixer_selem_id_get_name(sid);

            if (info->elem == NULL &&
                strcmp(elementName, info->name) == 0 &&
                hasVolume[i] (elem)) {

                info->elem = elem;
                getVolumeRange[i] (elem, &info->min, &info->max);
                info->volume = info->max;
                setVol[i] (elem, info->volume);
                if (i == SND_PCM_STREAM_PLAYBACK &&
                    snd_mixer_selem_has_playback_switch (elem))
                    snd_mixer_selem_set_playback_switch_all (elem, 1);
                break;
            }
        }

        LOGV("Mixer: master '%s' %s.", info->name, info->elem ? "found" : "not found");

        for (int j = 0; mixerProp[j][i].device; j++) {

            mixer_info_t *info = mixerProp[j][i].mInfo = new mixer_info_t;

            property_get (mixerProp[j][i].propName,
                          info->name,
                          mixerProp[j][i].propDefault);

            for (snd_mixer_elem_t *elem = snd_mixer_first_elem(mMixer[i]);
                 elem;
                 elem = snd_mixer_elem_next(elem)) {

                if (!snd_mixer_selem_is_active(elem))
                    continue;

                snd_mixer_selem_get_id(elem, sid);

                // Find PCM playback volume control element.
                const char *elementName = snd_mixer_selem_id_get_name(sid);

               if (info->elem == NULL &&
                    strcmp(elementName, info->name) == 0 &&
                    hasVolume[i] (elem)) {

                    info->elem = elem;
                    getVolumeRange[i] (elem, &info->min, &info->max);
                    info->volume = info->max;
                    setVol[i] (elem, info->volume);
                    if (i == SND_PCM_STREAM_PLAYBACK &&
                        snd_mixer_selem_has_playback_switch (elem))
                        snd_mixer_selem_set_playback_switch_all (elem, 1);
                    break;
                }
            }
            LOGV("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
        }
    }

#ifdef AUDIO_MODEM_TI
    ALSAControl control("hw:00");
    status_t error;
#if 0//(WORKAROUND_AVOID_VOICE_VOLUME_SATURATION == 1) //[LG_FW_P970_MERGE] - jungsoo1221.lee
    LOGV("Workaround: Voice call max volume limited to: %d", WORKAROUND_MAX_VOICE_VOLUME);
#endif
#if 0//(WORKAROUND_SET_VOICE_VOLUME_MIN == 1) //[LG_FW_P970_MERGE] - jungsoo1221.lee
    LOGV("Workaround: Voice call min volume limited to: %d", WORKAROUND_MIN_VOICE_VOLUME);
#endif
    for (int i = 0; inCallVolumeProp[i].device; i++) {
        mixer_incall_vol_info_t *info = inCallVolumeProp[i].mInfo = new mixer_incall_vol_info_t;

        property_get (inCallVolumeProp[i].propName,
                      info->name,
                      inCallVolumeProp[i].propDefault);

        error = control.get(info->name, info->volume, 0);
        error = control.getmin(info->name, info->min);
        error = control.getmax(info->name, info->max);

#if 0//(WORKAROUND_AVOID_VOICE_VOLUME_SATURATION == 1) //[LG_FW_P970_MERGE] - jungsoo1221.lee
        info->max = WORKAROUND_MAX_VOICE_VOLUME;
#endif
#if 0//(WORKAROUND_SET_VOICE_VOLUME_MIN == 1) //[LG_FW_P970_MERGE] - jungsoo1221.lee
        info->min = WORKAROUND_MIN_VOICE_VOLUME;
#endif

        if (error < 0) {
            LOGV("Mixer: In Call Volume '%s': not found", info->name);
        } else {
            LOGV("Mixer: In Call Volume '%s': vol. %d min. %d max. %d",
                    info->name, info->volume, info->min, info->max);
        }
    }
#endif
    LOGV("mixer initialized.");
}
Exemple #14
0
bool AlsaMixer::StepVolume( const char* channel, int step )
{
	LOG( Logger::LOG_DEBUG, "AlsaMixer::StepVolume( %s, %d )", channel, step);
	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;
		}

		for (int chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			long volume;
			if (snd_mixer_selem_get_playback_volume(elem, (snd_mixer_selem_channel_id_t)chn, &volume ) >= 0)
			{
				volume += step;
				if( volume > max )volume = max;
				if( volume < min )volume = min;

				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;
		}
		for (int chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			long volume;
			if (snd_mixer_selem_get_capture_volume(elem, (snd_mixer_selem_channel_id_t)chn, &volume ) >= 0)
			{
				volume += step;
				if( volume > max )volume = max;
				if( volume < min )volume = min;

				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 #15
0
void toggleMute(struct playerHandles *ph, int *mute){
	long val;
	int err;
	float range_p;
	long current=*mute;
	long vmin,vmax;
	char tail[OUTPUT_TAIL_SIZE];
	snd_mixer_t *handle;
	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,"PCM");

	if(snd_mixer_open(&handle,0)<0)
		return;

	if(snd_mixer_attach(handle,"default")<0){
		snd_mixer_close(handle);
		return;
	}

	if(snd_mixer_selem_register(handle,NULL,NULL)<0){
		snd_mixer_close(handle);
		return;
	}

	if(snd_mixer_load(handle)<0){
		snd_mixer_close(handle);
		return;
	}

	elem=snd_mixer_find_selem(handle,sid);
	if(!elem){
		snd_mixer_close(handle);
		return;
	}

	snd_mixer_selem_get_playback_volume_range(elem,&vmin,&vmax);
	range_p = (100.0f/(float)(vmax-vmin));
	if(*mute>0){ // Unmute and perform volume change
		*mute=0;
		sprintf(tail,"Volume: %ld%%",current);
		addStatusTail(tail,ph->outdetail);
		current=current/range_p+vmin;
	}
	else{ // Mute
		snd_mixer_selem_get_playback_volume(elem,0,&current);
		*mute=current*range_p+vmin;
		current=0;
		addStatusTail("Volume Muted",ph->outdetail);
	}
	fflush(stdout);

	if(snd_mixer_selem_set_playback_volume(elem,0,current)<0){
		snd_mixer_close(handle);
		return;
	}
	if(snd_mixer_selem_set_playback_volume(elem,1,current)<0){
		snd_mixer_close(handle);
		return;
	}

	snd_mixer_close(handle);
}
Exemple #16
0
int main(int argc, char * argv[])
{
   int pos = 125;
   long min, max;
   long gpiodelay_value = 250;		// was 50

   snd_mixer_t *handle;
   snd_mixer_selem_id_t *sid;

   const char *card = "default";
   // Previous linux driver's mixer name
   //   const char *selem_name = "Playback Digital";
   //	const char *selem_name = "PCM";
   const char *selem_name = "Digital";	// Linux 4.1.6-v7+ #810
   int x, mute_state;
   long i, currentVolume;

   printf("IQaudIO.com Pi-DAC Volume Control support Rotary Encoder) v1.5 Aug 30th 2015\n\n");

   wiringPiSetup ();

   /* pull up is needed as encoder common is grounded */
   pinMode (ENCODER_A, INPUT);
   pullUpDnControl (ENCODER_A, PUD_UP);
   pinMode (ENCODER_B, INPUT);
   pullUpDnControl (ENCODER_B, PUD_UP);

   encoderPos = pos;

   // Setup ALSA access
   snd_mixer_open(&handle, 0);
   snd_mixer_attach(handle, card);
   snd_mixer_selem_register(handle, NULL, NULL);
   snd_mixer_load(handle);

   snd_mixer_selem_id_alloca(&sid);
   snd_mixer_selem_id_set_index(sid, 0);
   snd_mixer_selem_id_set_name(sid, selem_name);
   snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);

   snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
   if (DEBUG_PRINT) printf("Returned card VOLUME range - min: %ld, max: %ld\n", min, max);

   // Minimum given is mute, we need the first real value
   min++;

   // Get current volume
   if (x = snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &currentVolume))
   {
        printf("%d %s\n", x, snd_strerror(x));
   }
   else if (DEBUG_PRINT) printf("Current ALSA volume LEFT: %ld\n", currentVolume);

   if (x = snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_RIGHT, &currentVolume))
   {
        printf("%d %s\n", x, snd_strerror(x));
   }
   else if (DEBUG_PRINT) printf("Current ALSA volume RIGHT: %ld\n", currentVolume);


   /* monitor encoder level changes */
   wiringPiISR (ENCODER_A, INT_EDGE_BOTH, &encoderPulse);
   wiringPiISR (ENCODER_B, INT_EDGE_BOTH, &encoderPulse);


   // Now sit and spin waiting for GPIO pins to go active...
   while (1)
   {
      if (encoderPos != pos)
      {
              // get current volume
	      if (x = snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &currentVolume))
              {
        		printf("%d %s\n", x, snd_strerror(x));
              }
	      else if (DEBUG_PRINT) printf(" Current ALSA volume: %ld\n", currentVolume);

              // Adjust for MUTE
	      if (currentVolume < min) 
              {
                        currentVolume = 0;
			if (DEBUG_PRINT) printf(" Current ALSA volume set to min: %ld\n", currentVolume);
              }

              // What way did the encoder go?
	      if (encoderPos > pos)
	      {
		         pos = encoderPos;
			 currentVolume = currentVolume + 10;
			 // Adjust for MAX volume
			 if (currentVolume > max) currentVolume = max;
		         if (DEBUG_PRINT) printf("Volume UP %d - %ld", pos, currentVolume);
	      }
	      else if (encoderPos < pos)
	      {
		         pos = encoderPos;
                         currentVolume = currentVolume - 10;
 
			 // Adjust for MUTE
			 if (currentVolume < min) currentVolume = 0;
		         if (DEBUG_PRINT) printf("Volume DOWN %d - %ld", pos, currentVolume);
	      }

              if (x = snd_mixer_selem_set_playback_volume_all(elem, currentVolume))
              {
                     printf(" ERROR %d %s\n", x, snd_strerror(x));
              } else if (DEBUG_PRINT) printf(" Volume successfully set to %ld using ALSA!\n", currentVolume);
	}

	// Check x times per second, MAY NEED TO ADJUST THS FREQUENCY FOR SOME ENCODERS */
	delay(gpiodelay_value); /* check pos x times per second */
   }

   // We never get here but should close the sockets etc. on exit.
   snd_mixer_close(handle);
}
Exemple #17
0
void changeVolume(struct playerHandles *ph, int mod){
	long val;
	int err;
	float range_p;
	long cur_vol,new_volume;
	long vmin,vmax;
	char tail[OUTPUT_TAIL_SIZE];
	snd_mixer_t *handle;
	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,"PCM");

	if(snd_mixer_open(&handle,0)<0)
		return;

	if(snd_mixer_attach(handle,"default")<0){
		snd_mixer_close(handle);
		return;
	}

	if(snd_mixer_selem_register(handle,NULL,NULL)<0){
		snd_mixer_close(handle);
		return;
	}

	if(snd_mixer_load(handle)<0){
		snd_mixer_close(handle);
		return;
	}

	elem=snd_mixer_find_selem(handle,sid);
	if(!elem){
		snd_mixer_close(handle);
		return;
	}

	snd_mixer_selem_get_playback_volume_range(elem,&vmin,&vmax);
	range_p = (100.0f/(float)(vmax-vmin));

	snd_mixer_selem_get_playback_volume(elem,0,&cur_vol);
	new_volume = cur_vol+vmin+mod/range_p;
	if(new_volume==cur_vol && mod!=0)new_volume+=(mod<0?-1:1);
	if(new_volume<vmin)new_volume=vmin;
	if(new_volume>vmax)new_volume=vmax;
	if(snd_mixer_selem_set_playback_volume(elem,0,new_volume)<0){
		snd_mixer_close(handle);
		return;
	}

	sprintf(tail,"Volume: %d%%",(int)((float)range_p*(float)new_volume));
	addStatusTail(tail,ph->outdetail);

	snd_mixer_selem_get_playback_volume(elem,1,&cur_vol);
	new_volume = cur_vol+vmin+mod/range_p;
	if(new_volume==cur_vol && mod!=0)new_volume+=(mod<0?-1:1);
	if(new_volume<vmin)new_volume=vmin;
	if(new_volume>vmax)new_volume=vmax;
	if(snd_mixer_selem_set_playback_volume(elem,1,new_volume)<0){
		snd_mixer_close(handle);
		return;
	}

	snd_mixer_close(handle);
}
Exemple #18
0
int getvolume(long* left_volume, long* right_volume) {
	int ret = 0;

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

	static const char* mix_name = "Master";
	static const char* card = "default";
	static int mix_index = 0;

	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 ((snd_mixer_open(&handle, 0)) < 0)
		return -1;
	if ((snd_mixer_attach(handle, card)) < 0) {
		snd_mixer_close(handle);
		return -2;
	}
	if ((snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
		snd_mixer_close(handle);
		return -3;
	}
	ret = snd_mixer_load(handle);
	if (ret < 0) {
		snd_mixer_close(handle);
		return -4;
	}
	elem = snd_mixer_find_selem(handle, sid);
	if (!elem) {
		snd_mixer_close(handle);
		return -5;
	}

	long minv;
	long  maxv;
	snd_mixer_selem_get_playback_volume_range (elem, &minv, &maxv);

	if(snd_mixer_selem_get_playback_volume(elem, 0, left_volume) < 0) {
		snd_mixer_close(handle);
		return -3;
	}

	/* make the value bound to 100 */
	*left_volume -= minv;
	maxv -= minv;
	minv = 0;
	*left_volume = 100 * (*left_volume) / maxv; // make the value bound from 0 to 100

	snd_mixer_selem_get_playback_volume_range (elem, &minv, &maxv);

	if(snd_mixer_selem_get_playback_volume(elem, 1, right_volume) < 0) {
		snd_mixer_close(handle);
		return -4;
	}

	/* make the value bound to 100 */
	*right_volume -= minv;
	maxv -= minv;
	minv = 0;
	*right_volume = 100 * (*right_volume) / maxv; // make the value bound from 0 to 100

	snd_mixer_close(handle);
	return 0;

}
Exemple #19
0
static int alsa_mixer_init(alsa_mixer_t *mixer, char *card) {
  snd_mixer_selem_id_t *sid;
  snd_mixer_elem_t *elem;
  snd_mixer_selem_id_alloca(&sid);
  int err;

  if ((err = snd_mixer_open(&mixer->handle, 0)) < 0) {
    DEBUG("Mixer %s open error: %s", card, snd_strerror(err));
    mixer->handle = NULL;
    return err;
  }

  if ((err = snd_mixer_attach(mixer->handle, card)) < 0) {
    DEBUG("Mixer %s local error: %s\n", card, snd_strerror(err));
    snd_mixer_close(mixer->handle);
    mixer->handle = NULL;
    return err;
  }

  if ((err = snd_mixer_selem_register(mixer->handle, NULL, NULL)) < 0) {
    DEBUG("Mixer register error: %s", snd_strerror(err));
    snd_mixer_close(mixer->handle);
    return err;
  }

  snd_mixer_set_callback(mixer->handle, on_mixer_event);
  err = snd_mixer_load(mixer->handle);
  if (err < 0) {
    DEBUG("Mixer %s load error: %s", card, snd_strerror(err));
    snd_mixer_close(mixer->handle);
    return err;
  }

  for (elem = snd_mixer_first_elem(mixer->handle); elem; elem = snd_mixer_elem_next(elem)) {
    const char *name = NULL;
    snd_mixer_selem_get_id(elem, sid);
    if (!snd_mixer_selem_is_active(elem))
      continue;

    name = snd_mixer_selem_id_get_name(sid);
    if(snd_mixer_selem_has_playback_volume(elem)) {
      if(strcmp(name, "Master") == 0)
        mixer->master = elem;
      else if(strcmp(name, "PCM") == 0)
        mixer->pcm = elem;
    } else if(snd_mixer_selem_has_capture_volume(elem) || snd_mixer_selem_has_capture_switch(elem)) {
      DEBUG("capture elem name = %s\n", name);
      /**make sure have one capture source if capture is available*/
      if(NULL == mixer->mic) {
        mixer->mic = elem;
      }
      /**if have Microphone, replace it*/
      if(strcmp(name, "Microphone") == 0)
        mixer->mic = elem;
      if(strcmp(name, "Capture") == 0)
        mixer->mic = elem;
    }
  }

  DEBUG("master = %x, pcm = %x, microphone = %x\n", mixer->master, mixer->pcm, mixer->mic);
  return 0;
}
Exemple #20
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 #21
0
/*
  Drawbacks. Sets volume on both channels but gets volume on one. Can be easily adapted.
 */
int audio_volume(audio_volume_action action, long* outvol) {
	int ret = 0;
	snd_mixer_t* handle;
	snd_mixer_elem_t* elem;
	snd_mixer_selem_id_t* sid;

	static const char* mix_name = "Master";
	static const char* card = "default";
	static int mix_index = 0;

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

	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 ((snd_mixer_open(&handle, 0)) < 0)
		return -1;
	if ((snd_mixer_attach(handle, card)) < 0) {
		snd_mixer_close(handle);
		return -2;
	}
	if ((snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
		snd_mixer_close(handle);
		return -3;
	}
	ret = snd_mixer_load(handle);
	if (ret < 0) {
		snd_mixer_close(handle);
		return -4;
	}
	elem = snd_mixer_find_selem(handle, sid);
	if (!elem) {
		snd_mixer_close(handle);
		return -5;
	}

	long minv, maxv;

	snd_mixer_selem_get_playback_volume_range (elem, &minv, &maxv);
	fprintf(stderr, "Volume range <%li,%li>\n", minv, maxv);

	if(action == AUDIO_VOLUME_GET) {
		if(snd_mixer_selem_get_playback_volume(elem, 0, outvol) < 0) {
			snd_mixer_close(handle);
			return -6;
		}

		fprintf(stderr, "Get volume %li with status %i\n", *outvol, ret);
		/* make the value bound to 100 */
		*outvol -= minv;
		maxv -= minv;
		minv = 0;
		*outvol = 100 * (*outvol) / maxv; // make the value bound from 0 to 100
	}
	else if(action == AUDIO_VOLUME_SET) {
		if(*outvol < 0 || *outvol > VOLUME_BOUND) // out of bounds
			return -7;
		*outvol = (*outvol * (maxv - minv) / (100-1)) + minv;

		if(snd_mixer_selem_set_playback_volume(elem, 0, *outvol) < 0) {
			snd_mixer_close(handle);
			return -8;
		}
		if(snd_mixer_selem_set_playback_volume(elem, 1, *outvol) < 0) {
			snd_mixer_close(handle);
			return -9;
		}
		fprintf(stderr, "Set volume %li with status %i\n", *outvol, ret);
	}

	snd_mixer_close(handle);
	return 0;
	}
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;
}