Fix --device bug
authorAndre <maan@p133.(none)>
Thu, 23 Feb 2006 17:29:45 +0000 (18:29 +0100)
committerAndre <maan@p133.(none)>
Thu, 23 Feb 2006 17:29:45 +0000 (18:29 +0100)
Duuuh, the --device option never worked because "plug:swmix" was harcoded
in play.c instead of using the value from the configuration. Even worse,
the default in play.ggo was _also_ set to "plug:swmix". Replace that by
"plughw:0,0".

This patch also simplifies and optimizes play_pcm().

Anyway, software mixing is still recommended. Here's an aprropriate
/etc/asound.conf:

---------------------------------------------------- /etc/asound.conf
pcm.swmix {
type dmix
# any unique number here
ipc_key 313
        ipc_perm 0666

slave {
pcm "hw:0,0"
# these settings may require tweaking for different sound
# cards; this is for the Powerbook's built-in snd-powermac
# probably not required at all for well-behaved cards...
period_time 0
period_size 1024
buffer_size 8192
# mentioning rate fixes wrong speed/pitch in native ALSA stuff
# rate 44100
}
}

pcm.dsp0 {
type plug
slave.pcm "swmix"
}

ctl.mixer0 {
type hw
card 0
}

pcm.!default {
type plug
slave.pcm "swmix"
}
---------------------------------------------------------------------

a Use the
: Use a large input
buffer and For one, the

play.c
play.ggo

diff --git a/play.c b/play.c
index 99c2316..c7289c0 100644 (file)
--- a/play.c
+++ b/play.c
@@ -57,7 +57,7 @@ enum {        E_BROKEN_CONF,          /* Broken configuration for this PCM */
 
 #define EXIT(EXP) \
 do { if (EXP) \
 
 #define EXIT(EXP) \
 do { if (EXP) \
-        fprintf (stderr, "error: " #EXP "\n"); exit(EXP);} \
+       fprintf (stderr, "error: " #EXP "\n"); exit(EXP);} \
 while (0)
 
 static snd_pcm_t *handle;
 while (0)
 
 static snd_pcm_t *handle;
@@ -151,25 +151,19 @@ static void set_alsa_params(void)
 
 /*
  * pcm_write - push out pcm frames
 
 /*
  * pcm_write - push out pcm frames
- * @data: pointer do data to be written
- * @count: number of frames
+ * \param data pointer do data to be written
+ * \param count number of frames
  *
  *
- * Return value: Number of bytes written. Exit on errors.
+ * \return Number of bytes written. Exit on errors.
  */
 static snd_pcm_sframes_t pcm_write(u_char *data, size_t count)
 {
        snd_pcm_sframes_t r, result = 0;
  */
 static snd_pcm_sframes_t pcm_write(u_char *data, size_t count)
 {
        snd_pcm_sframes_t r, result = 0;
-#if 0
-       if (count < chunk_size) {
-               snd_pcm_format_set_silence(FORMAT, data
-                       + count * bytes_per_frame,
-                       (chunk_size - count) * conf.channels_arg);
-               count = chunk_size;
-       }
-#endif
        while (count > 0) {
                /* write interleaved frames */
                r = snd_pcm_writei(handle, data, count);
        while (count > 0) {
                /* write interleaved frames */
                r = snd_pcm_writei(handle, data, count);
+               if (r < 0)
+                       fprintf(stderr, "write error: %s\n", snd_strerror(r));
                if (r == -EAGAIN || (r >= 0 && r < count))
                        snd_pcm_wait(handle, 1);
                else if (r == -EPIPE)
                if (r == -EAGAIN || (r >= 0 && r < count))
                        snd_pcm_wait(handle, 1);
                else if (r == -EPIPE)
@@ -187,7 +181,7 @@ static snd_pcm_sframes_t pcm_write(u_char *data, size_t count)
 
 /*
  * start_time_in_future - check if current time is later than start_time
 
 /*
  * start_time_in_future - check if current time is later than start_time
- * @diff: pointer to write remaining time to
+ * \param diff pointer to write remaining time to
  *
  * If start_time was not given, or current time is later than given
  * start_time, return 0. Otherwise, return 1 and write the time
  *
  * If start_time was not given, or current time is later than given
  * start_time, return 0. Otherwise, return 1 and write the time
@@ -213,79 +207,69 @@ static int start_time_in_future(struct timeval *diff)
  * or if the given start time is in the past.
  *
  */
  * or if the given start time is in the past.
  *
  */
-static void do_initial_delay(void)
+static void do_initial_delay(struct timeval *delay)
 {
 {
-       struct timeval diff;
-       int ret;
-
-       fprintf(stderr, "initial delay\n");
-       if (!conf.start_time_given)
-               return;
-again:
-       if (!start_time_in_future(&diff))
-               return;
-       ret = select(1, NULL, NULL, NULL, &diff);
-       if (ret < 0 && errno == EINTR)
-               goto again;
+       fprintf(stderr, "sleeping %lums\n", tv2ms(delay));
+       do
+               select(1, NULL, NULL, NULL, delay);
+       while (start_time_in_future(delay));
 }
 
 }
 
-
 /*
  * play_pcm - play raw pcm data
 /*
  * play_pcm - play raw pcm data
- * @l: number of bytes already loaded
+ * \param loaded number of bytes already loaded
  *
  * If start_time was given, prebuffer data until buffer is full or
  * start_time is reached. In any case, do not start playing before
  * start_time.
  */
  *
  * If start_time was given, prebuffer data until buffer is full or
  * start_time is reached. In any case, do not start playing before
  * start_time.
  */
-static void play_pcm(size_t l)
+static void play_pcm(size_t loaded)
 {
 {
-       ssize_t r, w;
-       unsigned long written = 0;
-       size_t chunk_bytes;
+       size_t chunk_bytes, bufsize, written = 0;
+       ssize_t ret;
+       unsigned char *p;
+       int dont_write;
+       struct timeval delay;
 
        set_alsa_params();
        chunk_bytes = chunk_size * bytes_per_frame;
 
        set_alsa_params();
        chunk_bytes = chunk_size * bytes_per_frame;
-       audiobuf = realloc(audiobuf, BUFFER_SIZE);
-//     fprintf(stderr, "loaded: %d, chunk_bytes: %d\n", l, chunk_bytes);
+       bufsize = chunk_bytes * 1024;
+       audiobuf = realloc(audiobuf, bufsize);
        if (!audiobuf)
                EXIT(E_MEM);
        if (!audiobuf)
                EXIT(E_MEM);
-       for (;;) {
-               for (;;) {
-                       if (l >= chunk_bytes) {
-                               if (written)
-                                       break;
-                               if (!start_time)
-                                       break;
-                               if (!start_time_in_future(NULL))
-                                       break;
-                               if (l > BUFFER_SIZE) {
-                                       do_initial_delay();
-                                       break;
-                               }
+again:
+       dont_write = 0;
+       if (!written && start_time)
+               dont_write = start_time_in_future(&delay);
+       if (!dont_write) {
+               p = audiobuf;
+               while (loaded >= chunk_bytes) {
+                       ret = (ssize_t) pcm_write(p, chunk_size) * bytes_per_frame;
+                       if (ret <= 0) {
+                               fprintf(stderr, "write error: %d\n", ret);
+                               EXIT(E_WRITE);
                        }
                        }
-//                     fprintf(stderr, "l = %d, chunk_Bytes = %d\n", l, chunk_bytes);
-                       r = read(STDIN_FILENO, audiobuf + l, BUFFER_SIZE -l);
-                       if (r < 0)
-                               EXIT(E_READ);
-                       l += r;
-//                     fprintf(stderr, "loaded: %d, r= %d\n", l, r);
-                       if (!r)
-                               goto out;;
+                       p += ret;
+                       written += ret;
+                       loaded -= ret;
                }
                }
-               w = MIN(chunk_bytes, l);
-//             fprintf(stderr, "play: writing %d\n", w);
-               r = (ssize_t) pcm_write(audiobuf, w / bytes_per_frame) * bytes_per_frame;
-//             fprintf(stderr, "wrote %d\n", r);
-               if (r < 0)
-                       EXIT(E_WRITE);
-               written += r;
-               l -= r;
-               if (l)
-                       memmove(audiobuf, audiobuf + r, l);
-//             fprintf(stderr, "written %lu, loaded : %d\n", written, l);
+               if (loaded && p != audiobuf) {
+                       fprintf(stderr, "memcpy: %d\n", loaded);
+                       memcpy(audiobuf, p, loaded);
+               }
+       }
+       if (dont_write && loaded >= bufsize) {
+               do_initial_delay(&delay);
+               start_time = NULL;
+               goto again;
+       }
+       ret = read(STDIN_FILENO, audiobuf, bufsize - loaded);
+       if (ret < 0)
+               EXIT(E_READ);
+       if (ret) {
+               loaded += ret;
+               goto again;
        }
        }
-out:
        snd_pcm_drain(handle);
 }
 
        snd_pcm_drain(handle);
 }
 
@@ -325,7 +309,7 @@ int main(int argc, char *argv[])
        snd_pcm_info_alloca(&info);
        if (snd_output_stdio_attach(&log, stderr, 0) < 0)
                EXIT(E_LOG);
        snd_pcm_info_alloca(&info);
        if (snd_output_stdio_attach(&log, stderr, 0) < 0)
                EXIT(E_LOG);
-       err = snd_pcm_open(&handle, "plug:swmix",
+       err = snd_pcm_open(&handle, conf.device_arg,
                SND_PCM_STREAM_PLAYBACK, 0);
        if (err < 0)
                EXIT(E_PCM_OPEN);
                SND_PCM_STREAM_PLAYBACK, 0);
        if (err < 0)
                EXIT(E_PCM_OPEN);
@@ -336,7 +320,7 @@ int main(int argc, char *argv[])
        play_pcm(check_wave());
        snd_pcm_close(handle);
        free(audiobuf);
        play_pcm(check_wave());
        snd_pcm_close(handle);
        free(audiobuf);
-       snd_output_close(log);
+//     snd_output_close(log);
        snd_config_update_free_global();
        return EXIT_SUCCESS;
 }
        snd_config_update_free_global();
        return EXIT_SUCCESS;
 }
index 75fb1ba..6b6aa9c 100644 (file)
--- a/play.ggo
+++ b/play.ggo
@@ -1,5 +1,5 @@
 section "general options"
 option "start_time" t "start playback at given time which must be in a:b format where a denotes seconds and b denotes microseconds since the epoch" string typestr="timeval" no
 section "general options"
 option "start_time" t "start playback at given time which must be in a:b format where a denotes seconds and b denotes microseconds since the epoch" string typestr="timeval" no
-option "device" d "set PCM device" string typestr="device" default="plug:swmix" no
+option "device" d "set PCM device" string typestr="device" default="plughw:0,0" no
 option "channels" c "number of channels (only neccessary for raw audio)" int typestr="num" default="2" no
 option "sample_rate" s "force given sample rate (only neccessary for raw audio)" int typestr="num" default="44100" no
 option "channels" c "number of channels (only neccessary for raw audio)" int typestr="num" default="2" no
 option "sample_rate" s "force given sample rate (only neccessary for raw audio)" int typestr="num" default="44100" no