コード例 #1
0
ファイル: sndqueue.c プロジェクト: xrobau/despotify
void snd_ioctl (struct despotify_session* ds, int cmd, void *data, int length)
{
        switch (cmd) {
            case SND_CMD_CHANNEL_END:
                /* end of substream */
                if (ds->dlabort) {
                    DSFYDEBUG("ds->dlstate = DL_DRAINING\n");
                    ds->dlstate = DL_DRAINING;
                }
                else
                    if (ds->dlstate != DL_END_OF_LIST) {
                        DSFYDEBUG("ds->dlstate = DL_FILLING\n");
                        ds->dlstate = DL_FILLING; /* step down from DL_FILLING_BUSY */
                    }
                return;

            case SND_CMD_END:
                /* end of track. end of playlist? */
                if (!ds->track) {
                    DSFYDEBUG("ds->dlstate = DL_END_OF_LIST\n");
                    ds->dlstate = DL_END_OF_LIST;
                }
                break;
        }

        if (ds->dlabort) {
            if (data)
                free(data);
            return;
        }

        struct ds_snd_buffer* buff = malloc(sizeof(struct ds_snd_buffer));
	if (!buff) {
		perror ("malloc failed");
		exit (-1);
	}

        buff->length = length;
	buff->cmd = cmd;
        buff->consumed = 0;
        buff->ptr = data;
	buff->next = NULL;

        pthread_mutex_lock (&ds->fifo->lock);

	DSFYDEBUG_SNDQUEUE("Current FIFO totbytes=%d, pushed data length is %d\n", ds->fifo->totbytes, length);

	/* Drop the first ogg page if it is Spotify's
           spec-violating single-page same-serial-number stream */
	if (ds->fifo->lastcmd == SND_CMD_START && (buff->ptr[5] == 6)) {
            int offset = 28; /* size of ogg header */

            /* calculate size of page */
            for (int i=0; i < buff->ptr[26]; i++)
                offset += buff->ptr[i+27];

            if (offset < buff->length) {
                memmove(buff->ptr, buff->ptr + offset, length - offset);
                buff->length -= offset;
                DSFYDEBUG("Dropping the first %d bytes of data in this stream, new length is %d\n", offset, buff->length);
            }
            else {
                DSFYDEBUG("Corrupt first OGG packet gave offset %d. Skipping.", offset);
            }
        }

	/* Hook in entry in linked list */
	if (ds->fifo->end)
            ds->fifo->end->next = buff;

	ds->fifo->end = buff;

	/* If this is the first entry */
	if (ds->fifo->start == NULL)
		ds->fifo->start = buff;

	ds->fifo->totbytes += buff->length;

	/* Signal receiver */
	pthread_cond_signal (&ds->fifo->cs);
	pthread_mutex_unlock (&ds->fifo->lock);

        ds->fifo->lastcmd = cmd;
}
コード例 #2
0
ファイル: sndqueue.c プロジェクト: pukko/despotify
/*
 * 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;
}