Skip to content

Commit 7d80f05

Browse files
author
Farzaneh Soltanzadeh
committed
playback audio from raw rtp file
1 parent cec0afa commit 7d80f05

File tree

4 files changed

+178
-10
lines changed

4 files changed

+178
-10
lines changed

daemon/call_interfaces.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,6 +1903,12 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h
19031903
case CSH_LOOKUP("file"):
19041904
out->file = s;
19051905
break;
1906+
case CSH_LOOKUP("audio-raw-rtp-file"):
1907+
out->audio_raw_rtp_file = s;
1908+
break;
1909+
case CSH_LOOKUP("audio-raw-rtp-codec"):
1910+
out->audio_raw_rtp_codec = s;
1911+
break;
19061912
case CSH_LOOKUP("frequency"):
19071913
case CSH_LOOKUP("frequencies"):
19081914
call_ng_flags_freqs(parser, value, out);
@@ -3870,6 +3876,8 @@ const char *call_play_media_ng(ng_command_ctx_t *ctx) {
38703876
.codec_set = flags.codec_set,
38713877
.file = flags.file,
38723878
.blob = flags.blob,
3879+
.audio_raw_rtp_file = flags.audio_raw_rtp_file,
3880+
.audio_raw_rtp_codec = flags.audio_raw_rtp_codec,
38733881
.db_id = flags.db_id,
38743882
);
38753883

daemon/media_player.c

Lines changed: 157 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,57 @@ static int media_player_find_file_begin(struct media_player *mp) {
11041104
static bool media_player_read_packet(struct media_player *mp) {
11051105
if (!mp->coder.fmtctx)
11061106
return true;
1107+
// Handle raw RTP file playback
1108+
if (mp->coder.audio_raw_rtp_mode) {
1109+
// Check if we have more data
1110+
if (mp->coder.audio_raw_rtp_pos >= mp->coder.audio_raw_rtp_data.len) {
1111+
ilog(LOG_DEBUG, "End of raw RTP file reached");
1112+
return true;
1113+
}
1114+
1115+
// Calculate bytes to read (one frame)
1116+
size_t bytes_to_read = MIN(mp->coder.audio_raw_rtp_frame_size,
1117+
mp->coder.audio_raw_rtp_data.len - mp->coder.audio_raw_rtp_pos);
1118+
// Allocate packet
1119+
mp->coder.pkt = av_packet_alloc();
1120+
if (!mp->coder.pkt) {
1121+
ilog(LOG_ERR, "Failed to allocate packet");
1122+
return true;
1123+
}
1124+
1125+
// Fill packet with raw RTP data
1126+
if (av_new_packet(mp->coder.pkt, bytes_to_read) < 0) {
1127+
ilog(LOG_ERR, "Failed to create packet");
1128+
av_packet_free(&mp->coder.pkt);
1129+
return true;
1130+
}
1131+
if (bytes_to_read > 0) {
1132+
memcpy(mp->coder.pkt->data,
1133+
mp->coder.audio_raw_rtp_data.s + mp->coder.audio_raw_rtp_pos,
1134+
bytes_to_read);
1135+
}
1136+
if (bytes_to_read < mp->coder.audio_raw_rtp_frame_size) {
1137+
// Pad with silence if needed
1138+
memset(mp->coder.pkt->data + bytes_to_read,
1139+
mp->coder.silence_byte,
1140+
mp->coder.audio_raw_rtp_frame_size - bytes_to_read);
1141+
ilog(LOG_DEBUG, "Padding %zu bytes of silence",
1142+
mp->coder.audio_raw_rtp_frame_size - bytes_to_read);
1143+
}
1144+
mp->coder.audio_raw_rtp_pos += bytes_to_read;
1145+
1146+
// Simulate packet timing (20ms per frame)
1147+
mp->coder.pkt->pts = mp->last_frame_ts;
1148+
mp->coder.pkt->duration = 160;
1149+
mp->last_frame_ts += mp->coder.pkt->duration;
1150+
// Process packet
1151+
media_player_coder_add_packet(&mp->coder, media_player_add_packet, mp);
1152+
av_packet_free(&mp->coder.pkt);
1153+
1154+
// Schedule next read in 20ms
1155+
mp->next_run = rtpe_now + 20000;
1156+
return false;
1157+
}
11071158

11081159
int ret = av_read_frame(mp->coder.fmtctx, mp->coder.pkt);
11091160
if (ret < 0) {
@@ -1232,17 +1283,18 @@ static bool media_player_play_start(struct media_player *mp, const rtp_payload_t
12321283
return true;
12331284

12341285
mp->next_run = rtpe_now;
1235-
// give ourselves a bit of a head start with decoding
1236-
mp->next_run -= 50000;
1237-
1238-
// if start_pos is positive, try to seek to that position
1239-
if (mp->opts.start_pos > 0) {
1240-
ilog(LOG_DEBUG, "Seeking to position %lli", mp->opts.start_pos);
1241-
av_seek_frame(mp->coder.fmtctx, 0, mp->opts.start_pos, 0);
1286+
if (!mp->coder.audio_raw_rtp_mode) {
1287+
// give ourselves a bit of a head start with decoding
1288+
mp->next_run -= 50000;
1289+
1290+
// if start_pos is positive, try to seek to that position
1291+
if (mp->opts.start_pos > 0) {
1292+
ilog(LOG_DEBUG, "Seeking to position %lli", mp->opts.start_pos);
1293+
av_seek_frame(mp->coder.fmtctx, 0, mp->opts.start_pos, 0);
1294+
}
1295+
else // in case this is a repeated start
1296+
av_seek_frame(mp->coder.fmtctx, 0, 0, 0);
12421297
}
1243-
else // in case this is a repeated start
1244-
av_seek_frame(mp->coder.fmtctx, 0, 0, 0);
1245-
12461298
media_player_read_packet(mp);
12471299

12481300
return true;
@@ -1475,6 +1527,97 @@ static mp_cached_code __media_player_add_file(struct media_player *mp,
14751527
return MPC_OK;
14761528
}
14771529

1530+
static bool __media_player_open_audio_raw_rtp_file(struct media_player *mp, media_player_opts_t opts) {
1531+
// Validate codec
1532+
if (!opts.audio_raw_rtp_codec.len) {
1533+
ilog(LOG_ERR, "Raw RTP playback requires codec specification");
1534+
return false;
1535+
}
1536+
1537+
// Convert file path
1538+
char file_path[PATH_MAX];
1539+
snprintf(file_path, sizeof(file_path), STR_FORMAT, STR_FMT(&opts.audio_raw_rtp_file));
1540+
1541+
// Open file
1542+
FILE *f = fopen(file_path, "rb");
1543+
if (!f) {
1544+
ilog(LOG_ERR, "Failed to open raw RTP file: %s", file_path);
1545+
return false;
1546+
}
1547+
1548+
// Get file size
1549+
fseek(f, 0, SEEK_END);
1550+
long file_size = ftell(f);
1551+
fseek(f, 0, SEEK_SET);
1552+
// Read entire file into memory
1553+
char *file_data = malloc(file_size);
1554+
if (!file_data || fread(file_data, 1, file_size, f) != file_size) {
1555+
ilog(LOG_ERR, "Failed to read raw RTP file");
1556+
fclose(f);
1557+
free(file_data);
1558+
return false;
1559+
}
1560+
fclose(f);
1561+
1562+
// Store in player context
1563+
mp->coder.audio_raw_rtp_data.s = file_data;
1564+
mp->coder.audio_raw_rtp_data.len = file_size;
1565+
mp->coder.audio_raw_rtp_pos = 0;
1566+
// Set codec parameters based on input
1567+
if (opts.audio_raw_rtp_codec.len == 4 && strncasecmp(opts.audio_raw_rtp_codec.s, "PCMU", 4) == 0) {
1568+
mp->coder.audio_raw_rtp_codec = AV_CODEC_ID_PCM_MULAW;
1569+
mp->coder.audio_raw_rtp_frame_size = 160; // 20ms frames
1570+
mp->coder.silence_byte = 0xFF; // μ-law silence
1571+
mp->coder.time_base = (AVRational){1, 8000}; // Default for 8kHz audio
1572+
}
1573+
else if (opts.audio_raw_rtp_codec.len == 4 && strncasecmp(opts.audio_raw_rtp_codec.s, "PCMA", 4) == 0) {
1574+
mp->coder.audio_raw_rtp_codec = AV_CODEC_ID_PCM_ALAW;
1575+
mp->coder.audio_raw_rtp_frame_size = 160; // 20ms frames
1576+
mp->coder.silence_byte = 0x55; // A-law silence
1577+
mp->coder.time_base = (AVRational){1, 8000}; // Default for 8kHz audio
1578+
}
1579+
else {
1580+
ilog(LOG_ERR, "Unsupported raw RTP codec: " STR_FORMAT, STR_FMT(&opts.audio_raw_rtp_codec));
1581+
free(file_data);
1582+
return false;
1583+
}
1584+
1585+
return true;
1586+
}
1587+
1588+
static bool media_player_play_audio_raw_rtp_file(struct media_player *mp, media_player_opts_t opts) {
1589+
const rtp_payload_type *dst_pt = media_player_play_init(mp);
1590+
if (!dst_pt)
1591+
return false;
1592+
1593+
if (!__media_player_open_audio_raw_rtp_file(mp, opts))
1594+
return false;
1595+
1596+
// Set up fake format context
1597+
mp->coder.fmtctx = avformat_alloc_context();
1598+
if (!mp->coder.fmtctx) {
1599+
ilog(LOG_ERR, "Failed to alloc format context");
1600+
return false;
1601+
}
1602+
1603+
// Create a dummy stream
1604+
AVStream *stream = avformat_new_stream(mp->coder.fmtctx, NULL);
1605+
if (!stream) {
1606+
ilog(LOG_ERR, "Failed to create stream");
1607+
return false;
1608+
}
1609+
1610+
// Set codec parameters
1611+
stream->time_base = mp->coder.time_base;
1612+
stream->codecpar->codec_id = mp->coder.audio_raw_rtp_codec;
1613+
stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
1614+
stream->codecpar->channels = 1;
1615+
stream->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
1616+
1617+
mp->coder.audio_raw_rtp_mode = true;
1618+
return media_player_play_start(mp, dst_pt, opts.codec_set);
1619+
}
1620+
14781621
// call->master_lock held in W
14791622
static bool media_player_play_file(struct media_player *mp, media_player_opts_t opts) {
14801623
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,
16811824
if (!media_player_play_db(ml->player, opts))
16821825
return "Failed to start media playback from database";
16831826
}
1827+
else if (opts.audio_raw_rtp_file.len ) {
1828+
if (!media_player_play_audio_raw_rtp_file(ml->player, opts))
1829+
return "Failed to start audio raw RTP file playback";
1830+
}
16841831
else
16851832
return "No media file specified";
16861833
return NULL;

include/call_interfaces.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ struct sdp_ng_flags {
162162
str moh_file;
163163
str blob;
164164
str moh_blob;
165+
str audio_raw_rtp_file;
166+
str audio_raw_rtp_codec;
165167
long long db_id;
166168
long long moh_db_id;
167169
long long duration;

include/media_player.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ typedef struct {
2626
unsigned int block_egress:1,
2727
moh:1;
2828
str file, blob;
29+
30+
str audio_raw_rtp_file; // Path to audio raw RTP file
31+
str audio_raw_rtp_codec; // Codec for audio raw RTP (e.g., "PCMU")
32+
2933
long long db_id;
3034
} media_player_opts_t;
3135

@@ -58,6 +62,13 @@ struct media_player_coder {
5862
str blob;
5963
str read_pos;
6064
struct codec_handler *handler;
65+
unsigned int audio_raw_rtp_mode:1;
66+
str audio_raw_rtp_data;
67+
size_t audio_raw_rtp_pos;
68+
int audio_raw_rtp_frame_size;
69+
unsigned char silence_byte;
70+
enum AVCodecID audio_raw_rtp_codec;
71+
AVRational time_base;
6172
};
6273

6374
struct media_player {

0 commit comments

Comments
 (0)