media/libcubeb/src/cubeb_alsa.c

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

     1 /*
     2  * Copyright © 2011 Mozilla Foundation
     3  *
     4  * This program is made available under an ISC-style license.  See the
     5  * accompanying file LICENSE for details.
     6  */
     7 #undef NDEBUG
     8 #define _BSD_SOURCE
     9 #define _XOPEN_SOURCE 500
    10 #include <pthread.h>
    11 #include <sys/time.h>
    12 #include <assert.h>
    13 #include <limits.h>
    14 #include <poll.h>
    15 #include <unistd.h>
    16 #include <alsa/asoundlib.h>
    17 #include "cubeb/cubeb.h"
    18 #include "cubeb-internal.h"
    20 #define CUBEB_STREAM_MAX 16
    21 #define CUBEB_WATCHDOG_MS 10000
    23 #define CUBEB_ALSA_PCM_NAME "default"
    25 #define ALSA_PA_PLUGIN "ALSA <-> PulseAudio PCM I/O Plugin"
    27 /* ALSA is not thread-safe.  snd_pcm_t instances are individually protected
    28    by the owning cubeb_stream's mutex.  snd_pcm_t creation and destruction
    29    is not thread-safe until ALSA 1.0.24 (see alsa-lib.git commit 91c9c8f1),
    30    so those calls must be wrapped in the following mutex. */
    31 static pthread_mutex_t cubeb_alsa_mutex = PTHREAD_MUTEX_INITIALIZER;
    32 static int cubeb_alsa_error_handler_set = 0;
    34 static struct cubeb_ops const alsa_ops;
    36 struct cubeb {
    37   struct cubeb_ops const * ops;
    39   pthread_t thread;
    41   /* Mutex for streams array, must not be held while blocked in poll(2). */
    42   pthread_mutex_t mutex;
    44   /* Sparse array of streams managed by this context. */
    45   cubeb_stream * streams[CUBEB_STREAM_MAX];
    47   /* fds and nfds are only updated by alsa_run when rebuild is set. */
    48   struct pollfd * fds;
    49   nfds_t nfds;
    50   int rebuild;
    52   int shutdown;
    54   /* Control pipe for forcing poll to wake and rebuild fds or recalculate the timeout. */
    55   int control_fd_read;
    56   int control_fd_write;
    58   /* Track number of active streams.  This is limited to CUBEB_STREAM_MAX
    59      due to resource contraints. */
    60   unsigned int active_streams;
    62   /* Local configuration with handle_underrun workaround set for PulseAudio
    63      ALSA plugin.  Will be NULL if the PA ALSA plugin is not in use or the
    64      workaround is not required. */
    65   snd_config_t * local_config;
    66   int is_pa;
    67 };
    69 enum stream_state {
    70   INACTIVE,
    71   RUNNING,
    72   DRAINING,
    73   PROCESSING,
    74   ERROR
    75 };
    77 struct cubeb_stream {
    78   cubeb * context;
    79   pthread_mutex_t mutex;
    80   snd_pcm_t * pcm;
    81   cubeb_data_callback data_callback;
    82   cubeb_state_callback state_callback;
    83   void * user_ptr;
    84   snd_pcm_uframes_t write_position;
    85   snd_pcm_uframes_t last_position;
    86   snd_pcm_uframes_t buffer_size;
    87   snd_pcm_uframes_t period_size;
    88   cubeb_stream_params params;
    90   /* Every member after this comment is protected by the owning context's
    91      mutex rather than the stream's mutex, or is only used on the context's
    92      run thread. */
    93   pthread_cond_t cond; /* Signaled when the stream's state is changed. */
    95   enum stream_state state;
    97   struct pollfd * saved_fds; /* A copy of the pollfds passed in at init time. */
    98   struct pollfd * fds; /* Pointer to this waitable's pollfds within struct cubeb's fds. */
    99   nfds_t nfds;
   101   struct timeval drain_timeout;
   103   /* XXX: Horrible hack -- if an active stream has been idle for
   104      CUBEB_WATCHDOG_MS it will be disabled and the error callback will be
   105      called.  This works around a bug seen with older versions of ALSA and
   106      PulseAudio where streams would stop requesting new data despite still
   107      being logically active and playing. */
   108   struct timeval last_activity;
   109 };
   111 static int
   112 any_revents(struct pollfd * fds, nfds_t nfds)
   113 {
   114   nfds_t i;
   116   for (i = 0; i < nfds; ++i) {
   117     if (fds[i].revents) {
   118       return 1;
   119     }
   120   }
   122   return 0;
   123 }
   125 static int
   126 cmp_timeval(struct timeval * a, struct timeval * b)
   127 {
   128   if (a->tv_sec == b->tv_sec) {
   129     if (a->tv_usec == b->tv_usec) {
   130       return 0;
   131     }
   132     return a->tv_usec > b->tv_usec ? 1 : -1;
   133   }
   134   return a->tv_sec > b->tv_sec ? 1 : -1;
   135 }
   137 static int
   138 timeval_to_relative_ms(struct timeval * tv)
   139 {
   140   struct timeval now;
   141   struct timeval dt;
   142   long long t;
   143   int r;
   145   gettimeofday(&now, NULL);
   146   r = cmp_timeval(tv, &now);
   147   if (r >= 0) {
   148     timersub(tv, &now, &dt);
   149   } else {
   150     timersub(&now, tv, &dt);
   151   }
   152   t = dt.tv_sec;
   153   t *= 1000;
   154   t += (dt.tv_usec + 500) / 1000;
   156   if (t > INT_MAX) {
   157     t = INT_MAX;
   158   } else if (t < INT_MIN) {
   159     t = INT_MIN;
   160   }
   162   return r >= 0 ? t : -t;
   163 }
   165 static int
   166 ms_until(struct timeval * tv)
   167 {
   168   return timeval_to_relative_ms(tv);
   169 }
   171 static int
   172 ms_since(struct timeval * tv)
   173 {
   174   return -timeval_to_relative_ms(tv);
   175 }
   177 static void
   178 rebuild(cubeb * ctx)
   179 {
   180   nfds_t nfds;
   181   int i;
   182   nfds_t j;
   183   cubeb_stream * stm;
   185   assert(ctx->rebuild);
   187   /* Always count context's control pipe fd. */
   188   nfds = 1;
   189   for (i = 0; i < CUBEB_STREAM_MAX; ++i) {
   190     stm = ctx->streams[i];
   191     if (stm) {
   192       stm->fds = NULL;
   193       if (stm->state == RUNNING) {
   194         nfds += stm->nfds;
   195       }
   196     }
   197   }
   199   free(ctx->fds);
   200   ctx->fds = calloc(nfds, sizeof(struct pollfd));
   201   assert(ctx->fds);
   202   ctx->nfds = nfds;
   204   /* Include context's control pipe fd. */
   205   ctx->fds[0].fd = ctx->control_fd_read;
   206   ctx->fds[0].events = POLLIN | POLLERR;
   208   for (i = 0, j = 1; i < CUBEB_STREAM_MAX; ++i) {
   209     stm = ctx->streams[i];
   210     if (stm && stm->state == RUNNING) {
   211       memcpy(&ctx->fds[j], stm->saved_fds, stm->nfds * sizeof(struct pollfd));
   212       stm->fds = &ctx->fds[j];
   213       j += stm->nfds;
   214     }
   215   }
   217   ctx->rebuild = 0;
   218 }
   220 static void
   221 poll_wake(cubeb * ctx)
   222 {
   223   write(ctx->control_fd_write, "x", 1);
   224 }
   226 static void
   227 set_timeout(struct timeval * timeout, unsigned int ms)
   228 {
   229   gettimeofday(timeout, NULL);
   230   timeout->tv_sec += ms / 1000;
   231   timeout->tv_usec += (ms % 1000) * 1000;
   232 }
   234 static void
   235 alsa_set_stream_state(cubeb_stream * stm, enum stream_state state)
   236 {
   237   cubeb * ctx;
   238   int r;
   240   ctx = stm->context;
   241   stm->state = state;
   242   r = pthread_cond_broadcast(&stm->cond);
   243   assert(r == 0);
   244   ctx->rebuild = 1;
   245   poll_wake(ctx);
   246 }
   248 static enum stream_state
   249 alsa_refill_stream(cubeb_stream * stm)
   250 {
   251   int r;
   252   unsigned short revents;
   253   snd_pcm_sframes_t avail;
   254   long got;
   255   void * p;
   256   int draining;
   258   draining = 0;
   260   pthread_mutex_lock(&stm->mutex);
   262   r = snd_pcm_poll_descriptors_revents(stm->pcm, stm->fds, stm->nfds, &revents);
   263   if (r < 0 || revents != POLLOUT) {
   264     /* This should be a stream error; it makes no sense for poll(2) to wake
   265        for this stream and then have the stream report that it's not ready.
   266        Unfortunately, this does happen, so just bail out and try again. */
   267     pthread_mutex_unlock(&stm->mutex);
   268     return RUNNING;
   269   }
   271   avail = snd_pcm_avail_update(stm->pcm);
   272   if (avail == -EPIPE) {
   273     snd_pcm_recover(stm->pcm, avail, 1);
   274     avail = snd_pcm_avail_update(stm->pcm);
   275   }
   277   /* Failed to recover from an xrun, this stream must be broken. */
   278   if (avail < 0) {
   279     pthread_mutex_unlock(&stm->mutex);
   280     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
   281     return ERROR;
   282   }
   284   /* This should never happen. */
   285   if ((unsigned int) avail > stm->buffer_size) {
   286     avail = stm->buffer_size;
   287   }
   289   /* poll(2) claims this stream is active, so there should be some space
   290      available to write.  If avail is still zero here, the stream must be in
   291      a funky state, so recover and try again. */
   292   if (avail == 0) {
   293     snd_pcm_recover(stm->pcm, -EPIPE, 1);
   294     avail = snd_pcm_avail_update(stm->pcm);
   295     if (avail <= 0) {
   296       pthread_mutex_unlock(&stm->mutex);
   297       stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
   298       return ERROR;
   299     }
   300   }
   302   p = calloc(1, snd_pcm_frames_to_bytes(stm->pcm, avail));
   303   assert(p);
   305   pthread_mutex_unlock(&stm->mutex);
   306   got = stm->data_callback(stm, stm->user_ptr, p, avail);
   307   pthread_mutex_lock(&stm->mutex);
   308   if (got < 0) {
   309     pthread_mutex_unlock(&stm->mutex);
   310     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
   311     return ERROR;
   312   }
   313   if (got > 0) {
   314     snd_pcm_sframes_t wrote = snd_pcm_writei(stm->pcm, p, got);
   315     if (wrote == -EPIPE) {
   316       snd_pcm_recover(stm->pcm, wrote, 1);
   317       wrote = snd_pcm_writei(stm->pcm, p, got);
   318     }
   319     assert(wrote >= 0 && wrote == got);
   320     stm->write_position += wrote;
   321     gettimeofday(&stm->last_activity, NULL);
   322   }
   323   if (got != avail) {
   324     long buffer_fill = stm->buffer_size - (avail - got);
   325     double buffer_time = (double) buffer_fill / stm->params.rate;
   327     /* Fill the remaining buffer with silence to guarantee one full period
   328        has been written. */
   329     snd_pcm_writei(stm->pcm, (char *) p + got, avail - got);
   331     set_timeout(&stm->drain_timeout, buffer_time * 1000);
   333     draining = 1;
   334   }
   336   free(p);
   337   pthread_mutex_unlock(&stm->mutex);
   338   return draining ? DRAINING : RUNNING;
   339 }
   341 static int
   342 alsa_run(cubeb * ctx)
   343 {
   344   int r;
   345   int timeout;
   346   int i;
   347   char dummy;
   348   cubeb_stream * stm;
   349   enum stream_state state;
   351   pthread_mutex_lock(&ctx->mutex);
   353   if (ctx->rebuild) {
   354     rebuild(ctx);
   355   }
   357   /* Wake up at least once per second for the watchdog. */
   358   timeout = 1000;
   359   for (i = 0; i < CUBEB_STREAM_MAX; ++i) {
   360     stm = ctx->streams[i];
   361     if (stm && stm->state == DRAINING) {
   362       r = ms_until(&stm->drain_timeout);
   363       if (r >= 0 && timeout > r) {
   364         timeout = r;
   365       }
   366     }
   367   }
   369   pthread_mutex_unlock(&ctx->mutex);
   370   r = poll(ctx->fds, ctx->nfds, timeout);
   371   pthread_mutex_lock(&ctx->mutex);
   373   if (r > 0) {
   374     if (ctx->fds[0].revents & POLLIN) {
   375       read(ctx->control_fd_read, &dummy, 1);
   377       if (ctx->shutdown) {
   378         pthread_mutex_unlock(&ctx->mutex);
   379         return -1;
   380       }
   381     }
   383     for (i = 0; i < CUBEB_STREAM_MAX; ++i) {
   384       stm = ctx->streams[i];
   385       if (stm && stm->state == RUNNING && stm->fds && any_revents(stm->fds, stm->nfds)) {
   386         alsa_set_stream_state(stm, PROCESSING);
   387         pthread_mutex_unlock(&ctx->mutex);
   388         state = alsa_refill_stream(stm);
   389         pthread_mutex_lock(&ctx->mutex);
   390         alsa_set_stream_state(stm, state);
   391       }
   392     }
   393   } else if (r == 0) {
   394     for (i = 0; i < CUBEB_STREAM_MAX; ++i) {
   395       stm = ctx->streams[i];
   396       if (stm) {
   397         if (stm->state == DRAINING && ms_since(&stm->drain_timeout) >= 0) {
   398           alsa_set_stream_state(stm, INACTIVE);
   399           stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
   400         } else if (stm->state == RUNNING && ms_since(&stm->last_activity) > CUBEB_WATCHDOG_MS) {
   401           alsa_set_stream_state(stm, ERROR);
   402           stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
   403         }
   404       }
   405     }
   406   }
   408   pthread_mutex_unlock(&ctx->mutex);
   410   return 0;
   411 }
   413 static void *
   414 alsa_run_thread(void * context)
   415 {
   416   cubeb * ctx = context;
   417   int r;
   419   do {
   420     r = alsa_run(ctx);
   421   } while (r >= 0);
   423   return NULL;
   424 }
   426 static snd_config_t *
   427 get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm)
   428 {
   429   int r;
   430   snd_config_t * slave_pcm;
   431   snd_config_t * slave_def;
   432   snd_config_t * pcm;
   433   char const * string;
   434   char node_name[64];
   436   slave_def = NULL;
   438   r = snd_config_search(root_pcm, "slave", &slave_pcm);
   439   if (r < 0) {
   440     return NULL;
   441   }
   443   r = snd_config_get_string(slave_pcm, &string);
   444   if (r >= 0) {
   445     r = snd_config_search_definition(lconf, "pcm_slave", string, &slave_def);
   446     if (r < 0) {
   447       return NULL;
   448     }
   449   }
   451   do {
   452     r = snd_config_search(slave_def ? slave_def : slave_pcm, "pcm", &pcm);
   453     if (r < 0) {
   454       break;
   455     }
   457     r = snd_config_get_string(slave_def ? slave_def : slave_pcm, &string);
   458     if (r < 0) {
   459       break;
   460     }
   462     r = snprintf(node_name, sizeof(node_name), "pcm.%s", string);
   463     if (r < 0 || r > (int) sizeof(node_name)) {
   464       break;
   465     }
   466     r = snd_config_search(lconf, node_name, &pcm);
   467     if (r < 0) {
   468       break;
   469     }
   471     return pcm;
   472   } while (0);
   474   if (slave_def) {
   475     snd_config_delete(slave_def);
   476   }
   478   return NULL;
   479 }
   481 /* Work around PulseAudio ALSA plugin bug where the PA server forces a
   482    higher than requested latency, but the plugin does not update its (and
   483    ALSA's) internal state to reflect that, leading to an immediate underrun
   484    situation.  Inspired by WINE's make_handle_underrun_config.
   485    Reference: http://mailman.alsa-project.org/pipermail/alsa-devel/2012-July/05 */
   486 static snd_config_t *
   487 init_local_config_with_workaround(char const * pcm_name)
   488 {
   489   int r;
   490   snd_config_t * lconf;
   491   snd_config_t * pcm_node;
   492   snd_config_t * node;
   493   char const * string;
   494   char node_name[64];
   496   lconf = NULL;
   498   if (snd_config == NULL) {
   499     return NULL;
   500   }
   502   r = snd_config_copy(&lconf, snd_config);
   503   if (r < 0) {
   504     return NULL;
   505   }
   507   do {
   508     r = snd_config_search_definition(lconf, "pcm", pcm_name, &pcm_node);
   509     if (r < 0) {
   510       break;
   511     }
   513     r = snd_config_get_id(pcm_node, &string);
   514     if (r < 0) {
   515       break;
   516     }
   518     r = snprintf(node_name, sizeof(node_name), "pcm.%s", string);
   519     if (r < 0 || r > (int) sizeof(node_name)) {
   520       break;
   521     }
   522     r = snd_config_search(lconf, node_name, &pcm_node);
   523     if (r < 0) {
   524       break;
   525     }
   527     /* If this PCM has a slave, walk the slave configurations until we reach the bottom. */
   528     while ((node = get_slave_pcm_node(lconf, pcm_node)) != NULL) {
   529       pcm_node = node;
   530     }
   532     /* Fetch the PCM node's type, and bail out if it's not the PulseAudio plugin. */
   533     r = snd_config_search(pcm_node, "type", &node);
   534     if (r < 0) {
   535       break;
   536     }
   538     r = snd_config_get_string(node, &string);
   539     if (r < 0) {
   540       break;
   541     }
   543     if (strcmp(string, "pulse") != 0) {
   544       break;
   545     }
   547     /* Don't clobber an explicit existing handle_underrun value, set it only
   548        if it doesn't already exist. */
   549     r = snd_config_search(pcm_node, "handle_underrun", &node);
   550     if (r != -ENOENT) {
   551       break;
   552     }
   554     /* Disable pcm_pulse's asynchronous underrun handling. */
   555     r = snd_config_imake_integer(&node, "handle_underrun", 0);
   556     if (r < 0) {
   557       break;
   558     }
   560     r = snd_config_add(pcm_node, node);
   561     if (r < 0) {
   562       break;
   563     }
   565     return lconf;
   566   } while (0);
   568   snd_config_delete(lconf);
   570   return NULL;
   571 }
   573 static int
   574 alsa_locked_pcm_open(snd_pcm_t ** pcm, snd_pcm_stream_t stream, snd_config_t * local_config)
   575 {
   576   int r;
   578   pthread_mutex_lock(&cubeb_alsa_mutex);
   579   if (local_config) {
   580     r = snd_pcm_open_lconf(pcm, CUBEB_ALSA_PCM_NAME, stream, SND_PCM_NONBLOCK, local_config);
   581   } else {
   582     r = snd_pcm_open(pcm, CUBEB_ALSA_PCM_NAME, stream, SND_PCM_NONBLOCK);
   583   }
   584   pthread_mutex_unlock(&cubeb_alsa_mutex);
   586   return r;
   587 }
   589 static int
   590 alsa_locked_pcm_close(snd_pcm_t * pcm)
   591 {
   592   int r;
   594   pthread_mutex_lock(&cubeb_alsa_mutex);
   595   r = snd_pcm_close(pcm);
   596   pthread_mutex_unlock(&cubeb_alsa_mutex);
   598   return r;
   599 }
   601 static int
   602 alsa_register_stream(cubeb * ctx, cubeb_stream * stm)
   603 {
   604   int i;
   606   pthread_mutex_lock(&ctx->mutex);
   607   for (i = 0; i < CUBEB_STREAM_MAX; ++i) {
   608     if (!ctx->streams[i]) {
   609       ctx->streams[i] = stm;
   610       break;
   611     }
   612   }
   613   pthread_mutex_unlock(&ctx->mutex);
   615   return i == CUBEB_STREAM_MAX;
   616 }
   618 static void
   619 alsa_unregister_stream(cubeb_stream * stm)
   620 {
   621   cubeb * ctx;
   622   int i;
   624   ctx = stm->context;
   626   pthread_mutex_lock(&ctx->mutex);
   627   for (i = 0; i < CUBEB_STREAM_MAX; ++i) {
   628     if (ctx->streams[i] == stm) {
   629       ctx->streams[i] = NULL;
   630       break;
   631     }
   632   }
   633   pthread_mutex_unlock(&ctx->mutex);
   634 }
   636 static void
   637 silent_error_handler(char const * file, int line, char const * function,
   638                      int err, char const * fmt, ...)
   639 {
   640 }
   642 /*static*/ int
   643 alsa_init(cubeb ** context, char const * context_name)
   644 {
   645   cubeb * ctx;
   646   int r;
   647   int i;
   648   int fd[2];
   649   pthread_attr_t attr;
   650   snd_pcm_t * dummy;
   652   assert(context);
   653   *context = NULL;
   655   pthread_mutex_lock(&cubeb_alsa_mutex);
   656   if (!cubeb_alsa_error_handler_set) {
   657     snd_lib_error_set_handler(silent_error_handler);
   658     cubeb_alsa_error_handler_set = 1;
   659   }
   660   pthread_mutex_unlock(&cubeb_alsa_mutex);
   662   ctx = calloc(1, sizeof(*ctx));
   663   assert(ctx);
   665   ctx->ops = &alsa_ops;
   667   r = pthread_mutex_init(&ctx->mutex, NULL);
   668   assert(r == 0);
   670   r = pipe(fd);
   671   assert(r == 0);
   673   for (i = 0; i < 2; ++i) {
   674     fcntl(fd[i], F_SETFD, fcntl(fd[i], F_GETFD) | FD_CLOEXEC);
   675     fcntl(fd[i], F_SETFL, fcntl(fd[i], F_GETFL) | O_NONBLOCK);
   676   }
   678   ctx->control_fd_read = fd[0];
   679   ctx->control_fd_write = fd[1];
   681   /* Force an early rebuild when alsa_run is first called to ensure fds and
   682      nfds have been initialized. */
   683   ctx->rebuild = 1;
   685   r = pthread_attr_init(&attr);
   686   assert(r == 0);
   688   r = pthread_attr_setstacksize(&attr, 256 * 1024);
   689   assert(r == 0);
   691   r = pthread_create(&ctx->thread, &attr, alsa_run_thread, ctx);
   692   assert(r == 0);
   694   r = pthread_attr_destroy(&attr);
   695   assert(r == 0);
   697   /* Open a dummy PCM to force the configuration space to be evaluated so that
   698      init_local_config_with_workaround can find and modify the default node. */
   699   r = alsa_locked_pcm_open(&dummy, SND_PCM_STREAM_PLAYBACK, NULL);
   700   if (r >= 0) {
   701     alsa_locked_pcm_close(dummy);
   702   }
   703   ctx->is_pa = 0;
   704   pthread_mutex_lock(&cubeb_alsa_mutex);
   705   ctx->local_config = init_local_config_with_workaround(CUBEB_ALSA_PCM_NAME);
   706   pthread_mutex_unlock(&cubeb_alsa_mutex);
   707   if (ctx->local_config) {
   708     ctx->is_pa = 1;
   709     r = alsa_locked_pcm_open(&dummy, SND_PCM_STREAM_PLAYBACK, ctx->local_config);
   710     /* If we got a local_config, we found a PA PCM.  If opening a PCM with that
   711        config fails with EINVAL, the PA PCM is too old for this workaround. */
   712     if (r == -EINVAL) {
   713       pthread_mutex_lock(&cubeb_alsa_mutex);
   714       snd_config_delete(ctx->local_config);
   715       pthread_mutex_unlock(&cubeb_alsa_mutex);
   716       ctx->local_config = NULL;
   717     } else if (r >= 0) {
   718       alsa_locked_pcm_close(dummy);
   719     }
   720   }
   722   *context = ctx;
   724   return CUBEB_OK;
   725 }
   727 static char const *
   728 alsa_get_backend_id(cubeb * ctx)
   729 {
   730   return "alsa";
   731 }
   733 static void
   734 alsa_destroy(cubeb * ctx)
   735 {
   736   int r;
   738   assert(ctx);
   740   pthread_mutex_lock(&ctx->mutex);
   741   ctx->shutdown = 1;
   742   poll_wake(ctx);
   743   pthread_mutex_unlock(&ctx->mutex);
   745   r = pthread_join(ctx->thread, NULL);
   746   assert(r == 0);
   748   close(ctx->control_fd_read);
   749   close(ctx->control_fd_write);
   750   pthread_mutex_destroy(&ctx->mutex);
   751   free(ctx->fds);
   753   if (ctx->local_config) {
   754     pthread_mutex_lock(&cubeb_alsa_mutex);
   755     snd_config_delete(ctx->local_config);
   756     pthread_mutex_unlock(&cubeb_alsa_mutex);
   757   }
   759   free(ctx);
   760 }
   762 static void alsa_stream_destroy(cubeb_stream * stm);
   764 static int
   765 alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
   766                  cubeb_stream_params stream_params, unsigned int latency,
   767                  cubeb_data_callback data_callback, cubeb_state_callback state_callback,
   768                  void * user_ptr)
   769 {
   770   cubeb_stream * stm;
   771   int r;
   772   snd_pcm_format_t format;
   774   assert(ctx && stream);
   776   *stream = NULL;
   778   switch (stream_params.format) {
   779   case CUBEB_SAMPLE_S16LE:
   780     format = SND_PCM_FORMAT_S16_LE;
   781     break;
   782   case CUBEB_SAMPLE_S16BE:
   783     format = SND_PCM_FORMAT_S16_BE;
   784     break;
   785   case CUBEB_SAMPLE_FLOAT32LE:
   786     format = SND_PCM_FORMAT_FLOAT_LE;
   787     break;
   788   case CUBEB_SAMPLE_FLOAT32BE:
   789     format = SND_PCM_FORMAT_FLOAT_BE;
   790     break;
   791   default:
   792     return CUBEB_ERROR_INVALID_FORMAT;
   793   }
   795   pthread_mutex_lock(&ctx->mutex);
   796   if (ctx->active_streams >= CUBEB_STREAM_MAX) {
   797     pthread_mutex_unlock(&ctx->mutex);
   798     return CUBEB_ERROR;
   799   }
   800   ctx->active_streams += 1;
   801   pthread_mutex_unlock(&ctx->mutex);
   803   stm = calloc(1, sizeof(*stm));
   804   assert(stm);
   806   stm->context = ctx;
   807   stm->data_callback = data_callback;
   808   stm->state_callback = state_callback;
   809   stm->user_ptr = user_ptr;
   810   stm->params = stream_params;
   811   stm->state = INACTIVE;
   813   r = pthread_mutex_init(&stm->mutex, NULL);
   814   assert(r == 0);
   816   r = alsa_locked_pcm_open(&stm->pcm, SND_PCM_STREAM_PLAYBACK, ctx->local_config);
   817   if (r < 0) {
   818     alsa_stream_destroy(stm);
   819     return CUBEB_ERROR;
   820   }
   822   r = snd_pcm_nonblock(stm->pcm, 1);
   823   assert(r == 0);
   825   /* Ugly hack: the PA ALSA plugin allows buffer configurations that can't
   826      possibly work.  See https://bugzilla.mozilla.org/show_bug.cgi?id=761274.
   827      Only resort to this hack if the handle_underrun workaround failed. */
   828   if (!ctx->local_config && ctx->is_pa) {
   829     latency = latency < 500 ? 500 : latency;
   830   }
   832   r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED,
   833                          stm->params.channels, stm->params.rate, 1,
   834                          latency * 1000);
   835   if (r < 0) {
   836     alsa_stream_destroy(stm);
   837     return CUBEB_ERROR_INVALID_FORMAT;
   838   }
   840   r = snd_pcm_get_params(stm->pcm, &stm->buffer_size, &stm->period_size);
   841   assert(r == 0);
   843   stm->nfds = snd_pcm_poll_descriptors_count(stm->pcm);
   844   assert(stm->nfds > 0);
   846   stm->saved_fds = calloc(stm->nfds, sizeof(struct pollfd));
   847   assert(stm->saved_fds);
   848   r = snd_pcm_poll_descriptors(stm->pcm, stm->saved_fds, stm->nfds);
   849   assert((nfds_t) r == stm->nfds);
   851   r = pthread_cond_init(&stm->cond, NULL);
   852   assert(r == 0);
   854   if (alsa_register_stream(ctx, stm) != 0) {
   855     alsa_stream_destroy(stm);
   856     return CUBEB_ERROR;
   857   }
   859   *stream = stm;
   861   return CUBEB_OK;
   862 }
   864 static void
   865 alsa_stream_destroy(cubeb_stream * stm)
   866 {
   867   int r;
   868   cubeb * ctx;
   870   assert(stm && (stm->state == INACTIVE || stm->state == ERROR));
   872   ctx = stm->context;
   874   pthread_mutex_lock(&stm->mutex);
   875   if (stm->pcm) {
   876     alsa_locked_pcm_close(stm->pcm);
   877     stm->pcm = NULL;
   878   }
   879   free(stm->saved_fds);
   880   pthread_mutex_unlock(&stm->mutex);
   881   pthread_mutex_destroy(&stm->mutex);
   883   r = pthread_cond_destroy(&stm->cond);
   884   assert(r == 0);
   886   alsa_unregister_stream(stm);
   888   pthread_mutex_lock(&ctx->mutex);
   889   assert(ctx->active_streams >= 1);
   890   ctx->active_streams -= 1;
   891   pthread_mutex_unlock(&ctx->mutex);
   893   free(stm);
   894 }
   896 static int
   897 alsa_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
   898 {
   899   int rv;
   900   cubeb_stream * stm;
   901   snd_pcm_hw_params_t* hw_params;
   902   cubeb_stream_params params;
   903   params.rate = 44100;
   904   params.format = CUBEB_SAMPLE_FLOAT32NE;
   905   params.channels = 2;
   907   snd_pcm_hw_params_alloca(&hw_params);
   909   assert(ctx);
   911   rv = alsa_stream_init(ctx, &stm, "", params, 100, NULL, NULL, NULL);
   912   if (rv != CUBEB_OK) {
   913     return CUBEB_ERROR;
   914   }
   916   rv = snd_pcm_hw_params_any(stm->pcm, hw_params);
   917   if (rv < 0) {
   918     return CUBEB_ERROR;
   919   }
   921   rv = snd_pcm_hw_params_get_channels_max(hw_params, max_channels);
   922   if (rv < 0) {
   923     return CUBEB_ERROR;
   924   }
   926   alsa_stream_destroy(stm);
   928   return CUBEB_OK;
   929 }
   931 static int
   932 alsa_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) {
   933   int rv, dir;
   934   snd_pcm_t * pcm;
   935   snd_pcm_hw_params_t * hw_params;
   937   snd_pcm_hw_params_alloca(&hw_params);
   939   /* get a pcm, disabling resampling, so we get a rate the
   940    * hardware/dmix/pulse/etc. supports. */
   941   rv = snd_pcm_open(&pcm, "", SND_PCM_STREAM_PLAYBACK | SND_PCM_NO_AUTO_RESAMPLE, 0);
   942   if (rv < 0) {
   943     return CUBEB_ERROR;
   944   }
   946   rv = snd_pcm_hw_params_any(pcm, hw_params);
   947   if (rv < 0) {
   948     snd_pcm_close(pcm);
   949     return CUBEB_ERROR;
   950   }
   952   rv = snd_pcm_hw_params_get_rate(hw_params, rate, &dir);
   953   if (rv >= 0) {
   954     /* There is a default rate: use it. */
   955     snd_pcm_close(pcm);
   956     return CUBEB_OK;
   957   }
   959   /* Use a common rate, alsa may adjust it based on hw/etc. capabilities. */
   960   *rate = 44100;
   962   rv = snd_pcm_hw_params_set_rate_near(pcm, hw_params, rate, NULL);
   963   if (rv < 0) {
   964     snd_pcm_close(pcm);
   965     return CUBEB_ERROR;
   966   }
   968   snd_pcm_close(pcm);
   970   return CUBEB_OK;
   971 }
   973 static int
   974 alsa_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
   975 {
   976   /* This is found to be an acceptable minimum, even on a super low-end
   977   * machine. */
   978   *latency_ms = 40;
   980   return CUBEB_OK;
   981 }
   983 static int
   984 alsa_stream_start(cubeb_stream * stm)
   985 {
   986   cubeb * ctx;
   988   assert(stm);
   989   ctx = stm->context;
   991   pthread_mutex_lock(&stm->mutex);
   992   snd_pcm_pause(stm->pcm, 0);
   993   gettimeofday(&stm->last_activity, NULL);
   994   pthread_mutex_unlock(&stm->mutex);
   996   pthread_mutex_lock(&ctx->mutex);
   997   if (stm->state != INACTIVE) {
   998     pthread_mutex_unlock(&ctx->mutex);
   999     return CUBEB_ERROR;
  1001   alsa_set_stream_state(stm, RUNNING);
  1002   pthread_mutex_unlock(&ctx->mutex);
  1004   return CUBEB_OK;
  1007 static int
  1008 alsa_stream_stop(cubeb_stream * stm)
  1010   cubeb * ctx;
  1011   int r;
  1013   assert(stm);
  1014   ctx = stm->context;
  1016   pthread_mutex_lock(&ctx->mutex);
  1017   while (stm->state == PROCESSING) {
  1018     r = pthread_cond_wait(&stm->cond, &ctx->mutex);
  1019     assert(r == 0);
  1022   alsa_set_stream_state(stm, INACTIVE);
  1023   pthread_mutex_unlock(&ctx->mutex);
  1025   pthread_mutex_lock(&stm->mutex);
  1026   snd_pcm_pause(stm->pcm, 1);
  1027   pthread_mutex_unlock(&stm->mutex);
  1029   return CUBEB_OK;
  1032 static int
  1033 alsa_stream_get_position(cubeb_stream * stm, uint64_t * position)
  1035   snd_pcm_sframes_t delay;
  1037   assert(stm && position);
  1039   pthread_mutex_lock(&stm->mutex);
  1041   delay = -1;
  1042   if (snd_pcm_state(stm->pcm) != SND_PCM_STATE_RUNNING ||
  1043       snd_pcm_delay(stm->pcm, &delay) != 0) {
  1044     *position = stm->last_position;
  1045     pthread_mutex_unlock(&stm->mutex);
  1046     return CUBEB_OK;
  1049   assert(delay >= 0);
  1051   *position = 0;
  1052   if (stm->write_position >= (snd_pcm_uframes_t) delay) {
  1053     *position = stm->write_position - delay;
  1056   stm->last_position = *position;
  1058   pthread_mutex_unlock(&stm->mutex);
  1059   return CUBEB_OK;
  1062 int
  1063 alsa_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
  1065   snd_pcm_sframes_t delay;
  1066   /* This function returns the delay in frames until a frame written using
  1067      snd_pcm_writei is sent to the DAC. The DAC delay should be < 1ms anyways. */
  1068   if (snd_pcm_delay(stm->pcm, &delay)) {
  1069     return CUBEB_ERROR;
  1072   *latency = delay;
  1074   return CUBEB_OK;
  1077 static struct cubeb_ops const alsa_ops = {
  1078   .init = alsa_init,
  1079   .get_backend_id = alsa_get_backend_id,
  1080   .get_max_channel_count = alsa_get_max_channel_count,
  1081   .get_min_latency = alsa_get_min_latency,
  1082   .get_preferred_sample_rate = alsa_get_preferred_sample_rate,
  1083   .destroy = alsa_destroy,
  1084   .stream_init = alsa_stream_init,
  1085   .stream_destroy = alsa_stream_destroy,
  1086   .stream_start = alsa_stream_start,
  1087   .stream_stop = alsa_stream_stop,
  1088   .stream_get_position = alsa_stream_get_position,
  1089   .stream_get_latency = alsa_stream_get_latency
  1090 };

mercurial