Hi, I am still working on the AudioExtender, for now I copied my Entry from the HackSpace Siegen wiki. Once I find time, I will translate it.

Update

I finally got the playback working. You can find my software here: LAES@github

Current Status

  • discovering devices is working
  • playback with multiple extenders

Hardware

  • Audio Extender made by devolo
  • RCA and mini-TSA connectors
  • data over powerline (Homeplug AV, 85Mbit/s)
  • on ebay for around 10€
  • 3 Leds, Power, Lan, Connected to Server

Windows-Software

  • works only up to vista
  • works only for 32bits
  • no linux version
  • uses a virtual soundcard to pipe all audio to the extender
  • Audioformat: PCM, Stereo, 44100, 16bits signed
  • shoutcast server on 12000
  • apparently command channel on port 12001, nothing know yet
  • communicates with the extender by http and cgi
  • streamer.cgi?cmd=srvstart to start playback etc

Network traffic

Some stuff I captured with wireshark to base my program on. Be careful, the ips may vary! I try to alter the ips to fit:

  • PC(Server) 192.168.0.101
  • Extender(Client) 192.168.0.187
Server2Client
GET /streamer.cgi?cmd=srvstart
HTTP/1.0
X-Arkados-Url: http://192.168.0.101:12200
X-Arkados-Cmd: http://192.168.0.101:12201
HTTP/1.0 200 OK
Stream command received.
Client öffnet Stream
GET / HTTP/1.0
User-Agent: testShout
Accept: */*
Icy-Metadata: 1
ICY 200 OK
content-type: audio/pcm
Icy-MetaInt: 8192
Sysinfo vom Client
GET /sysinfo.html
HTTP/1.0
Host: 192.168.0.187
HTTP/1.1 200 OK
Server: NetPort Software 1.1
Date: Sat, 21 Dec 1996 12:00:00 GMT
Content-type: text/html
Transferred data
<!--?xml version="1.0"?-->
<status>
<devicetype>dLAN Audio extender</devicetype>
<version>1</version>
<ip-address>192.168.0.187</ip-address>
<netmask>255.255.255.0</netmask></status>
<status>
<audio>
<server-status>Playing</server-status>
<url-playing>http://192.168.0.1:12200</url-playing>
<drop-count>0</drop-count>
</audio>
<firmware>
<version>1</version>
<date>2007-09-04</date>
<internal-version>2007-09-04</internal-version>
</firmware>
<homeplug>
<mac-address>00:0b:3b:38:79:a4</mac-address>
</homeplug>
</status>
Client Broadcast
0000 ff ff ff ff ff ff 00 0b 3b 38 79 a5 08 00 45 00 ........;8y...E.
0010 00 93 15 50 00 00 40 11 a3 a7 c0 a8 00 bb ff ff ...P..@.........
0020 ff ff 4b af 4b af 00 7f bf 6b 68 65 6c 6c 6f 00 ..K.K....khello.
0030 64 4c 41 4e 20 41 75 64 69 6f 20 65 78 74 65 6e dLAN Audio exten
0040 64 65 72 00 30 30 3a 30 42 3a 33 42 3a 33 38 3a der.00:0B:3B:38:
0050 37 39 3a 41 35 00 31 39 32 2e 31 36 38 2e 30 2e 79:A5.192.168.0.
0060 31 38 37 00 32 35 35 2e 32 35 35 2e 32 35 35 2e 187.255.255.255.
0070 30 00 68 74 74 70 3a 2f 2f 31 39 32 2e 31 36 38 0.http://192.168
0080 2e 30 2e 31 38 37 2f 73 79 73 69 6e 66 6f 2e 68 .0.187/sysinfo.h
0090 74 6d 6c 00 41 52 4b 39 36 30 36 30 38 39 34 38 tml.ARK960608948
00a0 00 .
Server Broadcast
0000 ff ff ff ff ff ff 00 11 d8 8a 73 77 08 00 45 00 ..........sw..E.
0010 00 43 3e 60 00 00 80 11 79 95 c0 a8 00 65 c0 a8 .C>`....y....e..
0020 00 ff 4b af 4b af 00 2f 5b a6 77 68 6f 69 73 74 ..K.K../[.whoist
0030 68 65 72 65 00 31 39 32 2e 31 36 38 2e 30 2e 31 here.192.168.0.1
0040 30 31 00 32 35 35 2e 32 35 35 2e 32 35 35 2e 30 01.255.255.255.0
0050 00 .

Self-Made Software

Right now I have a python script in place which is able to discover the Audio Extenders by broadcasting a special message (the audio extender must be paired with your network beforehand, I most likely will not look into this)

This is all work in progress and not meant to be used by a end user but for testing purposes.

I am also working on the streaming part by right now I haven't figured out how to buffer the data correctly leading to a DDoS of the device which need a reboot to work again.

#!/usr/bin/python
import time
import socket
import urllib2
from xml.etree import ElementTree as ET
LOCAL_IP = ""
#find good method for windows and linux
LOCAL_IP=raw_input("Please enter local ip:")
ipparts = LOCAL_IP.split(".")
UDP_IP=".".join([ipparts[0], ipparts[1], ipparts[2], "255"])
UDP_PORT=19375
#this is fixed
MESSAGE = 'whoisthere\x00' + LOCAL_IP + '\x00255.255.255.0\x00'
#this is also fixed
print "Local IP:", LOCAL_IP
print "UDP target IP:", UDP_IP
print "UDP target port:", UDP_PORT
def getDevices():
print "Sending multicast and waiting 10s for replies"
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind(('0.0.0.0', 19375))
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
data = []
timeout = sock.gettimeout()
sock.settimeout(1)
b = time.clock()
while time.clock()-b<4:
try:
singledata=sock.recv(10240)
if not singledata in data and not "whoisthere" in singledata:
data.append(singledata)
except socket.timeout:
pass
sock.settimeout(timeout)
return list2AEs(data)
class AudioExtender:
def __init__(self, mac, ip, subnet, infourl, name, unknown):
self.mac = mac
self.ip = ip
self.subnet = subnet
self.name = name
self.infourl = infourl
self.unknown = unknown
def infos(self):
print "Name: ", self.name
print "MAC: ", self.mac
print "IP: ", self.ip
print "SUBNET: ", self.subnet
print "UNKNOWN: ", self.unknown
print "Getting infos from the infopage:"
statusside = urllib2.urlopen(self.infourl)
element = ET.XML(statusside.read())
statusside.close()
for sub in element:
print sub.tag, "\t", sub.text
for subsub in sub:
print "\t", subsub.tag, "\t", subsub.text
def connectto(self, ip):
PORT = 7060
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
sys.stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(1)
try:
sock.connect((self.ip, PORT))
except socket.error, msg:
sys.stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(2)
sock.send("GET /streamer.cgi?cmd=srvstart HTTP/1.0\r\nX-Arkados-Url:\
http://%s:12200\r\nX-Arkados-Cmd: http://%s:12201\r\n\r\n" % (ip, ip))
data = sock.recv(1024)
string = ""
while len(data):
string = string + data
data = sock.recv(1024)
sock.close()
print string
def list2AEs(data):
aoes = []
for line in data:
parts = line.split("\x00")
if not parts[0] == "hello":
print "Something strange here!!"
name = parts[1]
mac = parts[2]
ip = parts[3]
subnet = parts[4]
infourl = parts[5]
unknown = parts[6]
#no idea what this is for
aoes.append(AudioExtender(mac, ip, subnet, infourl, name, unknown))
return aoes
def test():
chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav" #Format ist PCM, Stereo, Rate 44100, 16bit
#import fcntl
#import struct
#def get_ip_address(ifname):
# s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# return socket.inet_ntoa(fcntl.ioctl( # s.fileno(),
# 0x8915,
# SIOCGIFADDR
# struct.pack('256s', ifname[:15])
# )[20:24])
#>>> get_ip_address('lo')
#'127.0.0.1'
#>>> get_ip_address('eth0')
#'38.113.228.130'
def main():
a = getDevices()
a[0].infos()
a[0].connectto("192.168.0.105")
if __name__=="__main__":
main()