shithub: opus-tools

Download patch

ref: f7455e66cab87a238b6c3ebe79c40c22f0ff384a
parent: 380b5aeb5322914724994d3e059438ff5bf5c41f
author: Ralph Giles <giles@mozilla.com>
date: Wed Oct 3 17:54:43 EDT 2012

Calculate timestamps from packet durations.

Previously, everything was hard-coded to 20 ms. Now we increment
rtp timestamps and ogg granulepos based on the packet duration
as described by the ToC header.

This adds a dependency on libopus, but the opus_packet() calls
as small and can stand alone, so they could be extracted and
supplied separately if necessary.

Granulepos values are still ignored when reading from a .opus
file. It would probably be better to either warn, or use those
as much as possible to set the rtp timestamps to better represent
the recorded data.

--- a/Makefile.am
+++ b/Makefile.am
@@ -56,6 +56,6 @@
 opusinfo_MANS = man/opusinfo.1
 
 opusrtp_SOURCES = src/opusrtp.c
-opusrtp_LDADD = @LIBPCAP@ $(OGG_LIBS)
+opusrtp_LDADD = @LIBPCAP@ $(OGG_LIBS) $(Opus_LIBS)
 
 #TESTS = FIXME
--- a/Makefile.unix
+++ b/Makefile.unix
@@ -21,7 +21,7 @@
 	$(CC) $(LDFLAGS) src/opus_header.o src/opusinfo.o src/info_opus.o -o opusinfo -logg
 
 opusrtp: src/opusrtp.o
-	$(CC) $(LDFLAGS) src/opusrtp.o -o opusrtp -logg
+	$(CC) $(LDFLAGS) src/opusrtp.o -o opusrtp ../opus/.libs/libopus.a -logg
 
 clean:
 	rm -f src/*.o $(PROGS) opusrtp
--- a/src/opusrtp.c
+++ b/src/opusrtp.c
@@ -58,6 +58,7 @@
 #ifdef HAVE_PCAP
 #include <pcap.h>
 #endif
+#include <opus.h>
 #include <ogg/ogg.h>
 
 #define OPUS_PAYLOAD_TYPE 113
@@ -67,6 +68,7 @@
   ogg_stream_state *stream;
   FILE *out;
   int seq;
+  ogg_int64_t granulepos;
   int linktype;
 } state;
 
@@ -215,7 +217,17 @@
   return 0;
 }
 
+/* calculate the number of samples in an opus packet */
+int opus_samples(const unsigned char *packet, int size)
+{
+  /* number of samples per frame at 48 kHz */
+  int samples = opus_packet_get_samples_per_frame(packet, 48000);
+  /* number "frames" in this packet */
+  int frames = opus_packet_get_nb_frames(packet, size);
 
+  return samples*frames;
+}
+
 /* helper, write out available ogg pages */
 int ogg_write(state *params)
 {
@@ -588,6 +600,7 @@
     }
     /* read and process available packets */
     while (ogg_stream_packetout(&os,&op) == 1) {
+      int samples;
       /* skip header packets */
       if (state == 1 && op.bytes >= 19 && !memcmp(op.packet, "OpusHead", 8)) {
         state++;
@@ -597,13 +610,14 @@
         state++;
         continue;
       }
+      /* get packet duration */
+      samples = opus_samples(op.packet, op.bytes);
       /* update the rtp header and send */
-      rtp.time += 960;
-      // TODO: rtp.time += count_samples(op.packet, op.bytes);
       rtp.seq++;
+      rtp.time += samples;
       rtp.payload_size = op.bytes;
       send_rtp_packet(fd, (struct sockaddr *)&sin, &rtp, op.packet);
-      usleep(20000);
+      usleep(samples*1000/48);
     }
   }
   }
@@ -733,7 +747,9 @@
 
   /* write the payload to our opus file */
   ogg_packet *op = op_from_pkt(packet, size);
-  op->granulepos = 960*rtp.seq; // FIXME: get this from the toc byte
+  op->packetno = rtp.seq;
+  params->granulepos += opus_samples(packet, size);
+  op->granulepos = params->granulepos;
   ogg_stream_packetin(params->stream, op);
   free(op);
   ogg_write(params);
@@ -783,6 +799,7 @@
     return -2;
   }
   params->seq = 0;
+  params->granulepos = 0;
 
   /* write stream headers */
   op = op_opushead();