TT#132251 implement media silencing

Change-Id: I0902bd72e2733b96ff75bcf52856a58c51a750f6
pull/1346/head
Richard Fuchs 4 years ago
parent c2b78aa9cd
commit 413798e43f

@ -571,6 +571,8 @@ a string and determines the type of message. Currently the following commands ar
* unblock DTMF
* block media
* unblock media
* silence media
* unsilence media
* start forwarding
* stop forwarding
* play media
@ -751,9 +753,10 @@ Optionally included keys are:
- `all`
Only relevant to the `unblock media` message. Instructs *rtpengine* to remove not only a
full-call media block, but also remove directional media blocks that were imposed on
individual participants.
Only relevant to the `unblock media` and `unsilence media`
messages. Instructs *rtpengine* to remove not only a full-call
media block, but also remove directional media blocks that were
imposed on individual participants.
- `pad crypto`
@ -1805,6 +1808,13 @@ Analogous to `block DTMF` and `unblock DTMF` but blocks media packets instead of
can still pass through when media blocking is enabled. Media packets can be blocked for an entire call, or
directionally for individual participants. See `block DTMF` above for details.
`silence media` and `unsilence media` Messages
----------------------------------------------
Identical to `block media` and `unblock media` except that media packets are
not simply blocked, but rather have their payload replaced with silence audio.
This is only supported for certain trivial audio codecs (i.e. G.711, G.722).
`start forwarding` and `stop forwarding` Messages
-------------------------------------------------

@ -2212,6 +2212,63 @@ const char *call_unblock_media_ng(bencode_item_t *input, bencode_item_t *output)
}
const char *call_silence_media_ng(bencode_item_t *input, bencode_item_t *output) {
AUTO_CLEANUP_NULL(struct call *call, call_unlock_release);
struct call_monologue *monologue;
const char *errstr = NULL;
struct sdp_ng_flags flags;
errstr = media_block_match(&call, &monologue, &flags, input, OP_OTHER);
if (errstr)
return errstr;
if (monologue) {
ilog(LOG_INFO, "Silencing directional media (tag '" STR_FORMAT_M "')",
STR_FMT_M(&monologue->tag));
monologue->silence_media = 1;
__monologue_unkernelize(monologue);
}
else {
ilog(LOG_INFO, "Blocking media (entire call)");
call->silence_media = 1;
__call_unkernelize(call);
}
return NULL;
}
const char *call_unsilence_media_ng(bencode_item_t *input, bencode_item_t *output) {
AUTO_CLEANUP_NULL(struct call *call, call_unlock_release);
struct call_monologue *monologue;
const char *errstr = NULL;
struct sdp_ng_flags flags;
errstr = media_block_match(&call, &monologue, &flags, input, OP_OTHER);
if (errstr)
return errstr;
if (monologue) {
ilog(LOG_INFO, "Unsilencing directional media (tag '" STR_FORMAT_M "')",
STR_FMT_M(&monologue->tag));
monologue->silence_media = 0;
__monologue_unkernelize(monologue);
}
else {
ilog(LOG_INFO, "Unsilencing media (entire call)");
call->silence_media = 0;
if (flags.all) {
for (GList *l = call->monologues.head; l; l = l->next) {
monologue = l->data;
monologue->silence_media = 0;
}
}
__call_unkernelize(call);
}
return NULL;
}
#ifdef WITH_TRANSCODING
static const char *play_media_select_party(struct call **call, GQueue *monologues,
bencode_item_t *input)

@ -1307,8 +1307,26 @@ void codec_add_raw_packet(struct media_packet *mp, unsigned int clockrate) {
}
g_queue_push_tail(&mp->packets_out, p);
}
static int handler_func_passthrough(struct codec_handler *h, struct media_packet *mp) {
static bool handler_silence_block(struct codec_handler *h, struct media_packet *mp) {
if (mp->call->block_media || mp->media->monologue->block_media)
return false;
if (mp->call->silence_media || mp->media->monologue->silence_media) {
if (h->source_pt.codec_def && h->source_pt.codec_def->silence_pattern.len) {
if (h->source_pt.codec_def->silence_pattern.len == 1)
memset(mp->payload.s, h->source_pt.codec_def->silence_pattern.s[0],
mp->payload.len);
else {
for (size_t pos = 0; pos < mp->payload.len;
pos += h->source_pt.codec_def->silence_pattern.len)
memcpy(&mp->payload.s[pos], h->source_pt.codec_def->silence_pattern.s,
h->source_pt.codec_def->silence_pattern.len);
}
}
}
return true;
}
static int handler_func_passthrough(struct codec_handler *h, struct media_packet *mp) {
if (!handler_silence_block(h, mp))
return 0;
if (mp->rtp)
@ -1928,7 +1946,7 @@ void codec_init_payload_type(struct rtp_payload_type *pt, enum media_type type)
static int handler_func_passthrough_ssrc(struct codec_handler *h, struct media_packet *mp) {
if (G_UNLIKELY(!mp->rtp))
return handler_func_passthrough(h, mp);
if (mp->call->block_media || mp->media->monologue->block_media)
if (!handler_silence_block(h, mp))
return 0;
if (mp->rtp)
@ -2820,7 +2838,7 @@ void codec_calc_jitter(struct ssrc_ctx *ssrc, unsigned long ts, unsigned int clo
static int handler_func_transcode(struct codec_handler *h, struct media_packet *mp) {
if (G_UNLIKELY(!mp->rtp))
return handler_func_passthrough(h, mp);
if (mp->call->block_media || mp->media->monologue->block_media)
if (!handler_silence_block(h, mp))
return 0;
// use main codec handler for supp codecs

@ -38,13 +38,13 @@ const char *ng_command_strings[NGC_COUNT] = {
"ping", "offer", "answer", "delete", "query", "list", "start recording",
"stop recording", "start forwarding", "stop forwarding", "block DTMF",
"unblock DTMF", "block media", "unblock media", "play media", "stop media",
"play DTMF", "statistics",
"play DTMF", "statistics", "silence media", "unsilence media",
};
const char *ng_command_strings_short[NGC_COUNT] = {
"Ping", "Offer", "Answer", "Delete", "Query", "List", "StartRec",
"StopRec", "StartFwd", "StopFwd", "BlkDTMF",
"UnblkDTMF", "BlkMedia", "UnblkMedia", "PlayMedia", "StopMedia",
"PlayDTMF", "Stats",
"PlayDTMF", "Stats", "SlnMedia", "UnslnMedia",
};
static void timeval_update_request_time(struct request_time *request, const struct timeval *offer_diff) {
@ -282,6 +282,14 @@ int control_ng_process(str *buf, const endpoint_t *sin, char *addr,
errstr = call_unblock_media_ng(dict, resp);
command = NGC_UNBLOCK_MEDIA;
break;
case CSH_LOOKUP("silence media"):
errstr = call_silence_media_ng(dict, resp);
command = NGC_SILENCE_MEDIA;
break;
case CSH_LOOKUP("unsilence media"):
errstr = call_unsilence_media_ng(dict, resp);
command = NGC_UNSILENCE_MEDIA;
break;
case CSH_LOOKUP("play media"):
errstr = call_play_media_ng(dict, resp);
command = NGC_PLAY_MEDIA;

@ -1210,13 +1210,17 @@ static const char *kernelize_one(struct rtpengine_target_info *reti, GQueue *out
rs = l->data;
// only add payload types that are passthrough for all sinks
bool can_kernelize = true;
bool silenced = (call->silence_media || media->monologue->silence_media) ? true : false;
unsigned int clockrate = 0;
str replace_pattern = STR_NULL;
for (GList *k = sinks->head; k; k = k->next) {
struct sink_handler *ksh = k->data;
struct packet_stream *ksink = ksh->sink;
struct codec_handler *ch = codec_handler_get(media, rs->payload_type,
ksink->media);
clockrate = ch->source_pt.clock_rate;
if (silenced && ch->source_pt.codec_def)
replace_pattern = ch->source_pt.codec_def->silence_pattern;
if (ch->kernelize)
continue;
can_kernelize = false;
@ -1224,9 +1228,17 @@ static const char *kernelize_one(struct rtpengine_target_info *reti, GQueue *out
}
if (!can_kernelize)
continue;
struct rtpengine_payload_type *rpt = &reti->payload_types[reti->num_payload_types++];
rpt->pt_num = rs->payload_type;
rpt->clock_rate = clockrate;
if (replace_pattern.len > sizeof(reti->payload_types->replace_pattern))
ilog(LOG_WARNING | LOG_FLAG_LIMIT, "Payload replacement pattern too long (%zu)",
replace_pattern.len);
else {
rpt->replace_pattern_len = replace_pattern.len;
memcpy(rpt->replace_pattern, replace_pattern.s, replace_pattern.len);
}
}
g_list_free(values);
}

@ -417,6 +417,7 @@ struct call_monologue {
unsigned int block_dtmf:1;
unsigned int block_media:1;
unsigned int silence_media:1;
unsigned int rec_forwarding:1;
unsigned int inject_dtmf:1;
};
@ -515,6 +516,7 @@ struct call {
unsigned int block_dtmf:1;
unsigned int block_media:1;
unsigned int silence_media:1;
unsigned int recording_on:1;
unsigned int rec_forwarding:1;
unsigned int drop_traffic:1;

@ -170,6 +170,8 @@ const char *call_block_dtmf_ng(bencode_item_t *, bencode_item_t *);
const char *call_unblock_dtmf_ng(bencode_item_t *, bencode_item_t *);
const char *call_block_media_ng(bencode_item_t *, bencode_item_t *);
const char *call_unblock_media_ng(bencode_item_t *, bencode_item_t *);
const char *call_silence_media_ng(bencode_item_t *, bencode_item_t *);
const char *call_unsilence_media_ng(bencode_item_t *, bencode_item_t *);
const char *call_play_media_ng(bencode_item_t *, bencode_item_t *);
const char *call_stop_media_ng(bencode_item_t *, bencode_item_t *);
const char *call_play_dtmf_ng(bencode_item_t *, bencode_item_t *);

@ -29,6 +29,8 @@ enum ng_command {
NGC_STOP_MEDIA,
NGC_PLAY_DTMF,
NGC_STATISTICS,
NGC_SILENCE_MEDIA,
NGC_UNSILENCE_MEDIA,
NGC_COUNT // last, number of elements
};

@ -1629,11 +1629,15 @@ static int proc_list_show(struct seq_file *f, void *v) {
(unsigned long long) atomic64_read(&g->stats.bytes),
(unsigned long long) atomic64_read(&g->stats.packets),
(unsigned long long) atomic64_read(&g->stats.errors));
for (i = 0; i < g->target.num_payload_types; i++)
for (i = 0; i < g->target.num_payload_types; i++) {
seq_printf(f, " RTP payload type %3u: %20llu bytes, %20llu packets\n",
g->target.payload_types[i].pt_num,
(unsigned long long) atomic64_read(&g->rtp_stats[i].bytes),
(unsigned long long) atomic64_read(&g->rtp_stats[i].packets));
if (g->target.payload_types[i].replace_pattern_len)
seq_printf(f, " %u bytes replacement payload\n",
g->target.payload_types[i].replace_pattern_len);
}
if (g->target.ssrc)
seq_printf(f, " SSRC in: %lx\n", (unsigned long) ntohl(g->target.ssrc));
proc_list_crypto_print(f, &g->decrypt, &g->target.decrypt, "decryption");
@ -4483,6 +4487,19 @@ intercept_done:
}
no_intercept:
// pattern rewriting
if (rtp_pt_idx >= 0 && g->target.payload_types[rtp_pt_idx].replace_pattern_len && rtp.ok) {
if (g->target.payload_types[rtp_pt_idx].replace_pattern_len == 1)
memset(rtp.payload, g->target.payload_types[rtp_pt_idx].replace_pattern[0],
rtp.payload_len);
else {
for (i = 0; i < rtp.payload_len;
i += g->target.payload_types[rtp_pt_idx].replace_pattern_len)
memcpy(&rtp.payload[i], g->target.payload_types[rtp_pt_idx].replace_pattern,
g->target.payload_types[rtp_pt_idx].replace_pattern_len);
}
}
// output
for (i = 0; i < g->target.num_destinations; i++) {
struct rtpengine_output *o = &g->outputs[i];

@ -94,7 +94,9 @@ enum rtpengine_src_mismatch {
struct rtpengine_payload_type {
unsigned char pt_num;
unsigned char replace_pattern_len;
uint32_t clock_rate;
char replace_pattern[16];
};
struct rtpengine_target_info {

@ -162,6 +162,7 @@ static codec_def_t __codec_defs[] = {
.bits_per_sample = 8,
.media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec,
.silence_pattern = STR_CONST_INIT("\xd5"),
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
[DTX_CN] = &dtx_method_cn,
@ -178,6 +179,7 @@ static codec_def_t __codec_defs[] = {
.bits_per_sample = 8,
.media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec,
.silence_pattern = STR_CONST_INIT("\xff"),
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
[DTX_CN] = &dtx_method_cn,
@ -210,6 +212,7 @@ static codec_def_t __codec_defs[] = {
.bits_per_sample = 8,
.media_type = MT_AUDIO,
.codec_type = &codec_type_avcodec,
.silence_pattern = STR_CONST_INIT("\xfa"),
.dtx_methods = {
[DTX_SILENCE] = &dtx_method_silence,
[DTX_CN] = &dtx_method_cn,

@ -142,6 +142,7 @@ struct codec_def_s {
packetizer_f * const packetizer;
const int bits_per_sample;
const enum media_type media_type;
const str silence_pattern;
// codec-specific callbacks
format_init_f *init;
@ -386,6 +387,7 @@ struct codec_def_s {
int dtmf;
int supplemental;
format_cmp_f * const format_cmp;
const str silence_pattern;
};
struct packet_sequencer_s {
};

@ -372,6 +372,7 @@ static void dtmf(const char *s) {
#define PCMU_payload "\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00"
#define PCMA_payload "\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a"
#define PCMA_silence "\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5"
#define PCMU_silence "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
#define G722_payload "\x23\x84\x20\x84\x20\x84\x04\x84\x04\x04\x84\x04\x84\x04\x84\x05\x85\x46\x87\x48\xc8\x48\x88\x48\xc8\x49\x8a\x4b\xcc\x4c\x8c\x4c\xcc\x4c\x8c\x4d\xce\x50\xcf\x51\x90\x50\xcf\x12\xd1\x52\xd2\x54\x91\x52\xd2\x54\x92\x54\xd3\x56\x93\xd6\x94\xd4\x93\xd7\xd5\x55\x94\x55\xd5\x55\xd4\x56\xd5\x17\xd7\x5a\x95\xd7\x97\xd9\xd4\x16\x58\x57\x98\xd5\xd7\x5b\x96\xda\xd6\x1b\x57\x5a\xd6\x1a\x57\x5b\x98\xd6\xd8\x56\x98\xd7\xd9\x5a\x95\xdb\xd6\x1c\x52\x5e\xd7\x5c\x93\xdf\x99\xd5\xd7\x5f\xd9\x14\x56\x7f\x92\xda\xd9\x5c\x92\xdd\xd7\x5d\x92\xff\xd6\x5a\x96\xdc\xd5\x18\x56\x7e\xd2\x5e\x96\xde\x94\xd8\xd8\x58\xd3\x79\x93\xfb\x90\xdc\xd6\x5b\xdd\x58\x96\xff"
#define AMR_WB_payload "\xf0\x1c\xf3\x06\x08\x10\x77\x32\x23\x20\xd3\x50\x62\x12\xc7\x7c\xe2\xea\x84\x0e\x6e\xf4\x4d\xe4\x7f\xc9\x4c\xcc\x58\x5d\xed\xcc\x5d\x7c\x6c\x14\x7d\xc0" // octet aligned
#define AMR_WB_payload_noe "\xf1\xfc\xc1\x82\x04\x1d\xcc\x88\xc8\x34\xd4\x18\x84\xb1\xdf\x38\xba\xa1\x03\x9b\xbd\x13\x79\x1f\xf2\x53\x33\x16\x17\x7b\x73\x17\x5f\x1b\x05\x1f\x70" // bandwidth efficient
@ -1575,6 +1576,98 @@ int main(void) {
expect(B, "0/PCMU/8000 8/PCMA/8000 9/G722/8000");
end();
// media silencing PCMA
start();
sdp_pt(8, PCMA, 8000);
offer();
expect(A, "8/PCMA/8000");
expect(B, "8/PCMA/8000");
sdp_pt(8, PCMA, 8000);
answer();
expect(A, "8/PCMA/8000");
expect(B, "8/PCMA/8000");
packet_seq(A, 8, PCMA_payload, 0, 0, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 0, 0, 8, PCMA_payload);
packet_seq(A, 8, PCMA_payload, 160, 1, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 160, 1, 8, PCMA_payload);
call.silence_media = 1;
packet_seq(A, 8, PCMA_payload, 320, 2, 8, PCMA_silence);
packet_seq(B, 8, PCMA_payload, 320, 2, 8, PCMA_silence);
packet_seq(A, 8, PCMA_payload, 480, 3, 8, PCMA_silence);
packet_seq(B, 8, PCMA_payload, 480, 3, 8, PCMA_silence);
call.silence_media = 0;
packet_seq(A, 8, PCMA_payload, 640, 4, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 640, 4, 8, PCMA_payload);
packet_seq(A, 8, PCMA_payload, 800, 5, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 800, 5, 8, PCMA_payload);
ml_A.silence_media = 1;
packet_seq(A, 8, PCMA_payload, 960, 6, 8, PCMA_silence);
packet_seq(B, 8, PCMA_payload, 960, 6, 8, PCMA_payload);
packet_seq(A, 8, PCMA_payload, 1120, 7, 8, PCMA_silence);
packet_seq(B, 8, PCMA_payload, 1120, 7, 8, PCMA_payload);
ml_A.silence_media = 0;
packet_seq(A, 8, PCMA_payload, 1280, 8, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 1280, 8, 8, PCMA_payload);
packet_seq(A, 8, PCMA_payload, 1440, 9, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 1440, 9, 8, PCMA_payload);
ml_B.silence_media = 1;
packet_seq(A, 8, PCMA_payload, 1600, 10, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 1600, 10, 8, PCMA_silence);
packet_seq(A, 8, PCMA_payload, 1760, 11, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 1760, 11, 8, PCMA_silence);
ml_B.silence_media = 0;
packet_seq(A, 8, PCMA_payload, 1920, 12, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 1920, 12, 8, PCMA_payload);
packet_seq(A, 8, PCMA_payload, 2080, 13, 8, PCMA_payload);
packet_seq(B, 8, PCMA_payload, 2080, 13, 8, PCMA_payload);
end();
// media silencing PCMU
start();
sdp_pt(0, PCMU, 8000);
offer();
expect(A, "0/PCMU/8000");
expect(B, "0/PCMU/8000");
sdp_pt(0, PCMU, 8000);
answer();
expect(A, "0/PCMU/8000");
expect(B, "0/PCMU/8000");
packet_seq(A, 0, PCMU_payload, 0, 0, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 0, 0, 0, PCMU_payload);
packet_seq(A, 0, PCMU_payload, 160, 1, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 160, 1, 0, PCMU_payload);
call.silence_media = 1;
packet_seq(A, 0, PCMU_payload, 320, 2, 0, PCMU_silence);
packet_seq(B, 0, PCMU_payload, 320, 2, 0, PCMU_silence);
packet_seq(A, 0, PCMU_payload, 480, 3, 0, PCMU_silence);
packet_seq(B, 0, PCMU_payload, 480, 3, 0, PCMU_silence);
call.silence_media = 0;
packet_seq(A, 0, PCMU_payload, 640, 4, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 640, 4, 0, PCMU_payload);
packet_seq(A, 0, PCMU_payload, 800, 5, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 800, 5, 0, PCMU_payload);
ml_A.silence_media = 1;
packet_seq(A, 0, PCMU_payload, 960, 6, 0, PCMU_silence);
packet_seq(B, 0, PCMU_payload, 960, 6, 0, PCMU_payload);
packet_seq(A, 0, PCMU_payload, 1120, 7, 0, PCMU_silence);
packet_seq(B, 0, PCMU_payload, 1120, 7, 0, PCMU_payload);
ml_A.silence_media = 0;
packet_seq(A, 0, PCMU_payload, 1280, 8, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 1280, 8, 0, PCMU_payload);
packet_seq(A, 0, PCMU_payload, 1440, 9, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 1440, 9, 0, PCMU_payload);
ml_B.silence_media = 1;
packet_seq(A, 0, PCMU_payload, 1600, 10, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 1600, 10, 0, PCMU_silence);
packet_seq(A, 0, PCMU_payload, 1760, 11, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 1760, 11, 0, PCMU_silence);
ml_B.silence_media = 0;
packet_seq(A, 0, PCMU_payload, 1920, 12, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 1920, 12, 0, PCMU_payload);
packet_seq(A, 0, PCMU_payload, 2080, 13, 0, PCMU_payload);
packet_seq(B, 0, PCMU_payload, 2080, 13, 0, PCMU_payload);
end();
return 0;
}

Loading…
Cancel
Save