コード例 #1
0
ファイル: track.c プロジェクト: F35X70/feng
/**
 * @brief Tells how many buffers are queued to be seen
 *
 * @param consumer The consumer object to check
 *
 * @return The number of buffers queued in the producer that have not
 *         been seen.
 *
 * @note This function will require exclusive access to the producer,
 *       and will thus lock its mutex.
 */
gulong bq_consumer_unseen(RTP_session *consumer) {
    Track *producer = consumer->track;
    gulong unseen = 0;

    if (bq_consumer_stopped(consumer))
        return unseen;

    /* Ensure we have the exclusive access */
    g_mutex_lock(producer->lock);

    if ( consumer->queue_serial != producer->queue_serial )
        unseen = g_queue_get_length(producer->queue);
    else if ( producer->queue->head != NULL )
        unseen = producer->next_serial - consumer->last_element_serial;

    /* Leave the exclusive access */
    g_mutex_unlock(producer->lock);

    return unseen;
}
コード例 #2
0
ファイル: track.c プロジェクト: F35X70/feng
/**
 * @brief Get the next element from the consumer list
 *
 * @param consumer The consumer object to get the data from
 *
 * @return A pointer to the newly selected element
 *
 * @retval NULL No element can be read; this might be due to no data
 *              present in the producer, or if the producer was
 *              stopped. To know which one of the two conditions
 *              happened, @ref bq_consumer_stopped should be called.
 *
 * @note This function will require exclusive access to the producer,
 *       and will thus lock its mutex.
 *
 * This function marks as seen the previously-selected element, if
 * any; the new selection is not freed until the cursor is moved or
 * the consumer is deleted.
 */
struct MParserBuffer *bq_consumer_get(RTP_session *consumer) {
    Track *producer = consumer->track;
    struct MParserBuffer *element = NULL;
    GList *c_cep;

    if ( bq_consumer_stopped(consumer) )
        return NULL;

    /* Ensure we have the exclusive access */
    g_mutex_lock(producer->lock);
    bq_debug("C:%p LES:%lu:%u PQHS:%lu:%u PQH:%p pointer %p",
             consumer,
             consumer->queue_serial, consumer->last_element_serial,
             producer->queue_serial,
             producer->queue->head ? GLIST_TO_BQELEM(producer->queue->head)->seq_no : 0,
             producer->queue->head,
             consumer->current_element_pointer);

    c_cep = bq_consumer_confirm_pointer(consumer);

    /* If we don't have a queue yet, like for the first read, “move
     * next” (or rather first).
     */
    if ( c_cep == NULL )
        bq_consumer_move_internal(consumer);

    element = BQ_OBJECT(consumer);

    bq_debug("C:%p pointer %p object %p seen %lu/%d",
             consumer,
             consumer->current_element_pointer,
             element,
             element ? element->seen : 0,
             producer->consumers);

    /* Leave the exclusive access */
    g_mutex_unlock(producer->lock);
    return element;
}
コード例 #3
0
ファイル: track.c プロジェクト: F35X70/feng
/**
 * @brief Move to the next element in a consumer
 *
 * @param consumer The consumer object to move
 *
 * @retval true The move was successful
 * @retval false The move wasn't successful, the producer may be stopped.
 *
 * @note This function will require exclusive access to the producer,
 *       and will thus lock its mutex.
 *
 * This is actually just a locking-wrapper around @ref
 * bq_consumer_move_internal.
 */
gboolean bq_consumer_move(RTP_session *consumer) {
    Track *producer = consumer->track;
    gboolean ret;

    bq_debug("(before) C:%p pointer %p",
            consumer,
            consumer->current_element_pointer);

    if ( bq_consumer_stopped(consumer) )
        return false;

    /* Ensure we have the exclusive access */
    g_mutex_lock(producer->lock);
    ret = bq_consumer_move_internal(consumer);

    bq_debug("(after) C:%p pointer %p",
            consumer,
            consumer->current_element_pointer);

    /* Leave the exclusive access */
    g_mutex_unlock(producer->lock);

    return ret;
}
コード例 #4
0
ファイル: rtp.c プロジェクト: phully/feng_build
/**
 * Send pending RTP packets to a session.
 *
 * @param loop eventloop
 * @param w contains the session the RTP session for which to send the packets
 * @todo implement a saner ratecontrol
 */
static void rtp_write_cb(struct ev_loop *loop, ev_periodic *w,
                         ATTR_UNUSED int revents)
{
    RTP_session *session = w->data;
    Resource *resource = session->track->parent;
    MParserBuffer *buffer = NULL;
    ev_tstamp next_time = w->offset;

#ifdef HAVE_METADATA
    if (session->metadata)
        cpd_send(session, now);
#endif
    /* If there is no buffer, it means that either the producer
     * has been stopped (as we reached the end of stream) or that
     * there is no data for the consumer to read. If that's the
     * case we just give control back to the main loop for now.
     */
    if ( bq_consumer_stopped(session->consumer) ) {
        /* If the producer has been stopped, we send the
         * finishing packets and go away.
         */
        fnc_log(FNC_LOG_INFO, "[rtp] Stream Finished");
        rtcp_send_sr(session, BYE);
        return;
    }

    /* Check whether we have enough extra frames to send. If we have
     * no extra frames we have a problem, since we're going to send
     * one packet at least.
     */
    if (resource->eor)
        fnc_log(FNC_LOG_INFO,
                "[%s] end of resource %d packets to be fetched",
                session->track->properties.encoding_name,
                bq_consumer_unseen(session->consumer));

    /* Get the current buffer, if there is enough data */
    if ( !(buffer = bq_consumer_get(session->consumer)) ) {
        /* We wait a bit of time to get the data but before it is
         * expired.
         */
        if (resource->eor) {
            fnc_log(FNC_LOG_INFO, "[rtp] Stream Finished");
            rtcp_send_sr(session, BYE);
            return;
        }
        next_time += 0.01; // assumed to be enough
    } else {
        MParserBuffer *next;
        double delivery  = buffer->delivery;
        double timestamp = buffer->timestamp;
        double duration  = buffer->duration;
        gboolean marker  = buffer->marker;

        rtp_packet_send(session, buffer);

        if (session->pkt_count % 29 == 1)
            rtcp_send_sr(session, SDES);

        if (bq_consumer_move(session->consumer)) {
            next = bq_consumer_get(session->consumer);
            if(delivery != next->delivery) {
                if (session->track->properties.media_source == MS_live)
                    next_time += next->delivery - delivery;
                else
                    next_time = session->range->playback_time -
                                session->range->begin_time +
                                next->delivery;
            }
        } else {
            if (marker)
                next_time += duration;
        }

        fnc_log(FNC_LOG_VERBOSE,
                "[%s] Now: %5.4f, cur %5.4f[%5.4f][%5.4f], next %5.4f %s\n",
                session->track->properties.encoding_name,
                ev_now(loop) - session->range->playback_time,
                delivery,
                timestamp,
                duration,
                next_time - session->range->playback_time,
                marker? "M" : " ");
    }
    ev_periodic_set(w, next_time, 0, NULL);
    ev_periodic_again(loop, w);

    rtp_session_fill(session);
}
コード例 #5
0
ファイル: rtp.c プロジェクト: dulton/hm-platform
static gboolean
rtp_lwrite_cb(GEvent *ev, gint revents, void *user_data)
{
#define XBUFLEN   256
	RTP_session *rtp_s = (RTP_session*)user_data;
	Resource *resource = rtp_s->track->parent;
	MParserBuffer *buffer;
	gchar x[XBUFLEN];
	gint n, fd = g_event_fd(ev);
	ev_tstamp now;

	while ( TRUE )
	{
		n = read(fd, x, XBUFLEN);
		if (n > 0)
			continue;
			
		if (n < 0 && errno == EAGAIN)
			break;

		rc_log(
			RC_LOG_WARN,
			"[rtp] writer stopped, something wrong with rtp->fd[0]."
		);

		rtcp_send_sr(rtp_s, BYE);
		return FALSE;
	}	

	if (G_UNLIKELY(bq_consumer_stopped(rtp_s->consumer)))
	{
	    rc_log(FNC_LOG_INFO, "[rtp] one live stream finished.");
		rtcp_send_sr(rtp_s, BYE);
	    return FALSE;
	}

	while ( TRUE )
	{	
		if (rtp_session_would_block(rtp_s))
		{
			break;
		}

		if (!(buffer = bq_consumer_get(rtp_s->consumer)))
		{
			if (resource->eor)
	        {
	            fnc_log(FNC_LOG_INFO, "[rtp] Stream Finished"); 
				rtp_packet_send_eof(rtp_s, (time_t)now);
				rtcp_send_sr(rtp_s, BYE);
	      		return FALSE;
	        }
			break;
		}

		if (buffer == LS_EOF)
		{
            fnc_log(FNC_LOG_INFO, "[rtp] Stream Finished"); 
			rtp_packet_send_eof(rtp_s, (time_t)now);
			rtcp_send_sr(rtp_s, BYE);
      		return FALSE;					
		}

		now = g_event_time_now_sync(ev);
		rtp_packet_send(rtp_s, buffer, (time_t)now);

		if (!bq_consumer_move(rtp_s->consumer))
			break;
	}

	return TRUE;
}
コード例 #6
0
ファイル: rtp.c プロジェクト: dulton/hm-platform
static gboolean
rtp_timer_cb(GEvent *ev, gint revents, void *user_data)
{
    RTP_session *session = (RTP_session*)user_data;
    Resource *resource = session->track->parent;
    MParserBuffer *buffer = NULL;
    ev_tstamp now, sleep_secs;
    gint to_send = MAX_SND_BLOCKSIZE;

	now = g_event_time_now_sync(ev);
	sleep_secs = .01;

#ifdef HAVE_METADATA
    if (session->metadata)
        cpd_send(session, now);
#endif

	if (!session->audio_rtp && resource->audio_rtp)
	{//Fixme, race against rtp_session_kill(resource->audio_rtp)
		session->audio_rtp = rtp_session_ref(resource->audio_rtp);
	}

	for (;;)
	{
		if (to_send <= 0)
		{
			break;
		}

	    if (bq_consumer_stopped(session->consumer))
	    {
	
	        fnc_log(FNC_LOG_INFO, "[rtp] Stream Finished");
			rtcp_send_sr(session, BYE);
	        return FALSE;
	    }

		if (rtp_session_would_block(session))
		{
			break;
		}

	    if (!(buffer = bq_consumer_get(session->consumer)))
	    {
	        if (resource->eor)
	        {
	            fnc_log(FNC_LOG_INFO, "[rtp] Stream Finished");
				rtp_packet_send_eof(session, (time_t)now);
				rtcp_send_sr(session, BYE);
				sleep_secs = 1;
				break;
	        }
	        sleep_secs = .005;
	        break;
	    }

		if (buffer->mtype != MP_video)
		{
			if (session->audio_rtp)
			{
				rtp_packet_send_rtp(session->audio_rtp, buffer, (time_t)now);
			}
		}
		else
		{
			rtp_packet_send_rtp(session, buffer, (time_t)now);
		}
		to_send -= buffer->data_size;

		if (!bq_consumer_move(session->consumer))
		{
			break;
		}
	}

	g_event_mod_timer_sync(ev, sleep_secs);
    rtp_session_fill(session);

	return TRUE;
}