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 32bitsOO
  • 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 Steam

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

Trasferred 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()

Published

Category

projects

Tags