Revision
14661
Author
gmaruzz
Date
2009-08-28 07:25:39 -0500 (Fri, 28 Aug 2009)

Log Message

celliax: if you like s**t, you can have some from here. But audio i/o now works, and a cellphone call to echo() do what's expected :-)

Modified Paths

Diff

Modified: freeswitch/branches/gmaruzz/mod_celliax/celliax.h (14660 => 14661)


--- freeswitch/branches/gmaruzz/mod_celliax/celliax.h	2009-08-28 12:20:41 UTC (rev 14660)
+++ freeswitch/branches/gmaruzz/mod_celliax/celliax.h	2009-08-28 12:25:39 UTC (rev 14661)
@@ -543,6 +543,5 @@
 int alsa_init(private_t * tech_pvt);
 int alsa_shutdown(private_t * tech_pvt);
 snd_pcm_t *alsa_open_dev(private_t * tech_pvt, snd_pcm_stream_t stream);
-struct ast_frame *alsa_read(private_t * tech_pvt);
-int alsa_write(private_t * tech_pvt, struct ast_frame *f);
+int alsa_write(private_t * tech_pvt, short * data, int datalen);
 #endif /* CELLIAX_ALSA */

Modified: freeswitch/branches/gmaruzz/mod_celliax/celliax_protocol.c (14660 => 14661)


--- freeswitch/branches/gmaruzz/mod_celliax/celliax_protocol.c	2009-08-28 12:20:41 UTC (rev 14660)
+++ freeswitch/branches/gmaruzz/mod_celliax/celliax_protocol.c	2009-08-28 12:25:39 UTC (rev 14661)
@@ -4447,6 +4447,7 @@
 
     memset(sizbuf2, 0, sizeof(sizbuf2));
     if (tech_pvt->alsa_play_is_mono) {
+    ERRORA("data=%p, datalen=%d, sizbuf=%p, len/2=%d\n", SKYPIAX_P_LOG, (void *)data, datalen, (void *)sizbuf, len/2);
       res = snd_pcm_writei(tech_pvt->alsap, sizbuf, len / 2);
     } else {
       int a = 0;
@@ -4577,4 +4578,216 @@
 
 	return 0;
 }
+/*! \brief Write audio frames to interface */
+int alsa_write(private_t * tech_pvt, short * data, int datalen)
+{
+  static char sizbuf[8000];
+  static char sizbuf2[16000];
+  static char silencebuf[8000];
+  static int sizpos = 0;
+  int len = sizpos;
+  int pos;
+  int res = 0;
+  time_t now_timestamp;
+  /* size_t frames = 0; */
+  snd_pcm_state_t state;
+  snd_pcm_sframes_t delayp1;
+  snd_pcm_sframes_t delayp2;
 
+    //ERRORA("data=%p, datalen=%d\n", SKYPIAX_P_LOG, (void *)data, datalen);
+  /* We have to digest the frame in 160-byte portions */
+  if (datalen > sizeof(sizbuf) - sizpos) {
+    ERRORA("Frame too large\n", SKYPIAX_P_LOG);
+    res = -1;
+  } else {
+    memcpy(sizbuf + sizpos, data, datalen);
+    len += datalen;
+    pos = 0;
+#ifdef ALSA_MONITOR
+    alsa_monitor_write(sizbuf, len);
+#endif
+    state = snd_pcm_state(tech_pvt->alsap);
+    if (state == SND_PCM_STATE_XRUN) {
+      int i;
+
+      DEBUGA_SKYPE
+        ("You've got an ALSA write XRUN in the past (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file\n",
+         SKYPIAX_P_LOG, tech_pvt->alsa_periods_in_buffer);
+      res = snd_pcm_prepare(tech_pvt->alsap);
+      if (res) {
+        ERRORA("audio play prepare failed: %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+      } else {
+        res = snd_pcm_format_set_silence(celliax_format, silencebuf, len / 2);
+        if (res < 0) {
+          DEBUGA_SKYPE("Silence error %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+          res = -1;
+        }
+        for (i = 0; i < (tech_pvt->alsa_periods_in_buffer - 1); i++) {
+          res = snd_pcm_writei(tech_pvt->alsap, silencebuf, len / 2);
+          if (res != len / 2) {
+            DEBUGA_SKYPE("Write returned a different quantity: %d\n", SKYPIAX_P_LOG, res);
+            res = -1;
+          } else if (res < 0) {
+            DEBUGA_SKYPE("Write error %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+            res = -1;
+          }
+        }
+      }
+
+    }
+
+    res = snd_pcm_delay(tech_pvt->alsap, &delayp1);
+    if (res < 0) {
+      DEBUGA_SKYPE("Error %d on snd_pcm_delay: \"%s\"\n", SKYPIAX_P_LOG, res,
+                   snd_strerror(res));
+      res = snd_pcm_prepare(tech_pvt->alsap);
+      if (res) {
+        DEBUGA_SKYPE("snd_pcm_prepare failed: '%s'\n", SKYPIAX_P_LOG, snd_strerror(res));
+      }
+      res = snd_pcm_delay(tech_pvt->alsap, &delayp1);
+    }
+
+    delayp2 = snd_pcm_avail_update(tech_pvt->alsap);
+    if (delayp2 < 0) {
+      DEBUGA_SKYPE("Error %d on snd_pcm_avail_update: \"%s\"\n", SKYPIAX_P_LOG,
+                   (int) delayp2, snd_strerror(delayp2));
+
+      res = snd_pcm_prepare(tech_pvt->alsap);
+      if (res) {
+        DEBUGA_SKYPE("snd_pcm_prepare failed: '%s'\n", SKYPIAX_P_LOG, snd_strerror(res));
+      }
+      delayp2 = snd_pcm_avail_update(tech_pvt->alsap);
+    }
+
+    if (                        /* delayp1 != 0 && delayp1 != 160 */
+         delayp1 < 160 || delayp2 > tech_pvt->alsa_buffer_size) {
+
+      res = snd_pcm_prepare(tech_pvt->alsap);
+      if (res) {
+        DEBUGA_SKYPE
+          ("snd_pcm_prepare failed while trying to prevent an ALSA write XRUN: %s, delayp1=%d, delayp2=%d\n",
+           SKYPIAX_P_LOG, snd_strerror(res), (int) delayp1, (int) delayp2);
+      } else {
+
+        int i;
+        for (i = 0; i < (tech_pvt->alsa_periods_in_buffer - 1); i++) {
+          res = snd_pcm_format_set_silence(celliax_format, silencebuf, len / 2);
+          if (res < 0) {
+            DEBUGA_SKYPE("Silence error %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+            res = -1;
+          }
+          res = snd_pcm_writei(tech_pvt->alsap, silencebuf, len / 2);
+          if (res < 0) {
+            DEBUGA_SKYPE("Write error %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+            res = -1;
+          } else if (res != len / 2) {
+            DEBUGA_SKYPE("Write returned a different quantity: %d\n", SKYPIAX_P_LOG, res);
+            res = -1;
+          }
+        }
+
+        DEBUGA_SKYPE
+          ("PREVENTING an ALSA write XRUN (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file. delayp1=%d, delayp2=%d\n",
+           SKYPIAX_P_LOG, tech_pvt->alsa_periods_in_buffer, (int) delayp1, (int) delayp2);
+      }
+
+    }
+
+    memset(sizbuf2, 0, sizeof(sizbuf2));
+    if (tech_pvt->alsa_play_is_mono) {
+      res = snd_pcm_writei(tech_pvt->alsap, sizbuf, len / 2);
+    } else {
+      int a = 0;
+      int i = 0;
+      for (i = 0; i < 8000;) {
+        sizbuf2[a] = sizbuf[i];
+        a++;
+        i++;
+        sizbuf2[a] = sizbuf[i];
+        a++;
+        i--;
+        sizbuf2[a] = sizbuf[i]; // comment out this line to use only left 
+        a++;
+        i++;
+        sizbuf2[a] = sizbuf[i]; // comment out this line to use only left
+        a++;
+        i++;
+      }
+      res = snd_pcm_writei(tech_pvt->alsap, sizbuf2, len);
+    }
+    if (res == -EPIPE) {
+      DEBUGA_SKYPE
+        ("ALSA write EPIPE (XRUN) (celliax can't fill the soundcard buffer fast enough). If this happens often (not after silence or after a pause in the speech, that's OK), and appear to damage the sound quality, first check if you have some IRQ problem, maybe sharing the soundcard IRQ with a broken or heavy loaded ethernet or graphic card. Then consider to increase the alsa_periods_in_buffer (now is set to %d) for this interface in the config file. delayp1=%d, delayp2=%d\n",
+         SKYPIAX_P_LOG, tech_pvt->alsa_periods_in_buffer, (int) delayp1, (int) delayp2);
+      res = snd_pcm_prepare(tech_pvt->alsap);
+      if (res) {
+        ERRORA("audio play prepare failed: %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+      } else {
+
+        if (tech_pvt->alsa_play_is_mono) {
+          res = snd_pcm_writei(tech_pvt->alsap, sizbuf, len / 2);
+        } else {
+          int a = 0;
+          int i = 0;
+          for (i = 0; i < 8000;) {
+            sizbuf2[a] = sizbuf[i];
+            a++;
+            i++;
+            sizbuf2[a] = sizbuf[i];
+            a++;
+            i--;
+            sizbuf2[a] = sizbuf[i];
+            a++;
+            i++;
+            sizbuf2[a] = sizbuf[i];
+            a++;
+            i++;
+          }
+          res = snd_pcm_writei(tech_pvt->alsap, sizbuf2, len);
+        }
+
+      }
+
+    } else {
+      if (res == -ESTRPIPE) {
+        ERRORA("You've got some big problems\n", SKYPIAX_P_LOG);
+      } else if (res == -EAGAIN) {
+        res = 0;
+      } else if (res < 0) {
+        ERRORA("Error %d on audio write: \"%s\"\n", SKYPIAX_P_LOG, res,
+               snd_strerror(res));
+      }
+    }
+  }
+
+  if (tech_pvt->audio_play_reset_period) {
+    time(&now_timestamp);
+    if ((now_timestamp - tech_pvt->audio_play_reset_timestamp) > tech_pvt->audio_play_reset_period) {
+      if (option_debug)
+        DEBUGA_SKYPE("reset audio play\n", SKYPIAX_P_LOG);
+      res = snd_pcm_wait(tech_pvt->alsap, 1000);
+      if (res < 0) {
+        ERRORA("audio play wait failed: %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+      }
+      res = snd_pcm_drop(tech_pvt->alsap);
+      if (res) {
+        ERRORA("audio play drop failed: %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+      }
+      res = snd_pcm_prepare(tech_pvt->alsap);
+      if (res) {
+        ERRORA("audio play prepare failed: %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+      }
+      res = snd_pcm_wait(tech_pvt->alsap, 1000);
+      if (res < 0) {
+        ERRORA("audio play wait failed: %s\n", SKYPIAX_P_LOG, snd_strerror(res));
+      }
+      time(&tech_pvt->audio_play_reset_timestamp);
+    }
+  }
+  res = 0;
+  if (res > 0)
+    res = 0;
+  return res;
+}
+
+

Modified: freeswitch/branches/gmaruzz/mod_celliax/mod_celliax.c (14660 => 14661)


--- freeswitch/branches/gmaruzz/mod_celliax/mod_celliax.c	2009-08-28 12:20:41 UTC (rev 14660)
+++ freeswitch/branches/gmaruzz/mod_celliax/mod_celliax.c	2009-08-28 12:25:39 UTC (rev 14661)
@@ -649,7 +649,6 @@
 
 
 
-usleep(2000);
 int samples;
 
 		if ((samples = snd_pcm_readi(tech_pvt->alsac, tech_pvt->read_frame.data, tech_pvt->read_codec.implementation->samples_per_packet)) > 0) {
@@ -661,10 +660,11 @@
 			*frame = &tech_pvt->read_frame;
 
 			//status = SWITCH_STATUS_SUCCESS;
+		}
 		switch_set_flag(tech_pvt, TFLAG_VOICE);
-		}
 
 
+usleep(17000);
 
 
 
@@ -704,7 +704,7 @@
 				switch_swap_linear((*frame)->data, (int) (*frame)->datalen / 2);
 			}
 #endif
-		WARNINGA("HERE\n", SKYPIAX_P_LOG);
+		//WARNINGA("HERE\n", SKYPIAX_P_LOG);
 			return SWITCH_STATUS_SUCCESS;
 		}
 
@@ -753,9 +753,11 @@
 
 	sent = frame->datalen;
 
-		ERRORA("PLAY \n", SKYPIAX_P_LOG);
-	            snd_pcm_writei(tech_pvt->alsap, (short *) frame->data, (int) (frame->datalen / 2));
+		//ERRORA("PLAY \n", SKYPIAX_P_LOG);
+	            //snd_pcm_writei(tech_pvt->alsap, (short *) frame->data, (int) (frame->datalen / 2));
 
+ alsa_write(tech_pvt, frame->data, (int) (frame->datalen));
+
 #ifdef NOTDEF //FIXME
 #ifdef WIN32
 	switch_file_write(tech_pvt->audioskypepipe[1], frame->data, &sent);
@@ -1382,8 +1384,8 @@
   globals.SKYPIAX_INTERFACES[interface_id].alsa_periods_in_buffer = 4;
   globals.SKYPIAX_INTERFACES[interface_id].celliax_sound_rate = 8000;
 
-  switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].alsacname , "plughw:0");
-  switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].alsapname , "plughw:0");
+  switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].alsacname , "plughw:1");
+  switch_set_string(globals.SKYPIAX_INTERFACES[interface_id].alsapname , "plughw:1");