diff --git a/src/opusrtp.c b/src/opusrtp.c index d405112..3ad7871 100644 --- a/src/opusrtp.c +++ b/src/opusrtp.c @@ -68,10 +68,13 @@ typedef struct { ogg_stream_state *stream; FILE *out; int seq; + int time; ogg_int64_t granulepos; int linktype; int dst_port; int payload_type; + int samplerate; + int dtx; } state; /* helper, write a little-endian 32 bit int to memory */ @@ -700,7 +703,7 @@ int send_rtp_packet(int fd, struct sockaddr *addr, socklen_t addrlen, } int rtp_send_file_to_addr(const char *filename, struct sockaddr *addr, - socklen_t addrlen, int payload_type) + socklen_t addrlen, int payload_type, int samplerate) { rtp_header rtp; int fd; @@ -808,7 +811,7 @@ int rtp_send_file_to_addr(const char *filename, struct sockaddr *addr, continue; } /* get packet duration */ - samples = opus_packet_get_nb_samples(op.packet, op.bytes, 48000); + samples = opus_packet_get_nb_samples(op.packet, op.bytes, samplerate); if (samples <= 0) { fprintf(stderr, "skipping invalid packet\n"); continue; @@ -834,7 +837,7 @@ int rtp_send_file_to_addr(const char *filename, struct sockaddr *addr, } int rtp_send_file(const char *filename, const char *dest, const char *port, - int payload_type) + int payload_type, int samplerate) { int ret; struct addrinfo *addrs; @@ -852,13 +855,13 @@ int rtp_send_file(const char *filename, const char *dest, const char *port, return -1; } ret = rtp_send_file_to_addr(filename, addrs->ai_addr, addrs->ai_addrlen, - payload_type); + payload_type, samplerate); freeaddrinfo(addrs); return ret; } #else /* !HAVE_SOCKETS */ int rtp_send_file(const char *filename, const char *dest, const char *port, - int payload_type) + int payload_type, int samplerate) { fprintf(stderr, "Cannot send %s to %s:%s'. Socket support not available.\n", filename, dest, port); @@ -883,6 +886,8 @@ void write_packet(u_char *args, const struct pcap_pkthdr *header, ogg_packet *op; int samples; int header_size; + int packets = 1; + long bytes; fprintf(stderr, "Got %d byte packet (%d bytes captured)\n", header->len, header->caplen); @@ -1040,10 +1045,26 @@ void write_packet(u_char *args, const struct pcap_pkthdr *header, /* write the payload to our opus file */ op = op_from_pkt(packet, size); op->packetno = rtp.seq; - samples = opus_packet_get_nb_samples(packet, size, 48000); - if (samples > 0) params->granulepos += samples; - op->granulepos = params->granulepos; - ogg_stream_packetin(params->stream, op); + samples = opus_packet_get_nb_samples(packet, size, params->samplerate); + + if (params->time && params->dtx) packets = (rtp.time - params->time) / samples; + params->time = rtp.time; + + for (int i = 1; i <= packets; i++) { + bytes = op->bytes; + + /* handle dtx by inserting silence packets before the real packet */ + if (params->dtx && i != packets) { + /* a silence packet is 1 byte containing only the 0x78 OPUS packet prefix */ + op->bytes = 1; + } + + if (samples > 0) params->granulepos += samples; + op->granulepos = params->granulepos; + ogg_stream_packetin(params->stream, op); + op->bytes = bytes; + } + free(op); ogg_write(params); @@ -1087,7 +1108,7 @@ void show_devices(void) /* use libpcap to capture packets and write them to a file */ int sniff(const char *input_file, const char *device, const char *output_file, - int dst_port, int payload_type, int samplerate, int channels) + int dst_port, int payload_type, int samplerate, int channels, int dtx) { state *params; pcap_t *pcap; @@ -1137,6 +1158,8 @@ int sniff(const char *input_file, const char *device, const char *output_file, params->granulepos = 0; params->dst_port = dst_port; params->payload_type = payload_type; + params->samplerate = samplerate; + params->dtx = dtx; if (output_file) { if (strcmp(output_file, "-") == 0) { @@ -1207,6 +1230,7 @@ void usage(void) printf(" -o, --output out.opus Write Ogg Opus output file\n"); printf(" -r, --rate n Set original sample rate (default 48000)\n"); printf(" -c, --channels n Set channel count (default 2)\n"); + printf(" -x, --dtx Enable DTX support\n"); printf("\n"); printf("Display help or version information:\n"); printf(" opusrtp -h|--help\n"); @@ -1226,6 +1250,7 @@ int main(int argc, char *argv[]) int payload_type = -1; int samplerate = 48000; int channels = 2; + int dtx = 0; struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, @@ -1238,11 +1263,12 @@ int main(int argc, char *argv[]) {"type", required_argument, NULL, 't'}, {"sniff", required_argument, NULL, 0}, {"extract", required_argument, NULL, 'e'}, + {"dtx", no_argument, NULL, 'x'}, {0, 0, 0, 0} }; /* process command line arguments */ - while ((option = getopt_long(argc, argv, "hVqo:d:p:r:c:t:e:", + while ((option = getopt_long(argc, argv, "hVqxo:d:p:r:c:t:e:", long_options, &i)) != -1) { switch (option) { case 0: @@ -1289,6 +1315,9 @@ int main(int argc, char *argv[]) if (optarg) payload_type = atoi(optarg); break; + case 'x': + dtx = 1; + break; case 'h': usage(); return 0; @@ -1309,7 +1338,7 @@ int main(int argc, char *argv[]) if (!port) port = "1234"; if (payload_type < 0) payload_type = 120; for (i = optind; i < argc; i++) { - rtp_send_file(argv[i], dest, port, payload_type); + rtp_send_file(argv[i], dest, port, payload_type, samplerate); } return 0; } @@ -1322,7 +1351,7 @@ int main(int argc, char *argv[]) return 1; } return sniff(input_pcap, device, output_file, port_num, payload_type, - samplerate, channels); + samplerate, channels, dtx); #else (void)input_pcap; (void)device;