Example #1
0
static int audio_open(audiodevice_t *dev, chanfmt_t fmt) {
	audio_alsa05_t *alsa = (audio_alsa05_t *)dev->data_pcm;
	
	snd_pcm_channel_params_t p;
	snd_pcm_channel_setup_t  s;
	
	if (0 > snd_pcm_open(&alsa->pcm_handle, alsa->card, alsa->pcm_dev, SND_PCM_OPEN_PLAYBACK)) {
		WARNING("Opening audio device %d failed\n", alsa->pcm_dev);
		goto _err_exit;
	}
	
	memset(&alsa->info, 0, sizeof(snd_pcm_channel_info_t));
	
	if (0 > snd_pcm_channel_info(alsa->pcm_handle, &alsa->info)) {
		WARNING("param get failed\n");
		goto _err_exit;
	}
	
	memset(&p, 0, sizeof(p));
	p.mode = SND_PCM_MODE_BLOCK;
	p.start_mode = SND_PCM_START_DATA;
	p.channel    = SND_PCM_CHANNEL_PLAYBACK;
	p.stop_mode  = SND_PCM_STOP_STOP;
	p.buf.block.frag_size = 1536;
	p.buf.block.frags_max =  6;
	p.buf.block.frags_min =  1;
	p.format.rate   = fmt.rate;
	p.format.format = fmt.bit == 8 ? SND_PCM_SFMT_U8 : SND_PCM_SFMT_S16;
	p.format.voices = fmt.ch;
	p.format.interleave = 1;
	alsa->silence  = fmt.bit == 8 ? 0x80 : 0;
	
	if (0 > snd_pcm_channel_params(alsa->pcm_handle, &p)) {
		WARNING("Unable to set channel params\n");
		goto _err_exit;
	}
	
	if (0 > snd_pcm_channel_prepare(alsa->pcm_handle, SND_PCM_CHANNEL_PLAYBACK)) {
		WARNING("Unable to prepare channel\n");
		goto _err_exit;
	}
	
	memset(&s, 0, sizeof(s));
	s.mode    = SND_PCM_MODE_BLOCK;
	s.channel = SND_PCM_CHANNEL_PLAYBACK;
	
	if (0 > snd_pcm_channel_setup(alsa->pcm_handle, &s)) {
		WARNING("Unable to obtain setup\n");
		goto _err_exit;
	}
	
	dev->buf.len = s.buf.block.frag_size;
	dev->fd = snd_pcm_file_descriptor(alsa->pcm_handle, SND_PCM_CHANNEL_PLAYBACK); 
	return OK;
	
 _err_exit:
	dev->fd = -1;
	return NG;
}
Example #2
0
int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info)
{
    snd_pcm_generic_t *generic = pcm->private_data;
    if (pcm->mmap_shadow) {
        /* No own buffer is required - the plugin won't change
         * the data on the buffer, or do safely on-the-place
         * conversion
         */
        return snd_pcm_channel_info(generic->slave, info);
    } else {
        /* Allocate own buffer */
        return snd_pcm_channel_info_shm(pcm, info, -1);
    }
}
static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream,
					     struct snd_pcm_channel_info32 __user *src)
{
	struct snd_pcm_channel_info info;
	int err;

	if (get_user(info.channel, &src->channel) ||
	    get_user(info.offset, &src->offset) ||
	    get_user(info.first, &src->first) ||
	    get_user(info.step, &src->step))
		return -EFAULT;
	err = snd_pcm_channel_info(substream, &info);
	if (err < 0)
		return err;
	if (put_user(info.channel, &src->channel) ||
	    put_user(info.offset, &src->offset) ||
	    put_user(info.first, &src->first) ||
	    put_user(info.step, &src->step))
		return -EFAULT;
	return err;
}
Example #4
0
static void *alsa_qsa_init(const char *device,
      unsigned rate, unsigned latency, unsigned block_frames,
      unsigned *new_rate)
{
   int err, card, dev, i;
   snd_pcm_channel_info_t pi;
   snd_pcm_channel_params_t params = {0};
   snd_pcm_channel_setup_t setup   = {0};
   alsa_t *alsa                    = (alsa_t*)calloc(1, sizeof(alsa_t));
   if (!alsa)
      return NULL;

   (void)device;
   (void)rate;
   (void)latency;

   if ((err = snd_pcm_open_preferred(&alsa->pcm, &card, &dev,
               SND_PCM_OPEN_PLAYBACK)) < 0)
   {
      RARCH_ERR("[ALSA QSA]: Audio open error: %s\n",
            snd_strerror(err));
      goto error;
   }

   if((err = snd_pcm_nonblock_mode(alsa->pcm, 1)) < 0)
   {
      RARCH_ERR("[ALSA QSA]: Can't set blocking mode: %s\n",
            snd_strerror(err));
      goto error;
   }

   memset(&pi, 0, sizeof(pi));
   pi.channel = SND_PCM_CHANNEL_PLAYBACK;
   if ((err = snd_pcm_channel_info(alsa->pcm, &pi)) < 0)
   {
      RARCH_ERR("[ALSA QSA]: snd_pcm_channel_info failed: %s\n",
            snd_strerror(err));
      goto error;
   }

   memset(&params, 0, sizeof(params));

   params.channel = SND_PCM_CHANNEL_PLAYBACK;
   params.mode = SND_PCM_MODE_BLOCK;

   params.format.interleave = 1;
   params.format.format = SND_PCM_SFMT_S16_LE;
   params.format.rate = DEFAULT_RATE;
   params.format.voices = 2;

   params.start_mode = SND_PCM_START_FULL;
   params.stop_mode = SND_PCM_STOP_STOP;

   params.buf.block.frag_size = pi.max_fragment_size;
   params.buf.block.frags_min = 2;
   params.buf.block.frags_max = 8;

   RARCH_LOG("Fragment size: %d\n", params.buf.block.frag_size);
   RARCH_LOG("Min Fragment size: %d\n", params.buf.block.frags_min);
   RARCH_LOG("Max Fragment size: %d\n", params.buf.block.frags_max);

   if ((err = snd_pcm_channel_params(alsa->pcm, &params)) < 0)
   {
      RARCH_ERR("[ALSA QSA]: Channel Parameter Error: %s\n",
            snd_strerror(err));
      goto error;
   }

   setup.channel = SND_PCM_CHANNEL_PLAYBACK;

   if ((err = snd_pcm_channel_setup(alsa->pcm, &setup)) < 0)
   {
      RARCH_ERR("[ALSA QSA]: Channel Parameter Read Back Error: %s\n",
            snd_strerror(err));
      goto error;
   }

   if (block_frames)
      alsa->buf_size = block_frames * 4;
   else
      alsa->buf_size = next_pow2(32 * latency);

   RARCH_LOG("[ALSA QSA]: buffer size: %u bytes\n", alsa->buf_size);

   alsa->buf_count = (latency * 4 * rate + 500) / 1000;
   alsa->buf_count = (alsa->buf_count + alsa->buf_size / 2) / alsa->buf_size;

   if ((err = snd_pcm_channel_prepare(alsa->pcm,
               SND_PCM_CHANNEL_PLAYBACK)) < 0)
   {
      RARCH_ERR("[ALSA QSA]: Channel Prepare Error: %s\n",
            snd_strerror(err));
      goto error;
   }

   alsa->buffer = (uint8_t**)calloc(sizeof(uint8_t*), alsa->buf_count);
   if (!alsa->buffer)
      goto error;

   alsa->buffer_chunk = (uint8_t*)calloc(alsa->buf_count, alsa->buf_size);
   if (!alsa->buffer_chunk)
      goto error;

   for (i = 0; i < alsa->buf_count; i++)
      alsa->buffer[i] = alsa->buffer_chunk + i * alsa->buf_size;

   alsa->has_float = false;
   alsa->can_pause = true;
   RARCH_LOG("[ALSA QSA]: Can pause: %s.\n",
         alsa->can_pause ? "yes" : "no");

   return alsa;

error:
   return (void*)-1;
}
int snd_pcm_mmap(snd_pcm_t *pcm)
{
	int err;
	unsigned int c;
	assert(pcm);
	if (CHECK_SANITY(! pcm->setup)) {
		SNDMSG("PCM not set up");
		return -EIO;
	}
	if (CHECK_SANITY(pcm->mmap_channels || pcm->running_areas)) {
		SNDMSG("Already mmapped");
		return -EBUSY;
	}
	err = pcm->ops->mmap(pcm);
	if (err < 0)
		return err;
	if (pcm->mmap_shadow)
		return 0;
	pcm->mmap_channels = calloc(pcm->channels, sizeof(pcm->mmap_channels[0]));
	if (!pcm->mmap_channels)
		return -ENOMEM;
	pcm->running_areas = calloc(pcm->channels, sizeof(pcm->running_areas[0]));
	if (!pcm->running_areas) {
		free(pcm->mmap_channels);
		pcm->mmap_channels = NULL;
		return -ENOMEM;
	}
	for (c = 0; c < pcm->channels; ++c) {
		snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
		i->channel = c;
		err = snd_pcm_channel_info(pcm, i);
		if (err < 0)
			return err;
	}
	for (c = 0; c < pcm->channels; ++c) {
		snd_pcm_channel_info_t *i = &pcm->mmap_channels[c];
		snd_pcm_channel_area_t *a = &pcm->running_areas[c];
		char *ptr;
		size_t size;
		unsigned int c1;
		if (i->addr) {
        		a->addr = i->addr;
        		a->first = i->first;
        		a->step = i->step;
		        continue;
                }
                size = i->first + i->step * (pcm->buffer_size - 1) + pcm->sample_bits;
		for (c1 = c + 1; c1 < pcm->channels; ++c1) {
			snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
			size_t s;
			if (i1->type != i->type)
				continue;
			switch (i1->type) {
			case SND_PCM_AREA_MMAP:
				if (i1->u.mmap.fd != i->u.mmap.fd ||
				    i1->u.mmap.offset != i->u.mmap.offset)
					continue;
				break;
			case SND_PCM_AREA_SHM:
				if (i1->u.shm.shmid != i->u.shm.shmid)
					continue;
				break;
			case SND_PCM_AREA_LOCAL:
				break;
			default:
				assert(0);
			}
			s = i1->first + i1->step * (pcm->buffer_size - 1) + pcm->sample_bits;
			if (s > size)
				size = s;
		}
		size = (size + 7) / 8;
		size = page_align(size);
		switch (i->type) {
		case SND_PCM_AREA_MMAP:
			ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset);
			if (ptr == MAP_FAILED) {
				SYSERR("mmap failed");
				return -errno;
			}
			i->addr = ptr;
			break;
		case SND_PCM_AREA_SHM:
			if (i->u.shm.shmid < 0) {
				int id;
				/* FIXME: safer permission? */
				id = shmget(IPC_PRIVATE, size, 0666);
				if (id < 0) {
					SYSERR("shmget failed");
					return -errno;
				}
				i->u.shm.shmid = id;
				ptr = shmat(i->u.shm.shmid, 0, 0);
				if (ptr == (void *) -1) {
					SYSERR("shmat failed");
					return -errno;
				}
				/* automatically remove segment if not used */
				if (shmctl(id, IPC_RMID, NULL) < 0){
					SYSERR("shmctl mark remove failed");
					return -errno;
				}
				i->u.shm.area = snd_shm_area_create(id, ptr);
				if (i->u.shm.area == NULL) {
					SYSERR("snd_shm_area_create failed");
					return -ENOMEM;
				}
				if (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
				    pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
					unsigned int c1;
					for (c1 = c + 1; c1 < pcm->channels; c1++) {
						snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
						if (i1->u.shm.shmid < 0) {
							i1->u.shm.shmid = id;
							i1->u.shm.area = snd_shm_area_share(i->u.shm.area);
						}
					}
				}
			} else {
				ptr = shmat(i->u.shm.shmid, 0, 0);
				if (ptr == (void*) -1) {
					SYSERR("shmat failed");
					return -errno;
				}
			}
			i->addr = ptr;
			break;
		case SND_PCM_AREA_LOCAL:
			ptr = malloc(size);
			if (ptr == NULL) {
				SYSERR("malloc failed");
				return -errno;
			}
			i->addr = ptr;
			break;
		default:
			assert(0);
		}
		for (c1 = c + 1; c1 < pcm->channels; ++c1) {
			snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
			if (i1->type != i->type)
				continue;
			switch (i1->type) {
			case SND_PCM_AREA_MMAP:
				if (i1->u.mmap.fd != i->u.mmap.fd ||
                                    i1->u.mmap.offset != i->u.mmap.offset)
					continue;
				break;
			case SND_PCM_AREA_SHM:
				if (i1->u.shm.shmid != i->u.shm.shmid)
					continue;
				/* follow thru */
			case SND_PCM_AREA_LOCAL:
				if (pcm->access != SND_PCM_ACCESS_MMAP_INTERLEAVED &&
				    pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED)
				        continue;
				break;
			default:
				assert(0);
			}
			i1->addr = i->addr;
		}
		a->addr = i->addr;
		a->first = i->first;
		a->step = i->step;
	}
	return 0;
}
Example #6
0
PcmDevice *
openPcmDevice (int errorLevel, const char *device) {
    PcmDevice *pcm;
    if ((pcm = malloc(sizeof(*pcm)))) {
        int code;

        if (*device) {
            {
                int ok = 0;
                long number;
                char *end;
                const char *component = device;

                number = strtol(component, &end, 0);
                if ((*end && (*end != ':')) || (number < 0) || (number > 0XFF)) {
                    logMessage(errorLevel, "Invalid QSA card number: %s", device);
                } else if (end == component) {
                    logMessage(errorLevel, "Missing QSA card number: %s", device);
                } else {
                    pcm->card = number;

                    if (*end) {
                        component = end + 1;
                        number = strtol(component, &end, 0);
                        if (*end || (number < 0) || (number > 0XFF)) {
                            logMessage(errorLevel, "Invalid QSA device number: %s", device);
                        } else if (end == component) {
                            logMessage(errorLevel, "Missing QSA device number: %s", device);
                        } else {
                            pcm->device = number;
                            ok = 1;
                        }
                    } else {
                        pcm->device = 0;
                        ok = 1;
                    }
                }

                if (!ok) goto openError;
            }

            if ((code = snd_pcm_open(&pcm->handle, pcm->card, pcm->device, SND_PCM_OPEN_PLAYBACK)) < 0) {
                logPcmError(errorLevel, "open", code);
                goto openError;
            }
        } else if ((code = snd_pcm_open_preferred(&pcm->handle, &pcm->card, &pcm->device, SND_PCM_OPEN_PLAYBACK)) < 0) {
            logPcmError(errorLevel, "preferred open", code);
            goto openError;
        }
        logMessage(LOG_DEBUG, "QSA PCM device opened: %d:%d", pcm->card, pcm->device);

        {
            snd_pcm_channel_info_t info;
            info.channel = SND_PCM_CHANNEL_PLAYBACK;
            if ((code = snd_pcm_channel_info(pcm->handle, &info)) >= 0) {
                logMessage(LOG_DEBUG, "QSA PCM Info: Frag=%d-%d Rate=%d-%d Chan=%d-%d",
                           info.min_fragment_size, info.max_fragment_size,
                           info.min_rate, info.max_rate,
                           info.min_voices, info.max_voices);
                memset(&pcm->parameters, 0, sizeof(pcm->parameters));

                pcm->parameters.channel = info.channel;
                pcm->parameters.start_mode = SND_PCM_START_DATA;
                pcm->parameters.stop_mode = SND_PCM_STOP_ROLLOVER;

                switch (pcm->parameters.mode = SND_PCM_MODE_BLOCK) {
                case SND_PCM_MODE_BLOCK:
                    pcm->parameters.buf.block.frag_size = MIN(MAX(0X400, info.min_fragment_size), info.max_fragment_size);
                    pcm->parameters.buf.block.frags_min = 1;
                    pcm->parameters.buf.block.frags_max = 0X40;
                    break;

                default:
                    logMessage(LOG_WARNING, "Unsupported QSA PCM mode: %d", pcm->parameters.mode);
                    goto openError;
                }

                pcm->parameters.format.interleave = 1;
                pcm->parameters.format.rate = info.max_rate;
                pcm->parameters.format.voices = MIN(MAX(1, info.min_voices), info.max_voices);
                pcm->parameters.format.format = SND_PCM_SFMT_S16;

                if (reconfigurePcmChannel(pcm, errorLevel)) {
                    if ((code = snd_pcm_channel_prepare(pcm->handle, pcm->parameters.channel)) >= 0) {
                        return pcm;
                    } else {
                        logPcmError(errorLevel, "prepare channel", code);
                    }
                }
            } else {
                logPcmError(errorLevel, "get channel information", code);
            }
        }

openError:
        free(pcm);
    } else {
        logSystemError("PCM device allocation");
    }

    return NULL;
}
Example #7
0
/*
    open & setup audio device
    return: 1=success 0=fail
*/
static int init(int rate_hz, int channels, int format, int flags)
{
    int err;
    int cards = -1;
    snd_pcm_channel_params_t params;
    snd_pcm_channel_setup_t setup;
    snd_pcm_info_t info;
    snd_pcm_channel_info_t chninfo;

    mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_ALSA5_InitInfo, rate_hz,
	channels, af_fmt2str_short(format));

    alsa_handler = NULL;

    mp_msg(MSGT_AO, MSGL_V, "alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR,
        SND_LIB_VERSION);

    if ((cards = snd_cards()) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_SoundCardNotFound);
	return 0;
    }

    ao_data.format = format;
    ao_data.channels = channels;
    ao_data.samplerate = rate_hz;
    ao_data.bps = ao_data.samplerate*ao_data.channels;
    ao_data.outburst = OUTBURST;
    ao_data.buffersize = 16384;

    memset(&alsa_format, 0, sizeof(alsa_format));
    switch (format)
    {
	case AF_FORMAT_S8:
	    alsa_format.format = SND_PCM_SFMT_S8;
	    break;
	case AF_FORMAT_U8:
	    alsa_format.format = SND_PCM_SFMT_U8;
	    break;
	case AF_FORMAT_U16_LE:
	    alsa_format.format = SND_PCM_SFMT_U16_LE;
	    break;
	case AF_FORMAT_U16_BE:
	    alsa_format.format = SND_PCM_SFMT_U16_BE;
	    break;
	case AF_FORMAT_AC3_LE:
	case AF_FORMAT_S16_LE:
	    alsa_format.format = SND_PCM_SFMT_S16_LE;
	    break;
	case AF_FORMAT_AC3_BE:
	case AF_FORMAT_S16_BE:
	    alsa_format.format = SND_PCM_SFMT_S16_BE;
	    break;
	default:
	    alsa_format.format = SND_PCM_SFMT_MPEG;
	    break;
    }

    switch(alsa_format.format)
    {
	case SND_PCM_SFMT_S16_LE:
	case SND_PCM_SFMT_U16_LE:
	    ao_data.bps *= 2;
	    break;
	case -1:
	    mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_InvalidFormatReq,af_fmt2str_short(format));
	    return 0;
	default:
	    break;
    }

    switch(rate_hz)
    {
	case 8000:
	    alsa_rate = SND_PCM_RATE_8000;
	    break;
	case 11025:
	    alsa_rate = SND_PCM_RATE_11025;
	    break;
	case 16000:
	    alsa_rate = SND_PCM_RATE_16000;
	    break;
	case 22050:
	    alsa_rate = SND_PCM_RATE_22050;
	    break;
	case 32000:
	    alsa_rate = SND_PCM_RATE_32000;
	    break;
	case 44100:
	    alsa_rate = SND_PCM_RATE_44100;
	    break;
	case 48000:
	    alsa_rate = SND_PCM_RATE_48000;
	    break;
	case 88200:
	    alsa_rate = SND_PCM_RATE_88200;
	    break;
	case 96000:
	    alsa_rate = SND_PCM_RATE_96000;
	    break;
	case 176400:
	    alsa_rate = SND_PCM_RATE_176400;
	    break;
	case 192000:
	    alsa_rate = SND_PCM_RATE_192000;
	    break;
	default:
	    alsa_rate = SND_PCM_RATE_CONTINUOUS;
	    break;
    }

    alsa_format.rate = ao_data.samplerate;
    alsa_format.voices = ao_data.channels;
    alsa_format.interleave = 1;

    if ((err = snd_pcm_open(&alsa_handler, 0, 0, SND_PCM_OPEN_PLAYBACK)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PlayBackError, snd_strerror(err));
	return 0;
    }

    if ((err = snd_pcm_info(alsa_handler, &info)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PcmInfoError, snd_strerror(err));
	return 0;
    }

    mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_ALSA5_SoundcardsFound,
	cards, info.name);

    if (info.flags & SND_PCM_INFO_PLAYBACK)
    {
	memset(&chninfo, 0, sizeof(chninfo));
	chninfo.channel = SND_PCM_CHANNEL_PLAYBACK;
	if ((err = snd_pcm_channel_info(alsa_handler, &chninfo)) < 0)
	{
	    mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PcmChanInfoError, snd_strerror(err));
	    return 0;
	}

#ifndef __QNX__
	if (chninfo.buffer_size)
	    ao_data.buffersize = chninfo.buffer_size;
#endif

	mp_msg(MSGT_AO, MSGL_V, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
	    ao_data.buffersize);
    }

    memset(&params, 0, sizeof(params));
    params.channel = SND_PCM_CHANNEL_PLAYBACK;
    params.mode = SND_PCM_MODE_STREAM;
    params.format = alsa_format;
    params.start_mode = SND_PCM_START_DATA;
    params.stop_mode = SND_PCM_STOP_ROLLOVER;
    params.buf.stream.queue_size = ao_data.buffersize;
    params.buf.stream.fill = SND_PCM_FILL_NONE;

    if ((err = snd_pcm_channel_params(alsa_handler, &params)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_CantSetParms, snd_strerror(err));
	return 0;
    }

    memset(&setup, 0, sizeof(setup));
    setup.channel = SND_PCM_CHANNEL_PLAYBACK;
    setup.mode = SND_PCM_MODE_STREAM;
    setup.format = alsa_format;
    setup.buf.stream.queue_size = ao_data.buffersize;
    setup.msbits_per_sample = ao_data.bps;

    if ((err = snd_pcm_channel_setup(alsa_handler, &setup)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_CantSetChan, snd_strerror(err));
	return 0;
    }

    if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ChanPrepareError, snd_strerror(err));
	return 0;
    }

    mp_msg(MSGT_AO, MSGL_INFO, "AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n",
	ao_data.samplerate, ao_data.channels, ao_data.bps, ao_data.buffersize,
	snd_pcm_get_format_name(alsa_format.format));
    return 1;
}
Example #8
0
qboolean
SNDDMA_Init (void)
{
	int         rc = 0, i;
	char       *err_msg = "";
	int         rate = -1, format = -1, bps, stereo = -1, frag_size;
	unsigned int mask;

	mask = snd_cards_mask ();
	if (!mask) {
		Con_Printf ("No sound cards detected\n");
		return 0;
	}
	if ((i = COM_CheckParm ("-sndcard")) != 0) {
		card = atoi (com_argv[i + 1]);
	}
	if ((i = COM_CheckParm ("-snddev")) != 0) {
		dev = atoi (com_argv[i + 1]);
	}
	if ((i = COM_CheckParm ("-sndbits")) != 0) {
		i = atoi (com_argv[i + 1]);
		if (i == 16) {
			format = SND_PCM_SFMT_S16_LE;
		} else if (i == 8) {
			format = SND_PCM_SFMT_U8;
		} else {
			Con_Printf ("Error: invalid sample bits: %d\n", i);
			return 0;
		}
	}
	if ((i = COM_CheckParm ("-sndspeed")) != 0) {
		rate = atoi (com_argv[i + 1]);
		if (rate != 44100 && rate != 22050 && rate != 11025) {
			Con_Printf ("Error: invalid sample rate: %d\n", rate);
			return 0;
		}
	}
	if ((i = COM_CheckParm ("-sndmono")) != 0) {
		stereo = 0;
	}
	if (card == -1) {
		for (card = 0; card < SND_CARDS; card++) {
			if (!(mask & (1 << card)))
				continue;
			rc = check_card (card);
			if (rc < 0)
				return 0;
			if (!rc)
				goto dev_openned;
		}
	} else {
		if (dev == -1) {
			rc = check_card (card);
			if (rc < 0)
				return 0;
			if (!rc)
				goto dev_openned;
		} else {
			if ((rc = snd_pcm_open (&pcm_handle, card, dev,
									SND_PCM_OPEN_PLAYBACK
									| SND_PCM_OPEN_NONBLOCK)) < 0) {
				Con_Printf ("Error: audio open error: %s\n", snd_strerror (rc));
				return 0;
			}
			goto dev_openned;
		}
	}
	Con_Printf ("Error: audio open error: %s\n", snd_strerror (rc));
	return 0;

  dev_openned:
	Con_Printf ("Using card %d, device %d.\n", card, dev);
	memset (&cinfo, 0, sizeof (cinfo));
	cinfo.channel = SND_PCM_CHANNEL_PLAYBACK;
	snd_pcm_channel_info (pcm_handle, &cinfo);
	Con_Printf ("%08x %08x %08x\n", cinfo.flags, cinfo.formats, cinfo.rates);
	if ((rate == -1 || rate == 44100) && cinfo.rates & SND_PCM_RATE_44100) {
		rate = 44100;
		frag_size = 512;				/* assuming stereo 8 bit */
	} else if ((rate == -1 || rate == 22050)
			   && cinfo.rates & SND_PCM_RATE_22050) {
		rate = 22050;
		frag_size = 256;				/* assuming stereo 8 bit */
	} else if ((rate == -1 || rate == 11025)
			   && cinfo.rates & SND_PCM_RATE_11025) {
		rate = 11025;
		frag_size = 128;				/* assuming stereo 8 bit */
	} else {
		Con_Printf ("ALSA: desired rates not supported\n");
		goto error_2;
	}
	if ((format == -1 || format == SND_PCM_SFMT_S16_LE)
		&& cinfo.formats & SND_PCM_FMT_S16_LE) {
		format = SND_PCM_SFMT_S16_LE;
		bps = 16;
		frag_size *= 2;
	} else if ((format == -1 || format == SND_PCM_SFMT_U8)
			   && cinfo.formats & SND_PCM_FMT_U8) {
		format = SND_PCM_SFMT_U8;
		bps = 8;
	} else {
		Con_Printf ("ALSA: desired formats not supported\n");
		goto error_2;
	}
	if (stereo && cinfo.max_voices >= 2) {
		stereo = 1;
	} else {
		stereo = 0;
		frag_size /= 2;
	}

//  err_msg="audio flush";
//  if ((rc=snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK))<0)
//      goto error;
	err_msg = "audio munmap";
	if ((rc = snd_pcm_munmap (pcm_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0)
		goto error;

	memset (&params, 0, sizeof (params));
	params.channel = SND_PCM_CHANNEL_PLAYBACK;
	params.mode = SND_PCM_MODE_BLOCK;
	params.format.interleave = 1;
	params.format.format = format;
	params.format.rate = rate;
	params.format.voices = stereo + 1;
	params.start_mode = SND_PCM_START_GO;
	params.stop_mode = SND_PCM_STOP_ROLLOVER;
	params.buf.block.frag_size = frag_size;
	params.buf.block.frags_min = 1;
	params.buf.block.frags_max = -1;
//  err_msg="audio flush";
//  if ((rc=snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK))<0)
//      goto error;
	err_msg = "audio params";
	if ((rc = snd_pcm_channel_params (pcm_handle, &params)) < 0)
		goto error;

	err_msg = "audio mmap";
	if (
		(rc =
		 snd_pcm_mmap (pcm_handle, SND_PCM_CHANNEL_PLAYBACK, &mmap_control,
					   (void **) &mmap_data)) < 0)
		goto error;
	err_msg = "audio prepare";
	if ((rc = snd_pcm_plugin_prepare (pcm_handle, SND_PCM_CHANNEL_PLAYBACK)) <
		0) goto error;

	memset (&setup, 0, sizeof (setup));
	setup.mode = SND_PCM_MODE_BLOCK;
	setup.channel = SND_PCM_CHANNEL_PLAYBACK;
	err_msg = "audio setup";
	if ((rc = snd_pcm_channel_setup (pcm_handle, &setup)) < 0)
		goto error;

	shm = &sn;
	memset ((dma_t *) shm, 0, sizeof (*shm));
	shm->splitbuffer = 0;
	shm->channels = setup.format.voices;
	shm->submission_chunk = 128;		// don't mix less than this #
	shm->samplepos = 0;					// in mono samples
	shm->samplebits = setup.format.format == SND_PCM_SFMT_S16_LE ? 16 : 8;
	shm->samples =
		setup.buf.block.frags * setup.buf.block.frag_size / (shm->samplebits / 8);	// mono 
																					// samples 
																					// in 
																					// buffer
	shm->speed = setup.format.rate;
	shm->buffer = (unsigned char *) mmap_data;
	Con_Printf ("%5d stereo\n", shm->channels - 1);
	Con_Printf ("%5d samples\n", shm->samples);
	Con_Printf ("%5d samplepos\n", shm->samplepos);
	Con_Printf ("%5d samplebits\n", shm->samplebits);
	Con_Printf ("%5d submission_chunk\n", shm->submission_chunk);
	Con_Printf ("%5d speed\n", shm->speed);
	Con_Printf ("0x%x dma buffer\n", (int) shm->buffer);
	Con_Printf ("%5d total_channels\n", total_channels);

	snd_inited = 1;
	return 1;
  error:
	Con_Printf ("Error: %s: %s\n", err_msg, snd_strerror (rc));
  error_2:
	snd_pcm_close (pcm_handle);
	return 0;
}
// Initialize audio and report back a few parameters of the channel
int setupAudio( )
{
    int error;
    snd_pcm_channel_info_t pi;
    snd_pcm_channel_params_t pp;
    snd_pcm_channel_setup_t ps;

    //if ((error = snd_pcm_open_name (&playback_handle, "pcmPreferred", SND_PCM_OPEN_PLAYBACK)) < 0) {
    if ((error = snd_pcm_open_name (&playback_handle, "tones", SND_PCM_OPEN_PLAYBACK)) < 0) {
        slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to open preferred audio driver\n");
        return -error;
    }

    sample_handle = snd_pcm_file_descriptor( playback_handle, SND_PCM_CHANNEL_PLAYBACK );

    if ((error = snd_pcm_plugin_set_disable (playback_handle, PLUGIN_DISABLE_MMAP)) < 0) {
        slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to disable mmap\n");
        snd_pcm_close(playback_handle);
        return -error;
    }

    if ((error = snd_pcm_plugin_set_enable (playback_handle, PLUGIN_ROUTING)) < 0)
    {
        slogf ( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "snd_pcm_plugin_set_enable failed: %s\n", snd_strerror (error));
        snd_pcm_close(playback_handle);
        return -error;
    }

    // Find what sample rate and format to use
    memset( &pi, 0, sizeof(pi) );
    pi.channel = SND_PCM_CHANNEL_PLAYBACK;
    if ((error = snd_pcm_channel_info (playback_handle, &pi)) < 0) {
        slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to get plugin info\n");
        snd_pcm_close(playback_handle);
        return -error;
    }

    // Initialize the playback channel
    memset(&pp, 0, sizeof(pp) );
    pp.mode = SND_PCM_MODE_BLOCK;
    pp.channel = SND_PCM_CHANNEL_PLAYBACK;
    pp.start_mode = SND_PCM_START_FULL;
    pp.stop_mode = SND_PCM_STOP_STOP;
    pp.buf.block.frag_size = pi.max_fragment_size;
    pp.buf.block.frags_max = 3;
    pp.buf.block.frags_min = 1;
    pp.format.interleave = 1;
    pp.format.format =  SND_PCM_SFMT_S16_LE;
    pp.format.rate = 48000;
    pp.format.voices = 2;

    memset( &ps, 0, sizeof( ps ) );
    memset( &group, 0, sizeof( group ) );
    ps.channel = SND_PCM_CHANNEL_PLAYBACK;
    ps.mixer_gid = &group.gid;
    //strcpy(pp.sw_mixer_subchn_name, "Wave playback channel");
    strcpy(pp.sw_mixer_subchn_name, "voice_ringtone");

    if ((error = snd_pcm_plugin_params( playback_handle, &pp)) < 0)
    {
        slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set plugin params\n");
        snd_pcm_close(playback_handle);
        return -error;
    }

    if ((error = snd_pcm_plugin_prepare (playback_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0) {
        slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set prepare plugin\n");
        snd_pcm_close(playback_handle);
        return -error;
    }

    if ((error = snd_pcm_plugin_setup (playback_handle, &ps)) < 0) {
        slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to setup plugin\n");
        snd_pcm_close(playback_handle);
        return -error;
    }

    card = ps.mixer_card;
    device = ps.mixer_device;

    if( audioman_handle ) {
        if ((error = snd_pcm_set_audioman_handle (playback_handle, audioman_handle)) < 0) {
            slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set audioman handle \n");
            snd_pcm_close(playback_handle);
            return -error;
        }
    }

    sample_frequency = ps.format.rate;
    frag_samples = ps.buf.block.frag_size / 4;
    frame_size = ps.buf.block.frag_size;
    format = pp.format.format;
/*
    // Only support 16-bit samples for now
    frag_buffer = malloc( ps.buf.block.frag_size * 2 );
    if( frag_buffer == NULL ) {
        slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to alloc frag buffer\n");
        snd_pcm_close(playback_handle);
        return ENOMEM;
    }
*/
	fprintf (stderr,"Playback Format %s card = %d\n", snd_pcm_get_format_name (ps.format.format),card);
	fprintf (stderr,"Playback preferred frame_size %d \n", pi.max_fragment_size);
	fprintf (stderr,"Playback frame_size %d \n", ps.buf.block.frag_size);
	fprintf (stderr,"Playback frame_samples %d \n", frag_samples);
	fprintf (stderr,"Playback Rate %d \n", ps.format.rate);

	if (group.gid.name[0] == 0)
	{
		fprintf (stderr,"Playback Mixer Pcm Group [%s] Not Set \n", group.gid.name);
        return -1;
	}
	fprintf (stderr, "Playback Mixer Pcm Group [%s]\n", group.gid.name);

    return EOK;
}