Skip to content

Commit e175f22

Browse files
committed
rtp/audio processing (pcm broken)
1 parent 3599d94 commit e175f22

File tree

7 files changed

+85
-9
lines changed

7 files changed

+85
-9
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ lcov.info
88
*.pid
99
*.gz
1010
*.pcap
11+
*.pcm
1112

1213
pids
1314
logs

lib/audioprocessor.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
var Speaker = require('speaker');
2+
3+
var audioProcessor = function(rtspServer) {
4+
var self = this;
5+
6+
var speaker = new Speaker({
7+
channels: 2, // 2 channels
8+
bitDepth: 16, // 16-bit samples
9+
sampleRate: 44100 // 44,100 Hz sample rate
10+
});
11+
12+
self.process = function(bytes) {
13+
speaker.write(bytes);
14+
};
15+
16+
};
17+
18+
module.exports = audioProcessor;

lib/rtp.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
var dgram = require('dgram');
2+
var tools = require('./rtsphelper');
3+
var crypto = require('crypto');
24

35
var rtpServer = function(rtspServer) {
46
var self = this;
@@ -13,16 +15,28 @@ var rtpServer = function(rtspServer) {
1315
};
1416

1517
baseServer.on('message', function(msg) {
16-
//console.log(msg.length + ' BYTES SENT TO SERVER PORT');
18+
var meta = msg.slice(0, 12);
19+
var sequenceNumber = meta.slice(2, 4).readUInt16BE(0);
20+
console.log(sequenceNumber + "; ");
21+
console.log(meta.slice(2, 4));
22+
23+
var encryptedAudio = msg.slice(12);
24+
25+
var decipher = crypto.createDecipheriv('aes-128-cbc', rtspServer.audioAesKey, rtspServer.audioAesIv);
26+
decipher.setAutoPadding(false);
27+
28+
var audio = decipher.update(encryptedAudio);
29+
30+
console.log(audio);
31+
32+
rtspServer.audioProcessor.process(audio);
1733
});
1834
controlServer.on('message', function(msg) {
1935
console.log(msg.length + ' BYTES SENT TO CONTROL PORT');
2036
});
2137
timingServer.on('message', function(msg) {
2238
console.log(msg.length + ' BYTES SENT TO TIMING PORT');
2339
});
24-
25-
return self;
2640
}
2741

2842
module.exports = rtpServer;

lib/rtsp.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var ip = require('ip');
44
var tools = require('./rtsphelper');
55
var getmac = require('getmac');
66
var RtpServer = require('./rtp');
7+
var AudioProcessor = require('./audioprocessor');
78

89
var errorList = {
910
400: "BAD REQUEST"
@@ -17,7 +18,8 @@ var server = function() {
1718
self.controlPort = 63379;
1819
self.timingPort = 50607;
1920

20-
self.rtp = RtpServer(self);
21+
self.rtp = new RtpServer(self);
22+
self.audioProcessor = new AudioProcessor(self);
2123

2224
// pull method processors
2325
var methodMapping = require('./rtspmethods')(self);

lib/rtsphelper.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,32 @@ var messageBuilder = function(socket) {
3333
};
3434
};
3535

36+
var parseSdp = function(msg) {
37+
var multi = [ 'a', 'p', 'b' ];
38+
39+
var lines = msg.split('\r\n');
40+
var output = {};
41+
for (var i = 0; i < lines.length; i++) {
42+
43+
var sp = lines[i].split(/=(.+)?/);
44+
if (sp.length == 3) { // for some reason there's an empty item?
45+
if (multi.indexOf(sp[0]) != -1) { // some attributes are multiline...
46+
if (!output[sp[0]])
47+
output[sp[0]] = new Array();
48+
49+
output[sp[0]].push(sp[1]);
50+
} else {
51+
output[sp[0]] = sp[1];
52+
}
53+
}
54+
}
55+
return output;
56+
};
57+
58+
var privkey = ursa.createPrivateKey(fs.readFileSync('private.key'));
59+
3660
var generateAppleResponse = function(challengeBuf, ipAddr, macAddr) {
37-
macAddr = new Buffer('5F513885F785', 'hex');
61+
macAddr = new Buffer('5F513885F785', 'hex'); // inject?
3862
var fullChallenge = Buffer.concat([ challengeBuf, ipAddr, macAddr ]);
3963

4064
// im sure there's an easier way to pad this buffer
@@ -44,11 +68,12 @@ var generateAppleResponse = function(challengeBuf, ipAddr, macAddr) {
4468
}
4569
fullChallenge = Buffer.concat([ fullChallenge, new Buffer(padding) ]);
4670

47-
var privkey = ursa.createPrivateKey(fs.readFileSync('private.key'));
4871
var response = privkey.privateEncrypt(fullChallenge, 'base64', 'base64');
4972

5073
return response;
5174
};
5275

76+
module.exports.parseSdp = parseSdp;
5377
module.exports.MessageBuilder = messageBuilder;
54-
module.exports.generateAppleResponse = generateAppleResponse;
78+
module.exports.generateAppleResponse = generateAppleResponse;
79+
module.exports.rsaOperations = privkey;

lib/rtspmethods.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
var tools = require('./rtsphelper');
33
var ip = require('ip');
4+
45
module.exports = function(rtspServer) {
56

67
var rtspServer = rtspServer;
@@ -25,6 +26,21 @@ module.exports = function(rtspServer) {
2526
};
2627

2728
var announce = function(response, headers, content) {
29+
var sdp = tools.parseSdp(content);
30+
for (var i = 0; i < sdp.a.length; i++) {
31+
var sp = sdp.a[i].split(':');
32+
if (sp.length == 2) {
33+
if (sp[0] == 'rsaaeskey') {
34+
rtspServer.audioAesKey = tools.rsaOperations.decrypt(new Buffer(sp[1], 'base64'));
35+
} else if (sp[0] == 'aesiv') {
36+
rtspServer.audioAesIv = new Buffer(sp[1], 'base64');
37+
} else if (sp[0] == 'rtpmap') {
38+
rtspServer.audioCodec = sp[1];
39+
}
40+
}
41+
}
42+
rtspServer.clientName = sdp.i;
43+
2844
response.setOK(headers['CSeq']);
2945
response.send();
3046
};

lib/start.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var txtSetup = {
77
txtvers: '1', // txt record version?
88
tx: '1', // ?
99
ch: '2', // # channels
10-
cn: '0,2', // codec; 0=pcm, 1=alac, 2=aac, 3=aac elc; fwiw Sonos supports aac; pcm required for iPad+Spotify; OS X works with pcm
10+
cn: '0', // codec; 0=pcm, 1=alac, 2=aac, 3=aac elc; fwiw Sonos supports aac; pcm required for iPad+Spotify; OS X works with pcm
1111
et: '0,1', // encryption; 0=none, 1=rsa, 3=fairplay, 4=mfisap, 5=fairplay2.5; need rsa for os x
1212
md: '0', // metadata; 0=text, 1=artwork, 2=progress
1313
pw: 'false', // password enabled
@@ -17,7 +17,7 @@ var txtSetup = {
1717
vs: '130.14', // server version?
1818
am: 'AirSonos', // device model
1919

20-
ek: '1', // ? from ApEx; setting to 1 enables iTunes
20+
ek: '1', // ? from ApEx; setting to 1 enables iTunes; seems to use ALAC regardless of 'cn' setting
2121
//sv: 'false', // ? from ApEx
2222
//da: 'true', // ? from ApEx
2323
//vn: '65537', // ? from ApEx; maybe rsa key modulus? happens to be the same value

0 commit comments

Comments
 (0)