Browse Source

playback audio from raw rtp file

pull/1993/head
Farzaneh Soltanzadeh 4 months ago
parent
commit
de0d8ab5d5
4 changed files with 178 additions and 10 deletions
  1. +8
    -0
      daemon/call_interfaces.c
  2. +157
    -10
      daemon/media_player.c
  3. +2
    -0
      include/call_interfaces.h
  4. +11
    -0
      include/media_player.h

+ 8
- 0
daemon/call_interfaces.c View File

@ -1903,6 +1903,12 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h
case CSH_LOOKUP("file"):
out->file = s;
break;
case CSH_LOOKUP("audio-raw-rtp-file"):
out->audio_raw_rtp_file = s;
break;
case CSH_LOOKUP("audio-raw-rtp-codec"):
out->audio_raw_rtp_codec = s;
break;
case CSH_LOOKUP("frequency"):
case CSH_LOOKUP("frequencies"):
call_ng_flags_freqs(parser, value, out);
@ -3870,6 +3876,8 @@ const char *call_play_media_ng(ng_command_ctx_t *ctx) {
.codec_set = flags.codec_set,
.file = flags.file,
.blob = flags.blob,
.audio_raw_rtp_file = flags.audio_raw_rtp_file,
.audio_raw_rtp_codec = flags.audio_raw_rtp_codec,
.db_id = flags.db_id,
);


+ 157
- 10
daemon/media_player.c View File

@ -1104,6 +1104,57 @@ static int media_player_find_file_begin(struct media_player *mp) {
static bool media_player_read_packet(struct media_player *mp) {
if (!mp->coder.fmtctx)
return true;
// Handle raw RTP file playback
if (mp->coder.audio_raw_rtp_mode) {
// Check if we have more data
if (mp->coder.audio_raw_rtp_pos >= mp->coder.audio_raw_rtp_data.len) {
ilog(LOG_DEBUG, "End of raw RTP file reached");
return true;
}
// Calculate bytes to read (one frame)
size_t bytes_to_read = MIN(mp->coder.audio_raw_rtp_frame_size,
mp->coder.audio_raw_rtp_data.len - mp->coder.audio_raw_rtp_pos);
// Allocate packet
mp->coder.pkt = av_packet_alloc();
if (!mp->coder.pkt) {
ilog(LOG_ERR, "Failed to allocate packet");
return true;
}
// Fill packet with raw RTP data
if (av_new_packet(mp->coder.pkt, bytes_to_read) < 0) {
ilog(LOG_ERR, "Failed to create packet");
av_packet_free(&mp->coder.pkt);
return true;
}
if (bytes_to_read > 0) {
memcpy(mp->coder.pkt->data,
mp->coder.audio_raw_rtp_data.s + mp->coder.audio_raw_rtp_pos,
bytes_to_read);
}
if (bytes_to_read < mp->coder.audio_raw_rtp_frame_size) {
// Pad with silence if needed
memset(mp->coder.pkt->data + bytes_to_read,
mp->coder.silence_byte,
mp->coder.audio_raw_rtp_frame_size - bytes_to_read);
ilog(LOG_DEBUG, "Padding %zu bytes of silence",
mp->coder.audio_raw_rtp_frame_size - bytes_to_read);
}
mp->coder.audio_raw_rtp_pos += bytes_to_read;
// Simulate packet timing (20ms per frame)
mp->coder.pkt->pts = mp->last_frame_ts;
mp->coder.pkt->duration = 160;
mp->last_frame_ts += mp->coder.pkt->duration;
// Process packet
media_player_coder_add_packet(&mp->coder, media_player_add_packet, mp);
av_packet_free(&mp->coder.pkt);
// Schedule next read in 20ms
mp->next_run = rtpe_now + 20000;
return false;
}
int ret = av_read_frame(mp->coder.fmtctx, mp->coder.pkt);
if (ret < 0) {
@ -1232,17 +1283,18 @@ static bool media_player_play_start(struct media_player *mp, const rtp_payload_t
return true;
mp->next_run = rtpe_now;
// give ourselves a bit of a head start with decoding
mp->next_run -= 50000;
// if start_pos is positive, try to seek to that position
if (mp->opts.start_pos > 0) {
ilog(LOG_DEBUG, "Seeking to position %lli", mp->opts.start_pos);
av_seek_frame(mp->coder.fmtctx, 0, mp->opts.start_pos, 0);
if (!mp->coder.audio_raw_rtp_mode) {
// give ourselves a bit of a head start with decoding
mp->next_run -= 50000;
// if start_pos is positive, try to seek to that position
if (mp->opts.start_pos > 0) {
ilog(LOG_DEBUG, "Seeking to position %lli", mp->opts.start_pos);
av_seek_frame(mp->coder.fmtctx, 0, mp->opts.start_pos, 0);
}
else // in case this is a repeated start
av_seek_frame(mp->coder.fmtctx, 0, 0, 0);
}
else // in case this is a repeated start
av_seek_frame(mp->coder.fmtctx, 0, 0, 0);
media_player_read_packet(mp);
return true;
@ -1475,6 +1527,97 @@ static mp_cached_code __media_player_add_file(struct media_player *mp,
return MPC_OK;
}
static bool __media_player_open_audio_raw_rtp_file(struct media_player *mp, media_player_opts_t opts) {
// Validate codec
if (!opts.audio_raw_rtp_codec.len) {
ilog(LOG_ERR, "Raw RTP playback requires codec specification");
return false;
}
// Convert file path
char file_path[PATH_MAX];
snprintf(file_path, sizeof(file_path), STR_FORMAT, STR_FMT(&opts.audio_raw_rtp_file));
// Open file
FILE *f = fopen(file_path, "rb");
if (!f) {
ilog(LOG_ERR, "Failed to open raw RTP file: %s", file_path);
return false;
}
// Get file size
fseek(f, 0, SEEK_END);
long file_size = ftell(f);
fseek(f, 0, SEEK_SET);
// Read entire file into memory
char *file_data = malloc(file_size);
if (!file_data || fread(file_data, 1, file_size, f) != file_size) {
ilog(LOG_ERR, "Failed to read raw RTP file");
fclose(f);
free(file_data);
return false;
}
fclose(f);
// Store in player context
mp->coder.audio_raw_rtp_data.s = file_data;
mp->coder.audio_raw_rtp_data.len = file_size;
mp->coder.audio_raw_rtp_pos = 0;
// Set codec parameters based on input
if (opts.audio_raw_rtp_codec.len == 4 && strncasecmp(opts.audio_raw_rtp_codec.s, "PCMU", 4) == 0) {
mp->coder.audio_raw_rtp_codec = AV_CODEC_ID_PCM_MULAW;
mp->coder.audio_raw_rtp_frame_size = 160; // 20ms frames
mp->coder.silence_byte = 0xFF; // μ-law silence
mp->coder.time_base = (AVRational){1, 8000}; // Default for 8kHz audio
}
else if (opts.audio_raw_rtp_codec.len == 4 && strncasecmp(opts.audio_raw_rtp_codec.s, "PCMA", 4) == 0) {
mp->coder.audio_raw_rtp_codec = AV_CODEC_ID_PCM_ALAW;
mp->coder.audio_raw_rtp_frame_size = 160; // 20ms frames
mp->coder.silence_byte = 0x55; // A-law silence
mp->coder.time_base = (AVRational){1, 8000}; // Default for 8kHz audio
}
else {
ilog(LOG_ERR, "Unsupported raw RTP codec: " STR_FORMAT, STR_FMT(&opts.audio_raw_rtp_codec));
free(file_data);
return false;
}
return true;
}
static bool media_player_play_audio_raw_rtp_file(struct media_player *mp, media_player_opts_t opts) {
const rtp_payload_type *dst_pt = media_player_play_init(mp);
if (!dst_pt)
return false;
if (!__media_player_open_audio_raw_rtp_file(mp, opts))
return false;
// Set up fake format context
mp->coder.fmtctx = avformat_alloc_context();
if (!mp->coder.fmtctx) {
ilog(LOG_ERR, "Failed to alloc format context");
return false;
}
// Create a dummy stream
AVStream *stream = avformat_new_stream(mp->coder.fmtctx, NULL);
if (!stream) {
ilog(LOG_ERR, "Failed to create stream");
return false;
}
// Set codec parameters
stream->time_base = mp->coder.time_base;
stream->codecpar->codec_id = mp->coder.audio_raw_rtp_codec;
stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
stream->codecpar->channels = 1;
stream->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
mp->coder.audio_raw_rtp_mode = true;
return media_player_play_start(mp, dst_pt, opts.codec_set);
}
// call->master_lock held in W
static bool media_player_play_file(struct media_player *mp, media_player_opts_t opts) {
const rtp_payload_type *dst_pt = media_player_play_init(mp);
@ -1681,6 +1824,10 @@ const char * call_play_media_for_ml(struct call_monologue *ml,
if (!media_player_play_db(ml->player, opts))
return "Failed to start media playback from database";
}
else if (opts.audio_raw_rtp_file.len ) {
if (!media_player_play_audio_raw_rtp_file(ml->player, opts))
return "Failed to start audio raw RTP file playback";
}
else
return "No media file specified";
return NULL;


+ 2
- 0
include/call_interfaces.h View File

@ -162,6 +162,8 @@ struct sdp_ng_flags {
str moh_file;
str blob;
str moh_blob;
str audio_raw_rtp_file;
str audio_raw_rtp_codec;
long long db_id;
long long moh_db_id;
long long duration;


+ 11
- 0
include/media_player.h View File

@ -26,6 +26,10 @@ typedef struct {
unsigned int block_egress:1,
moh:1;
str file, blob;
str audio_raw_rtp_file; // Path to audio raw RTP file
str audio_raw_rtp_codec; // Codec for audio raw RTP (e.g., "PCMU")
long long db_id;
} media_player_opts_t;
@ -58,6 +62,13 @@ struct media_player_coder {
str blob;
str read_pos;
struct codec_handler *handler;
unsigned int audio_raw_rtp_mode:1;
str audio_raw_rtp_data;
size_t audio_raw_rtp_pos;
int audio_raw_rtp_frame_size;
unsigned char silence_byte;
enum AVCodecID audio_raw_rtp_codec;
AVRational time_base;
};
struct media_player {


Loading…
Cancel
Save