This is an automatic generated email to let you know that the following patch 
were queued at the 
http://git.linuxtv.org/cgit.cgi/tvtime.git tree:

Subject: alsa_stream: Sync with xawtv3 version
Author:  Hans de Goede <[email protected]>
Date:    Sat Feb 13 16:47:22 2016 -0200

The xawtv3 copy of alsa_stream.c has several improvements / bug fixes,
sync these into tvtime.

Signed-off-by: Hans de Goede <[email protected]>
Signed-off-by: Mauro Carvalho Chehab <[email protected]>

 src/alsa_stream.c | 195 +++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 134 insertions(+), 61 deletions(-)

---

http://git.linuxtv.org/cgit.cgi/tvtime.git/commit/?id=c26f9ce769d83bd05e5b4f509aa66889381ad3eb
diff --git a/src/alsa_stream.c b/src/alsa_stream.c
index 99cea05943f2..8cedad798b93 100644
--- a/src/alsa_stream.c
+++ b/src/alsa_stream.c
@@ -1,8 +1,9 @@
 /*
- *  tvtime ALSA device support
+ *  ALSA streaming support
  *
- *  Copyright (c) by Devin Heitmueller <[email protected]>
- * 
+ *  Originally written by:
+ *      Copyright (c) by Devin Heitmueller <[email protected]>
+ *     for usage at tvtime
  *  Derived from the alsa-driver test tool latency.c:
  *    Copyright (c) by Jaroslav Kysela <[email protected]>
  *
@@ -25,6 +26,8 @@
  *
  */
 
+#include "config.h"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -37,8 +40,9 @@
 #include <math.h>
 #include "alsa_stream.h"
 
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
+
 /* Private vars to control alsa thread status */
-static int alsa_is_running = 0;
 static int stop_alsa = 0;
 
 /* Error handlers */
@@ -56,7 +60,7 @@ struct final_params {
 static int setparams_stream(snd_pcm_t *handle,
                            snd_pcm_hw_params_t *params,
                            snd_pcm_format_t format,
-                           int channels,
+                           int *channels,
                            const char *id)
 {
     int err;
@@ -83,10 +87,16 @@ static int setparams_stream(snd_pcm_t *handle,
               snd_strerror(err));
        return err;
     }
-    err = snd_pcm_hw_params_set_channels(handle, params, channels);
+
+retry:
+    err = snd_pcm_hw_params_set_channels(handle, params, *channels);
     if (err < 0) {
+       if (strcmp(id, "capture") == 0 && *channels == 2) {
+           *channels = 1;
+           goto retry; /* Retry with mono capture */
+       }
        fprintf(error_fp, "alsa: Channels count (%i) not available for %s: 
%s\n",
-               channels, id, snd_strerror(err));
+               *channels, id, snd_strerror(err));
        return err;
     }
 
@@ -97,9 +107,10 @@ static void getparams_periods(snd_pcm_t *handle,
                      snd_pcm_hw_params_t *params,
                      unsigned int *usecs,
                      unsigned int *count,
-                     const char *id)
+                     int allow_adjust, const char *id)
 {
     unsigned min = 0, max = 0;
+    unsigned desired = *usecs * *count;
 
     snd_pcm_hw_params_get_periods_min(params, &min, 0);
     snd_pcm_hw_params_get_periods_max(params, &max, 0);
@@ -125,6 +136,13 @@ static void getparams_periods(snd_pcm_t *handle,
        if (*usecs > max)
            *usecs = max;
     }
+
+    /* If we deviate from the desired size by more then 20% adjust count */
+    if (allow_adjust && (((*usecs * *count) < (desired *  8 / 10)) ||
+                        ((*usecs * *count) > (desired * 12 / 10)))) {
+       *count = (desired + *usecs / 2) / *usecs;
+       getparams_periods(handle, params, usecs, count, 0, id);
+    }
 }
 
 static int setparams_periods(snd_pcm_t *handle,
@@ -199,6 +217,33 @@ static int setparams_set(snd_pcm_t *handle,
     return 0;
 }
 
+static int alsa_try_rate(snd_pcm_t *phandle, snd_pcm_t *chandle,
+                       snd_pcm_hw_params_t *p_hwparams,
+                       snd_pcm_hw_params_t *c_hwparams,
+                       int allow_resample, unsigned *ratep, unsigned *ratec)
+{
+    int err;
+
+    err = snd_pcm_hw_params_set_rate_near(chandle, c_hwparams, ratec, 0);
+    if (err)
+       return err;
+
+    *ratep = *ratec;
+    err = snd_pcm_hw_params_set_rate_near(phandle, p_hwparams, ratep, 0);
+    if (err)
+       return err;
+
+    if (*ratep == *ratec)
+       return 0;
+
+    if (verbose)
+       fprintf(error_fp,
+               "alsa_try_rate: capture wanted %u, playback wanted %u%s\n",
+               *ratec, *ratep, allow_resample ? " with resample enabled": "");
+
+    return 1; /* No error, but also no match */
+}
+
 static int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle,
                     snd_pcm_format_t format,
                     int latency, int allow_resample,
@@ -214,16 +259,17 @@ static int setparams(snd_pcm_t *phandle, snd_pcm_t 
*chandle,
     /* Our latency is 2 periods (in usecs) */
     unsigned int c_periods = 2, p_periods;
     unsigned int c_periodtime, p_periodtime;
+    const unsigned int prefered_rates[] = { 44100, 48000, 32000 };
 
     snd_pcm_hw_params_alloca(&p_hwparams);
     snd_pcm_hw_params_alloca(&c_hwparams);
     snd_pcm_sw_params_alloca(&p_swparams);
     snd_pcm_sw_params_alloca(&c_swparams);
 
-    if (setparams_stream(phandle, p_hwparams, format, channels, "playback"))
+    if (setparams_stream(chandle, c_hwparams, format, &channels, "capture"))
        return 1;
 
-    if (setparams_stream(chandle, c_hwparams, format, channels, "capture"))
+    if (setparams_stream(phandle, p_hwparams, format, &channels, "playback"))
        return 1;
 
     if (allow_resample) {
@@ -258,25 +304,40 @@ static int setparams(snd_pcm_t *phandle, snd_pcm_t 
*chandle,
     }
 
     if (verbose)
-       fprintf(error_fp, "alsa: Will search a common rate between %u and %u\n",
+       fprintf(error_fp,
+               "alsa: Will search a common rate between %u and %u\n",
                ratemin, ratemax);
 
-    for (i = ratemax; i <= ratemin; i -= 100) {
-       err = snd_pcm_hw_params_set_rate_near(chandle, c_hwparams, &i, 0);
-       if (err)
-           continue;
-       ratec = i;
-       ratep = i;
-       err = snd_pcm_hw_params_set_rate_near(phandle, p_hwparams, &ratep, 0);
-       if (err)
+    /* First try a set of common rates */
+    err = -1;
+    for (i = 0; i < ARRAY_SIZE(prefered_rates); i++) {
+       if (prefered_rates[i] < ratemin || prefered_rates[i] > ratemax)
            continue;
-       if (ratep == ratec)
+       ratep = ratec = prefered_rates[i];
+       err = alsa_try_rate(phandle, chandle, p_hwparams, c_hwparams,
+                           allow_resample, &ratep, &ratec);
+       if (err == 0)
            break;
-       if (verbose)
-           fprintf(error_fp,
-                   "alsa: Failed to set to %u: capture wanted %u, playback 
wanted %u%s\n",
-                   i, ratec, ratep,
-                   allow_resample ? " with resample enabled": "");
+    }
+
+    if (err != 0) {
+       if (ratemin >= 44100) {
+           for (i = ratemin; i <= ratemax; i += 100) {
+               ratep = ratec = i;
+               err = alsa_try_rate(phandle, chandle, p_hwparams, c_hwparams,
+                                   allow_resample, &ratep, &ratec);
+               if (err == 0)
+                   break;
+           }
+       } else {
+           for (i = ratemax; i >= ratemin; i -= 100) {
+               ratep = ratec = i;
+               err = alsa_try_rate(phandle, chandle, p_hwparams, c_hwparams,
+                                   allow_resample, &ratep, &ratec);
+               if (err == 0)
+                   break;
+           }
+       }
     }
 
     if (err < 0) {
@@ -293,15 +354,19 @@ static int setparams(snd_pcm_t *phandle, snd_pcm_t 
*chandle,
     if (verbose)
        fprintf(error_fp, "alsa: Using Rate %d\n", ratec);
 
-    /* Negociate period parameters */
+    /* Negotiate period parameters */
 
     c_periodtime = latency * 1000 / c_periods;
-    getparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, 
"capture");
+    getparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, 1, 
"capture");
     p_periods = c_periods * 2;
     p_periodtime = c_periodtime;
-    getparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, 
"playback");
+    getparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, 0, 
"playback");
     c_periods = p_periods / 2;
 
+    if (verbose)
+       fprintf(error_fp, "alsa: Capture %u periods of %u usecs, Playback %u 
periods of %u usecs\n",
+               c_periods, c_periodtime, p_periods, p_periodtime);
+
     /*
      * Some playback devices support a very limited periodtime range. If the 
user needs to
      * use a higher latency to avoid overrun/underrun, use an alternate 
algorithm of incresing
@@ -310,10 +375,10 @@ static int setparams(snd_pcm_t *phandle, snd_pcm_t 
*chandle,
     if (p_periodtime < c_periodtime) {
        c_periodtime = p_periodtime;
        c_periods = round (latency * 1000.0 / c_periodtime + 0.5);
-       getparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, 
"capture");
+       getparams_periods(chandle, c_hwparams, &c_periodtime, &c_periods, 0, 
"capture");
        p_periods = c_periods * 2;
        p_periodtime = c_periodtime;
-       getparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, 
"playback");
+       getparams_periods(phandle, p_hwparams, &p_periodtime, &p_periods, 0, 
"playback");
        c_periods = p_periods / 2;
     }
 
@@ -427,6 +492,7 @@ static int alsa_stream(const char *pdevice, const char 
*cdevice, int latency)
                            SND_PCM_NONBLOCK)) < 0) {
        fprintf(error_fp, "alsa: Cannot open capture device %s: %s\n",
                cdevice, snd_strerror(err));
+       snd_pcm_close(phandle);
        return 0;
     }
 
@@ -445,6 +511,8 @@ static int alsa_stream(const char *pdevice, const char 
*cdevice, int latency)
                                0)) < 0) {
            fprintf(error_fp, "alsa: Cannot open playback device %s: %s\n",
                    pdevice, snd_strerror(err));
+           snd_pcm_close(chandle);
+           return 0;
        }
 
        err = setparams(phandle, chandle, format, latency, 1, &negotiated);
@@ -452,6 +520,8 @@ static int alsa_stream(const char *pdevice, const char 
*cdevice, int latency)
 
     if (err != 0) {
        fprintf(error_fp, "alsa: setparams failed\n");
+       snd_pcm_close(phandle);
+       snd_pcm_close(chandle);
        return 1;
     }
 
@@ -459,20 +529,17 @@ static int alsa_stream(const char *pdevice, const char 
*cdevice, int latency)
                    * negotiated.channels);
     if (buffer == NULL) {
        fprintf(error_fp, "alsa: Failed allocating buffer for audio\n");
+       snd_pcm_close(phandle);
+       snd_pcm_close(chandle);
        return 0;
     }
 
-    /*
-     * Buffering delay is due for capture and for playback, so we
-     * need to multiply it by two.
-     */
-    fprintf(error_fp,
+    if (verbose)
+       fprintf(error_fp,
            "alsa: stream started from %s to %s (%i Hz, buffer delay = %.2f 
ms)\n",
            cdevice, pdevice, negotiated.rate,
            negotiated.latency * 1000.0 / negotiated.rate);
 
-    alsa_is_running = 1;
-
     while (!stop_alsa) {
        /* We start with a read and not a wait to auto(re)start the capture */
        r = readbuf(chandle, buffer, negotiated.bufsize);
@@ -481,12 +548,12 @@ static int alsa_stream(const char *pdevice, const char 
*cdevice, int latency)
        if (r > 0)
            writebuf(phandle, buffer, r);
        /* use poll to wait for next event */
-       snd_pcm_wait(chandle, 1000);
+       while (!stop_alsa && !snd_pcm_wait(chandle, 50))
+           ;
     }
 
     snd_pcm_drop(chandle);
-    snd_pcm_nonblock(phandle, 0);
-    snd_pcm_drain(phandle);
+    snd_pcm_drop(phandle);
 
     snd_pcm_unlink(chandle);
     snd_pcm_hw_free(phandle);
@@ -495,7 +562,6 @@ static int alsa_stream(const char *pdevice, const char 
*cdevice, int latency)
     snd_pcm_close(phandle);
     snd_pcm_close(chandle);
 
-    alsa_is_running = 0;
     return 0;
 }
 
@@ -513,7 +579,8 @@ static void *alsa_thread_entry(void *whatever)
        fprintf(error_fp, "alsa: starting copying alsa stream from %s to %s\n",
                inputs->cdevice, inputs->pdevice);
     alsa_stream(inputs->pdevice, inputs->cdevice, inputs->latency);
-    fprintf(error_fp, "alsa: stream stopped\n");
+    if (verbose)
+       fprintf(error_fp, "alsa: stream stopped\n");
 
     free(inputs->pdevice);
     free(inputs->cdevice);
@@ -526,12 +593,18 @@ static void *alsa_thread_entry(void *whatever)
  Public functions
  *************************************************************************/
 
+static int alsa_is_running = 0;
+static pthread_t alsa_thread;
+
 int alsa_thread_startup(const char *pdevice, const char *cdevice, int latency,
                        FILE *__error_fp, int __verbose)
 {
     int ret;
-    pthread_t thread;
-    struct input_params *inputs = malloc(sizeof(struct input_params));
+    struct input_params *inputs;
+
+    if ((strcasecmp(pdevice, "disabled") == 0) ||
+       (strcasecmp(cdevice, "disabled") == 0))
+       return 0;
 
     if (__error_fp)
        error_fp = __error_fp;
@@ -540,41 +613,41 @@ int alsa_thread_startup(const char *pdevice, const char 
*cdevice, int latency,
 
     verbose = __verbose;
 
+    if (alsa_is_running) {
+       fprintf(error_fp, "alsa: Already running\n");
+       return EBUSY;
+    }
 
+    inputs = malloc(sizeof(struct input_params));
     if (inputs == NULL) {
        fprintf(error_fp, "alsa: failed allocating memory for inputs\n");
-       return 0;
-    }
-
-    if ((strcasecmp(pdevice, "disabled") == 0) ||
-       (strcasecmp(cdevice, "disabled") == 0)) {
-       free(inputs);
-       return 0;
+       return ENOMEM;
     }
 
     inputs->pdevice = strdup(pdevice);
     inputs->cdevice = strdup(cdevice);
     inputs->latency = latency;
 
-    if (alsa_is_running) {
-       stop_alsa = 1;
-       while ((volatile int)alsa_is_running)
-              usleep(10);
-    }
-
     stop_alsa = 0;
-
-    ret = pthread_create(&thread, NULL,
+    ret = pthread_create(&alsa_thread, NULL,
                         &alsa_thread_entry, (void *) inputs);
+    if (ret == 0)
+       alsa_is_running = 1;
+
     return ret;
 }
 
 void alsa_thread_stop(void)
 {
-       stop_alsa = 1;
+    if (!alsa_is_running)
+       return;
+
+    stop_alsa = 1;
+    pthread_join(alsa_thread, NULL);
+    alsa_is_running = 0;
 }
 
 int alsa_thread_is_running(void)
 {
-       return alsa_is_running;
+    return alsa_is_running;
 }

_______________________________________________
linuxtv-commits mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to