CVS: rdesktop rdpsnd_alsa.c,1.14,1.15

Pierre Ossman <[email protected]> Tue, 02 Jan 2007 08:36:53 -0800
Newsgroups gmane.network.rdesktop.cvs
Message-ID <[email protected]>
Update of /cvsroot/rdesktop/rdesktop
In directory sc8-pr-cvs9.sourceforge.net:/tmp/cvs-serv17211

Modified Files:
	rdpsnd_alsa.c 
Log Message:
Add capture support to the alsa backend.


Index: rdpsnd_alsa.c
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/rdpsnd_alsa.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** rdpsnd_alsa.c	2 Jan 2007 11:39:56 -0000	1.14
--- rdpsnd_alsa.c	2 Jan 2007 16:36:51 -0000	1.15
***************
*** 5,8 ****
--- 5,9 ----
     Copyright (C) GuoJunBo [email protected] 2003
     Copyright (C) Michael Gernoth [email protected] 2006
+    Copyright 2006 Pierre Ossman <[email protected]> for Cendio AB
  
     This program is free software; you can redistribute it and/or modify
***************
*** 33,48 ****
  #define MAX_FRAMES	32
  
! static struct pollfd pfds[32];
! static int num_fds;
  
- static snd_pcm_t *pcm_handle = NULL;
- static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
  static BOOL reopened;
! static short samplewidth;
! static int audiochannels;
! static unsigned int rate;
  static char *pcm_name;
  
  void alsa_play(void);
  
  void
--- 34,60 ----
  #define MAX_FRAMES	32
  
! static struct pollfd pfds_out[32];
! static int num_fds_out;
! 
! static struct pollfd pfds_in[32];
! static int num_fds_in;
! 
! static snd_pcm_t *out_handle = NULL;
! static snd_pcm_t *in_handle = NULL;
  
  static BOOL reopened;
! 
! static short samplewidth_out;
! static int audiochannels_out;
! static unsigned int rate_out;
! 
! static short samplewidth_in;
! static int audiochannels_in;
! static unsigned int rate_in;
! 
  static char *pcm_name;
  
  void alsa_play(void);
+ void alsa_record(void);
  
  void
***************
*** 52,78 ****
  	struct pollfd *f;
  
! 	if (!pcm_handle)
! 		return;
! 
! 	if (rdpsnd_queue_empty())
! 		return;
  
! 	num_fds = snd_pcm_poll_descriptors_count(pcm_handle);
  
! 	if (num_fds > sizeof(pfds) / sizeof(*pfds))
! 		return;
  
! 	err = snd_pcm_poll_descriptors(pcm_handle, pfds, num_fds);
! 	if (err < 0)
! 		return;
  
! 	for (f = pfds; f < &pfds[num_fds]; f++)
  	{
! 		if (f->events & POLLIN)
! 			FD_SET(f->fd, rfds);
! 		if (f->events & POLLOUT)
! 			FD_SET(f->fd, wfds);
! 		if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
! 			*n = f->fd;
  	}
  }
--- 64,109 ----
  	struct pollfd *f;
  
! 	if (out_handle && !rdpsnd_queue_empty())
! 	{
! 		num_fds_out = snd_pcm_poll_descriptors_count(out_handle);
  
! 		if (num_fds_out > sizeof(pfds_out) / sizeof(*pfds_out))
! 			return;
  
! 		err = snd_pcm_poll_descriptors(out_handle, pfds_out, num_fds_out);
! 		if (err < 0)
! 			return;
  
! 		for (f = pfds_out; f < &pfds_out[num_fds_out]; f++)
! 		{
! 			if (f->events & POLLIN)
! 				FD_SET(f->fd, rfds);
! 			if (f->events & POLLOUT)
! 				FD_SET(f->fd, wfds);
! 			if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
! 				*n = f->fd;
! 		}
! 	}
  
! 	if (in_handle)
  	{
! 		num_fds_in = snd_pcm_poll_descriptors_count(in_handle);
! 
! 		if (num_fds_in > sizeof(pfds_in) / sizeof(*pfds_in))
! 			return;
! 
! 		err = snd_pcm_poll_descriptors(in_handle, pfds_in, num_fds_in);
! 		if (err < 0)
! 			return;
! 
! 		for (f = pfds_in; f < &pfds_in[num_fds_in]; f++)
! 		{
! 			if (f->events & POLLIN)
! 				FD_SET(f->fd, rfds);
! 			if (f->events & POLLOUT)
! 				FD_SET(f->fd, wfds);
! 			if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
! 				*n = f->fd;
! 		}
  	}
  }
***************
*** 85,181 ****
  	unsigned short revents;
  
! 	if (!pcm_handle)
! 		return;
! 
! 	for (f = pfds; f < &pfds[num_fds]; f++)
  	{
! 		f->revents = 0;
! 		if (f->fd != -1)
  		{
! 			/* Fixme: This doesn't properly deal with things like POLLHUP */
! 			if (FD_ISSET(f->fd, rfds))
! 				f->revents |= POLLIN;
! 			if (FD_ISSET(f->fd, wfds))
! 				f->revents |= POLLOUT;
  		}
- 	}
- 
- 	err = snd_pcm_poll_descriptors_revents(pcm_handle, pfds, num_fds, &revents);
- 	if (err < 0)
- 		return;
- 
- 	if (revents & POLLOUT)
- 		alsa_play();
- }
  
! BOOL
! alsa_open(void)
! {
! 	int err;
  
! 	if ((err = snd_pcm_open(&pcm_handle, pcm_name, stream, 0)) < 0)
! 	{
! 		error("snd_pcm_open: %s\n", snd_strerror(err));
! 		return False;
  	}
  
- 	reopened = True;
- 
- 	return True;
- }
- 
- void
- alsa_close(void)
- {
- 	/* Ack all remaining packets */
- 	while (!rdpsnd_queue_empty())
- 		rdpsnd_queue_next(0);
  
! 	if (pcm_handle)
  	{
! 		snd_pcm_close(pcm_handle);
! 		pcm_handle = NULL;
! 	}
! }
! 
! BOOL
! alsa_format_supported(WAVEFORMATEX * pwfx)
! {
! #if 0
! 	int err;
! 	snd_pcm_hw_params_t *hwparams = NULL;
  
! 	if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
! 	{
! 		error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
! 		return False;
! 	}
  
! 	if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
! 	{
! 		error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
! 		return False;
  	}
- 	snd_pcm_hw_params_free(hwparams);
- #endif
- 
- 	if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
- 		return False;
- 	if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
- 		return False;
- 	if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
- 		return False;
- 	if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))
- 		return False;
- 
- 	return True;
  }
  
! BOOL
! alsa_set_format(WAVEFORMATEX * pwfx)
  {
  	snd_pcm_hw_params_t *hwparams = NULL;
  	int err;
  	unsigned int buffertime;
  
  	samplewidth = pwfx->wBitsPerSample / 8;
--- 116,176 ----
  	unsigned short revents;
  
! 	if (out_handle && !rdpsnd_queue_empty())
  	{
! 		for (f = pfds_out; f < &pfds_out[num_fds_out]; f++)
  		{
! 			f->revents = 0;
! 			if (f->fd != -1)
! 			{
! 				/* Fixme: This doesn't properly deal with things like POLLHUP */
! 				if (FD_ISSET(f->fd, rfds))
! 					f->revents |= POLLIN;
! 				if (FD_ISSET(f->fd, wfds))
! 					f->revents |= POLLOUT;
! 			}
  		}
  
! 		err = snd_pcm_poll_descriptors_revents(out_handle, pfds_out, num_fds_out, &revents);
! 		if (err < 0)
! 			return;
  
! 		if (revents & POLLOUT)
! 			alsa_play();
  	}
  
  
! 	if (in_handle)
  	{
! 		for (f = pfds_in; f < &pfds_in[num_fds_in]; f++)
! 		{
! 			f->revents = 0;
! 			if (f->fd != -1)
! 			{
! 				/* Fixme: This doesn't properly deal with things like POLLHUP */
! 				if (FD_ISSET(f->fd, rfds))
! 					f->revents |= POLLIN;
! 				if (FD_ISSET(f->fd, wfds))
! 					f->revents |= POLLOUT;
! 			}
! 		}
  
! 		err = snd_pcm_poll_descriptors_revents(in_handle, pfds_in, num_fds_in, &revents);
! 		if (err < 0)
! 			return;
  
! 		if (revents & POLLIN)
! 			alsa_record();
  	}
  }
  
! static BOOL
! alsa_set_format(snd_pcm_t * pcm, WAVEFORMATEX * pwfx)
  {
  	snd_pcm_hw_params_t *hwparams = NULL;
  	int err;
  	unsigned int buffertime;
+ 	short samplewidth;
+ 	int audiochannels;
+ 	unsigned int rate;
  
  	samplewidth = pwfx->wBitsPerSample / 8;
***************
*** 187,191 ****
  	}
  
! 	if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
  	{
  		error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));
--- 182,186 ----
  	}
  
! 	if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0)
  	{
  		error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));
***************
*** 193,198 ****
  	}
  
! 	if ((err =
! 	     snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
  	{
  		error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));
--- 188,192 ----
  	}
  
! 	if ((err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
  	{
  		error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));
***************
*** 202,207 ****
  	if (pwfx->wBitsPerSample == 16)
  	{
! 		if ((err =
! 		     snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
  		{
  			error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
--- 196,200 ----
  	if (pwfx->wBitsPerSample == 16)
  	{
! 		if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
  		{
  			error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
***************
*** 211,216 ****
  	else
  	{
! 		if ((err =
! 		     snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S8)) < 0)
  		{
  			error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
--- 204,208 ----
  	else
  	{
! 		if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S8)) < 0)
  		{
  			error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
***************
*** 220,224 ****
  
  #if 0
! 	if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 1)) < 0)
  	{
  		error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));
--- 212,216 ----
  
  #if 0
! 	if ((err = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 1)) < 0)
  	{
  		error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));
***************
*** 228,232 ****
  
  	rate = pwfx->nSamplesPerSec;
! 	if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0)) < 0)
  	{
  		error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));
--- 220,224 ----
  
  	rate = pwfx->nSamplesPerSec;
! 	if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0)
  	{
  		error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));
***************
*** 235,239 ****
  
  	audiochannels = pwfx->nChannels;
! 	if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, pwfx->nChannels)) < 0)
  	{
  		error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));
--- 227,231 ----
  
  	audiochannels = pwfx->nChannels;
! 	if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams, pwfx->nChannels)) < 0)
  	{
  		error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));
***************
*** 243,248 ****
  
  	buffertime = 500000;	/* microseconds */
! 	if ((err =
! 	     snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffertime, 0)) < 0)
  	{
  		error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));
--- 235,239 ----
  
  	buffertime = 500000;	/* microseconds */
! 	if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams, &buffertime, 0)) < 0)
  	{
  		error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));
***************
*** 250,254 ****
  	}
  
! 	if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
  	{
  		error("snd_pcm_hw_params: %s\n", snd_strerror(err));
--- 241,245 ----
  	}
  
! 	if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0)
  	{
  		error("snd_pcm_hw_params: %s\n", snd_strerror(err));
***************
*** 258,262 ****
  	snd_pcm_hw_params_free(hwparams);
  
! 	if ((err = snd_pcm_prepare(pcm_handle)) < 0)
  	{
  		error("snd_pcm_prepare: %s\n", snd_strerror(err));
--- 249,253 ----
  	snd_pcm_hw_params_free(hwparams);
  
! 	if ((err = snd_pcm_prepare(pcm)) < 0)
  	{
  		error("snd_pcm_prepare: %s\n", snd_strerror(err));
***************
*** 269,272 ****
--- 260,339 ----
  }
  
+ BOOL
+ alsa_open_out(void)
+ {
+ 	int err;
+ 
+ 	if ((err = snd_pcm_open(&out_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
+ 	{
+ 		error("snd_pcm_open: %s\n", snd_strerror(err));
+ 		return False;
+ 	}
+ 
+ 	reopened = True;
+ 
+ 	return True;
+ }
+ 
+ void
+ alsa_close_out(void)
+ {
+ 	/* Ack all remaining packets */
+ 	while (!rdpsnd_queue_empty())
+ 		rdpsnd_queue_next(0);
+ 
+ 	if (out_handle)
+ 	{
+ 		snd_pcm_close(out_handle);
+ 		out_handle = NULL;
+ 	}
+ }
+ 
+ BOOL
+ alsa_format_supported(WAVEFORMATEX * pwfx)
+ {
+ #if 0
+ 	int err;
+ 	snd_pcm_hw_params_t *hwparams = NULL;
+ 
+ 	if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
+ 	{
+ 		error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
+ 		return False;
+ 	}
+ 
+ 	if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
+ 	{
+ 		error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
+ 		return False;
+ 	}
+ 	snd_pcm_hw_params_free(hwparams);
+ #endif
+ 
+ 	if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
+ 		return False;
+ 	if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
+ 		return False;
+ 	if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
+ 		return False;
+ 	if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))
+ 		return False;
+ 
+ 	return True;
+ }
+ 
+ BOOL
+ alsa_set_format_out(WAVEFORMATEX * pwfx)
+ {
+ 	if (!alsa_set_format(out_handle, pwfx))
+ 		return False;
+ 
+ 	samplewidth_out = pwfx->wBitsPerSample / 8;
+ 	audiochannels_out = pwfx->nChannels;
+ 	rate_out = pwfx->nSamplesPerSec;
+ 
+ 	return True;
+ }
+ 
  void
  alsa_play(void)
***************
*** 297,307 ****
  	next_tick = rdpsnd_queue_next_tick();
  
! 	len = (out->end - out->p) / (samplewidth * audiochannels);
! 	if ((len = snd_pcm_writei(pcm_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
  	{
! 		snd_pcm_prepare(pcm_handle);
  		len = 0;
  	}
! 	out->p += (len * samplewidth * audiochannels);
  
  	gettimeofday(&tv, NULL);
--- 364,375 ----
  	next_tick = rdpsnd_queue_next_tick();
  
! 	len = (out->end - out->p) / (samplewidth_out * audiochannels_out);
! 	if ((len = snd_pcm_writei(out_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
  	{
! 		printf("Fooo!\n");
! 		snd_pcm_prepare(out_handle);
  		len = 0;
  	}
! 	out->p += (len * samplewidth_out * audiochannels_out);
  
  	gettimeofday(&tv, NULL);
***************
*** 327,336 ****
  		}
  
! 		if (snd_pcm_delay(pcm_handle, &delay_frames) < 0)
! 			delay_frames = out->size / (samplewidth * audiochannels);
  		if (delay_frames < 0)
  			delay_frames = 0;
  
! 		delay_us = delay_frames * (1000000 / rate);
  
  		rdpsnd_queue_next(delay_us);
--- 395,404 ----
  		}
  
! 		if (snd_pcm_delay(out_handle, &delay_frames) < 0)
! 			delay_frames = out->size / (samplewidth_out * audiochannels_out);
  		if (delay_frames < 0)
  			delay_frames = 0;
  
! 		delay_us = delay_frames * (1000000 / rate_out);
  
  		rdpsnd_queue_next(delay_us);
***************
*** 338,341 ****
--- 406,472 ----
  }
  
+ BOOL
+ alsa_open_in(void)
+ {
+ 	int err;
+ 
+ 	if ((err =
+ 	     snd_pcm_open(&in_handle, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0)
+ 	{
+ 		error("snd_pcm_open: %s\n", snd_strerror(err));
+ 		return False;
+ 	}
+ 
+ 	return True;
+ }
+ 
+ void
+ alsa_close_in(void)
+ {
+ 	if (in_handle)
+ 	{
+ 		snd_pcm_close(in_handle);
+ 		in_handle = NULL;
+ 	}
+ }
+ 
+ BOOL
+ alsa_set_format_in(WAVEFORMATEX * pwfx)
+ {
+ 	int err;
+ 
+ 	if (!alsa_set_format(in_handle, pwfx))
+ 		return False;
+ 
+ 	if ((err = snd_pcm_start(in_handle)) < 0)
+ 	{
+ 		error("snd_pcm_start: %s\n", snd_strerror(err));
+ 		return False;
+ 	}
+ 
+ 	samplewidth_in = pwfx->wBitsPerSample / 8;
+ 	audiochannels_in = pwfx->nChannels;
+ 	rate_in = pwfx->nSamplesPerSec;
+ 
+ 	return True;
+ }
+ 
+ void
+ alsa_record(void)
+ {
+ 	int len;
+ 	char buffer[32768];
+ 
+ 	len = snd_pcm_readi(in_handle, buffer,
+ 			    sizeof(buffer) / (samplewidth_in * audiochannels_in));
+ 	if (len < 0)
+ 	{
+ 		snd_pcm_prepare(in_handle);
+ 		len = 0;
+ 	}
+ 
+ 	rdpsnd_record(buffer, len * samplewidth_in * audiochannels_in);
+ }
+ 
  struct audio_driver *
  alsa_register(char *options)
***************
*** 351,360 ****
  	alsa_driver.check_fds = alsa_check_fds;
  
! 	alsa_driver.wave_out_open = alsa_open;
! 	alsa_driver.wave_out_close = alsa_close;
  	alsa_driver.wave_out_format_supported = alsa_format_supported;
! 	alsa_driver.wave_out_set_format = alsa_set_format;
  	alsa_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
  
  	alsa_driver.need_byteswap_on_be = 0;
  	alsa_driver.need_resampling = 0;
--- 482,497 ----
  	alsa_driver.check_fds = alsa_check_fds;
  
! 	alsa_driver.wave_out_open = alsa_open_out;
! 	alsa_driver.wave_out_close = alsa_close_out;
  	alsa_driver.wave_out_format_supported = alsa_format_supported;
! 	alsa_driver.wave_out_set_format = alsa_set_format_out;
  	alsa_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
  
+ 	alsa_driver.wave_in_open = alsa_open_in;
+ 	alsa_driver.wave_in_close = alsa_close_in;
+ 	alsa_driver.wave_in_format_supported = alsa_format_supported;
+ 	alsa_driver.wave_in_set_format = alsa_set_format_in;
+ 	alsa_driver.wave_in_volume = NULL;	/* FIXME */
+ 
  	alsa_driver.need_byteswap_on_be = 0;
  	alsa_driver.need_resampling = 0;


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV