Skip to content

Commit

Permalink
libstreaming now use System.nanoTime() for a better temporal resoluti…
Browse files Browse the repository at this point in the history
…on. Streaming with wowza works much better, but there still is a weird lip sync issue...
  • Loading branch information
fyhertz committed May 14, 2013
1 parent 52d0214 commit 3cd905a
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 41 deletions.
4 changes: 2 additions & 2 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.majorkernelpanic.spydroid"
android:versionCode="802"
android:versionName="8.0.2" >
android:versionCode="810"
android:versionName="8.1" >

<uses-sdk
android:minSdkVersion="9"
Expand Down
4 changes: 2 additions & 2 deletions assets/www/js/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
var port = window.location.port;
var videoPlugin;
var videoStream;
var audioPlugin;
var audioPlugin;
var audioStream;
var error;

Expand Down Expand Up @@ -431,4 +431,4 @@
});


}());
}());
2 changes: 1 addition & 1 deletion src/net/majorkernelpanic/spydroid/ui/PreviewFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
SessionBuilder.getInstance().setSurfaceHolder(mSurfaceHolder);

}

return rootView;
}

Expand Down
15 changes: 13 additions & 2 deletions src/net/majorkernelpanic/streaming/rtcp/SenderReport.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class SenderReport {
private byte[] buffer = new byte[MTU];
private int ssrc, port = -1;
private int octetCount = 0, packetCount = 0;
private long ntp = 0;

public SenderReport() throws IOException {

Expand Down Expand Up @@ -96,8 +97,18 @@ public void setRtpTimestamp(long ts) {

/** Sets the NTP timestamp of the sender report. */
public void setNtpTimestamp(long ts) {
long hb = ts/1000;
long lb = ( ( ts - hb*1000 ) * 4294967296L )/1000;
ntp = ts;
long hb = ntp/1000000000;
long lb = ( ( ntp - hb*1000000000 ) * 4294967296L )/1000000000;
setLong(hb, 8, 12);
setLong(lb, 12, 16);
}

/** Updates the NTP timestamp of the sender report. */
public void updateNtpTimestamp(long delta) {
ntp += delta;
long hb = ntp/1000000000;
long lb = ( ( ntp - hb*1000000000 ) * 4294967296L )/1000000000;
setLong(hb, 8, 12);
setLong(lb, 12, 16);
}
Expand Down
22 changes: 12 additions & 10 deletions src/net/majorkernelpanic/streaming/rtp/AACADTSPacketizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

import java.io.IOException;

import android.os.SystemClock;
import android.util.Log;

/**
Expand All @@ -44,6 +43,7 @@ public class AACADTSPacketizer extends AbstractPacketizer implements Runnable {

private Thread t;
private int samplingRate = 8000;
private Statistics stats = new Statistics();

public AACADTSPacketizer() throws IOException {
super();
Expand Down Expand Up @@ -79,8 +79,10 @@ public void run() {
// Adts header fields that we need to parse
boolean protection;
int frameLength, sum, length, nbau, nbpk;
long oldtime = SystemClock.elapsedRealtime(), now = oldtime, delta = 5000, measured, lastmeasured = 5000, expected;
long oldtime = System.nanoTime(), now = oldtime, delta = 5000, measured, lastmeasured = 5000, expected, interval = 0;

stats.init(1024*1000000000/samplingRate);

try {
while (!Thread.interrupted()) {

Expand Down Expand Up @@ -112,14 +114,14 @@ public void run() {
if (!protection) is.read(buffer,rtphl,2);

// We update the RTP timestamp
ts += 1024; // FIXME: 1024 seems to work better on certain players...
ts += 1024; //stats.average()*samplingRate/1000000000;
socket.updateTimestamp(ts);

// We send one RTCP Sender Report every 5 secs
if (delta>5000) {
delta = 0;
report.setNtpTimestamp(now);
report.setRtpTimestamp(ts);
report.setNtpTimestamp(SystemClock.elapsedRealtime());
report.send();
}

Expand Down Expand Up @@ -158,8 +160,10 @@ public void run() {
}

// We wait a little to avoid sending to many packets too quickly
now = SystemClock.elapsedRealtime();
measured = now-oldtime;
now = System.nanoTime();
interval = now-oldtime;
measured = interval/1000000;
stats.push(interval);
delta += measured;
oldtime = now;
expected = nbau*1024*1000 / (nbpk*samplingRate);
Expand All @@ -169,16 +173,14 @@ public void run() {
if (measured<2*expected/3) {
Thread.sleep( 2*expected/3-measured );
}

}
} catch (IOException e) {
// Ignore
} catch (ArrayIndexOutOfBoundsException e) {
Log.e(TAG,"ArrayIndexOutOfBoundsException: "+(e.getMessage()!=null?e.getMessage():"unknown error"));
e.printStackTrace();
} catch (InterruptedException e) {
// Ignore
}
} catch (InterruptedException ignore) {}

Log.d(TAG,"AAC packetizer stopped !");

Expand Down
10 changes: 5 additions & 5 deletions src/net/majorkernelpanic/streaming/rtp/AMRNBPacketizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

import java.io.IOException;

import android.os.SystemClock;
import android.util.Log;

/**
Expand Down Expand Up @@ -68,8 +67,8 @@ public void stop() {
public void run() {

int frameLength, frameType, delta = 10000;
long now = SystemClock.elapsedRealtime(), oldtime = now, measured;
long expected = 20, lastmeasured = 10000;
long now = System.nanoTime(), oldtime = now, measured;
long expected = 20, lastmeasured = 10000, intervalNs = 0;

try {

Expand Down Expand Up @@ -104,8 +103,9 @@ public void run() {
socket.markNextPacket();

// We wait a little to avoid sending to many packets too quickly
now = SystemClock.elapsedRealtime();
measured = now-oldtime;
now = System.nanoTime();
intervalNs = now-oldtime;
measured = intervalNs/1000000;
delta += measured;
oldtime = now;
//Log.d(TAG,"expected: "+ expected + " measured: "+measured);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ protected static class Statistics {
public final static int COUNT=50;
private float m = 0, q = 0;

public void init(long value) {
m = value;
q = COUNT;
}

public void push(long duration) {
m = (m*q+duration)/(q+1);
if (q<COUNT) q++;
Expand Down
16 changes: 8 additions & 8 deletions src/net/majorkernelpanic/streaming/rtp/H263Packetizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ public void run() {

try {
while (!Thread.interrupted()) {
time = SystemClock.elapsedRealtime();
time = System.nanoTime();
if (fill(rtphl+j+2,MAXPACKETSIZE-rtphl-j-2)<0) return;
duration += SystemClock.elapsedRealtime() - time;
duration += System.nanoTime() - time;
j = 0;
// Each h263 frame starts with: 0000 0000 0000 0000 1000 00??
// Here we search where the next frame begins in the bit stream
Expand All @@ -105,21 +105,21 @@ public void run() {
}
if (j>0) {
// We send one RTCP Sender Report every 5 secs
delta += duration;
if (delta>5000 && duration>10) {
delta += duration/1000000;
if (delta>5000 && duration/1000000>10) {
delta = 0;
report.setRtpTimestamp(ts*90);
report.setNtpTimestamp(SystemClock.elapsedRealtime());
report.setRtpTimestamp(ts);
report.setNtpTimestamp(System.nanoTime());
report.send();
}
// We have found the end of the frame
stats.push(duration);
ts+= stats.average(); duration = 0;
ts+= stats.average()*9/100000; duration = 0;
//Log.d(TAG,"End of frame ! duration: "+stats.average());
// The last fragment of a frame has to be marked
socket.markNextPacket();
send(j);
socket.updateTimestamp(ts*90);
socket.updateTimestamp(ts);
System.arraycopy(buffer,j+2,buffer,rtphl+2,MAXPACKETSIZE-j-2);
j = MAXPACKETSIZE-j-2;
firstFragment = true;
Expand Down
20 changes: 11 additions & 9 deletions src/net/majorkernelpanic/streaming/rtp/H264Packetizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@

import java.io.IOException;

import android.os.SystemClock;
import android.util.Log;

/**
Expand Down Expand Up @@ -67,7 +66,7 @@ public void stop() {

public void run() {

long duration = 0, oldtime = 0, delta = 10000;
long duration = 0, oldtime = 0, delta = 10000, sum1 = 0, sum2 = 0;

// This will skip the MPEG4 header if this step fails we can't stream anything :(
try {
Expand All @@ -88,22 +87,25 @@ public void run() {
while (!Thread.interrupted()) {

// We measure how long it takes to receive the NAL unit from the phone
oldtime = SystemClock.elapsedRealtime();
oldtime = System.nanoTime();
send();
duration = SystemClock.elapsedRealtime() - oldtime;
duration = System.nanoTime() - oldtime;
sum2 += duration;

// We send one RTCP Sender Report every 5 secs
delta += duration;
delta += duration/1000000;
if (delta>5000) {
delta = 0;
report.setNtpTimestamp(SystemClock.elapsedRealtime());
report.setRtpTimestamp(ts*90);
report.setRtpTimestamp(ts);
report.setNtpTimestamp(System.nanoTime());
report.send();
//Log.d(TAG, "sum1: "+sum1/1000000+" sum2: "+sum2/1000000);
}

// Calculates the average duration of a NAL unit
stats.push(duration);
delay = stats.average();
sum1 += delay;

}
} catch (IOException e) {
Expand All @@ -129,8 +131,8 @@ private void send() throws IOException, InterruptedException {
// NAL unit type
type = buffer[rtphl]&0x1F;

ts += delay;
socket.updateTimestamp(ts*90);
ts += delay*9/100000;
socket.updateTimestamp(ts);

//Log.d(TAG,"- Nal unit length: " + naluLength + " delay: "+delay+" type: "+type);

Expand Down
15 changes: 13 additions & 2 deletions src/net/majorkernelpanic/streaming/rtsp/RtspServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ public void setPort(int port) {
editor.commit();
}

/** Starts (or restart if needed) the RTSP server. */
/**
* Starts (or restart if needed, if for example the configuration
* of the server has been modified) the RTSP server.
*/
public void start() {
if (!mEnabled || mRestart) stop();
if (mEnabled && mListenerThread == null) {
Expand All @@ -158,11 +161,19 @@ public void start() {
mRestart = false;
}

/** Stops the RTSP server but not the service. */
/**
* Stops the RTSP server but not the Android Service.
* To stop the Android Service you need to call {@link android.content.Context#stopService(Intent)};
*/
public void stop() {
if (mListenerThread != null) {
try {
mListenerThread.kill();
for ( Session session : mSessions.keySet() ) {
if ( session != null ) {
if (session.isStreaming()) session.stop();
}
}
} catch (Exception e) {
} finally {
mListenerThread = null;
Expand Down

0 comments on commit 3cd905a

Please sign in to comment.