dinsdag 19 juli 2016

Linux shell script to stream audio to a Zavio IP Camera

While I was showing an apprentice how to reverse engineer closed HTTP interfaces, we figured out how the proprietary Zavio webbrowser plugin streams audio data to the Zavio F3510 IP Cameras and other models from around 2016.

Then I wrote a rudimentary bash shell script that enables you to play MP3, WAV, FLAC, MIDI or any other file formats that avconv can handle through the camera's poor little speaker.

Interestingly, you can also use this script to continuously stream live audio from a HTTP URL to the camera and that way you can enjoy music anywhere you've installed your camera's.

Currently, this script is compatible with bash on Linux but I don't see why it wouldn't work on bash for Windows or Mac OS if you're into that kind of thing. Just make sure you have the necessary dependencies (avconv, curl,...) in your search PATH.

Enjoy!

#!/bin/bash
# Simple shell script to stream audio to a Zavio F3510 or other Zavio camera's from around the year 2014, 2015 and 2016
# No configuration is required, just supply the parameters on the command line
# Supported audio formats: mp3, mp2, wav, ogg and many more, thanks to avconv and all related projects
# Uses curl, the Swiss Army Knife of networking
# Copyleft by Tom Van Braeckel, 19-07-2016 🔥

# How it works:
# =============
# The Zavio needs to receive pcm_mulaw encoded audio samples
# at a sample rate of 8000 samples/second (8kHz) mono at 16 bits per sample through a HTTP web interface.
# The data is sent through periodic HTTP requests in chunks of 1000 bytes audio data + HTTP protocol overhead.

# Dependencies:
# -------------
# - avconv
# - curl
# - base64
# - sleep (a modern one that accepts non-integer arguments, as in: sleep 0.06)
# - echo (a modern one that supports the -e "\r" construct)


# Theoretical note:
# -----------------
# The HTTP API that we call has no active two-way synchronisation protocol so there will always be timer drift between the rate at which we send samples and the rate at which they are consumed. When there is drift, the Zavio seems to insert a few dummy samples or drop samples to correct the drift. This could theoretically be heard as clicks or cracks when playing long audio clips but it seems to work fine for me.

# Calculation of the rate at which we need to send chunks of audio to the HTTP API:
# ---------------------------------------------------------------------------------
# 1000 bytes/chunk / 2 bytes/sample = 500 samples/chunk
# 8k samples/second / 500 samples/chunk = 16 chunks/second = 1/16 second/chunk = 0.0625 second/chunk

sleep_time_per_audio_chunk=0.06 # target sleep time (0.0625 seconds) minus around 4% = 0.0025s overhead (forking new sleep process)

ip="$1"
auth="$2"
file="$3"
boost="$4"
if [ -z "$ip" -o -z "$auth" -o -z "$file" ]; then
echo "Usage: $0 ip_address username:password filename/url [volumeboost in dB]"
echo
echo "Example: $0 192.168.4.20 tom:supercool world_domination.wav"
echo "Example: $0 192.168.1.203 admin:admin audiofile.mp3 10"
echo "Example: $0 192.168.1.203 admin:admin http://streamingserver.com/stream -5"
exit 1
fi

# Default to 0 boost
if [ -z "$boost" ]; then
boost=0
fi
echo "boost = $boost"


# Encode the username:password pair in base64 encoding
auth64=$(echo -n "$auth" | base64)

# Arbitrary string of text
string="--As from earth's Bos om, sprung to sight"

echo -n "Sending audio sample..."
# Send the encoded audio to stdout with avconv and amplify it a bit, read it in chunks of 1000 bytes, add the HTTP prefix and let curl do the HTTP 1.0 request
# We do this while curl is doing requests of size > 1000 bytes, until the grep no longer exits successfully, which ends the loop
avconv -i "$file" -f wav -acodec pcm_mulaw -ar 8000 -ac 1 -af "volume=$boost"dB - | while (echo -en "$string\r\nContent-Type: audio/wav\r\n" ; head -c 1000 ) | curl -v --http1.0 -H "Content-Type: multipart/form-data; boundary=$string" -H "Authorization: Basic $auth64" --data-binary @- http://$ip/cgi-bin/operator/transmit 2>&1 | grep -q "Content-Length: 1[0-9][0-9][0-9]"; do
sleep "$sleep_time_per_audio_chunk"
echo -n .
done
echo "done."

woensdag 6 juli 2016

Nichrome and black powder electrical pyrotechnic igniter with GALCIT solid rocket propellant

We've made progress on the pyrotechnic igniter. It now uses nichrome wire because it has a high resistance, so it gets very hot when electricity is forced through it.

We wind the nichrome in a spiral so that it is longer, again for more electrical resistance, and place it on a paper rectangle of around 5x10cm.

Nichrome wire spiral

The nichrome wire has a diameter of 0.2mm and when stretched out is about 150mm long. With a resistance of 34 Ohm per meter, that is around 0.51 Ohm resistance in that piece of 150mm nichrome wire. 

Then we pour some black powder over the coil and roll it up into a cylinder, reinforced with some paper tape.

Black powder in paper with nichrome wire spiral inside

As a test we ignited a bit of leftover GALCIT in a heat resistant 2l lab beaker.

Heat resistant, yes, but as it turns out it was not GALCIT heat resistant. 

Our final setup looks like this, placed on a burn pile:

Pyrotechnic igniter installed in a lab beaker 

To get the nichrome to glow red hot, we used a powerful 18V battery from a Makita drill to supply the current through an old UTP cable. But a 4.5A 6V battery should also do the trick.

The ignition went smoothly and the burn was quite spectacular. The jet of fire that was spewed into the air indicated that we were already developing some thrust, which is remarkable with such a huge throat (in this case, beaker) area.

Here's the video: