Пример #1
0
bool AlsaMixer::GetVolumePercent( const char* channel, int* value )
{
	LOG( Logger::LOG_DEBUG, "AlsaMixer::GetVolume( %s )", channel);
	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;
		}
		long volume;
		for (int chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			if (snd_mixer_selem_get_playback_volume(elem, (snd_mixer_selem_channel_id_t)chn, &volume ) >= 0)
			{
				*value = (volume - min) * 100 / ( max - min );
				success = true;
				break;
			}
		}
	}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;
		}
		long volume;
		for (int chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
			if (snd_mixer_selem_get_capture_volume(elem, (snd_mixer_selem_channel_id_t)chn, &volume ) >= 0)
			{
				*value = (volume - min) * 100 / ( max - min );
				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;
}
Пример #2
0
static snd_mixer_elem_t *find_mixer_elem_by_name(const char *goal_name)
{
	snd_mixer_elem_t *elem;
	snd_mixer_selem_id_t *sid = NULL;

	snd_mixer_selem_id_malloc(&sid);

	for (elem = snd_mixer_first_elem(alsa_mixer_handle); elem;
		 elem = snd_mixer_elem_next(elem)) {

		const char *name;

		snd_mixer_selem_get_id(elem, sid);
		name = snd_mixer_selem_id_get_name(sid);
		d_print("name = %s\n", name);
		d_print("has playback volume = %d\n", snd_mixer_selem_has_playback_volume(elem));
		d_print("has playback switch = %d\n", snd_mixer_selem_has_playback_switch(elem));

		if (strcasecmp(name, goal_name) == 0) {
			if (!snd_mixer_selem_has_playback_volume(elem)) {
				d_print("mixer element `%s' does not have playback volume\n", name);
				elem = NULL;
			}
			break;
		}
	}

	snd_mixer_selem_id_free(sid);
	return elem;
}
Пример #3
0
static int alsa_mixer_open(int *volume_max)
{
	snd_mixer_selem_id_t *sid;
	snd_mixer_elem_t *elem;
	int count;
	int rc;

	snd_mixer_selem_id_alloca(&sid);

	rc = snd_mixer_open(&alsa_mixer_handle, 0);
	if (rc < 0)
		goto error;
	rc = snd_mixer_attach(alsa_mixer_handle, alsa_mixer_device);
	if (rc < 0)
		goto error;
	rc = snd_mixer_selem_register(alsa_mixer_handle, NULL, NULL);
	if (rc < 0)
		goto error;
	rc = snd_mixer_load(alsa_mixer_handle);
	if (rc < 0)
		goto error;
	count = snd_mixer_get_count(alsa_mixer_handle);
	if (count == 0) {
		d_print("error: mixer does not have elements\n");
		return -2;
	}
	elem = snd_mixer_first_elem(alsa_mixer_handle);
	while (elem) {
		const char *name;
		int has_vol, has_switch;

		snd_mixer_selem_get_id(elem, sid);
		name = snd_mixer_selem_id_get_name(sid);
		d_print("name = %s\n", name);
		d_print("has playback volume = %d\n", snd_mixer_selem_has_playback_volume(elem));
		d_print("has playback switch = %d\n", snd_mixer_selem_has_playback_switch(elem));
		if (strcasecmp(name, alsa_mixer_element)) {
			elem = snd_mixer_elem_next(elem);
			continue;
		}
		has_vol = snd_mixer_selem_has_playback_volume(elem);
		if (!has_vol) {
			d_print("mixer element `%s' does not have playback volume\n", name);
			return -2;
		}
		snd_mixer_selem_get_playback_volume_range(elem,
				&mixer_vol_min, &mixer_vol_max);
		has_switch = snd_mixer_selem_has_playback_switch(elem);
		/* FIXME: get number of channels */
		mixer_elem = elem;
		*volume_max = mixer_vol_max - mixer_vol_min;
		return 0;
	}
	d_print("error: mixer element `%s' not found\n", alsa_mixer_element);
	return -2;
error:
	d_print("error: %s\n", snd_strerror(rc));
	return -1;
}
Пример #4
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;
}
Пример #5
0
static int on_mixer_event(snd_mixer_t *handle, unsigned int mask, snd_mixer_elem_t *elem) {
  snd_mixer_selem_id_t *sid;

  if(mask & SND_CTL_EVENT_MASK_ADD) {
    snd_mixer_selem_id_alloca(&sid);
    snd_mixer_selem_get_id(elem, sid);
    DEBUG("set callback for mixer control = %s\n", snd_mixer_selem_id_get_name(sid));
    snd_mixer_elem_set_callback(elem, on_mixer_elem_event);
  }

  return 0;
}
Пример #6
0
static int on_mixer_elem_event(snd_mixer_elem_t *elem, unsigned int mask) {
  snd_mixer_selem_id_t *sid;
  void *data = NULL;

  if(elem)
    data = snd_mixer_elem_get_callback_private(elem);

  if(data) {
    long min, max, Rvol, Lvol;

    snd_mixer_selem_id_alloca(&sid);
    snd_mixer_selem_get_id(elem, sid);
    DEBUG("mixer elem control = %s, mask = %x, data = %x\n", snd_mixer_selem_id_get_name(sid), mask, data);
    if(mask & SND_CTL_EVENT_MASK_VALUE) {
      char path[1024] = {0};
      alsa_mixer_t *mixer = (alsa_mixer_t *)g_object_get_data(G_OBJECT(data), "mixer-obj");
      GtkWidget *img = (GtkWidget *)g_object_get_data(G_OBJECT(data), "image-obj");

      DEBUG("mixer = %x, img = %x\n", mixer, img);
      if(snd_mixer_selem_has_playback_volume(elem)) {
        if(mixer->pcm_muted != alsa_mixer_is_muted(elem, NULL)) {
          mixer->pcm_muted = !mixer->pcm_muted;
          g_snprintf(path, 1024, DVM_CONFIG_PATH"/%s", g_playback_iconset[mixer->pcm_muted ? 3: 0]);
          DEBUG("playback switch detected, image path = %s\n", path);
          gtk_image_set_from_file(GTK_IMAGE(img), path);
        }

        snd_mixer_selem_get_playback_volume(elem, 0, &Rvol);
        snd_mixer_selem_get_playback_volume(elem, 1, &Lvol);
        snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
        DEBUG("new val = %d, %d, min = %d, max = %d\n", Rvol, Lvol, min, max);
      } else if(snd_mixer_selem_has_capture_volume(elem)) {
        if(mixer->mic_muted != alsa_mixer_is_muted(elem, NULL)) {
          mixer->mic_muted = !mixer->mic_muted;
          g_snprintf(path, 1024, DVM_CONFIG_PATH"/%s", g_capture_iconset[mixer->mic_muted ? 3: 0]);
          DEBUG("capture switch detected, image path = %s\n", path);
          gtk_image_set_from_file(GTK_IMAGE(img), path);
        }

        snd_mixer_selem_get_capture_volume_range(elem, &min, &max);
        snd_mixer_selem_get_capture_volume(elem, 0, &Rvol);
        snd_mixer_selem_get_capture_volume(elem, 1, &Lvol);
        DEBUG("new val = %d, %d, min = %d, max = %d\n", Rvol, Lvol, min, max);
      }
      g_mixer_ui_updated = TRUE;
      gtk_adjustment_set_value(GTK_ADJUSTMENT(data), ((gdouble)(Rvol+Lvol)*50)/(max-min));
    }
  }

  return 0;
}
Пример #7
0
/*
 * The purpose of this function is to let the user to select 
 *   the input where he plugged his signals.
 * Now if user select "default", as device, we have to select the input
 *   on the mixer of the card used by  "default".
 * What is the card used by device  "default" ?
 */ 
static void
as_setup_input_combo (GtkWidget *combo, SoundParams *sparams)
{
   snd_mixer_t *handle;
   int i ;
   snd_mixer_selem_id_t *sid;
   snd_mixer_elem_t *elem;
   snd_mixer_selem_id_alloca(&sid);
   char *devname;
   char name[32];

   devname = sparams->device_name;
   if ( *sparams->indexstr == '-' ) {
      sprintf(name, "hw:%d", sparams->firstcard);
      devname = name;
   }
   handle = sound_open_mixer(devname);
   if ( handle == NULL ){
      return ;
   }   

   for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) {
      snd_mixer_selem_get_id(elem, sid);
      if (! snd_mixer_selem_is_active(elem)) {
	 continue;
      }
      const char *control_name = snd_mixer_selem_id_get_name(sid);
//      printf("Simple mixer control '%s',%i\n", control_name,  snd_mixer_selem_id_get_index(sid));
      if (snd_mixer_selem_is_enum_capture(elem)) {
	 int items;
	 char itemname[40];
	 app_free(sparams->control_name);
	 sparams->control_name = app_strdup(control_name);
	 items = snd_mixer_selem_get_enum_items(elem);
//	 printf("  Items:");
	 for (i = 0; i < items; i++) {
	    snd_mixer_selem_get_enum_item_name(elem, i, sizeof(itemname) - 1, itemname);
//	    printf(" '%s'", itemname);
            gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), itemname );
	    if ( i == sparams->input ) {
	       gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i);
	    }
	 }
//	 printf("\n");
      }
   }
   snd_mixer_close(handle);
   return ;
}
Пример #8
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);
}
Пример #9
0
void SoundPref::getMixerDevices(int mode)
{
	snd_mixer_t *mixer;
	QComboBox *cmb;
	if (mode == modePlayback)
		cmb = ui.playbackMixerDeviceCmb;
	else {
		// TODO : capture mixer devices
	}
	cmb->clear();

	int err;
	if ((err = snd->getMixer(&mixer, mixerCard)) < 0) {
		return;
	}

	snd_mixer_elem_t *elem;
	snd_mixer_selem_id_t *sid;
	snd_mixer_selem_id_alloca(&sid);
	int indx = 0;
	int current = -1;

	cmb->addItem("");

	for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) {
		snd_mixer_selem_get_id(elem, sid);
		if (!snd_mixer_selem_is_active(elem))
			continue;
		QString device = snd_mixer_selem_id_get_name(sid);
		if (mode == modePlayback) {
			if (snd_mixer_selem_has_playback_volume(elem))
				cmb->addItem(device);
		} else if (mode == modeCapture) {
			// TODO:
		} else
			continue;
		if (device == mixerDevice) {
			current = indx;
		}
		indx ++;
	}
	if (current >= 0)
		cmb->setCurrentIndex(current+1);
	
	snd_mixer_close(mixer);
}
Пример #10
0
static PxVolume get_volume(PxDev *dev, const char *name, int playback)
{
   const char *sname;
   int i;

   if (!dev->handle) {
      return 0.0;
   }

   for (i = 0; i < dev->numselems; i++) {
      sname = snd_mixer_selem_id_get_name(dev->selems[i].sid);
      if (strcmp(sname, name) == 0) {
         return get_volume_indexed(dev, i, playback);
      }
   }

   return 0.0;
}
Пример #11
0
MixerElem *lamixer_volelem_new(snd_mixer_elem_t *elem)
{
	MixerElem *mixer_elem;
	guint voltype=0, elemidx=0, mono;
	long minrange=0,maxrange=0,rangevalue_left=0,rangevalue_right=0;
	const char* selem_name = NULL;
	char elem_name[64];
	
	mixer_elem = g_malloc(sizeof(MixerElem));
	mixer_elem->elem = elem;
	mixer_elem->playback = NULL;
	mixer_elem->capture = NULL;
	mixer_elem->pswitch = NULL;
	mixer_elem->cswitch = NULL;
	mixer_elem->penum = NULL;
	mixer_elem->cenum = NULL;
	
	elemidx = snd_mixer_selem_get_index(elem);
	selem_name = snd_mixer_selem_id_get_name(sid);
	strcpy(elem_name, selem_name);
	if(elemidx > 0) {
		sprintf(elem_name,"%s %i",elem_name, elemidx);
	}
	
	if (!snd_mixer_selem_is_enumerated(elem)) {
		if (snd_mixer_selem_has_playback_volume(elem)) {
			voltype = 1;
			snd_mixer_selem_get_playback_volume_range (elem, &minrange, &maxrange);
			mono = snd_mixer_selem_is_playback_mono(elem);
			snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &rangevalue_left);
			
			if(!mono)
				snd_mixer_selem_get_playback_volume (elem, SND_MIXER_SCHN_FRONT_RIGHT, &rangevalue_right);
			
			mixer_elem->playback = lamixer_volbox_new(elem_name,mono, \
			                                                (snd_mixer_selem_has_playback_switch(elem) || snd_mixer_selem_has_playback_switch_joined(elem)), minrange, maxrange, elem, voltype);
		}
		else if (snd_mixer_selem_has_playback_switch(elem)) {
			voltype = 1;
			mixer_elem->pswitch = lamixer_switchbox_add(elem_name, elem, voltype);
		}
		
		if (snd_mixer_selem_has_capture_volume(elem)) {
			voltype = 2;
			snd_mixer_selem_get_capture_volume_range (elem, &minrange, &maxrange);
			mono = snd_mixer_selem_is_capture_mono(elem);
			snd_mixer_selem_get_capture_volume (elem, SND_MIXER_SCHN_FRONT_LEFT, &rangevalue_left);
			
			if(!mono)
				snd_mixer_selem_get_capture_volume (elem, SND_MIXER_SCHN_FRONT_RIGHT, &rangevalue_right);
			
			mixer_elem->capture = lamixer_volbox_new(elem_name,mono, \
									(snd_mixer_selem_has_capture_switch(elem) || snd_mixer_selem_has_capture_switch_joined(elem)), minrange, maxrange, elem, voltype);
		}
		else if (snd_mixer_selem_has_capture_switch(elem)) {
			voltype = 2;
			mixer_elem->cswitch = lamixer_switchbox_add(elem_name, elem, voltype);
		}
	}
	else {
		if (snd_mixer_selem_is_enum_playback(elem)) {
			voltype = 1;
			mixer_elem->penum = lamixer_enumbox_add(elem_name, elem, voltype);
		}
		else if (snd_mixer_selem_is_enum_capture(elem)) {
			voltype = 2;
			mixer_elem->cenum = lamixer_enumbox_add(elem_name, elem, voltype);
		}
	}
		
	return mixer_elem;
}
Пример #12
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;
}
Пример #13
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;
}
Пример #14
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;
}
Пример #15
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;
}
Пример #16
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;
}
Пример #17
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;
}
Пример #18
0
bool LapsusAlsaMixer::init()
{
	int err;
	snd_ctl_t *ctl_handle;
	snd_ctl_card_info_t *hw_info;

	snd_ctl_card_info_alloca(&hw_info);

	if ((err = snd_ctl_open (&ctl_handle, "default", 0)) < 0)
		return false;
	if ((err = snd_ctl_card_info (ctl_handle, hw_info)) < 0)
		return false;

	snd_ctl_close (ctl_handle);

	if ((err = snd_mixer_open (&_handle, 0)) < 0)
		return false;
	if ((err = snd_mixer_attach (_handle, "default")) < 0)
		return false;
	if ((err = snd_mixer_selem_register (_handle, 0, 0)) < 0)
		return false;

	if ((err = snd_mixer_load (_handle)) < 0)
		return false;

	// printf("Card name: '%s'\n", snd_ctl_card_info_get_name(hw_info));
	// printf("Device name: '%s'\n", snd_ctl_card_info_get_mixername(hw_info));

	snd_mixer_elem_t *elem;
	snd_mixer_selem_id_t *tmp_sid = 0;

	for (elem = snd_mixer_first_elem(_handle); elem; elem = snd_mixer_elem_next(elem))
	{
		if (snd_mixer_selem_is_active(elem))
		{
			if (!tmp_sid) tmp_sid = (snd_mixer_selem_id_t*) malloc(snd_mixer_selem_id_sizeof());

			snd_mixer_selem_get_id(elem, tmp_sid);

			const char *name = snd_mixer_selem_id_get_name( tmp_sid );

			if (!strcasecmp(name, "Headphone"))
			{
				if (sids[ID_HP]) delete sids[ID_HP];
				sids[ID_HP] = new SIDInfo(_handle, tmp_sid);
				tmp_sid = 0;
			}
			else if (!strcasecmp(name, "Front"))
			{
				if (sids[ID_F]) delete sids[ID_F];
				sids[ID_F] = new SIDInfo(_handle, tmp_sid);
				tmp_sid = 0;
			}
			else if (!strcasecmp(name, "Master"))
			{
				if (sids[ID_M]) delete sids[ID_M];
				sids[ID_M] = new SIDInfo(_handle, tmp_sid);
				tmp_sid = 0;
			}
		}
	}

	if (tmp_sid) free(tmp_sid);

	bool foundAny = false;

	for (int i = 0; i < ID_LAST; ++i)
	{
		if (sids[i])
		{
			if (sids[i]->hasMute)
			{
				foundAny = true;
			}

			if (sids[i]->hasVolume)
			{
				foundAny = true;

				long range = sids[i]->max - sids[i]->min;

				if (range > _globalMax)
					_globalMax = range;
			}
		}
	}

	if (_globalMax > INT_MAX)
		_globalMax = INT_MAX;

	if (!foundAny) return false;

	for (int i = 0; i < ID_LAST; ++i)
	{
		if (sids[i]) sids[i]->setGlobalMax(_globalMax);
	}

	if ((_count = snd_mixer_poll_descriptors_count(_handle)) < 0)
		return false;

	_fds = (struct pollfd*) calloc(_count, sizeof(struct pollfd));

	if (!_fds) return false;

	if ((err = snd_mixer_poll_descriptors(_handle, _fds, _count)) < 0)
		return false;

	if (err != _count) return 0;

	_sns = new QSocketNotifier*[_count];

	for ( int i = 0; i < _count; ++i )
	{
		_sns[i] = new QSocketNotifier(_fds[i].fd, QSocketNotifier::Read);
		connect(_sns[i], SIGNAL(activated(int)), this, SLOT(alsaEvent()));
	}

	// To read our current parameters. Signals will be emited, but those signals
	// are not yet connected to anything - this method is called from constructor
	// only.
	getVolume();
	mixerIsMuted();

	return true;
}
Пример #19
0
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.");
}
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.");
}
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;
            }
        }

        ALOGV("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;
                }
            }
            ALOGV("Mixer: route '%s' %s.", info->name, info->elem ? "found" : "not found");
        }
    }
    ALOGV("mixer initialized.");
}
Пример #22
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;
}