Esempio n. 1
0
static int audio_close(audiodevice_t *dev) {
	audio_alsa05_t *alsa = (audio_alsa05_t *)dev->data_pcm;
	snd_pcm_channel_status_t st;
	int err, bc;

	dev->fd = -1;
	if (alsa->pcm_handle) {
		memset(&st, 0, sizeof(st));
		if (0 > (err = snd_pcm_channel_status(alsa->pcm_handle, &st))) {
			WARNING("playback status err(%s)\n", snd_strerror(err));
			return snd_pcm_close(alsa->pcm_handle);
		}
		while (st.status == SND_PCM_STATUS_RUNNING) {
			memset(&st, 0, sizeof(st));
			bc = st.count;
			snd_pcm_channel_status(alsa->pcm_handle, &st);
			if (bc == st.count) {
				snd_pcm_channel_flush(alsa->pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
			}
			usleep(1000);
		}
		err = snd_pcm_close(alsa->pcm_handle);
		alsa->pcm_handle = NULL;
		return err;
	} else {
		return OK;
	}
}
Esempio n. 2
0
/* stop playing, keep buffers (for pause) */
static void audio_pause(void)
{
    int err;

    if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PauseDrainError, snd_strerror(err));
	return;
    }

    if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PauseFlushError, snd_strerror(err));
	return;
    }
}
Esempio n. 3
0
/* stop playing and empty buffers (for seeking/pause) */
static void reset(void)
{
    int err;

    if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ResetDrainError, snd_strerror(err));
	return;
    }

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

    if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ResetChanPrepareError, snd_strerror(err));
	return;
    }
}
Esempio n. 4
0
/* close audio device */
static void uninit(int immed)
{
    int err;

    if ((err = snd_pcm_playback_drain(alsa_handler)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_DrainError, snd_strerror(err));
	return;
    }

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

    if ((err = snd_pcm_close(alsa_handler)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PcmCloseError, snd_strerror(err));
	return;
    }
}
Esempio n. 5
0
int _alsa_write_buffer(ao_alsa_internal *s)
{
	snd_pcm_channel_status_t status;
	snd_pcm_t *pcm_handle = s->pcm_handle;
	int len = s->buf_end;
	ssize_t written, snd_pcm_write_ret;

	s->buf_end = 0;

	snd_pcm_write_ret = written = 0;
	while ((snd_pcm_write_ret >= 0) && (written < len)) {
		while ((snd_pcm_write_ret = snd_pcm_write(pcm_handle, s->buf, len)) == -EINTR)
			;
		if (snd_pcm_write_ret > 0)
			written += snd_pcm_write_ret;
	}

	memset(&status, 0, sizeof(status));
	if (snd_pcm_channel_status(pcm_handle, &status) < 0) {
		fprintf(stderr, "ALSA: could not get channel status\n");
		return 0;
	}       
	if (status.underrun) {
		/* fprintf(stderr, "ALSA: underrun. resetting channel\n"); */
		snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK);
		snd_pcm_playback_prepare(pcm_handle);
		snd_pcm_write(pcm_handle, s->buf, len);
		if (snd_pcm_channel_status(pcm_handle, &status) < 0) {
			fprintf(stderr, "ALSA: could not get channel status. giving up\n");
			return 0;
		}
		if (status.underrun) {
			fprintf(stderr, "ALSA: write error. giving up\n");
					return 0;
		}               
	}

	return 1;
}	
static gboolean
alsa_open (void *dp)
{
    alsa_driver * const d = dp;
    int mf, err;

    snd_pcm_format_t pf;

    //    snd_pcm_channel_info_t pcm_info;
    snd_pcm_channel_params_t pp;
    snd_pcm_channel_setup_t setup;

    snd_pcm_channel_flush(d->soundfd, SND_PCM_CHANNEL_PLAYBACK);
    memset(&pp, 0, sizeof(pp));

    err = snd_pcm_open(&(d->soundfd), d->card_number, d->device_number, SND_PCM_OPEN_PLAYBACK);
    if (err != 0) {
	char buf[256];
	g_sprintf(buf, _("Couldn't open ALSA device for sound output (card:%d, device:%d):\n%s"), 
		d->card_number, d->device_number, snd_strerror(err));
	error_error(buf);
	goto out;
    }

    // ---
    // Set non-blocking mode.
    // ---
    //    snd_pcm_nonblock_mode(d->soundfd, 1);

    d->outtime = 0;
    d->bits = 0;
    mf = 0;

    // --
    // Set channel parameters
    // --
    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_ROLLOVER;

    // ---
    // Select audio format
    // ---
    memset(&pf, 0, sizeof(pf));
    pf.interleave = 1;
    if (d->p_resolution == 16) {
      pf.format = SND_PCM_SFMT_S16_LE;
      d->bits = 16;
      mf = ST_MIXER_FORMAT_S16_LE;
    }
    else {
      pf.format = SND_PCM_SFMT_U8;
      d->bits = 8;
      mf = ST_MIXER_FORMAT_S8;
    }

    pf.rate = d->p_mixfreq;
    d->playrate = d->p_mixfreq;

    if(d->p_channels == 2) {
	d->stereo = 1;
	pf.voices = d->p_channels;
	mf |= ST_MIXER_FORMAT_STEREO;
    }
    else {
      pf.voices = d->p_channels;
      d->stereo = 0;
    }
    d->mf = mf;
    memcpy(&pp.format, &pf, sizeof(pf));

    //    pp.buf.block.frag_size = d->p_fragsize * pf.voices * (d->bits / 8);
    pp.buf.block.frag_size = d->p_fragsize;
    pp.buf.block.frags_max = -1;
    pp.buf.block.frags_min = 1;

    err = snd_pcm_channel_params(d->soundfd, &pp);
    if (err < 0) {
      error_error(_("Required output-channel parameters not supported.\n"));
      goto out;
    }

    if (snd_pcm_channel_prepare(d->soundfd, SND_PCM_CHANNEL_PLAYBACK) < 0) {
      error_error(_("Unable to prepare ALSA channel.\n"));
      goto out;
    }

    // ---
    // Get buffering parameters
    // ---
   
    memset(&setup, 0, sizeof(setup));
    setup.mode = SND_PCM_MODE_BLOCK;
    setup.channel = SND_PCM_CHANNEL_PLAYBACK;
    err = snd_pcm_channel_setup(d->soundfd, &setup);
    if (err < 0) {
      error_error(_("Alsa setup error.\n"));
      goto out;
    }

    //    snd_pcm_channel_status(d->soundfd, &pbstat);
    //    d->fragsize = pbstat.fragment_size;

    d->numfrags = setup.buf.block.frags;
    d->fragsize = setup.buf.block.frag_size;
    /*    fprintf(stderr, "Numfrags: %d\n", d->numfrags);
	  fprintf(stderr, "Fragsize: %d\n", d->fragsize); */

    d->sndbuf = calloc(1, d->fragsize);

    if(d->stereo == 1) { 
      d->fragsize /= 2;  
    } 
    if(d->bits == 16) {  
      d->fragsize /= 2;  
    } 
    
    d->polltag = audio_poll_add(snd_pcm_file_descriptor(d->soundfd, SND_PCM_CHANNEL_PLAYBACK), GDK_INPUT_WRITE, alsa_poll_ready_playing, d);
    /*    d->firstpoll = TRUE; */
    d->firstpoll = TRUE;
    d->playtime = 0;

    return TRUE;

  out:
    alsa_release(dp);
    return FALSE;
}
Esempio n. 7
0
/* Plays a sound with the Advanced Linux Sound Architecture, ALSA.
   Returns 0 on successful playback, nonzero on error. */
int PlayerALSA(u_int8_t *samples, unsigned int bits, unsigned int channels,
               unsigned int rate, unsigned int bytes)
{
    int i;

    /* ALSA is a bit verbose, and it tends to require
       lots of structures. */
    unsigned int alsa_device = 0, alsa_card = 0;
    char *alsa_card_name;
    snd_ctl_t *alsa_ctl;
    snd_ctl_hw_info_t alsa_hw_info;
    snd_pcm_t *alsa_pcm;
    snd_pcm_channel_params_t alsa_params;
	
    /* Playback status variables. */
    unsigned int position;

    /* Scan for ALSA cards and devices. Each card has an integer ID
       less than snd_cards(). We scan for the first available card
       in order to demonstrate ALSA's organization, but we could
       find the default card and PCM device numbers immediately with
       the snd_defaults_pcm_card(), snd_defaults_pcm_device() functions. */
    alsa_pcm = NULL;
    for (alsa_card = 0; alsa_card < (unsigned)snd_cards(); alsa_card++) {

	/* Try to open this card. */
	if (snd_ctl_open(&alsa_ctl,alsa_card) < 0)
	    continue;
		
	/* Retrieve card info. */
	if (snd_ctl_hw_info(alsa_ctl,&alsa_hw_info) < 0) {
	    snd_ctl_close(alsa_ctl);
	    continue;
	}
		
	snd_ctl_close(alsa_ctl);
		
	/* Find a suitable device on this card. */
	alsa_pcm = NULL;
	for (alsa_device = 0; alsa_device < alsa_hw_info.pcmdevs; alsa_device++) {
	    if (snd_pcm_open(&alsa_pcm,alsa_card,
			     alsa_device,SND_PCM_OPEN_PLAYBACK) < 0) continue;
	    
	    /* Device successfully opened. */
	    break;
	}
		
	if (alsa_pcm != NULL) break;
    }
	
    /* Were we able to open a device? */
    if (alsa_card == (unsigned)snd_cards()) {
	printf("ALSA player: unable to find a configured device.\n");
	return -1;
    }
	
    /* Print info about the device. */
    if (snd_card_get_longname(alsa_card,&alsa_card_name) < 0)
	alsa_card_name = "(unknown)";
    printf("ALSA player: using device %i:%i (%s)\n",
	   alsa_card, alsa_device, alsa_card_name);
	
    /* Configure the device for the loaded sound data. */
    memset(&alsa_params,0,sizeof (alsa_params));
    alsa_params.channel = SND_PCM_CHANNEL_PLAYBACK;

    /* Use stream mode. In this mode, we don't have to give ALSA complete
       blocks; we can send it data as we get it. Block mode is needed for
       mmap() functionality. Unlike OSS, ALSA's mmap() functionality is
       quite reliable, and easily accessible through library functions.
       We won't use it here, though; there's no need. */
    alsa_params.mode = SND_PCM_MODE_STREAM;
    alsa_params.format.interleave = 1;
    
    /* We'll assume little endian samples. You may wish to use the data in
       the GNU C Library's endian.h to support other endiannesses. We're
       ignoring that case for simplicity. */
    if (bits == 8)
	alsa_params.format.format = SND_PCM_SFMT_U8;
    else if (bits == 16)
	alsa_params.format.format = SND_PCM_SFMT_S16_LE;
    else {
	printf("ALSA player: invalid sample size.\n");
	return -1;
    }
    alsa_params.format.rate = rate;
    alsa_params.format.voices = channels;
    alsa_params.start_mode = SND_PCM_START_DATA;
    alsa_params.stop_mode = SND_PCM_STOP_ROLLOVER;
    alsa_params.buf.block.frag_size = 4096;
    alsa_params.buf.block.frags_min = 1;
    alsa_params.buf.block.frags_max = 2;
	
    if ((i = snd_pcm_plugin_params(alsa_pcm,&alsa_params)) < 0) {
	printf("ALSA player: unable to set parameters.\n");
	snd_pcm_close(alsa_pcm);
	return -1;
    }

    if (snd_pcm_plugin_prepare(alsa_pcm, SND_PCM_CHANNEL_PLAYBACK) < 0) {
	printf("ALSA player: unable to prepare playback.\n");
	snd_pcm_close(alsa_pcm);
	return -1;
    }
	
    /* Feed the sound data to ALSA. */
    position = 0;
    while (position < bytes) {
	int written, blocksize;
		
	if (bytes-position < 4096)
	    blocksize = bytes-position;
	else
	    blocksize = 4096;
		
	/* Write to the sound device. */
	written = snd_pcm_plugin_write(alsa_pcm, &samples[position], blocksize);

	/* If ALSA can't take any more data right now, it'll return -EAGAIN.
	   If this were sound code for a game, we'd probably just contine the
	   game loop and try to write data the next time around.
	   In a game, you'd probably also want to put the device in nonblocking
	   mode (see the snd_pcm_nonblock_mode() function). */
	if (written == -EAGAIN) {
	    /* Waste some time. This keeps us from using 100% CPU. */
	    usleep(1000);

	    written = 0;
	} else {
	    if (written < 0) {
		perror("\nALSA player: error writing to sound device");
		snd_pcm_close(alsa_pcm);
		return -1;
	    }
	}

	/* Update the position. */
	position += written;

	/* Print some information. */
	WritePlaybackStatus(position, bytes, channels, bits, rate);
	printf("\r");
	fflush(stdout);
    }

    printf("\n");

    /* Wait until ALSA's internal buffers are empty, then stop playback.
       This will make sure that the entire sound clip has played. */
    snd_pcm_channel_flush(alsa_pcm, SND_PCM_CHANNEL_PLAYBACK);
    snd_pcm_close(alsa_pcm);

    return 0;
}