mirror of https://github.com/sipwise/rtpengine.git
Change-Id: I8212f5c74bcb9557d41f80ef3a1595f53bafde8achanges/16/27616/10
parent
d96dbdea17
commit
83965bdb1f
@ -0,0 +1,141 @@
|
||||
#include "media_player.h"
|
||||
#include <glib.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include "obj.h"
|
||||
#include "log.h"
|
||||
#include "timerthread.h"
|
||||
#include "call.h"
|
||||
#include "str.h"
|
||||
|
||||
|
||||
|
||||
static struct timerthread media_player_thread;
|
||||
|
||||
|
||||
|
||||
// appropriate lock must be held
|
||||
static void media_player_shutdown(struct media_player *mp) {
|
||||
ilog(LOG_DEBUG, "shutting down media_player");
|
||||
timerthread_obj_deschedule(&mp->tt_obj);
|
||||
avformat_free_context(mp->fmtctx);
|
||||
mp->fmtctx = NULL;
|
||||
}
|
||||
|
||||
|
||||
void media_player_stop(struct media_player *mp) {
|
||||
media_player_shutdown(mp);
|
||||
}
|
||||
|
||||
|
||||
static void __media_player_free(void *p) {
|
||||
struct media_player *mp = p;
|
||||
|
||||
ilog(LOG_DEBUG, "freeing media_player");
|
||||
|
||||
media_player_shutdown(mp);
|
||||
mutex_destroy(&mp->lock);
|
||||
obj_put(mp->call);
|
||||
}
|
||||
|
||||
|
||||
// call->master_lock held in W
|
||||
struct media_player *media_player_new(struct call_monologue *ml) {
|
||||
ilog(LOG_DEBUG, "creating media_player");
|
||||
|
||||
struct media_player *mp = obj_alloc0("media_player", sizeof(*mp), __media_player_free);
|
||||
|
||||
mp->tt_obj.tt = &media_player_thread;
|
||||
mutex_init(&mp->lock);
|
||||
mp->call = obj_get(ml->call);
|
||||
mp->ml = ml;
|
||||
|
||||
av_init_packet(&mp->pkt);
|
||||
mp->pkt.data = NULL;
|
||||
mp->pkt.size = 0;
|
||||
|
||||
return mp;
|
||||
}
|
||||
|
||||
|
||||
// appropriate lock must be held
|
||||
static void media_player_read_packet(struct media_player *mp) {
|
||||
int ret = av_read_frame(mp->fmtctx, &mp->pkt);
|
||||
if (ret < 0) {
|
||||
if (ret == AVERROR_EOF) {
|
||||
ilog(LOG_DEBUG, "EOF reading from media stream");
|
||||
return;
|
||||
}
|
||||
ilog(LOG_ERR, "Error while reading from media stream");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mp->fmtctx->streams) {
|
||||
ilog(LOG_ERR, "No AVStream present in format context");
|
||||
goto out;
|
||||
}
|
||||
|
||||
AVStream *avs = mp->fmtctx->streams[0];
|
||||
if (!avs) {
|
||||
ilog(LOG_ERR, "No AVStream present in format context");
|
||||
goto out;
|
||||
}
|
||||
|
||||
long long us_dur = mp->pkt.duration * 1000000LL * avs->time_base.num / avs->time_base.den;
|
||||
ilog(LOG_DEBUG, "read media packet: duration %llu (%lli us), time_base %i/%i",
|
||||
(unsigned long long) mp->pkt.duration, us_dur,
|
||||
avs->time_base.num, avs->time_base.den);
|
||||
|
||||
timeval_add_usec(&mp->next_run, us_dur);
|
||||
timerthread_obj_schedule_abs(&mp->tt_obj, &mp->next_run);
|
||||
|
||||
out:
|
||||
av_packet_unref(&mp->pkt);
|
||||
}
|
||||
|
||||
|
||||
// call->master_lock held in W
|
||||
int media_player_play_file(struct media_player *mp, const str *file) {
|
||||
media_player_shutdown(mp);
|
||||
|
||||
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);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
// start playback now
|
||||
|
||||
mp->next_run = rtpe_now;
|
||||
media_player_read_packet(mp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void media_player_run(void *ptr) {
|
||||
struct media_player *mp = ptr;
|
||||
struct call *call = mp->call;
|
||||
|
||||
ilog(LOG_DEBUG, "running scheduled media_player");
|
||||
|
||||
rwlock_lock_r(&call->master_lock);
|
||||
mutex_lock(&mp->lock);
|
||||
|
||||
media_player_read_packet(mp);
|
||||
|
||||
mutex_unlock(&mp->lock);
|
||||
rwlock_unlock_r(&call->master_lock);
|
||||
}
|
||||
|
||||
|
||||
void media_player_init(void) {
|
||||
timerthread_init(&media_player_thread, media_player_run);
|
||||
}
|
||||
|
||||
|
||||
void media_player_loop(void *p) {
|
||||
ilog(LOG_DEBUG, "media_player_loop");
|
||||
timerthread_run(&media_player_thread);
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
#ifndef _MEDIA_PLAYER_H_
|
||||
#define _MEDIA_PLAYER_H_
|
||||
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include "auxlib.h"
|
||||
#include "timerthread.h"
|
||||
#include "str.h"
|
||||
|
||||
|
||||
|
||||
struct call;
|
||||
struct call_monologue;
|
||||
|
||||
|
||||
struct media_player {
|
||||
struct timerthread_obj tt_obj;
|
||||
mutex_t lock;
|
||||
struct call *call;
|
||||
struct call_monologue *ml;
|
||||
|
||||
struct timeval next_run;
|
||||
|
||||
AVFormatContext *fmtctx;
|
||||
AVPacket pkt;
|
||||
};
|
||||
|
||||
|
||||
struct media_player *media_player_new(struct call_monologue *);
|
||||
int media_player_play_file(struct media_player *, const str *);
|
||||
void media_player_stop(struct media_player *);
|
||||
|
||||
void media_player_init(void);
|
||||
void media_player_loop(void *);
|
||||
|
||||
|
||||
|
||||
INLINE void media_player_put(struct media_player **mp) {
|
||||
if (!*mp)
|
||||
return;
|
||||
obj_put(&(*mp)->tt_obj);
|
||||
*mp = NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue