Tomdee

18May/130

Testing a jitter buffer by presenting packet captures through a DatagramSocket interface

I've been working on the jitter buffer code in the FMJ project which is used by the Jitsi softclient. To know that the code is good, it's been handy to be able to try it out under real world conditions. To make this repeatable I wanted to be able to play packet captures through the jitter buffer and hear the results so I could then tweak the code and hear whether it improved things.

The easiest way to achieve this was to use the excellent libjitsi library from the Jitsi team. This just allows me to call LibJitsi.start() then I can use the MediaService to create a MediaDevice to play the audio and use a MediaStream connected to this device for dealing with the RTP. See here for the code.

The MediaStream is then connected to a new class I wrote which implements the StreamConnector interface. This class PCapStreamConnector, is a small class which has most of the interesting logic in another new class I wrote - PCapDatagramSocket. This presents a packet capture file through a DatagramSocket interface! It's fairly crude, and assumes the media file is written in the exact format that Jitsi uses for writing packet capture files, but that's all I need so no point doing any more.

It's a bit rough and ready at the moment. The fact that it doesn't actually use the RTP timings makes this borderline useless (!), but I will be adding that feature soon. At the same time, I'll be cleaning up the interface to allow the payload type to be passed in, or even better just try to detect it from the capture file. With a little more work, this could be a handy generic tool for playing media from RTP streams in any format that libjitsi supports - at least g711, SILK, Opus, g722, g723, iLBC and speex.

To really make this feature useful, I also enhanced the error reporting module so that users would have the chance to report a few minutes of media if they've experienced bad voice quality on a call.

 

5Aug/120

Free Wifi on Chiltern Railways and Dropbox

The free Wifi on Chiltern Railways annoyingly uses opendns.com for its DNS. This breaks dropbox with a rather confusing error

Unable to make a secure connection to the Dropbox servers because your computer's date and time settings are incorrect. Please correct your computer's date and time to allow a connection to Dropbox

The fix is to change the DNS servers after connecting to something else. I've just the google DNS servers at 8.8.8.8

The DNS servers can only be changed after connecting since DNS redirection is used for presenting the WIFI sign in page.

Filed under: Uncategorized No Comments
19Feb/120

JNI and Gluegen

I know I can develop software faster using Java so I want to learn how to interface with native code using JNI. No solution seems particularly elegant and going for a completely manual approach seems to involve a lot of boiler plate and work.

I had a quick look around google and Wikipedia and a couple of options to help with code generation - SWIG and Gluegen. The latter particularly caught my eye, in particular the ability to have structs treated as Java classes.

It took me a little while to get a hello world app running, so instructions are below to remind me in future and for anyone else that might find it useful.

Obtaining and building Gluegen

  • git clone git://github.com/mbien/gluegen.git gluegen
  • cd gluegen/make
  • ant clean all

This gives the required jars in the build directory

  • gluegen.jar for generating the Java version of C code and the bridging C code.
  • antlr.jar for parsing C code.
  • gluegen-rt.jar required at runtime.

Creating a sample application

The C code

int one_plus(int a) {
 return 1 + a;
}

Taken from the Gluegen website

The Java code

import testfunction.*;
 class Test
 {
 static {
 System.loadLibrary("nativelib");
 }
public static void main(String args[])
 {
 System.out.println(TestFunction.one_plus(5));
 }
}

I'm jumping ahead a little here. This code assumes that the C code is in a package call testfunction and that there is a native lib called nativelib.

Using Gluegen

Running Gluegen creates binding C code and the Java code that defines the C methods.

Gluegen needs some configuration to guide its behaviour. It's here that the Java package and class names are defined.

Package testfunction
 Style AllStatic
 JavaClass TestFunction
 JavaOutputDir gensrc/java
 NativeOutputDir gensrc/native

To run Gluegen, I went for the ant approach. My build file is below

<?xml version="1.0"?>
 <project name="sampleProject" basedir=".">
 <path id="gluegen.classpath">
 <pathelement location="gluegen.jar" />
 <pathelement location="antlr.jar" />
 </path>
<taskdef name="gluegen"
 classname="com.jogamp.gluegen.ant.GlueGenTask"
 classpathref="gluegen.classpath" />
 <target name="build">
 <gluegen src="function.h"
 config="function.cfg"
 emitter="com.jogamp.gluegen.JavaEmitter">
 <classpath refid="gluegen.classpath" />
 </gluegen>
 </target>
 </project>

running ant build results in a new directory "gensrc" containing a "native" and a "java" directory.

The generated native code is the Java to C glue code. The only thing worth noting about it is that it pulls in JNI.h C header file.

The generated java code has the "native" method and pulls in the runtime lib.

package testfunction;
import com.jogamp.gluegen.runtime.*;
 import com.jogamp.common.os.*;
 import com.jogamp.common.nio.*;
 import java.nio.*;
public class TestFunction {
 /** Interface to C language function: <br> <code> int one_plus(int a); </code> */
 public static native int one_plus(int a);
 } // end of class TestFunction

 Building the results

For me, this was the most challenging part. Most of the above is covered quite well on the Gluegen website. The following isn't.

Building the C code

 gcc -Wl,-soname,libnative.so -o libnativelib.so -fPIC --shared gensrc/native/TestFunction_JNI.c function.c -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux /usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/amd64/server/libjvm.so -lc

Quite a lot here.

  • gcc is used to build the code
  • -Wl passes options to the linker. In this case, the shared object name is set to libnative
  • -o specifies the output filename
  • -fPIC was required to avoid an error message along the lines of
    • /usr/bin/ld: /tmp/ccI3vLJd.o: relocation R_X86_64_PC32 against symbol `one_plus' can not be used when making a shared object; recompile with -fPIC
  • --shared causes a shared object to be built
  • TestFunction_JNI.c is the Gluegen generated code and function.c is the actual implemenation. These are the two files that are actually being built.
  • the two -I options specify the locations of the JNI headers (jni.h)
  • libjvm.so is also to be passed in.
This results in a file libnativelib.so in the current directory.

Building the Java Code

javac Test.java gensrc/java/testfunction/TestFunction.java -cp ../gluegen/build/gluegen-rt.jar

More straightforward. The Gluegen code and the code I wrote to drive it is compiled. The gluegen runtime jar needs to be on the classpath.

Running the Result

java -Djava.library.path=. -cp gensrc/java:. Test
6

Running the Java requires the native lib path to be specified. The program then specifies 6 as expected. Phew!



Filed under: Uncategorized No Comments
18Feb/120

(Re)Learning C

I've spent the day skimming over http://c.learncodethehardway.org/ I've currently only half written but covers all the basics including things like using valgrind, writing complete programs and obviously all the basic language constructs. It was a useful refresher and I would recommend it. I certainly think it has a lot more depth than I've had time to get out of it but it has still server as a great refresher/overview.

I've started looking at the librailfare code with my newly refreshed C knowledge. My previous aspirations for improving my Vim skills have gone out the window. I've been happily using Vim for the learncodethehard way examples but once I started wanting to poke round a multi-file project, I reached for trusty Eclipse. The CDT looks a lot more polished than when I last looked at it a few years ago and coupled with Msys and MiniGW I'm happily navigating my way around the code using familiar key bindings!

I've got librailfare compiled and running on linux (Ubuntu). I had to install the C Minimal Perfect Hashing libs. But I can't get it compiling on Windows yet - I need to work out how to compile the CMPH libs on windows first.

Filed under: Uncategorized No Comments
17Feb/120

Fares Data

I'm going to start looking at librailfare (http://librailfare.sourceforge.net/) for fare data. Looks like it could be a high performance way of getting detailed fares data.

My C is a little rusty so I'm working my way through "Learn C the hard way". (http://c.learncodethehardway.org/) It's still in Alpha but the overall structure seems to be there. Nothing too groundbreaking yet but I'm liking the style. I'm running Windows on my laptop so I've got Ubuntu Server in a VM for my compilation needs . Should be a good excuse to take my Vim skills to the next level too!

Once I've got the code compiling and I can query fares data I need to decide what to do with it. Current thoughts are porting it to Java (useful for me), porting it to .Net (useful for someone else) and/or exposing a web API to it.

Filed under: Uncategorized No Comments
3Apr/111

Monitoring a gas meter using an Arduino and a simple photo transistor

If I could turn my heating on and off remotely, I wanted a way of knowing whether it had worked! This lead me to come up with a way of reading my gas meter. This also has the nice side effect that I can monitor my usage long term and see if the extra control I have over my boiler gives me any reduction in my gas usage.

As far as I know, there aren't any off the shelf solutions for monitoring gas usage. Some meters come with a pulse counter though often these are sealed off and not intended for actual use. Some meters come with a silvered digit on the mechanical read out which makes spotting that digit easier. Unfortunatly, my gas meter has neither of these features.

The hardware

I chose to use the SY-CR102 from Maplin as it was both cheap and easy to get hold of. It provides both an infrared LED and phototransistor on a single package. I had to email them to get the data sheet, but it's not particularly informative - SY-CR102 datasheet.

I soldered it onto a little vero board following the circuit used here. I hooked it up to my arduino and used a bungee cord to fix the whole thing to my gas meter.

SY-CR102 attached to gas meter using bungee cord

SY-CR102 attached to gas meter using bungee cord

This arrangement allows me to see each revolution of the little red dial, which gives a resolution down to about 1/2 a penny of gas.

The software

Ideally, the SY-CR102 would give me a strong enough reading that I could use it to drive on of the interupt pins on the arduino. It gets nowhere near this unforunately. The signal drifts up and down with temperature and and the reading, which has a range of 0-1023, only changes by about 15 when the needle goes under the sensor. Thankfully, the needle never moves that fast so a software based polling approach is feasible.

The shape of the signal is a little odd, dipping as the needle approaching the sensor, then rising to a sharp peak before dipping again as the needle moves past the sensor. I found that the best approach to recording the passing of the needle was to tracking the highest value seen, and count a "tick" when the value fell by a certain threshold amount. This allows me to ignore the slow drift caused by temperature changes and to ignore the first dip as the needle nears the sensor whilst still counting the larger drop from the central peak.

To avoid having to fix a threshold amount, I record an array of threshold and can then choose which one to use on the fly. This allows me to monitor the values and choose a stable region. Moving the sensor, means I have to reperform this manual calibration.

 

void checkGasSensors()
{
  int reading = analogRead(analogInPinGas); 

  for (int ii = 5; ii < MAXDROP ; ii++)
  {
    if (reading > newHigh[ii])
    {
      newHigh[ii] = reading;
    }

    if ((newHigh[ii] - reading) > ii)
    {
      // A big fall has been witnessed
      gasTicks[ii]++;
      newHigh[ii] = reading;
    }
  }
}

 

Filed under: Uncategorized 1 Comment
16Feb/111

Controlling a central heating boiler using an arduino

To control my central heating, I needed some way of turning my boiler onand off.

First Attempt

Initially I thought I would have a direct connection to the boiler. So I managed to find the manuals on the Worcester Bosch web site and proceeded to dismantle my boiler to find out where I would need to make the conections. My boiler requires mains voltage signals to request heat so I built a relay to allow me to use 5V signals from my arduino to control the boiler.

I wasn't feeling masively positive about this approach since it would require me to have an arduino next to my boiler. Since I only had one arduino, this would mean I'd have to buy another for monitoring my gas usage - not ideal.

Second Attempt

Which brings me to my second attempt at designing this. I have a standard British Gas wireless thermostat.

British Gas Wireless Thermostat

The display on the front usually shows the current temperature, but when the dial on the front is rotated, it shows the desired temperature.

Inside, there's a small thermistor and a couple of switches. The dial on the front is had ridges on the back that trigger the switches as it turns. The two switches are out of phase with each other compared to the ridges, so turning the dial causes one switch to trigger before the other. The order of the triggering determines the direction of the dial.

With some help from GarethDEdwards I soldered some tidy wires to the back of the circuit board. I hen connected those to 3.5 mm audio jack on the bottom so I could easily plug it into my arduino.

Sample (simple?) code for control by arduino is below


////////////////////////////////////////////////
// Thermostat control section
////////////////////////////////////////////////
int delayTime = 10;

void setTemp(int desiredTemp)
{
  if (desiredTemp == currentTemp)
  {
    // Do Nothing
    //    Serial.println("Doing nothing"); 
  }
  else if (desiredTemp <=5)
  {
    // Requested a minimum temp, make sure we're really on the min temp...
    int numberOfDowns = 30;
    while (numberOfDowns > 0)
    {
      down();
      numberOfDowns--;
    } 
    currentTemp = 5;
  }
  else if (desiredTemp >=30)
  {
    // Requested a maximum temp, make sure we're really on the max temp...
    int numberOfUps = 30;
    while (numberOfUps > 0)
    {
      up();
      numberOfUps--;
    }
    currentTemp = 30;
  } 
  else
  {
    while (desiredTemp != currentTemp)
    {
      if (desiredTemp > currentTemp)
      {
        up();
        currentTemp++;
      }
      else
      {
        down();
        currentTemp--; 
      }
    } 
  }


}  
void down()
{
  //Serial.println("DOWN");
  leftDown();
  rightDown();
  leftUp();
  rightUp();
}

void up()
{
  //  Serial.println("UP");
  rightDown();
  leftDown();
  rightUp();
  leftUp();
}

void leftUp()
{
  //Serial.println("LU");
  pinMode(leftPin, INPUT);
  delay(delayTime);
}

void leftDown()
{
  //Serial.println("LD");
  pinMode(leftPin, OUTPUT);
  digitalWrite(leftPin, LOW);
  delay(delayTime);
}

void rightUp()
{
  //Serial.println("RU");
  pinMode(rightPin, INPUT); 
  delay(delayTime);
}

void rightDown()
{
  //Serial.println("RD");
  pinMode(rightPin, OUTPUT);
  digitalWrite(rightPin, LOW);
  delay(delayTime);
}

Filed under: Uncategorized 1 Comment
14Feb/110

Monitoring and controlling central heating

Just before Christmas I decided that I should dust off my neglected Arduino and do something with it. Ever keen to jump on the green bandwagon I decided that monitoring and controlling my central heating would be a good idea.

This is going to be the first in a series of posts decribing my adventures.

The plan was to give me control of my boiler so I could turn it on or off over the internet. This was to allow me to ensure the boiler wasn't on when I was out, or to turn it on before I got home.

There are a few parts to this project

  • Controlling the boiler
  • Monitoring how much gas I'm using
  • Monitoring the temperature

Here's what I had to work with:

Next post is going to be how I'm controlling the boiler.

13Feb/115

Creating a timelapse from a Foscam IP Camera

After purchasing a cheap Foscam FI8918W off eBay I couldn't resist creating a few simple timelapse videos. I created a simple perl script to help with the process. It allows me to specify

  • how many seconds I want the timelapse to last for
  • how long to wait between each shot

After its finished it uses ffmpeg to combine the jpegs into a timelapse movie.

Overall, I'm pretty happy with the results. The camera performs exceptionally well in low light conditions but seems unable to reliable pictures of outside during daylight - image are always washed out.

Anyhow, without further ado, the code is below:

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;

my $spacing       = 5;
my $captureLength = 30;
my $verbose       = 0;

my $result = GetOptions(
  "length=i"  => \$captureLength,    # numeric
  "spacing=i" => \$spacing,          # string
  "verbose"   => \$verbose
);

print "Capture every $spacing for a total of $captureLength\n\n";

my $startTime = time;
`mkdir -p $startTime`;
my $endTime = time + $captureLength;

$verbose && print "Started at $startTime and will finish at $endTime\n";

my $index = 0;

while (time < $endTime)
{
  $verbose && print "Time is " . time . "\n";
  my $output = sprintf("%s/image-%s-%05d.jpg", $startTime, $startTime, $index);
  `curl http://192.168.1.115/snapshot.cgi -u root:password -s -o $output`;
  $verbose && print "Saved $output\n";
  $index++;
  sleep($spacing);
}

# Now encode a video, naming it after the starttime.

`ffmpeg -r 30 -i $startTime/image-$startTime-%05d.jpg -b 4000k $startTime.mpeg`;