/**
 * \brief Wait for a HCTL to become ready (i.e. at least one event pending)
 * \param hctl HCTL handle
 * \param timeout maximum time in milliseconds to wait
 * \return a positive value on success otherwise a negative error code
 * \retval 0 timeout occurred
 * \retval 1 an event is pending
 */
int snd_hctl_wait(snd_hctl_t *hctl, int timeout)
{
	struct pollfd *pfd;
	unsigned short *revents;
	int i, npfds, pollio, err, err_poll;
	
	npfds = snd_hctl_poll_descriptors_count(hctl);
	if (npfds <= 0 || npfds >= 16) {
		SNDERR("Invalid poll_fds %d\n", npfds);
		return -EIO;
	}
	pfd = alloca(sizeof(*pfd) * npfds);
	revents = alloca(sizeof(*revents) * npfds);
	err = snd_hctl_poll_descriptors(hctl, pfd, npfds);
	if (err < 0)
		return err;
	if (err != npfds) {
		SNDMSG("invalid poll descriptors %d\n", err);
		return -EIO;
	}
	do {
		pollio = 0;
		err_poll = poll(pfd, npfds, timeout);
		if (err_poll < 0) {
			if (errno == EINTR)
				continue;
			return -errno;
		}
		if (! err_poll)
			break;
		err = snd_hctl_poll_descriptors_revents(hctl, pfd, npfds, revents);
		if (err < 0)
			return err;
		for (i = 0; i < npfds; i++) {
			if (revents[i] & (POLLERR | POLLNVAL))
				return -EIO;
			if ((revents[i] & (POLLIN | POLLOUT)) == 0)
				continue;
			pollio++;
		}
	} while (! pollio);
	return err_poll > 0 ? 1 : 0;
}
void CALSAHControlMonitor::Start()
{
  assert(m_fdMonitorIds.size() == 0);

  std::vector<struct pollfd> pollfds;
  std::vector<CFDEventMonitor::MonitoredFD> monitoredFDs;

  for (std::map<std::string, CTLHandle>::iterator it = m_ctlHandles.begin();
       it != m_ctlHandles.end(); ++it)
  {
    pollfds.resize(snd_hctl_poll_descriptors_count(it->second.handle));
    int fdcount = snd_hctl_poll_descriptors(it->second.handle, &pollfds[0], pollfds.size());

    for (int j = 0; j < fdcount; ++j)
    {
      monitoredFDs.push_back(CFDEventMonitor::MonitoredFD(pollfds[j].fd,
                                                          pollfds[j].events,
                                                          FDEventCallback,
                                                          it->second.handle));
    }
  }

  g_fdEventMonitor.AddFDs(monitoredFDs, m_fdMonitorIds);
}
int
phoneui_utils_sound_init_finish(GKeyFile *keyfile,char* suffix)
{
	int err, f;
	char *device_name;
	char *alsa;
	static GSourceFuncs funcs = {
		_sourcefunc_prepare,
		_sourcefunc_check,
		_sourcefunc_dispatch,
		0,
		0,
		0
	};

	alsa = malloc(strlen(suffix) + strlen("alsa") + 1);
	if (alsa) {
		strcpy(alsa, "alsa");
		strcat(alsa, suffix);
	}else{
		alsa = strdup("alsa");
		g_warning("Malloc failure in %s at line %d",__func__,__LINE__);
	}

	sound_state = SOUND_STATE_IDLE;
	sound_state_type = SOUND_STATE_TYPE_DEFAULT;

	device_name = g_key_file_get_string(keyfile, alsa, "hardware_control_name", NULL);
	if (!device_name) {
		g_message("No hw control found, using default");
		device_name = strdup("hw:0");
	}

	if (hctl) {
		snd_hctl_close(hctl);
	}
	err = snd_hctl_open(&hctl, device_name, 0);
	if (err) {
		g_warning("Cannot open alsa:hardware_control_name '%s': %s", device_name, snd_strerror(err));
		g_key_file_free(keyfile);
		return err;
	}

	err = snd_hctl_load(hctl);
	if (err) {
		g_warning("Cannot load alsa:hardware_control_name '%s': %s", device_name, snd_strerror(err));
	}
	
	free(device_name);

	/*FIXME: add idle bt */
	_phoneui_utils_sound_init_set_control(keyfile, "idle", suffix, SOUND_STATE_IDLE, SOUND_STATE_TYPE_HANDSET);
	_phoneui_utils_sound_init_set_control(keyfile, "bluetooth", suffix, SOUND_STATE_CALL, SOUND_STATE_TYPE_BLUETOOTH);
	_phoneui_utils_sound_init_set_control(keyfile, "handset", suffix, SOUND_STATE_CALL, SOUND_STATE_TYPE_HANDSET);
	_phoneui_utils_sound_init_set_control(keyfile, "headset", suffix, SOUND_STATE_CALL, SOUND_STATE_TYPE_HEADSET);
	_phoneui_utils_sound_init_set_control(keyfile, "speaker", suffix, SOUND_STATE_SPEAKER, SOUND_STATE_TYPE_HANDSET);

	snd_hctl_nonblock(hctl, 1);

	poll_fd_count = snd_hctl_poll_descriptors_count(hctl);
	poll_fds = malloc(sizeof(struct pollfd) * poll_fd_count);
	snd_hctl_poll_descriptors(hctl, poll_fds, poll_fd_count);

	source_alsa_poll = g_source_new(&funcs, sizeof(GSource));
	for (f = 0; f < poll_fd_count; f++) {
		g_source_add_poll(source_alsa_poll, (GPollFD *)&poll_fds[f]);
	}
	g_source_attach(source_alsa_poll, NULL);

	/*Register for HEADPHONE insertion */
	phoneui_info_register_input_events(_input_events_cb, NULL);

	fso_audio = (FreeSmartphoneDeviceAudio *)_fso
		(FREE_SMARTPHONE_DEVICE_TYPE_AUDIO_PROXY,
		 FSO_FRAMEWORK_DEVICE_ServiceDBusName,
		 FSO_FRAMEWORK_DEVICE_AudioServicePath,
		 FSO_FRAMEWORK_DEVICE_AudioServiceFace);

	g_key_file_free(keyfile);
	return err;
}