Example #1
0
static int ebml_create_client_data (format_plugin_t *format, client_t *client)
{

    ebml_client_data_t *ebml_client_data = calloc(1, sizeof(ebml_client_data_t));
    ebml_source_state_t *ebml_source_state = format->_state;

    int ret = 0;

    if ((ebml_client_data) && (ebml_source_state->header))
    {
        ebml_client_data->header = ebml_source_state->header;
        refbuf_addref (ebml_client_data->header);   // broken, assumes too much currently
    }
    client->format_data = ebml_client_data;
    client->free_client_data = ebml_free_client_data;

    if (client->refbuf == NULL)
        client->refbuf = refbuf_new (4096);
    client->refbuf->len = 0;
    if (format_general_headers (format, client) < 0)
        return -1;

    return ret;

}
Example #2
0
void client_set_queue (client_t *client, refbuf_t *refbuf)
{
    refbuf_t *to_release = client->refbuf;

    client->refbuf = refbuf;
    if (refbuf)
        refbuf_addref (client->refbuf);
    client->pos = 0;
    if (to_release)
        refbuf_release (to_release);
}
Example #3
0
refbuf_queue_t *format_vorbis_get_predata(format_plugin_t *self)
{
    refbuf_queue_t *queue;
    int i;
    vstate_t *state = (vstate_t *)self->_state;

    queue = NULL;
    for (i = 0; i < MAX_HEADER_PAGES; i++) {
        if (state->headbuf[i]) {
            refbuf_addref(state->headbuf[i]);
            refbuf_queue_add(&queue, state->headbuf[i]);
        } else {
            break;
        }
    }

    return queue;
}
Example #4
0
static int ebml_create_client_data(source_t *source, client_t *client)
{
    ebml_client_data_t *ebml_client_data;
    ebml_source_state_t *ebml_source_state = source->format->_state;

    if (!ebml_source_state->header)
        return -1;

    ebml_client_data = calloc(1, sizeof(ebml_client_data_t));
    if (!ebml_client_data)
        return -1;

    ebml_client_data->header = ebml_source_state->header;
    refbuf_addref(ebml_client_data->header);
    client->format_data = ebml_client_data;
    client->free_client_data = ebml_free_client_data;
    return 0;
}
/* called when preparing a refbuf with audio data to be passed
 * back for queueing
 */
static refbuf_t *complete_buffer (source_t *source, refbuf_t *refbuf)
{
    ogg_state_t *ogg_info = source->format->_state;

    refbuf->associated = ogg_info->header_pages;
    refbuf_addref (refbuf->associated);

    if (ogg_info->log_metadata)
    {
        update_comments (source);
        ogg_info->log_metadata = 0;
    }
    /* listeners can start anywhere unless the codecs themselves are
     * marking starting points */
    if (ogg_info->codec_sync == NULL)
        refbuf->flags |= SOURCE_BLOCK_SYNC;
    source->client->queue_pos += refbuf->len;
    return refbuf;
}
Example #6
0
/* read an mp3 stream which does not have shoutcast style metadata */
static refbuf_t *mp3_get_no_meta (source_t *source)
{
    refbuf_t *refbuf;
    mp3_state *source_mp3 = source->format->_state;

    if (complete_read (source) == 0)
        return NULL;

    refbuf = source_mp3->read_data;
    source_mp3->read_data = NULL;

    if (source_mp3->update_metadata)
    {
        mp3_set_title (source);
        source_mp3->update_metadata = 0;
    }
    refbuf->associated = source_mp3->metadata;
    refbuf_addref (source_mp3->metadata);
    refbuf->sync_point = 1;
    return refbuf;
}
Example #7
0
void client_set_queue (client_t *client, refbuf_t *refbuf)
{
    refbuf_t *next, *to_release = client->refbuf;

    while (to_release)
    {
        if (to_release->flags & REFBUF_SHARED)
        {
            ERROR1 ("content has a shared flag status for %s", client->connection.ip);
            break;
        }
        next = to_release->next;
        to_release->next = NULL;
        refbuf_release (to_release);
        to_release = next;
    }

    client->refbuf = refbuf;
    if (refbuf)
        refbuf_addref (client->refbuf);

    client->pos = 0;
}
Example #8
0
/* called when preparing a refbuf with audio data to be passed
 * back for queueing
 */
static refbuf_t *complete_buffer (source_t *source, refbuf_t *refbuf)
{
    ogg_state_t *ogg_info = source->format->_state;
    refbuf_t *header = ogg_info->header_pages;

    while (header)
    {
        refbuf_addref (header);
        header = header->next;
    }
    refbuf->associated = ogg_info->header_pages;

    if (ogg_info->log_metadata)
    {
        update_comments (source);
        ogg_info->log_metadata = 0;
    }
    /* listeners can start anywhere unless the codecs themselves are
     * marking starting points */
    if (ogg_info->codec_sync == NULL)
        refbuf->sync_point = 1;
    return refbuf;
}
Example #9
0
/* read mp3 data with inlined metadata from the source. Filter out the
 * metadata so that the mp3 data itself is store on the queue and the
 * metadata is is associated with it
 */
static refbuf_t *mp3_get_filter_meta (source_t *source)
{
    refbuf_t *refbuf;
    format_plugin_t *plugin = source->format;
    mp3_state *source_mp3 = plugin->_state;
    unsigned char *src;
    unsigned int bytes, mp3_block;

    if (complete_read (source) == 0)
        return NULL;

    refbuf = source_mp3->read_data;
    source_mp3->read_data = NULL;
    src = (unsigned char *)refbuf->data;

    if (source_mp3->update_metadata)
    {
        mp3_set_title (source);
        source_mp3->update_metadata = 0;
    }
    /* fill the buffer with the read data */
    bytes = source_mp3->read_count;
    refbuf->len = 0;
    while (bytes > 0)
    {
        unsigned int metadata_remaining;

        mp3_block = source_mp3->inline_metadata_interval - source_mp3->offset;

        /* is there only enough to account for mp3 data */
        if (bytes <= mp3_block)
        {
            refbuf->len += bytes;
            source_mp3->offset += bytes;
            break;
        }
        /* we have enough data to get to the metadata
         * block, but only transfer upto it */
        if (mp3_block)
        {
            src += mp3_block;
            bytes -= mp3_block;
            refbuf->len += mp3_block;
            source_mp3->offset += mp3_block;
            continue;
        }

        /* process the inline metadata, len == 0 indicates not seen any yet */
        if (source_mp3->build_metadata_len == 0)
        {
            memset (source_mp3->build_metadata, 0,
                    sizeof (source_mp3->build_metadata));
            source_mp3->build_metadata_offset = 0;
            source_mp3->build_metadata_len = 1 + (*src * 16);
        }

        /* do we have all of the metatdata block */
        metadata_remaining = source_mp3->build_metadata_len -
            source_mp3->build_metadata_offset;
        if (bytes < metadata_remaining)
        {
            memcpy (source_mp3->build_metadata +
                    source_mp3->build_metadata_offset, src, bytes);
            source_mp3->build_metadata_offset += bytes;
            break;
        }
        /* copy all bytes except the last one, that way we 
         * know a null byte terminates the message */
        memcpy (source_mp3->build_metadata + source_mp3->build_metadata_offset,
                src, metadata_remaining-1);

        /* overwrite metadata in the buffer */
        bytes -= metadata_remaining;
        memmove (src, src+metadata_remaining, bytes);

        /* assign metadata if it's greater than 1 byte, and the text has changed */
        if (source_mp3->build_metadata_len > 1 &&
                strcmp (source_mp3->build_metadata+1, source_mp3->metadata->data+1) != 0)
        {
            refbuf_t *meta = refbuf_new (source_mp3->build_metadata_len);
            memcpy (meta->data, source_mp3->build_metadata,
                    source_mp3->build_metadata_len);

	    ICECAST_LOG_DEBUG("shoutcast metadata %.*s", 4080, meta->data+1);
            if (strncmp (meta->data+1, "StreamTitle=", 12) == 0)
            {
                filter_shoutcast_metadata (source, source_mp3->build_metadata,
                        source_mp3->build_metadata_len);
                refbuf_release (source_mp3->metadata);
                source_mp3->metadata = meta;
                source_mp3->inline_url = strstr (meta->data+1, "StreamUrl='");
            }
            else
            {
                ICECAST_LOG_ERROR("Incorrect metadata format, ending stream");
                source->running = 0;
                refbuf_release (refbuf);
                refbuf_release (meta);
                return NULL;
            }
        }
        source_mp3->offset = 0;
        source_mp3->build_metadata_len = 0;
    }
    /* the data we have just read may of just been metadata */
    if (refbuf->len == 0)
    {
        refbuf_release (refbuf);
        return NULL;
    }
    refbuf->associated = source_mp3->metadata;
    refbuf_addref (source_mp3->metadata);
    refbuf->sync_point = 1;

    return refbuf;
}
Example #10
0
int format_vorbis_get_buffer(format_plugin_t *self, char *data, unsigned long len, refbuf_t **buffer)
{
    char *buf;
    int i, result;
    ogg_packet op;
    char *tag;
    refbuf_t *refbuf;
    vstate_t *state = (vstate_t *)self->_state;
#ifdef USE_YP
    source_t *source;
    time_t current_time;
#endif

    if (data) {
        /* write the data to the buffer */
        buf = ogg_sync_buffer(&state->oy, len);
        memcpy(buf, data, len);
        ogg_sync_wrote(&state->oy, len);
    }

    refbuf = NULL;
    if (ogg_sync_pageout(&state->oy, &state->og) == 1) {
        refbuf = refbuf_new(state->og.header_len + state->og.body_len);
        memcpy(refbuf->data, state->og.header, state->og.header_len);
        memcpy(&refbuf->data[state->og.header_len], state->og.body, state->og.body_len);

        if (state->serialno != ogg_page_serialno(&state->og)) {
            /* this is a new logical bitstream */
            state->header = 0;
            state->packets = 0;

            /* release old headers, stream state, vorbis data */
            for (i = 0; i < MAX_HEADER_PAGES; i++) {
                if (state->headbuf[i]) {
                    refbuf_release(state->headbuf[i]);
                    state->headbuf[i] = NULL;
                }
            }
            /* Clear old stuff. Rarely but occasionally needed. */
            ogg_stream_clear(&state->os);
            vorbis_comment_clear(&state->vc);
            vorbis_info_clear(&state->vi);

            state->serialno = ogg_page_serialno(&state->og);
            ogg_stream_init(&state->os, state->serialno);
            vorbis_info_init(&state->vi);
            vorbis_comment_init(&state->vc);
        }

        if (state->header >= 0) {
            /* FIXME: In some streams (non-vorbis ogg streams), this could get
             * extras pages beyond the header. We need to collect the pages
             * here anyway, but they may have to be discarded later.
             */
            if (ogg_page_granulepos(&state->og) <= 0) {
                state->header++;
            } else {
                /* we're done caching headers */
                state->header = -1;

                /* put known comments in the stats */
                tag = vorbis_comment_query(&state->vc, "TITLE", 0);
                if (tag) stats_event(self->mount, "title", tag);
                else stats_event(self->mount, "title", "unknown");
                tag = vorbis_comment_query(&state->vc, "ARTIST", 0);
                if (tag) stats_event(self->mount, "artist", tag);
                else stats_event(self->mount, "artist", "unknown");

                /* don't need these now */
                ogg_stream_clear(&state->os);
                vorbis_comment_clear(&state->vc);
                vorbis_info_clear(&state->vi);
#ifdef USE_YP
                /* If we get an update on the mountpoint, force a
                   yp touch */
                avl_tree_rlock(global.source_tree);
                source = source_find_mount(self->mount);
                avl_tree_unlock(global.source_tree);

                if (source) {
                    /* If we get an update on the mountpoint, force a
                       yp touch */
                    current_time = time(NULL);
                    for (i=0; i<source->num_yp_directories; i++) {
                        source->ypdata[i]->yp_last_touch = current_time -
                            source->ypdata[i]->yp_touch_interval + 2;
                    }
                }
#endif

            }
        }

        /* cache header pages */
        if (state->header > 0 && state->packets < 3) {
            if(state->header > MAX_HEADER_PAGES) {
                refbuf_release(refbuf);
                ERROR1("Bad vorbis input: header is more than %d pages long", MAX_HEADER_PAGES);

                return -1;
            }
            refbuf_addref(refbuf);
            state->headbuf[state->header - 1] = refbuf;

            if (state->packets >= 0 && state->packets < 3) {
                ogg_stream_pagein(&state->os, &state->og);
                while (state->packets < 3) {
                    result = ogg_stream_packetout(&state->os, &op);
                    if (result == 0) break; /* need more data */
                    if (result < 0) {
                        state->packets = -1;
                        break;
                    }

                    state->packets++;

                    if (vorbis_synthesis_headerin(&state->vi, &state->vc, &op) < 0) {
                        state->packets = -1;
                        break;
                    }
                }
            }
        }
    }

    *buffer = refbuf;
    return 0;
}
Example #11
0
void source_main (source_t *source)
{
    refbuf_t *refbuf;
    client_t *client;
    avl_node *client_node;

    source_init (source);

    while (global.running == ICE_RUNNING && source->running) {
        int remove_from_q;

        refbuf = get_next_buffer (source);

        remove_from_q = 0;
        source->short_delay = 0;

        if (refbuf)
        {
            /* append buffer to the in-flight data queue,  */
            if (source->stream_data == NULL)
            {
                source->stream_data = refbuf;
                source->burst_point = refbuf;
            }
            if (source->stream_data_tail)
                source->stream_data_tail->next = refbuf;
            source->stream_data_tail = refbuf;
            source->queue_size += refbuf->len;
            /* new buffer is referenced for burst */
            refbuf_addref (refbuf);

            /* new data on queue, so check the burst point */
            source->burst_offset += refbuf->len;
            while (source->burst_offset > source->burst_size)
            {
                refbuf_t *to_release = source->burst_point;

                if (to_release->next)
                {
                    source->burst_point = to_release->next;
                    source->burst_offset -= to_release->len;
                    refbuf_release (to_release);
                    continue;
                }
                break;
            }

            /* save stream to file */
            if (source->dumpfile && source->format->write_buf_to_file)
                source->format->write_buf_to_file (source, refbuf);
        }
        /* lets see if we have too much data in the queue, but don't remove it until later */
        if (source->queue_size > source->queue_size_limit)
            remove_from_q = 1;

        /* acquire write lock on pending_tree */
        avl_tree_wlock(source->pending_tree);

        /* acquire write lock on client_tree */
        avl_tree_wlock(source->client_tree);

        client_node = avl_get_first(source->client_tree);
        while (client_node) {
            client = (client_t *)client_node->key;

            send_to_listener (source, client, remove_from_q);

            if (client->con->error) {
                client_node = avl_get_next(client_node);
                if (client->respcode == 200)
                    stats_event_dec (NULL, "listeners");
                avl_delete(source->client_tree, (void *)client, _free_client);
                source->listeners--;
                DEBUG0("Client removed");
                continue;
            }
            client_node = avl_get_next(client_node);
        }

        /** add pending clients **/
        client_node = avl_get_first(source->pending_tree);
        while (client_node) {

            if(source->max_listeners != -1 && 
                    source->listeners >= (unsigned long)source->max_listeners) 
            {
                /* The common case is caught in the main connection handler,
                 * this deals with rarer cases (mostly concerning fallbacks)
                 * and doesn't give the listening client any information about
                 * why they were disconnected
                 */
                client = (client_t *)client_node->key;
                client_node = avl_get_next(client_node);
                avl_delete(source->pending_tree, (void *)client, _free_client);

                INFO0("Client deleted, exceeding maximum listeners for this "
                        "mountpoint.");
                continue;
            }
            
            /* Otherwise, the client is accepted, add it */
            avl_insert(source->client_tree, client_node->key);

            source->listeners++;
            DEBUG0("Client added");
            stats_event_inc(source->mount, "connections");

            client_node = avl_get_next(client_node);
        }

        /** clear pending tree **/
        while (avl_get_first(source->pending_tree)) {
            avl_delete(source->pending_tree, 
                    avl_get_first(source->pending_tree)->key, 
                    source_remove_client);
        }

        /* release write lock on pending_tree */
        avl_tree_unlock(source->pending_tree);

        /* update the stats if need be */
        if (source->listeners != source->prev_listeners)
        {
            source->prev_listeners = source->listeners;
            INFO2("listener count on %s now %lu", source->mount, source->listeners);
            if (source->listeners > source->peak_listeners)
            {
                source->peak_listeners = source->listeners;
                stats_event_args (source->mount, "listener_peak", "%lu", source->peak_listeners);
            }
            stats_event_args (source->mount, "listeners", "%lu", source->listeners);
            if (source->listeners == 0 && source->on_demand)
                source->running = 0;
        }

        /* lets reduce the queue, any lagging clients should of been
         * terminated by now
         */
        if (source->stream_data)
        {
            /* normal unreferenced queue data will have a refcount 1, but
             * burst queue data will be at least 2, active clients will also
             * increase refcount */
            while (source->stream_data->_count == 1)
            {
                refbuf_t *to_go = source->stream_data;

                if (to_go->next == NULL || source->burst_point == to_go)
                {
                    /* this should not happen */
                    ERROR0 ("queue state is unexpected");
                    source->running = 0;
                    break;
                }
                source->stream_data = to_go->next;
                source->queue_size -= to_go->len;
                to_go->next = NULL;
                refbuf_release (to_go);
            }
        }

        /* release write lock on client_tree */
        avl_tree_unlock(source->client_tree);
    }
    source_shutdown (source);
}