/* Destroy a sound session */ void snd_destroy (snd_SESSION * session) { int ret = 0; oggBUFF *b; /* This will stop any playing sound too */ if (session->actx) ret = audio_context_free (session->actx); /* Free the FIFO */ if (session->fifo) { pthread_mutex_lock(&session->fifo->lock); /*rKA*/ /* free oggBuffs */ while (session->fifo->start) { b = session->fifo->start; session->fifo->start = session->fifo->start->next; DSFYfree (b); } pthread_mutex_unlock(&session->fifo->lock); /*rKA*/ DSFYfree (session->fifo); pthread_cond_destroy (&session->fifo->cs); pthread_mutex_destroy (&session->fifo->lock); } pthread_mutex_destroy (&session->lock); DSFYfree (session); }
/* Initialize sound session, called once */ bool snd_init(struct despotify_session *ds) { DSFYDEBUG ("Initializing sound FIFO etc (happens once)\n"); DSFYDEBUG("Setting state to DL_FILLING\n"); ds->dlstate = DL_FILLING; /* This is the fifo that will hold fragments of compressed audio */ ds->fifo = calloc(1, sizeof(struct ds_snd_fifo)); if (!ds->fifo) return false; ds->fifo->maxbytes = 1024 * 1024; /* 1 MB default buffer size */ ds->fifo->watermark = 200 * 1024; /* 200 KB default watermark */ if (pthread_mutex_init (&ds->fifo->lock, NULL)) { DSFYfree (ds->fifo); return NULL; } if (pthread_cond_init (&ds->fifo->cs, NULL)) { DSFYfree (ds->fifo); pthread_mutex_destroy (&ds->fifo->lock); return NULL; } return true; }
/* Reset for new song */ void snd_reset(struct despotify_session* ds) { DSFYDEBUG("Setting state to DL_DRAINING\n"); ds->fifo->totbytes = 0; ds->dlstate = DL_DRAINING; ov_clear(ds->vf); DSFYfree(ds->vf); }
void snd_reset_codec(struct despotify_session* ds) { DSFYDEBUG("Resetting audio codec\n"); if ( ds->vf ) { ov_clear(ds->vf); DSFYfree(ds->vf); } else if ( ds->mf ) { mpg123_close(ds->mf); mpg123_delete(ds->mf); ds->mf = NULL; } }
/* Initialize sound session, called once */ snd_SESSION *snd_init (void) { snd_SESSION *session; DSFYDEBUG ("snd_init(): Entering..\n"); /* Init session struct */ session = (snd_SESSION *) malloc (sizeof (snd_SESSION)); if (!session) return NULL; session->vf = NULL; session->actx = NULL; session->dlstate = DL_IDLE; session->audio_request = NULL; session->audio_request_arg = NULL; session->buffer_threshold = BUFFER_THRESHOLD; session->audio_end = snd_stop; /* Default is to stop the snd thread */ session->time_tell = NULL; if (pthread_mutex_init (&session->lock, NULL)) { DSFYfree (session); return NULL; } /* This is the queue that will hold fragments of compressed audio */ session->fifo = (oggFIFO *) malloc (sizeof (oggFIFO)); if (!session->fifo) { pthread_mutex_destroy (&session->lock); DSFYfree (session); return NULL; } session->fifo->totbytes = 0; session->fifo->start = NULL; session->fifo->end = NULL; if (pthread_mutex_init (&session->fifo->lock, NULL)) { DSFYfree (session->fifo); pthread_mutex_destroy (&session->lock); DSFYfree (session); return NULL; } if (pthread_cond_init (&session->fifo->cs, NULL) != 0) { pthread_mutex_destroy (&session->fifo->lock); DSFYfree (session->fifo); pthread_mutex_destroy (&session->lock); DSFYfree (session); return NULL; } return session; }
void snd_reset_codec(struct despotify_session* ds) { #ifdef DECODERS DSFYDEBUG("Resetting audio codec\n"); if ( ds->vf ) { ov_clear(ds->vf); DSFYfree(ds->vf); } else if ( ds->mf ) { #ifdef MP3_SUPPORT mpg123_close(ds->mf); mpg123_delete(ds->mf); #endif ds->mf = NULL; } #endif }
int snd_next(struct despotify_session *ds) { pthread_mutex_lock(&ds->fifo->lock); /* go through fifo and look for next track */ struct ds_snd_buffer* b; struct ds_snd_buffer* next; for (b = ds->fifo->start; b; b = next) { if (b->cmd == SND_CMD_START) break; if (b->ptr) free(b->ptr); ds->fifo->totbytes -= b->length; next = b->next; free(b); } ds->fifo->start = b; if (!b) { /* we didn't have next track in memory */ ds->fifo->end = NULL; pthread_mutex_unlock(&ds->fifo->lock); return 0; } pthread_mutex_unlock(&ds->fifo->lock); /* notify client */ if (ds->client_callback) ds->client_callback(ds, DESPOTIFY_NEW_TRACK, b->ptr, ds->client_callback_data); /* tell decoder to start over */ ov_clear(ds->vf); DSFYfree(ds->vf); return 1; }
int snd_get_pcm(struct despotify_session* ds, struct ds_pcm_data* pcm) { if (!ds || !ds->fifo || !ds->fifo->start) { pcm->len = 0; shortsleep(); return 0; } /* top up fifo */ snd_fill_fifo(ds); if (!ds->vf) { DSFYDEBUG ("Initializing vorbisfile struct\n"); /* Allocate Vorbis struct */ ds->vf = calloc(1, sizeof (OggVorbis_File)); if (!ds->vf) return -1; /* Initialize Vorbis struct with the appropriate callbacks */ ov_callbacks callbacks; callbacks.read_func = snd_ov_read_callback; callbacks.seek_func = seek_func; callbacks.close_func = NULL; callbacks.tell_func = NULL; /* Now call ov_open_callbacks(). This will trigger the read_func */ _DSFYDEBUG("Calling ov_open_callbacks()\n"); int ret = ov_open_callbacks(ds, ds->vf, NULL, 0, callbacks); if (ret) { DSFYfree(ds->vf); DSFYDEBUG("ov_open_callbacks(): error %d (%s)\n", ret, ret == OV_ENOTVORBIS? "not Vorbis": ret == OV_EBADHEADER? "bad header": "unknown, check <vorbis/codec.h>") return ret * 10; } }
/* Destroy a sound session */ void snd_destroy (struct despotify_session* ds) { DSFYDEBUG ("Destroying sound FIFO etc\n"); /* Free the fifo */ if (ds->fifo) { pthread_mutex_lock(&ds->fifo->lock); /* free buffers */ while (ds->fifo->start) { struct ds_snd_buffer* b = ds->fifo->start; ds->fifo->start = ds->fifo->start->next; free (b->ptr); free (b); } pthread_mutex_unlock(&ds->fifo->lock); pthread_cond_destroy(&ds->fifo->cs); pthread_mutex_destroy(&ds->fifo->lock); DSFYfree (ds->fifo); } }
int pulseaudio_stop (AUDIOCTX * actx) { pa_PRIVATE *priv = (pa_PRIVATE *) actx->driverprivate; assert (priv != NULL); /* Tell loop thread to exit */ pthread_mutex_lock (&priv->lock); priv->state = PU_END; pthread_cond_wait (&priv->end, &priv->lock); pthread_mutex_unlock (&priv->lock); /* When the other loop has exited, free the non-audio * resources (memory, mutexes). */ pthread_mutex_destroy (&priv->lock); pthread_cond_destroy (&priv->end); pthread_cond_destroy (&priv->pause); DSFYfree (actx->driverprivate); return 0; }
/* * Ogg-Vorbis read() callback * Called by both ov_info() and ov_read() * * This functions dequeues buffers from the fifo * */ size_t snd_ov_read_callback(void *ptr, size_t size, size_t nmemb, void* session) { struct despotify_session* ds = session; pthread_mutex_lock(&ds->fifo->lock); int totlength = 0; bool loop = true; /* process data */ while (loop) { /* Check queue status */ if (ds->fifo->start == NULL) { _DSFYDEBUG ("Waiting for data (%d bytes)\n", ds->fifo->totbytes); pthread_cond_wait (&ds->fifo->cs, &ds->fifo->lock); _DSFYDEBUG ("Got data\n"); } DSFYDEBUG_SNDQUEUE("Processing one buffer at ds->fifo->start." " %zd items of size %zd requested. Totbytes: %d\n", size, nmemb, ds->fifo->totbytes ); struct ds_snd_buffer* b = ds->fifo->start; if (!b) break; _DSFYDEBUG("loop cmd:%d bytes:%d\n", b->cmd, ds->fifo->totbytes); switch (b->cmd) { case SND_CMD_START: /* first packet of a track */ DSFYDEBUG ("Got SND_CMD_START\n"); /* Increment by one */ ds->fifo->start = ds->fifo->start->next; /* notify client */ if (ds->client_callback) ds->client_callback(ds, DESPOTIFY_NEW_TRACK, b->ptr, ds->client_callback_data); /* If this was the last entry */ if (b == ds->fifo->end) ds->fifo->end = NULL; if (b->ptr) DSFYfree (b->ptr); DSFYfree (b); break; case SND_CMD_DATA: { /* data packet */ int remaining = b->length - b->consumed; int ptrsize = size * nmemb; int length; if (totlength + remaining < ptrsize) length = remaining; /* The entire buffer will fit */ else { length = ptrsize - totlength; /* Don't overrun ptrsize */ } memcpy (ptr + totlength, b->ptr + b->consumed, length); b->consumed += length; totlength += length; /* If we have used the entire buffer, free it */ if (b->consumed == b->length) { ds->fifo->start = ds->fifo->start->next; ds->fifo->totbytes -= b->length; /* If this was the last entry */ if (b == ds->fifo->end) ds->fifo->end = NULL; DSFYfree (b->ptr); DSFYfree (b); } /* exit if input is empty or output is full */ if (!ds->fifo->start || totlength == (int)(size*nmemb)) loop = false; break; } case SND_CMD_END: /* last packet of a track, return 0 bytes to signal EOF */ DSFYDEBUG ("Got SND_CMD_END\n"); /* if there already are bytes to return, send them first and then come back here empty */ if (totlength) { loop = false; break; } /* Increment by one */ ds->fifo->start = ds->fifo->start->next; /* If this was the last entry */ if (b == ds->fifo->end) ds->fifo->end = NULL; /* If this was the last entry */ if (b == ds->fifo->end) ds->fifo->end = NULL; if (b->ptr) DSFYfree (b->ptr); DSFYfree (b); _DSFYDEBUG("Calling despotify_end_of_track\n"); if (!ds->fifo->start) { /* (snd_stop locks the mutex internally) */ pthread_mutex_unlock(&ds->fifo->lock); snd_stop(ds); pthread_mutex_lock(&ds->fifo->lock); if (ds->client_callback) ds->client_callback(ds, DESPOTIFY_END_OF_PLAYLIST, NULL, ds->client_callback_data); } /* return 0 bytes as EOF marker to decoder */ loop = false; break; } } pthread_mutex_unlock(&ds->fifo->lock); /* Return number of bytes read to ogg-layer */ _DSFYDEBUG("Returning %d bytes. %d left.\n", totlength, ds->fifo->totbytes); return totlength; }
int libao_play (AUDIOCTX * actx) { ao_device *device; ao_PRIVATE *priv = (ao_PRIVATE *) actx->driverprivate; bool quit = false; assert (priv != NULL); device = (ao_device *) priv->device; /* Driver loop */ for (;;) { unsigned char buf[8192]; ssize_t r; /* Fetch state lock */ pthread_mutex_lock (&priv->lock); switch (priv->state) { case AO_END: quit = true; break; case AO_PAUSED: /* Wait for unpause signal */ pthread_cond_wait (&priv->pause, &priv->lock); break; case AO_PLAYING: case AO_IDLE: default: break; } pthread_mutex_unlock (&priv->lock); if (quit) break; /* Read some data ... */ r = pcm_read (actx->pcmprivate, (char *) buf, sizeof (buf), 0, 2, 1, NULL); if (r == OV_HOLE) { /* vorbis got garbage */ DSFYDEBUG ("pcm_read() == OV_HOLE\n"); continue; } if (r <= 0) { DSFYDEBUG ("pcm_read() == %zd\n", r); if (r == 0) /* EOF */ break; exit (-1); } /* ... and play it */ if (ao_play (device, (char *) buf, (int) r) == 0) { DSFYDEBUG ("ao_play() failed\n"); exit (-1); } } if (ao_close (device) == 0) { DSFYDEBUG ("ao_close() failed\n"); exit (-1); } pthread_mutex_destroy (&priv->lock); pthread_cond_destroy (&priv->pause); DSFYfree(actx->driverprivate); /* This will kill the thread */ DSFYDEBUG ("libao thread exiting\n"); return 0; }