diff --git a/daemon/codec.c b/daemon/codec.c index 335d2838b..fb4c8fd43 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -184,12 +184,13 @@ reset: } struct codec_handler *codec_handler_make_playback(struct rtp_payload_type *src_pt, - struct rtp_payload_type *dst_pt) + struct rtp_payload_type *dst_pt, unsigned long last_ts) { struct codec_handler *handler = __handler_new(src_pt); handler->dest_pt = *dst_pt; handler->func = handler_func_playback; handler->ssrc_handler = (void *) __ssrc_handler_transcode_new(handler); + handler->ssrc_handler->first_ts = last_ts; while (handler->ssrc_handler->first_ts == 0) handler->ssrc_handler->first_ts = random(); handler->ssrc_handler->rtp_mark = 1; @@ -712,6 +713,7 @@ static void __output_rtp(struct media_packet *mp, struct codec_ssrc_handler *ch, payload_tracker_add(&ssrc_out->tracker, handler->dest_pt.payload_type); p->free_func = free; p->source = handler; + p->rtp = rh; // this packet is dynamically allocated, so we're able to schedule it. // determine scheduled time to send diff --git a/daemon/media_player.c b/daemon/media_player.c index c427e15cb..9b89cdf43 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -250,7 +250,14 @@ found: ilog(LOG_DEBUG, "Output codec for media playback is " STR_FORMAT, STR_FMT(&dst_pt->encoding_with_params)); - mp->handler = codec_handler_make_playback(&src_pt, dst_pt); + // if we played anything before, scale our sync TS according to the time + // that has passed + if (mp->sync_ts_tv.tv_sec) { + long long ts_diff_us = timeval_diff(&rtpe_now, &mp->sync_ts_tv); + mp->sync_ts += ts_diff_us * dst_pt->clock_rate / 1000000 / dst_pt->codec_def->clockrate_mult; + } + + mp->handler = codec_handler_make_playback(&src_pt, dst_pt, mp->sync_ts); if (!mp->handler) return -1; @@ -326,6 +333,16 @@ static void media_player_read_packet(struct media_player *mp) { // update our global "now" timestamp gettimeofday(&rtpe_now, NULL); + // keep track of RTP timestamps and real clock. look at the last packet we received + // and update our sync TS. + if (packet.packets_out.head) { + struct codec_packet *p = packet.packets_out.head->data; + if (p->rtp) { + mp->sync_ts = ntohl(p->rtp->timestamp); + mp->sync_ts_tv = p->to_send; + } + } + mutex_lock(&mp->sink->out_lock); if (media_socket_dequeue(&packet, mp->sink)) ilog(LOG_ERR, "Error sending playback media to RTP sink"); diff --git a/include/codec.h b/include/codec.h index 6f9039696..add8949e3 100644 --- a/include/codec.h +++ b/include/codec.h @@ -16,6 +16,7 @@ struct media_packet; struct ssrc_hash; struct sdp_ng_flags; struct codec_ssrc_handler; +struct rtp_header; typedef int codec_handler_func(struct codec_handler *, struct media_packet *); @@ -36,6 +37,7 @@ struct codec_handler { struct codec_packet { str s; + struct rtp_header *rtp; void *source; // opaque void (*free_func)(void *); struct timeval to_send; @@ -45,7 +47,7 @@ struct codec_packet { struct codec_handler *codec_handler_get(struct call_media *, int payload_type); void codec_handlers_free(struct call_media *); struct codec_handler *codec_handler_make_playback(struct rtp_payload_type *src_pt, - struct rtp_payload_type *dst_pt); + struct rtp_payload_type *dst_pt, unsigned long ts); void codec_handler_free(struct codec_handler *handler); void codec_add_raw_packet(struct media_packet *mp); diff --git a/include/media_player.h b/include/media_player.h index 8546447e7..57a1934dc 100644 --- a/include/media_player.h +++ b/include/media_player.h @@ -38,6 +38,8 @@ struct media_player { struct codec_handler *handler; struct ssrc_ctx *ssrc_out; unsigned long seq; + unsigned long sync_ts; + struct timeval sync_ts_tv; AVIOContext *avioctx; str *blob;