diff --git a/README.md b/README.md index 1db249ec6..0005596bc 100644 --- a/README.md +++ b/README.md @@ -882,6 +882,10 @@ be engaged for that call. With transcoding active for a call, all unsupported codecs will be removed from the SDP. Transcoding happens in userspace only, so in-kernel packet forwarding will not be available for transcoded codecs. +However, even if the transcoding feature has been engaged for a call, not all codecs will necessarily +end up being transcoded. Codecs that are supported by both sides will simply be passed through +transparently (unless repacketization is active). In-kernel packet forwarding will still be available +for these codecs. The following codecs are supported by *rtpengine*: diff --git a/daemon/codec.c b/daemon/codec.c index cc5ed6a80..0ca571786 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -21,6 +21,7 @@ static void __rtp_payload_type_add_name(GHashTable *, struct rtp_payload_type *p static struct codec_handler codec_handler_stub = { .source_pt.payload_type = -1, .func = handler_func_passthrough, + .passthrough = 1, }; @@ -62,12 +63,14 @@ static void __transcode_packet_free(struct transcode_packet *); static struct codec_handler codec_handler_stub_ssrc = { .source_pt.payload_type = -1, .func = handler_func_passthrough_ssrc, + .passthrough = 1, }; static void __handler_shutdown(struct codec_handler *handler) { free_ssrc_hash(&handler->ssrc_hash); + handler->passthrough = 0; } static void __codec_handler_free(void *pp) { @@ -85,11 +88,13 @@ static struct codec_handler *__handler_new(struct rtp_payload_type *pt) { static void __make_passthrough(struct codec_handler *handler) { __handler_shutdown(handler); handler->func = handler_func_passthrough; + handler->passthrough = 1; } static void __make_passthrough_ssrc(struct codec_handler *handler) { __handler_shutdown(handler); handler->func = handler_func_passthrough_ssrc; + handler->passthrough = 1; } static void __make_transcoder(struct codec_handler *handler, struct rtp_payload_type *source, diff --git a/daemon/codec.h b/daemon/codec.h index 91620637b..0ec9aba6c 100644 --- a/daemon/codec.h +++ b/daemon/codec.h @@ -22,6 +22,7 @@ struct codec_handler { struct rtp_payload_type source_pt; // source_pt.payload_type = hashtable index struct rtp_payload_type dest_pt; codec_handler_func *func; + int passthrough; struct ssrc_hash *ssrc_hash; }; diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 27d0af5d4..59c1a80a7 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -941,8 +941,6 @@ void kernelize(struct packet_stream *stream) { return; if (call->recording != NULL && !selected_recording_method->kernel_support) goto no_kernel; - if (MEDIA_ISSET(stream->media, TRANSCODE)) // XXX make this granular per payload type? - goto no_kernel; if (!kernel.is_wanted) goto no_kernel; nk_warn_msg = "interface to kernel module not open"; @@ -993,7 +991,13 @@ void kernelize(struct packet_stream *stream) { __re_address_translate_ep(&reti.dst_addr, &sink->endpoint); __re_address_translate_ep(&reti.src_addr, &sink->selected_sfd->socket.local); - reti.ssrc = stream->ssrc_in ? htonl(stream->ssrc_in->parent->h.ssrc) : 0; + if (stream->ssrc_in) { + reti.ssrc = htonl(stream->ssrc_in->parent->h.ssrc); + if (MEDIA_ISSET(stream->media, TRANSCODE)) { + reti.ssrc_out = htonl(stream->ssrc_in->ssrc_map_out); + reti.transcoding = 1; + } + } stream->handler->in->kernel(&reti.decrypt, stream); stream->handler->out->kernel(&reti.encrypt, sink); @@ -1022,6 +1026,12 @@ void kernelize(struct packet_stream *stream) { break; } rs = l->data; + if (MEDIA_ISSET(stream->media, TRANSCODE)) { + // only add payload types that are passthrough + struct codec_handler *ch = codec_handler_get(stream->media, rs->payload_type); + if (!ch->passthrough) + continue; + } reti.payload_types[reti.num_payload_types++] = rs->payload_type; } g_list_free(values); diff --git a/daemon/ssrc.c b/daemon/ssrc.c index 8c6780d67..3e1a9b31d 100644 --- a/daemon/ssrc.c +++ b/daemon/ssrc.c @@ -8,7 +8,8 @@ static void init_ssrc_ctx(struct ssrc_ctx *c, struct ssrc_entry_call *parent) { c->parent = parent; - c->ssrc_map_out = random(); + while (!c->ssrc_map_out) + c->ssrc_map_out = random(); } static void init_ssrc_entry(struct ssrc_entry *ent, u_int32_t ssrc) { ent->ssrc = ssrc; diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c index d79477d49..19676ed74 100644 --- a/kernel-module/xt_RTPENGINE.c +++ b/kernel-module/xt_RTPENGINE.c @@ -1505,6 +1505,10 @@ static int proc_list_show(struct seq_file *f, void *v) { seq_printf(f, " option: rtcp-mux\n"); if (g->target.dtls) seq_printf(f, " option: dtls\n"); + if (g->target.stun) + seq_printf(f, " option: stun\n"); + if (g->target.transcoding) + seq_printf(f, " option: transcoding\n"); target_put(g); @@ -3913,6 +3917,10 @@ src_check_ok: if (unlikely((g->target.ssrc) && (g->target.ssrc != rtp.header->ssrc))) goto skip_error; + // if transcoding, only forward packets of passthrough payload types + if (g->target.transcoding && rtp_pt_idx < 0) + goto skip1; + pkt_idx = packet_index(&g->decrypt, &g->target.decrypt, rtp.header); errstr = "SRTP authentication tag mismatch"; if (srtp_auth_validate(&g->decrypt, &g->target.decrypt, &rtp, &pkt_idx)) @@ -3966,6 +3974,10 @@ no_intercept: srtp_encrypt(&g->encrypt, &g->target.encrypt, &rtp, pkt_idx); skb_put(skb, g->target.encrypt.mki_len + g->target.encrypt.auth_tag_len); srtp_authenticate(&g->encrypt, &g->target.encrypt, &rtp, pkt_idx); + + // SSRC substitution + if (g->target.transcoding && g->target.ssrc_out) + rtp.header->ssrc = g->target.ssrc_out; } err = send_proxy_packet(skb, &g->target.src_addr, &g->target.dst_addr, g->target.tos, par); diff --git a/kernel-module/xt_RTPENGINE.h b/kernel-module/xt_RTPENGINE.h index 812432b03..cd7978f98 100644 --- a/kernel-module/xt_RTPENGINE.h +++ b/kernel-module/xt_RTPENGINE.h @@ -92,6 +92,7 @@ struct rtpengine_target_info { struct rtpengine_srtp decrypt; struct rtpengine_srtp encrypt; u_int32_t ssrc; // Expose the SSRC to userspace when we resync. + u_int32_t ssrc_out; // Rewrite SSRC unsigned char payload_types[NUM_PAYLOAD_TYPES]; /* must be sorted */ unsigned int num_payload_types; @@ -102,7 +103,8 @@ struct rtpengine_target_info { stun:1, rtp:1, rtp_only:1, - do_intercept:1; + do_intercept:1, + transcoding:1; // SSRC subst and RTP PT filtering }; struct rtpengine_call_info {