[Sumover-dev] [svn commit] r3823 - rat/trunk
sumover-dev at cs.ucl.ac.uk
sumover-dev at cs.ucl.ac.uk
Fri Sep 8 19:31:28 BST 2006
Author: piers
Date: Fri Sep 8 19:30:56 2006
New Revision: 3823
Modified:
rat/trunk/auddev_alsa.c
Log:
Sorted out mixer device selection for all devices - the key was to add an alsa event
handling routine - handle_mixer_events(). Sorted out gain control so it
works for all devices including Audigy type devices (which don't have per mixer
element 'capture switches' - just input sliders).
However audio handling still doesn't work properly - It is basically usable - especially in nondebug compile but we're still seeing bursts of transmit XRUN's which cause minor audio breaks - anyone got any ideas?! (maybe related to cushion?)
Modified: rat/trunk/auddev_alsa.c
==============================================================================
--- rat/trunk/auddev_alsa.c (original)
+++ rat/trunk/auddev_alsa.c Fri Sep 8 19:30:56 2006
@@ -47,6 +47,7 @@
static RatCardInfo ratCards[MAX_RAT_CARDS];
static int nRatCards = 0;
+static int mixer_state_change = 0;
/* Define ALSA mixer identifiers. We use these to lookup the volume
* controls on the mixer. This feels like a bit of a hack, but
@@ -65,7 +66,8 @@
typedef struct _port_t {
audio_port_details_t details;
- snd_mixer_elem_t* mixer;
+ snd_mixer_selem_id_t *sid;
+ snd_mixer_elem_t* smixer_elem;
int priority;
} port_t;
@@ -113,6 +115,7 @@
current.mixer = NULL;
current.index = -1;
current.info = NULL;
+ current.iport = (audio_port_t)NULL;
}
@@ -127,30 +130,30 @@
"S16"
};
-// Ah, exceptions, I hardly new thee ...
+// Trimmed down Error macros
#define CHECKERR(msg) \
{ \
if (err < 0) \
{ \
- fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
+ debug_msg(msg); \
+ debug_msg("snd_strerror : %s\n", snd_strerror(err)); \
return FALSE; \
} \
- }
-#define CHECKERRCONT(msg) \
-{ \
- if (err < 0) \
- fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
- }
-#define VCHECKERR(msg) \
+}
+#define CHECKOPENERR(msg) \
{ \
if (err < 0) \
{ \
- fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
- return; \
+ debug_msg(msg); \
+ debug_msg("snd_strerror : %s\n", snd_strerror(err)); \
+ snd_pcm_close(stream->handle); \
+ stream->handle=NULL; \
+ return FALSE; \
} \
}
+
static int mapformat(deve_e encoding)
{
int format = -1;
@@ -235,18 +238,6 @@
/* *** Alsa driver implementation. *** */
-#undef CHECKOPENERR
-#define CHECKOPENERR(msg) \
-{ \
- if (err < 0) \
- { \
- fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
- snd_pcm_close(stream->handle); \
- stream->handle=NULL; \
- return FALSE; \
- } \
-}
-
static int open_stream(RatCardInfo *info, pcm_stream_t *stream,
snd_pcm_stream_t type, audio_format *fmt)
{
@@ -259,12 +250,13 @@
snd_pcm_sw_params_t *sw_params;
/* Set avail min inside a software configuration container */
/* Can we tweak this up/down?*/
- snd_pcm_uframes_t avail_min=4;
+ snd_pcm_uframes_t avail_min=100; //4
snd_pcm_uframes_t xfer_align=1;
err = snd_pcm_open(&stream->handle, info->pcm_device,
type, SND_PCM_NONBLOCK);
- CHECKERR("Card open failed");
+ debug_msg("ALSA:open_stream: %s\n",info->pcm_device);
+ if (err<0) { debug_msg("Card open failed"); return FALSE; }
snd_pcm_hw_params_alloca (&hw_params);
@@ -289,8 +281,10 @@
&rrate, &dir);
CHECKOPENERR("Failed to set sample rate");
if (rrate != fmt->sample_rate) {
- fprintf(stderr, "ALSA rate set to %d when we wanted %d\n",
+ debug_msg("Error: ALSA rate set to %d when we wanted %d\n",
rrate, fmt->sample_rate);
+ snd_pcm_close(stream->handle);
+ stream->handle=NULL;
return FALSE;
}
@@ -347,20 +341,6 @@
}
-// Get the mixer
-
-#undef CHECKOPENERR
-#define CHECKOPENERR(msg) \
-{ \
- if (err < 0) \
- { \
- fprintf(stderr, msg ": %s\n", snd_strerror(err)); \
- snd_mixer_close(current.mixer); \
- current.mixer=NULL; \
- return FALSE; \
- } \
-}
-
// Open a named mixer
static int open_volume_ctl(char *name, snd_mixer_elem_t **ctl)
@@ -376,8 +356,6 @@
snd_mixer_selem_id_set_name (sid, name);
*ctl = snd_mixer_find_selem(current.mixer, sid);
- //err = (int)*ctl;
- //CHECKOPENERR("Couldn't find mixer control element");
if (*ctl == NULL ) {
debug_msg("Couldn't find mixer control element (name:%s)\n",name);
return FALSE;
@@ -388,9 +366,11 @@
// FIXME: Does this always work?
snd_mixer_selem_set_playback_volume_range (*ctl, 0, 100);
- if ( snd_mixer_selem_has_playback_switch( *ctl ) ) {
- err = snd_mixer_selem_set_playback_switch_all(*ctl, 1);
- CHECKOPENERR("Failed to switch on playback volume");
+ if (snd_mixer_selem_has_playback_switch( *ctl ) ) {
+ if (snd_mixer_selem_set_playback_switch_all(*ctl, 1) < 0) {
+ debug_msg("Failed to switch on playback volume");
+ return FALSE;
+ }
}
} else if (snd_mixer_selem_has_capture_volume(*ctl)) {
@@ -398,7 +378,10 @@
snd_mixer_selem_set_capture_volume_range (*ctl, 0, 100);
err = snd_mixer_selem_set_capture_switch_all(*ctl, 1);
- CHECKOPENERR("Failed to switch on capture volume");
+ if (err<0) {
+ debug_msg("Failed to switch on capture volume");
+ return FALSE;
+ }
} else {
debug_msg("Unknown mixer type %s set\n", name);
@@ -416,53 +399,104 @@
return (((port_t*)a)->priority - ((port_t*)b)->priority);
}
+/* Not used for now. It seems to cause problems in mbus, however it
+ * may be useful for handling mixer updates from external sources
+ *
+static int
+mixer_callback (snd_mixer_t *mixer, unsigned int mask, snd_mixer_elem_t *elem)
+{
+ mixer_state_change = 1;
+ debug_msg("mixer_callback\n");
+ return 0;
+}
+*/
+
static int setup_mixers()
{
- snd_mixer_elem_t *elem;
+ snd_mixer_elem_t *elem, *selem;
+ snd_mixer_selem_id_t *sid;
int err;
unsigned i;
int need_cap_switch=1;
+ snd_mixer_selem_id_alloca(&sid);
+
err = snd_mixer_open (¤t.mixer, 0);
- CHECKERR("Failed to open the mixer");
+ if (err < 0) {
+ debug_msg("Failed to open the mixer(snd err: %s)",snd_strerror(err));
+ current.mixer=NULL;
+ return FALSE;
+ }
- // FIXME: Attach the mixer to the default card. Is this enough?
- //err = snd_mixer_attach(current.mixer, "default");
err = snd_mixer_attach(current.mixer, current.info->pcm_mixer);
-// err = snd_mixer_attach(current.mixer, "hw:0,0");
- CHECKOPENERR("Failed to attach mixer");
+ if (err < 0) {
+ debug_msg("Failed to attach the mixer(snd err: %s)",snd_strerror(err));
+ snd_mixer_close(current.mixer);
+ current.mixer=NULL;
+ return FALSE;
+ }
err = snd_mixer_selem_register(current.mixer, NULL, NULL);
- CHECKOPENERR("Failed to register mixer");
+ if (err < 0) {
+ debug_msg("Failed to register the mixer(snd err: %s)",snd_strerror(err));
+ snd_mixer_close(current.mixer);
+ current.mixer=NULL;
+ return FALSE;
+ }
- err = snd_mixer_load(current.mixer);
- CHECKOPENERR("Failed to load mixer");
+ /* Not used for now - see above */
+ /* snd_mixer_set_callback (current.mixer, mixer_callback); */
+ err = snd_mixer_load(current.mixer);
+ if (err < 0) {
+ debug_msg("Failed to load the mixer(snd err: %s)",snd_strerror(err));
+ snd_mixer_close(current.mixer);
+ current.mixer=NULL;
+ return FALSE;
+ }
- // Get the playback and capture volume controls
- /*if ((!open_volume_ctl(RAT_ALSA_MIXER_PCM_NAME, ¤t.txgain)) ||
- (!open_volume_ctl(RAT_ALSA_MIXER_CAPTURE_NAME, ¤t.rxgain)))
- return FALSE; */
- if (!open_volume_ctl(RAT_ALSA_MIXER_PCM_NAME, ¤t.txgain))
- return FALSE;
- if (!open_volume_ctl(RAT_ALSA_MIXER_CAPTURE_NAME, ¤t.rxgain))
+ /* Get the playback and capture volume controls
+ * If Capture open fails it ptobably means we have a capture card
+ * which does not support capture_switch - in which case we set the
+ * capture level of the selected input device.
+ */
+ if (!open_volume_ctl(RAT_ALSA_MIXER_PCM_NAME, ¤t.txgain)) {
+ snd_mixer_close(current.mixer);
+ current.mixer=NULL;
+ return FALSE;
+ }
+ if (!open_volume_ctl(RAT_ALSA_MIXER_CAPTURE_NAME, ¤t.rxgain)) {
need_cap_switch=0;
+ current.rxgain=0;
+ }
num_iports = 0;
- // We now scan the mixer for recording controls. We're interested in
- // the controls that are part of a group (i.e. radio-button types) that
- // can be flipped between.
+ /* We now scan the mixer for recording controls. We're interested in
+ * the controls that are part of a group (i.e. radio-button types) that
+ * can be flipped between.
+ */
for (elem = snd_mixer_first_elem (current.mixer);
elem && (num_iports < MAX_RAT_DEVICES);
elem = snd_mixer_elem_next (elem))
{
- int gid = snd_mixer_selem_get_capture_group(elem);
- const char *name = snd_mixer_selem_get_name(elem);
- debug_msg("Trying CAPTURE element '%s' of group %d \n", name, gid);
-
- if (snd_mixer_selem_has_capture_volume(elem) ||
- snd_mixer_selem_has_capture_switch(elem) )
+ if (!snd_mixer_selem_is_active(elem) ||
+ snd_mixer_selem_is_enumerated(elem))
+ continue;
+
+ sid = (snd_mixer_selem_id_t*)malloc(snd_mixer_selem_id_sizeof());
+ snd_mixer_selem_get_id( elem, sid );
+ /* Find the Simple mixer element */
+ selem = snd_mixer_find_selem(current.mixer, sid );
+
+ int gid = snd_mixer_selem_get_capture_group(selem);
+ const char *name = snd_mixer_selem_get_name(selem);
+
+ debug_msg("Trying CAPTURE element '%s' of group %d \n", name, gid);
+
+ /* The code below is minimal so it works for card without capture switch */
+ if (snd_mixer_selem_has_capture_volume(selem) ||
+ snd_mixer_selem_has_capture_switch(selem) )
// snd_mixer_selem_is_active (elem) &&
// (snd_mixer_selem_has_capture_switch(elem)) &&
// snd_mixer_selem_has_capture_switch_exclusive(elem))
@@ -471,12 +505,13 @@
// than one capture group, but RAT isn't really equipped to handle
// the case so we'll just ignore it for now.
-
debug_msg("Got CAPTURE element '%s' of group %d\n", name, gid);
snprintf(iports[num_iports].details.name, AUDIO_PORT_NAME_LENGTH,
"%s", name);
- iports[num_iports].mixer = elem;
+ iports[num_iports].smixer_elem = selem;
+ //iports[num_iports].sid = sid;
+ debug_msg("Found %s selem:%d (sid:%d)\n",iports[num_iports].details.name,selem,iports[num_iports].sid );
// The principle of least-surprise means that we should present
// the ports in the same order as the other drivers. As we're
@@ -520,39 +555,47 @@
//clear_current();
if (current.tx.handle != NULL) {
- fprintf(stderr, "Attempt to open a device while another is open\n");
+ debug_msg( "Attempt to open a device while another is open\n");
return FALSE;
}
current.index = ad;
current.info = ratCards + ad;
current.bytes_per_block = infmt->bytes_per_block;
- fprintf(stderr, "to open device for playback\n");
if (!open_stream(current.info, ¤t.tx,
SND_PCM_STREAM_PLAYBACK, outfmt)) {
alsa_audio_close(ad);
- fprintf(stderr, "Failed to open device for playback\n");
+ debug_msg( "Failed to open device for playback\n");
return FALSE;
}
- fprintf(stderr, "to open device for capture\n");
+ debug_msg( "to open device for capture\n");
if (!open_stream(current.info, ¤t.rx,
SND_PCM_STREAM_CAPTURE, infmt)) {
alsa_audio_close(ad);
- fprintf(stderr, "Failed to open device for capture\n");
+ debug_msg( "Failed to open device for capture\n");
return FALSE;
}
if (setup_mixers() == FALSE) {
alsa_audio_close(ad);
- fprintf(stderr, "Failed to set mixer levels \n");
+ debug_msg( "Failed to set mixer levels \n");
return FALSE;
}
err = snd_pcm_prepare(current.tx.handle);
- CHECKERR("Failed to prepare playback");
+ if (err<0) {
+ debug_msg("Failed to prepare playback");
+ alsa_audio_close(ad);
+ return FALSE;
+ }
+
err = snd_pcm_start(current.rx.handle);
- CHECKERR("Failed to start PCM capture");
+ if (err<0) {
+ debug_msg("Failed to start PCM capture");
+ alsa_audio_close(ad);
+ return FALSE;
+ }
return TRUE;
}
@@ -574,18 +617,18 @@
if (current.tx.handle != NULL ) {
err = snd_pcm_close(current.tx.handle);
- CHECKERRCONT("Error closing playback PCM");
+ if (err<0) debug_msg("Error closing playback PCM");
}
if (current.rx.handle != NULL ) {
err = snd_pcm_close(current.rx.handle);
- CHECKERRCONT("Error closing capture PCM");
+ if (err<0) debug_msg("Error closing capture PCM");
}
// Close mixer
if (current.mixer != NULL ) {
err = snd_mixer_close(current.mixer);
- CHECKERRCONT("Error closing mixer");
+ if (err<0) debug_msg("Error closing mixer");
}
clear_current();
@@ -600,22 +643,36 @@
debug_msg("audio_drain\n");
err = snd_pcm_drain(current.rx.handle);
- VCHECKERR("Problem draining input");
+ if (err<0) debug_msg("Problem draining input\n");
}
/*
- * Set record gain.
+ * Set capture gain.
*/
void alsa_audio_set_igain(audio_desc_t ad, int gain)
{
int err;
debug_msg("Set igain %d %d\n", ad, gain);
- //err = snd_mixer_selem_set_capture_volume_all(current.rxgain, gain);
- err = snd_mixer_selem_set_capture_volume_all(current.rxgain, gain);
- VCHECKERR("Couldn't set capture volume");
+ if (current.rxgain) {
+ if (snd_mixer_selem_has_capture_switch(current.rxgain)) {
+ err = snd_mixer_selem_set_capture_volume_all(current.rxgain, gain);
+ if (err<0) debug_msg("Failed to set capture volume\n");
+ } else {
+ // Or try setting capture level of selected input
+ debug_msg("Attempting to set input element capture volume\n");
+ err = snd_mixer_selem_set_capture_volume_all(iports[current.iport].smixer_elem, gain);
+ if(err<0) debug_msg("Failed to set capture volume\n");
+ }
+ } else {
+ // Or try setting capture level of selected input
+ debug_msg("current.rxgain=0 - Attempting to set input element capture volume\n");
+ err = snd_mixer_selem_set_capture_volume_all(iports[current.iport].smixer_elem, gain);
+ if(err<0) debug_msg("Failed to set capture volume\n");
+ }
+ mixer_state_change = 1;
}
@@ -624,14 +681,25 @@
*/
int alsa_audio_get_igain(audio_desc_t ad)
{
- long igain;
+ long igain=0;
int err;
debug_msg("Get igain %d\n", ad);
- //err = snd_mixer_selem_get_capture_volume(current.rxgain,
- err = snd_mixer_selem_get_capture_volume(current.rxgain,
- SND_MIXER_SCHN_MONO, &igain);
- CHECKERR("Failed to get capture volume");
+ if (current.rxgain) {
+ if (snd_mixer_selem_has_capture_switch(current.rxgain)) {
+ err = snd_mixer_selem_get_capture_volume(current.rxgain,
+ SND_MIXER_SCHN_MONO, &igain);
+ if(err<0) debug_msg("Failed to get capture volume");
+ } else {
+ // Or try getting capture level of selected input
+ err = snd_mixer_selem_get_capture_volume(iports[current.iport].smixer_elem, SND_MIXER_SCHN_MONO, &igain);
+ if(err<0) debug_msg("Failed to get capture volume");
+ }
+ } else {
+ // Or try getting capture level of selected input
+ err = snd_mixer_selem_get_capture_volume(iports[current.iport].smixer_elem, SND_MIXER_SCHN_MONO, &igain);
+ if(err<0) debug_msg("Failed to get capture volume");
+ }
return (int)igain;
}
@@ -651,11 +719,12 @@
debug_msg("Set ogain %d %d\n", ad, vol);
err = snd_mixer_selem_set_playback_switch_all(current.txgain, 1);
- VCHECKERR("Failed to switch on playback volume");
+ if(err<0) debug_msg("Failed to switch on playback volume");
err = snd_mixer_selem_set_playback_volume_all(current.txgain, vol);
- VCHECKERR("Couldn't set mixer playback volume");
+ if(err<0) debug_msg("Couldn't set mixer playback volume");
+ mixer_state_change = 1;
}
/*
@@ -664,34 +733,90 @@
int
alsa_audio_get_ogain(audio_desc_t ad)
{
- long ogain;
+ long ogain=0;
int err;
debug_msg("Get ogain %d\n", ad);
err = snd_mixer_selem_get_playback_volume(current.txgain,
SND_MIXER_SCHN_MONO, &ogain);
- CHECKERR("Failed to get capture volume");
+ if(err<0) debug_msg("Failed to get capture volume");
return (int)ogain;
}
+static void handle_mixer_events(snd_mixer_t *mixer_handle)
+{
+ int count, err;
+ struct pollfd *fds;
+ int num_revents = 0;
+ unsigned short revents;
+
+ /* Get count of poll descriptors for mixer handle */
+ if ((count = snd_mixer_poll_descriptors_count(mixer_handle)) < 0) {
+ debug_msg("Error in snd_mixer_poll_descriptors_count(%d)\n", count);
+ return;
+ }
+
+ fds =(struct pollfd*)calloc(count, sizeof(struct pollfd));
+ if (fds == NULL) {
+ debug_msg("snd_mixer fds calloc err\n");
+ return;
+ }
+
+ if ((err = snd_mixer_poll_descriptors(mixer_handle, fds, count)) < 0){
+ debug_msg ("snd_mixer_poll_descriptors err=%d\n", err);
+ free(fds);
+ return;
+ }
+
+ if (err != count){
+ debug_msg ("snd_mixer_poll_descriptors (err(%d) != count(%d))\n",err,count);
+ free(fds);
+ return;
+ }
+
+ num_revents = poll(fds, count, 1);
+
+ /* Graceful handling of signals recvd in poll() */
+ if (num_revents < 0 && errno == EINTR)
+ num_revents = 0;
+
+ if (num_revents > 0) {
+ if (snd_mixer_poll_descriptors_revents(mixer_handle, fds, count, &revents) >= 0) {
+ if (revents & POLLNVAL)
+ debug_msg ("snd_mixer_poll_descriptors (POLLNVAL)\n");
+ if (revents & POLLERR)
+ debug_msg ("snd_mixer_poll_descriptors (POLLERR)\n");
+ if (revents & POLLIN)
+ snd_mixer_handle_events(mixer_handle);
+ }
+ }
+ free(fds);
+}
+
/*
* Record audio data.
*/
int alsa_audio_read(audio_desc_t ad __attribute__((unused)),
u_char *buf, int bytes)
- {
- snd_pcm_sframes_t frames = snd_pcm_bytes_to_frames(current.rx.handle, bytes);
+{
snd_pcm_sframes_t fread;
int err;
+ if (mixer_state_change) {
+ mixer_state_change=0;
+ handle_mixer_events (current.mixer);
+ }
+
+ snd_pcm_sframes_t frames = snd_pcm_bytes_to_frames(current.rx.handle,bytes);
+
fread = snd_pcm_readi(current.rx.handle, buf, frames);
if (fread >= 0) {
// Normal case
fread = snd_pcm_frames_to_bytes(current.rx.handle, fread);
- debug_msg("Read %d bytes\n", fread);
+ //debug_msg("Read %d bytes\n", fread);
return fread;
}
@@ -703,26 +828,26 @@
return 0;
case -EPIPE:
- debug_msg("Got capture XRUN\n");
- err = snd_pcm_prepare(current.rx.handle);
- CHECKERR("Can't recover from capture overrun");
- err = snd_pcm_start(current.rx.handle);
- CHECKERR("Failed to start PCM capture");
- return FALSE;
-
- case -ESTRPIPE:
- debug_msg("Got capture ESTRPIPE\n");
- while ((err = snd_pcm_resume(current.rx.handle)) == -EAGAIN)
- sleep(1); /* wait until the suspend flag is released */
- if (err < 0) {
- err = snd_pcm_prepare(current.rx.handle);
- CHECKERR("Can't recovery from capture suspend");
- }
- return FALSE;
+ debug_msg("Got capture XRUN (EPIPE)\n");
+ err = snd_pcm_prepare(current.rx.handle);
+ if (err<0) debug_msg("Failed snd_pcm_prepare from capture overrun");
+ err = snd_pcm_start(current.rx.handle);
+ if (err<0) debug_msg("Failed to re-start PCM capture from XRUN");
+ return FALSE;
+
+ case -ESTRPIPE:
+ debug_msg("Got capture ESTRPIPE\n");
+ while ((err = snd_pcm_resume(current.rx.handle)) == -EAGAIN)
+ sleep(1); /* wait until the suspend flag is released */
+ if (err < 0) {
+ err = snd_pcm_prepare(current.rx.handle);
+ if (err<0) debug_msg("Failed snd_pcm_prepare from capture suspend");
+ }
+ return FALSE;
default:
- debug_msg("Write failed status=%d: %s\n", snd_strerror(fread));
- return 0;
+ //debug_msg("Read failed status= %s\n", snd_strerror(fread));
+ return 0;
}
}
@@ -734,18 +859,18 @@
int alsa_audio_write(audio_desc_t ad __attribute__((unused)),
u_char *buf, int bytes)
{
- int fwritten, err;
+ int fwritten, err, num_bytes=0;
snd_pcm_sframes_t frames =
snd_pcm_bytes_to_frames(current.tx.handle,bytes);
- debug_msg("Audio write %d\n", bytes);
+ ///debug_msg("Audio write %d\n", bytes);
fwritten = snd_pcm_writei(current.tx.handle, buf, frames);
if (fwritten >= 0) {
// Normal case
- fwritten = snd_pcm_frames_to_bytes(current.tx.handle, fwritten);
- debug_msg("Wrote %d bytes\n", fwritten);
- return fwritten;
+ num_bytes = snd_pcm_frames_to_bytes(current.tx.handle, fwritten);
+ debug_msg("Wrote %d bytes, frames: %d\n", num_bytes, fwritten);
+ return num_bytes;
}
// Something happened
@@ -753,14 +878,22 @@
{
case -EAGAIN:
// Normal when non-blocking
- return FALSE;
+ return 0;
case -EPIPE:
- debug_msg("Got transmit XRUN\n");
+ debug_msg("Got transmit XRUN (EPIPE)\n");
err = snd_pcm_prepare(current.tx.handle);
- err = snd_pcm_writei(current.tx.handle, buf, frames);
- CHECKERR("Can't recover from transmit overrun");
- return TRUE;
+ if (err<0) debug_msg("Failed snd_pcm_prepare from Transmit overrun\n");
+ debug_msg("Attempting Recovery from transmit overrun: Bytes:%d Frames:%d\n",num_bytes,fwritten);
+ fwritten = snd_pcm_writei(current.tx.handle, buf, frames);
+ if (fwritten<0) {
+ debug_msg("Can't recover from transmit overrun\n");
+ return 0;
+ } else {
+ num_bytes = snd_pcm_frames_to_bytes(current.tx.handle, fwritten);
+ debug_msg("Recovered from transmit overrun: Bytes:%d Frames:%d\n",num_bytes,fwritten);
+ return num_bytes;
+ }
case -ESTRPIPE:
debug_msg("Got transmit ESTRPIPE\n");
@@ -768,19 +901,19 @@
sleep(1); /* wait until the suspend flag is released */
if (err < 0) {
err = snd_pcm_prepare(current.tx.handle);
- CHECKERR("Can't recovery from transmit suspend");
- }
- return FALSE;
+ if (err<0) debug_msg("Can't recovery from transmit suspend\n");
+ }
+ return 0;
default:
- debug_msg("Write failed status=%d: %s\n", snd_strerror(fwritten));
- return FALSE;
+ //debug_msg("Write failed status=%d: %s\n", fwritten, snd_strerror(fwritten));
+ return 0;
}
- fwritten = snd_pcm_frames_to_bytes(current.tx.handle, fwritten);
- debug_msg("Audio wrote %d\n", fwritten);
- return fwritten;
+ num_bytes = snd_pcm_frames_to_bytes(current.tx.handle, fwritten);
+ debug_msg("Audio wrote %d\n", num_bytes);
+ return num_bytes;
}
@@ -793,22 +926,21 @@
debug_msg("Set nonblocking\n");
err = snd_pcm_nonblock(current.tx.handle, TRUE);
- VCHECKERR("Error setting TX non-blocking");
+ if(err<0) debug_msg("Error setting TX non-blocking");
err = snd_pcm_nonblock(current.rx.handle, TRUE);
- VCHECKERR("Error setting RX non-blocking");
- }
+ if(err<0) debug_msg("Error setting RX non-blocking");
+}
- /*
+/*
* Set options on audio device to be blocking.
- */
+ */
void alsa_audio_block(audio_desc_t ad)
{
int err;
debug_msg("[%d] set blocking\n", ad);
if ((err = snd_pcm_nonblock(current.tx.handle, FALSE)) < 0) {
- fprintf (stderr, "Cannot set blocking: %s\n",
- snd_strerror (err));
+ debug_msg ("Cannot set device to be blocking: %s\n", snd_strerror(err));
}
}
@@ -852,25 +984,51 @@
alsa_audio_iport_set(audio_desc_t ad, audio_port_t port)
{
int err = 0;
- audio_port_t i;
- debug_msg("iport_set %d %d\n", ad, port);
- current.iport = port;
-
- for (i=0; i < num_iports; i++) {
- err = snd_mixer_selem_set_capture_switch_all(
- iports[i].mixer, (i==port));
- }
- /* If there's an error assume that capture switches don't work on
- * this card so let RAT try and set the levels on the currently
- * selected input item directly
- */
- if (err<0)
- current.rxgain=iports[port].mixer;
+ audio_port_t i=port;
+ snd_mixer_elem_t *selem;
- VCHECKERR("Failed to set record switch");
+ ad=ad; // Silence compiler warning
+ current.iport = port;
+ //The following does not seems necessary - though it does work
+ //selem = snd_mixer_find_selem(current.mixer, iports[port].sid);
+ selem = iports[port].smixer_elem;
+ debug_msg("Selecting input port: %s\n",iports[i].details.name);
+
+ if(selem)
+ if (snd_mixer_selem_has_capture_switch(selem)) {
+ if (snd_mixer_selem_has_capture_switch_joined(selem)){
+ snd_mixer_selem_get_capture_switch(selem,SND_MIXER_SCHN_FRONT_LEFT,&err);
+ debug_msg("Found snd_mixer_selem_has_capture_switch_joined\n");
+ err=snd_mixer_selem_set_capture_switch_all(selem,1);
+ if (err<0) {
+ debug_msg("Error encountered setting joined capture switch\n" );
+ }
+ } else {
+ debug_msg("Found separate L+R captures levels\n" );
+ err=snd_mixer_selem_set_capture_switch(selem,SND_MIXER_SCHN_FRONT_LEFT,1);
+ if (err<0) {
+ debug_msg("Error setting Left capture switch \n" );
+ }
+ err=snd_mixer_selem_set_capture_switch(selem,SND_MIXER_SCHN_FRONT_RIGHT,1);
+ if (err<0) {
+ debug_msg("Error setting Right capture switch \n" );
+ }
+ }
+ }
+ // Make sure Capture switch is on.
+ if (current.rxgain) {
+ if (snd_mixer_selem_has_capture_switch(current.rxgain)) {
+ err=snd_mixer_selem_set_capture_switch_all(current.rxgain,1);
+ if (err<0) {
+ debug_msg("Error setting Capture switch\n" );
+ }
+ }
+ }
+ mixer_state_change = 1;
}
+
/*
* Get input port.
*/
@@ -884,13 +1042,15 @@
int
alsa_audio_iport_count(audio_desc_t ad)
{
- debug_msg("Get iport count for %d (=%d)\n", ad, num_iports);
+ debug_msg("Get iport count for %d (num=%d)\n", ad, num_iports);
return num_iports;
}
const audio_port_details_t* alsa_audio_iport_details(audio_desc_t ad, int idx)
{
- debug_msg("iport details ad=%d idx=%d\n", ad, idx);
+ int err;
+ snd_mixer_selem_get_capture_switch(iports[idx].smixer_elem,SND_MIXER_SCHN_FRONT_LEFT,&err);
+ debug_msg("iport details ad=%d idx=%d : %s (Enabled=%d)\n", ad, idx, iports[idx].details.name,err);
return &iports[idx].details;
}
@@ -907,32 +1067,34 @@
snd_pcm_status_alloca(&status);
err = snd_pcm_status(current.rx.handle, status);
- CHECKERR("Can't get status of rx");
+ if (err<0) {
+ debug_msg("Can't get status of rx");
+ return FALSE;
+ }
avail = snd_pcm_frames_to_bytes(current.rx.handle,
snd_pcm_status_get_avail(status));
- debug_msg("Audio ready == %d\n", avail);
+ //debug_msg("Audio ready == %d\n", avail);
return (avail >= current.bytes_per_block);
-
}
void alsa_audio_wait_for(audio_desc_t ad __attribute__((unused)), int delay_ms)
- {
- debug_msg("Audio wait %d\n", delay_ms);
+{
+ ///debug_msg("Audio wait %d\n", delay_ms);
snd_pcm_wait(current.rx.handle, delay_ms);
- }
+}
char* alsa_get_device_name(audio_desc_t idx)
- {
+{
debug_msg("Get name for card %d: \"%s\"\n", idx, ratCards[idx].name);
return ratCards[idx].name;
}
int alsa_audio_init()
- {
+{
int fd;
char buf[4096];
char *version;
@@ -971,13 +1133,13 @@
clear_current();
return result;
- }
+}
int alsa_get_device_count()
- {
+{
snd_ctl_t *ctl_handle;
snd_ctl_card_info_t *ctl_info;
- int err, cindex = 0;
+ int err, cindex = 0, alsaDevNo=0;
char card[128];
// Ptr to ratCards array
RatCardInfo *ratCard;
@@ -985,65 +1147,60 @@
debug_msg("ALSA get device count\n");
snd_ctl_card_info_alloca(&ctl_info);
+
+ // Get ALSA "default" card - so things like dsnoop etc can work
+ if (!snd_ctl_open(&ctl_handle, "default", SND_CTL_NONBLOCK)) {
+ if ((err = snd_ctl_card_info (ctl_handle, ctl_info) < 0)) {
+ debug_msg("ALSA default card query failed: %s\n", snd_strerror(err));
+ snd_ctl_close(ctl_handle);
+ } else {
+ ratCard = ratCards + cindex;
+ ratCard->card_number = cindex;
+ ratCard->pcm_device = strdup("default");
+ ratCard->pcm_mixer = strdup("default");
+ snprintf(card, sizeof(card), "ALSA default: %s",
+ snd_ctl_card_info_get_name (ctl_info));
+ ratCard->name = strdup (card);
+ debug_msg("Got \"default\" card %s\n", ratCard->name);
+ snd_ctl_close(ctl_handle);
+ cindex++;
+ }
+ }
do {
- sprintf (card , "hw:%d", cindex);
- debug_msg("ALSA for dev:%s\n",card);
+ sprintf (card , "hw:%d", alsaDevNo);
err = snd_ctl_open (&ctl_handle, card, SND_CTL_NONBLOCK);
if (err == 0) {
+ debug_msg("Opened ALSA dev:%s\n",card);
// Grab the card info
ratCard = ratCards + cindex;
ratCard->card_number = cindex;
ratCard->pcm_mixer = strdup(card);
- sprintf (card , "plughw:%d", cindex);
+ sprintf (card , "plughw:%d", alsaDevNo);
ratCard->pcm_device = strdup(card);
if ((err = snd_ctl_card_info (ctl_handle, ctl_info) < 0)) {
- fprintf(stderr, "Card query failed: %s\n", snd_strerror(err));
snprintf(card, sizeof(card), "ALSA %d: Not Available", cindex);
ratCard->name = strdup (card);
- debug_msg("Got failed ALSA card %s\n", ratCard->name);
- snd_ctl_close(ctl_handle);
- cindex++;
+ debug_msg("Got failed ALSA card %s (err:%s)\n", ratCard->name,snd_strerror(err));
err=0;
- continue;
- }
- snprintf(card, sizeof(card), "ALSA %d: %s", cindex,
- snd_ctl_card_info_get_name (ctl_info));
- ratCard->name = strdup (card);
- debug_msg("Got ALSA card %s\n", ratCard->name);
-
+ } else {
+ snprintf(card, sizeof(card), "ALSA %d: %s", cindex,
+ snd_ctl_card_info_get_name (ctl_info));
+ ratCard->name = strdup (card);
+ debug_msg("Got card %s\n", ratCard->name);
+ }
snd_ctl_close(ctl_handle);
+
}
cindex++;
+ alsaDevNo++;
} while (err == 0);
- cindex--;
-
- // Get ALSA "default" card - so things like dsnoop etc can work
- if (!snd_ctl_open(&ctl_handle, "default", SND_CTL_NONBLOCK)) {
- ratCard = ratCards + cindex;
- ratCard->card_number = cindex;
- ratCard->pcm_device = strdup("default");
- ratCard->pcm_mixer = "default";
- if ((err = snd_ctl_card_info (ctl_handle, ctl_info) < 0)) {
- fprintf(stderr, "ALSA default Card query failed: %s\n", snd_strerror(err));
- snd_ctl_close(ctl_handle);
- } else {
- snprintf(card, sizeof(card), "ALSA default: %s",
- snd_ctl_card_info_get_name (ctl_info));
- ratCard->name = strdup (card);
- debug_msg("Got \"default\" card %s\n", ratCard->name);
- snd_ctl_close(ctl_handle);
- cindex++;
- }
- }
- cindex++;
-
nRatCards = cindex - 1;
- debug_msg("Got %d devices\n", nRatCards);
+ debug_msg("Got %d ALSA devices\n", nRatCards);
return nRatCards;
}
@@ -1054,10 +1211,9 @@
unsigned rmin, rmax, cmin, cmax;
int err, dir;
- debug_msg("Got \"ALSA supports\" for %d\n", ad);
+ debug_msg("ALSA support %d\n", ad);
dump_audio_format(fmt);
-
snd_pcm_hw_params_alloca (&hw_params);
err = snd_pcm_hw_params_any (current.tx.handle, hw_params);
More information about the Sumover-dev
mailing list