diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index a9f8c801b..a3df6408d 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -2937,8 +2937,8 @@ const char *call_play_media_ng(bencode_item_t *input, bencode_item_t *output) { else return "No media file specified"; - if (l == monologues.head && monologue->player->duration) - bencode_dictionary_add_integer(output, "duration", monologue->player->duration); + if (l == monologues.head && monologue->player->coder.duration) + bencode_dictionary_add_integer(output, "duration", monologue->player->coder.duration); } return NULL; diff --git a/daemon/codec.c b/daemon/codec.c index ad3c98737..a5e842384 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -4826,8 +4826,8 @@ void codec_store_answer(struct codec_store *dst, struct codec_store *src, struct // synthetic answer for T.38: if (dst_media->type_id == MT_AUDIO && src_media->type_id == MT_IMAGE && dst->codec_prefs.length == 0) { if (dst_media->t38_gateway && dst_media->t38_gateway->pcm_player - && dst_media->t38_gateway->pcm_player->handler) { - codec_store_add_order(dst, &dst_media->t38_gateway->pcm_player->handler->dest_pt); + && dst_media->t38_gateway->pcm_player->coder.handler) { + codec_store_add_order(dst, &dst_media->t38_gateway->pcm_player->coder.handler->dest_pt); goto out; } } diff --git a/daemon/media_player.c b/daemon/media_player.c index b3e2c7f96..fa19d3a8a 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -60,27 +60,27 @@ static void media_player_shutdown(struct media_player *mp) { //ilog(LOG_DEBUG, "shutting down media_player"); timerthread_obj_deschedule(&mp->tt_obj); mp->next_run.tv_sec = 0; - avformat_close_input(&mp->fmtctx); + avformat_close_input(&mp->coder.fmtctx); if (mp->sink) { - unsigned int num = send_timer_flush(mp->sink->send_timer, mp->handler); + unsigned int num = send_timer_flush(mp->sink->send_timer, mp->coder.handler); ilog(LOG_DEBUG, "%u packets removed from send queue", num); // roll back seq numbers already used mp->ssrc_out->parent->seq_diff -= num; } mp->media = NULL; - codec_handler_free(&mp->handler); - if (mp->avioctx) { - if (mp->avioctx->buffer) - av_freep(&mp->avioctx->buffer); - av_freep(&mp->avioctx); + codec_handler_free(&mp->coder.handler); + if (mp->coder.avioctx) { + if (mp->coder.avioctx->buffer) + av_freep(&mp->coder.avioctx->buffer); + av_freep(&mp->coder.avioctx); } - mp->avstream = NULL; - if (mp->blob) - free(mp->blob); - mp->blob = NULL; - mp->read_pos = STR_NULL; + mp->coder.avstream = NULL; + if (mp->coder.blob) + free(mp->coder.blob); + mp->coder.blob = NULL; + mp->coder.read_pos = STR_NULL; } #endif @@ -105,7 +105,7 @@ static void __media_player_free(void *p) { ssrc_ctx_put(&mp->ssrc_out); mutex_destroy(&mp->lock); obj_put(mp->call); - av_packet_free(&mp->pkt); + av_packet_free(&mp->coder.pkt); } #endif @@ -132,9 +132,9 @@ struct media_player *media_player_new(struct call_monologue *ml) { mp->seq = ssl_random(); mp->ssrc_out = ssrc_ctx; - mp->pkt = av_packet_alloc(); - mp->pkt->data = NULL; - mp->pkt->size = 0; + mp->coder.pkt = av_packet_alloc(); + mp->coder.pkt->data = NULL; + mp->coder.pkt->size = 0; return mp; #else @@ -320,17 +320,17 @@ int media_player_setup(struct media_player *mp, const struct rtp_payload_type *s } // if we already have a handler, see if anything needs changing - if (mp->handler) { - if (!rtp_payload_type_eq_exact(&mp->handler->dest_pt, dst_pt) - || !rtp_payload_type_eq_exact(&mp->handler->source_pt, src_pt)) + if (mp->coder.handler) { + if (!rtp_payload_type_eq_exact(&mp->coder.handler->dest_pt, dst_pt) + || !rtp_payload_type_eq_exact(&mp->coder.handler->source_pt, src_pt)) { ilog(LOG_DEBUG, "Resetting codec handler for media player"); - codec_handler_free(&mp->handler); + codec_handler_free(&mp->coder.handler); } } - if (!mp->handler) - mp->handler = codec_handler_make_playback(src_pt, dst_pt, mp->sync_ts, mp->media); - if (!mp->handler) + if (!mp->coder.handler) + mp->coder.handler = codec_handler_make_playback(src_pt, dst_pt, mp->sync_ts, mp->media); + if (!mp->coder.handler) return -1; return 0; @@ -343,25 +343,26 @@ int media_player_setup(struct media_player *mp, const struct rtp_payload_type *s #endif static int __ensure_codec_handler(struct media_player *mp, const struct rtp_payload_type *dst_pt) { - if (mp->handler) + if (mp->coder.handler) return 0; // synthesise rtp payload type struct rtp_payload_type src_pt = { .payload_type = -1 }; - src_pt.codec_def = codec_find_by_av(mp->avstream->CODECPAR->codec_id); + src_pt.codec_def = codec_find_by_av(mp->coder.avstream->CODECPAR->codec_id); if (!src_pt.codec_def) { ilog(LOG_ERR, "Attempting to play media from an unsupported file format/codec"); return -1; } src_pt.encoding = src_pt.codec_def->rtpname_str; - src_pt.channels = GET_CHANNELS(mp->avstream->CODECPAR); - src_pt.clock_rate = mp->avstream->CODECPAR->sample_rate; + src_pt.channels = GET_CHANNELS(mp->coder.avstream->CODECPAR); + src_pt.clock_rate = mp->coder.avstream->CODECPAR->sample_rate; codec_init_payload_type(&src_pt, MT_AUDIO); if (media_player_setup(mp, &src_pt, dst_pt)) return -1; - mp->duration = mp->avstream->duration * 1000 * mp->avstream->time_base.num / mp->avstream->time_base.den; + mp->coder.duration = mp->coder.avstream->duration * 1000 * mp->coder.avstream->time_base.num + / mp->coder.avstream->time_base.den; payload_type_clear(&src_pt); return 0; @@ -389,7 +390,7 @@ void media_player_add_packet(struct media_player *mp, char *buf, size_t len, str_init_len(&packet.raw, buf, len); packet.payload = packet.raw; - mp->handler->handler_func(mp->handler, &packet); + mp->coder.handler->handler_func(mp->coder.handler, &packet); // as this is timing sensitive and we may have spent some time decoding, // update our global "now" timestamp @@ -419,22 +420,22 @@ void media_player_add_packet(struct media_player *mp, char *buf, size_t len, // appropriate lock must be held static void media_player_read_packet(struct media_player *mp) { - if (!mp->fmtctx) + if (!mp->coder.fmtctx) return; - int ret = av_read_frame(mp->fmtctx, mp->pkt); + int ret = av_read_frame(mp->coder.fmtctx, mp->coder.pkt); if (ret < 0) { if (ret == AVERROR_EOF) { if (mp->repeat > 1){ ilog(LOG_DEBUG, "EOF reading from media stream but will repeat %li time",mp->repeat); mp->repeat = mp->repeat - 1; - int64_t ret64 = avio_seek(mp->fmtctx->pb, 0, SEEK_SET); + int64_t ret64 = avio_seek(mp->coder.fmtctx->pb, 0, SEEK_SET); if (ret64 != 0) ilog(LOG_ERR, "Failed to seek to beginning of media file"); - ret = av_seek_frame(mp->fmtctx, -1, 0, 0); + ret = av_seek_frame(mp->coder.fmtctx, -1, 0, 0); if (ret < 0) ilog(LOG_ERR, "Failed to seek to beginning of media file"); - ret = av_read_frame(mp->fmtctx, mp->pkt); + ret = av_read_frame(mp->coder.fmtctx, mp->coder.pkt); } else { ilog(LOG_DEBUG, "EOF reading from media stream"); return; @@ -449,29 +450,30 @@ static void media_player_read_packet(struct media_player *mp) { } - mp->last_frame_ts = mp->pkt->pts; + mp->last_frame_ts = mp->coder.pkt->pts; // scale pts and duration according to sample rate - long long duration_scaled = mp->pkt->duration * mp->avstream->CODECPAR->sample_rate - * mp->avstream->time_base.num / mp->avstream->time_base.den; - unsigned long long pts_scaled = mp->pkt->pts * mp->avstream->CODECPAR->sample_rate - * mp->avstream->time_base.num / mp->avstream->time_base.den; + long long duration_scaled = mp->coder.pkt->duration * mp->coder.avstream->CODECPAR->sample_rate + * mp->coder.avstream->time_base.num / mp->coder.avstream->time_base.den; + unsigned long long pts_scaled = mp->coder.pkt->pts * mp->coder.avstream->CODECPAR->sample_rate + * mp->coder.avstream->time_base.num / mp->coder.avstream->time_base.den; - long long us_dur = mp->pkt->duration * 1000000LL * mp->avstream->time_base.num / mp->avstream->time_base.den; + long long us_dur = mp->coder.pkt->duration * 1000000LL * mp->coder.avstream->time_base.num + / mp->coder.avstream->time_base.den; ilog(LOG_DEBUG, "read media packet: pts %llu duration %lli (scaled %llu/%lli, %lli us), " "sample rate %i, time_base %i/%i", - (unsigned long long) mp->pkt->pts, - (long long) mp->pkt->duration, + (unsigned long long) mp->coder.pkt->pts, + (long long) mp->coder.pkt->duration, pts_scaled, duration_scaled, us_dur, - mp->avstream->CODECPAR->sample_rate, - mp->avstream->time_base.num, mp->avstream->time_base.den); + mp->coder.avstream->CODECPAR->sample_rate, + mp->coder.avstream->time_base.num, mp->coder.avstream->time_base.den); - media_player_add_packet(mp, (char *) mp->pkt->data, mp->pkt->size, us_dur, pts_scaled); + media_player_add_packet(mp, (char *) mp->coder.pkt->data, mp->coder.pkt->size, us_dur, pts_scaled); - av_packet_unref(mp->pkt); + av_packet_unref(mp->coder.pkt); } @@ -518,10 +520,10 @@ static void media_player_play_start(struct media_player *mp, const struct rtp_pa long long repeat, long long start_pos) { // needed to have usable duration for some formats. ignore errors. - avformat_find_stream_info(mp->fmtctx, NULL); + avformat_find_stream_info(mp->coder.fmtctx, NULL); - mp->avstream = mp->fmtctx->streams[0]; - if (!mp->avstream) { + mp->coder.avstream = mp->coder.fmtctx->streams[0]; + if (!mp->coder.avstream) { ilog(LOG_ERR, "No AVStream present in format context"); return; } @@ -535,7 +537,7 @@ static void media_player_play_start(struct media_player *mp, const struct rtp_pa // if start_pos is positive, try to seek to that position if (start_pos > 0) { ilog(LOG_DEBUG, "Seeking to position %lli", start_pos); - av_seek_frame(mp->fmtctx, 0, start_pos, 0); + av_seek_frame(mp->coder.fmtctx, 0, start_pos, 0); } media_player_read_packet(mp); mp->repeat = repeat; @@ -553,7 +555,7 @@ int media_player_play_file(struct media_player *mp, const str *file, long long r char file_s[PATH_MAX]; snprintf(file_s, sizeof(file_s), STR_FORMAT, STR_FMT(file)); - int ret = avformat_open_input(&mp->fmtctx, file_s, NULL, NULL); + int ret = avformat_open_input(&mp->coder.fmtctx, file_s, NULL, NULL); if (ret < 0) { ilog(LOG_ERR, "Failed to open media file for playback: %s", av_error(ret)); return -1; @@ -576,14 +578,14 @@ static int __mp_avio_read_wrap(void *opaque, uint8_t *buf, int buf_size) { return AVERROR(EINVAL); if (buf_size == 0) return 0; - if (!mp->read_pos.len) + if (!mp->coder.read_pos.len) return AVERROR_EOF; int len = buf_size; - if (len > mp->read_pos.len) - len = mp->read_pos.len; - memcpy(buf, mp->read_pos.s, len); - str_shift(&mp->read_pos, len); + if (len > mp->coder.read_pos.len) + len = mp->coder.read_pos.len; + memcpy(buf, mp->coder.read_pos.s, len); + str_shift(&mp->coder.read_pos, len); return len; } static int __mp_avio_read(void *opaque, uint8_t *buf, int buf_size) { @@ -596,8 +598,8 @@ static int64_t __mp_avio_seek_set(struct media_player *mp, int64_t offset) { ilog(LOG_DEBUG, "__mp_avio_seek_set(%" PRIi64 ")", offset); if (offset < 0) return AVERROR(EINVAL); - mp->read_pos = *mp->blob; - if (str_shift(&mp->read_pos, offset)) + mp->coder.read_pos = *mp->coder.blob; + if (str_shift(&mp->coder.read_pos, offset)) return AVERROR_EOF; return offset; } @@ -607,9 +609,9 @@ static int64_t __mp_avio_seek(void *opaque, int64_t offset, int whence) { if (whence == SEEK_SET) return __mp_avio_seek_set(mp, offset); if (whence == SEEK_CUR) - return __mp_avio_seek_set(mp, ((int64_t) (mp->read_pos.s - mp->blob->s)) + offset); + return __mp_avio_seek_set(mp, ((int64_t) (mp->coder.read_pos.s - mp->coder.blob->s)) + offset); if (whence == SEEK_END) - return __mp_avio_seek_set(mp, ((int64_t) mp->blob->len) + offset); + return __mp_avio_seek_set(mp, ((int64_t) mp->coder.blob->len) + offset); return AVERROR(EINVAL); } #endif @@ -626,15 +628,15 @@ int media_player_play_blob(struct media_player *mp, const str *blob, long long r if (!dst_pt) return -1; - mp->blob = str_dup(blob); + mp->coder.blob = str_dup(blob); err = "out of memory"; - if (!mp->blob) + if (!mp->coder.blob) goto err; - mp->read_pos = *mp->blob; + mp->coder.read_pos = *mp->coder.blob; err = "could not allocate AVFormatContext"; - mp->fmtctx = avformat_alloc_context(); - if (!mp->fmtctx) + mp->coder.fmtctx = avformat_alloc_context(); + if (!mp->coder.fmtctx) goto err; void *avio_buf = av_malloc(DEFAULT_AVIO_BUFSIZE); @@ -642,17 +644,17 @@ int media_player_play_blob(struct media_player *mp, const str *blob, long long r if (!avio_buf) goto err; - mp->avioctx = avio_alloc_context(avio_buf, DEFAULT_AVIO_BUFSIZE, 0, mp, __mp_avio_read, + mp->coder.avioctx = avio_alloc_context(avio_buf, DEFAULT_AVIO_BUFSIZE, 0, mp, __mp_avio_read, NULL, __mp_avio_seek); err = "failed to allocate AVIOContext"; - if (!mp->avioctx) + if (!mp->coder.avioctx) goto err; - mp->fmtctx->pb = mp->avioctx; + mp->coder.fmtctx->pb = mp->coder.avioctx; - // consumes allocated mp->fmtctx + // consumes allocated mp->coder.fmtctx err = "failed to open AVFormatContext input"; - av_ret = avformat_open_input(&mp->fmtctx, "dummy", NULL, NULL); + av_ret = avformat_open_input(&mp->coder.fmtctx, "dummy", NULL, NULL); if (av_ret < 0) goto err; diff --git a/daemon/mqtt.c b/daemon/mqtt.c index 87c85acdb..9410930ed 100644 --- a/daemon/mqtt.c +++ b/daemon/mqtt.c @@ -172,7 +172,7 @@ static void mqtt_monologue_stats(struct call_monologue *ml, JsonBuilder *json) { json_builder_begin_object(json); json_builder_set_member_name(json, "duration"); - json_builder_add_int_value(json, mp->duration); + json_builder_add_int_value(json, mp->coder.duration); json_builder_set_member_name(json, "repeat"); json_builder_add_int_value(json, mp->repeat); json_builder_set_member_name(json, "frame_time"); diff --git a/include/media_player.h b/include/media_player.h index f43b096d8..8415db167 100644 --- a/include/media_player.h +++ b/include/media_player.h @@ -28,6 +28,17 @@ struct rtp_payload_type; typedef void (*media_player_run_func)(struct media_player *); +struct media_player_coder { + AVFormatContext *fmtctx; + AVStream *avstream; + unsigned long duration; // in milliseconds + AVPacket *pkt; + AVIOContext *avioctx; + str *blob; + str read_pos; + struct codec_handler *handler; +}; + struct media_player { struct timerthread_obj tt_obj; mutex_t lock; @@ -41,20 +52,13 @@ struct media_player { struct timeval next_run; unsigned long repeat; - AVFormatContext *fmtctx; - AVStream *avstream; - unsigned long duration; // in milliseconds - AVPacket *pkt; - struct codec_handler *handler; + struct media_player_coder coder; + struct ssrc_ctx *ssrc_out; unsigned long seq; unsigned long sync_ts; struct timeval sync_ts_tv; long long last_frame_ts; - - AVIOContext *avioctx; - str *blob; - str read_pos; }; INLINE void media_player_put(struct media_player **mp) {