static void rtp_session_fill_cb(gpointer unused_data, gpointer session_p) { RTP_session *rtp_s = (RTP_session*)session_p; Resource *resource = rtp_s->track->parent; BufferQueue_Consumer *consumer = rtp_s->consumer; gulong unseen; unseen = bq_consumer_unseen(consumer); if (unseen >= MAX_RND_PACKAGES) return; while ((unseen = bq_consumer_unseen(consumer)) < 3*MAX_RND_PACKAGES) { if (r_read(resource) != RESOURCE_OK) break; } }
/** * @brief Callback for the queue filling for the resource * * @param consumer_p A generic pointer to the consumer for non-live queues * @param resource_p A generic pointer to the resource to fill the queue of * * This function takes care of reading the data from the demuxer (via * @ref Demuxer::read_packet); it will executed repeatedly until * either the resources ends (@ref Resource::eor becomes non-zero), * the thread is requested to stop (@ref Resource::fill_pool becomes * NULL), or, for non-live resources only, when the @ref consumer_p * queue is long enough for the client to receive data. * * @note For live streams, the @ref consume_p pointer should have the * value -1 to indicate that it shouldn't be used. * * @note This function will lock the @ref Resource::lock mutex * (repeatedly). */ static void r_read_cb(gpointer consumer_p, gpointer resource_p) { Resource *resource = (Resource*)resource_p; BufferQueue_Consumer *consumer = (BufferQueue_Consumer*)consumer_p; const gboolean live = resource->demuxer->source == LIVE_SOURCE; const gulong buffered_frames = feng_srv.buffered_frames; g_assert( (live && consumer == GINT_TO_POINTER(-1)) || (!live && consumer != GINT_TO_POINTER(-1)) ); do { /* setting this to NULL with an atomic, non-locking operation is our "stop" signal. */ if ( g_atomic_pointer_get(&resource->fill_pool) == NULL ) return; /* Only check for enough buffered frames if we're not doing live; otherwise keep on filling; we also assume that consumer will be NULL in that case. */ if ( !live && bq_consumer_unseen(consumer) >= buffered_frames ) return; // fprintf(stderr, "r_read_cb(%p)\n", resource); g_mutex_lock(resource->lock); switch( resource->demuxer->read_packet(resource) ) { case RESOURCE_OK: break; case RESOURCE_EOF: xlog(LOG_INF, "r_read_unlocked: %s read_packet() end of file.", resource->mrl); resource->eor = true; break; default: xlog(LOG_FAT, "r_read_unlocked: %s read_packet() error.", resource->mrl); resource->eor = true; break; } g_mutex_unlock(resource->lock); } while ( g_atomic_int_get(&resource->eor) == 0 ); }
/** * @brief Do the work of filling an RTP session with data * * @param unued_data Unused * @param session_p The session parameter from rtp_session_fill * * * @internal This function is used to initialize @ref * RTP_session::fill_pool. */ static void rtp_session_fill_cb(ATTR_UNUSED gpointer unused_data, gpointer session_p) { RTP_session *session = (RTP_session*)session_p; Resource *resource = session->track->parent; BufferQueue_Consumer *consumer = session->consumer; gulong unseen; const gulong buffered_frames = resource->srv->srvconf.buffered_frames; while ( (unseen = bq_consumer_unseen(consumer)) < buffered_frames ) { #if 0 fprintf(stderr, "calling read_packet from %p for %p[%s] (%u/%d)\n", session, resource, resource->info->mrl, unseen, buffered_frames); #endif if ( r_read(resource) != RESOURCE_OK ) break; } }
/** * 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); }