Hi Smurph,
In a word: WireShark.
I used a passive network tap (similar to this) and wireshark to sniff the packets going to (and coming from) the C4 amp. I did this while I had the entire C4 system set up the way it should be, i.e., the controller (media center? the main “thing” that does all the C4 stuff), amp, remotes and all the other devices were set up, I was just sniffing what was sent to the amp. Also, I was using a fairly old system, so I don’t know if the new ones are at all similar.
As far as I could tell, and my skills were very rudimentary at that point, the controller sends UDP packets to the amp for things like mute/un-mute channels, change volume or inputs, etc, and the amp sends a UDP packet back as acknowledgement. The Ack packet sent back was sent to the address of the device that sent the packet to begin with, so when I started sending the packets from my computer, the amp sent the Ack packets back to me instead of the controller.
The packages themselves are fairly straight-forward, the only odd part I can remember is there was a string of 4 (i think) digits at the front of the packet that had no apparent rhyme or reason other than they just increment with each command (regardless of the device it went to). I believe that is just sort of a packet “ID number” because it was included in the Ack packet sent back. If I just used the same number (i.e., 0001) on all the packets, the amp would only respond to the first one, then ignore the rest. So, I simply had a counter that counted up each time it sent a command and put that number in the packet (note, it has to be 4 (i think) digits long, so I had to pad with leading zeros. Actually, all the numbers used had to be a set length long, that’s why the “format” function is used in the python code below, it will pad with leading zeros when neccesary).
IIRC, there was a lot of other traffic as well, but because I used the home LAN/WIFI network, I suspect not all of it was directed at the amp. However, I would expect there to be a host of other data going to the amp for things like set-up, general health, etc. However, I would guess that would be standard TCP packets instead of the UDP ones because they would want the reliability there, not speed.
If you were starting from scratch, and wanted to just use the amp without the rest of the C4 system, it might be better to use a dedicated network (i.e., only the devices you’re interested in) with the router set up to mirror packets to your analyzer (or something like that, I really have very little knowledge in this area :mrgreen: ).
Since then, I have left the C4 behind in favor of something a little bit more user friendly: these amplifiers or others in the same series. They are really cheap, and I can take care of the volume control on my sending end, so they work really well for me. And, if you’re really handy, you might be able to re-purpose the C4 amp’s case and power supply and connectors, and… .
Anyway, I hope this helps, and good luck!
Ps, here is the python code I had to generate the UDP commands, my copy of the command list has been lost to the ravages of time and computer upgrades . It should give you an idea of what to look for on your particular set-up.
This is a snippet from a python program, so the different “defs” are different functions. Also, there are two “channels” for each set of speakers (right and left), so technically the amp was a 16-channel amp (8 stereo channels).
import socket
import binascii
import time
count = 0
UDP_IP = "192.168.1.141"
UDP_PORT = 8750
def sendChannelSelect(output, input):
global count #'global' here makes sure it uses the same variable for all the functions, instead of one for each
cmdString = '0s' + format(count, '04x') + ' c4.amp.out '\
+ getChannelFromNumber(output, 0) + ' '\
+ getChannelFromNumber(input, 0) + '\r\n'
sock.sendto(bytes(cmdString,'utf-8'), (UDP_IP, UDP_PORT))
count = count + 1
cmdString = '0s' + format(count, '04x') + ' c4.amp.out '\
+ getChannelFromNumber(output, 1) + ' '\
+ getChannelFromNumber(input, 1) + '\r\n'
sock.sendto(bytes(cmdString,'utf-8'), (UDP_IP, UDP_PORT))
count = count + 1
def sendChannelVol(output, volume):
global count
cmdString = '0s' + format(count, '04x') + ' c4.amp.chvol '\
+ getChannelFromNumber(output, 0) + ' '\
+ format(int(volume)+155, '02x') + '\r\n'
sock.sendto(bytes(cmdString,'utf-8'), (UDP_IP, UDP_PORT))
count = count + 1
cmdString = '0s' + format(count, '04x') + ' c4.amp.chvol '\
+ getChannelFromNumber(output, 1) + ' '\
+ format(int(volume)+155, '02x') + '\r\n'
sock.sendto(bytes(cmdString,'utf-8'), (UDP_IP, UDP_PORT))
count = count + 1
def sendOutputMute(output, mute):
global count
cmdString = '0s' + format(count, '04x') + ' c4.amp.mute '\
+ getChannelFromNumber(output, 0) + ' '\
+ format(mute, '02x') + '\r\n'
sock.sendto(bytes(cmdString,'utf-8'), (UDP_IP, UDP_PORT))
count = count + 1
cmdString = '0s' + format(count, '04x') + ' c4.amp.mute '\
+ getChannelFromNumber(output, 1) + ' '\
+ format(mute, '02x') + '\r\n'
sock.sendto(bytes(cmdString,'utf-8'), (UDP_IP, UDP_PORT))
count = count + 1
def getChannelFromNumber(number, channel):
if number>0:
return format(((number-1)*2 + channel + 1), '02x')
else:
return '00'