Permalink
Browse files

Initial release: iTunes communication is ok, but unable to play sound…

… and decode alac. Working on it.
  • Loading branch information...
Benjamin de Callatay Benjamin de Callatay
Benjamin de Callatay authored and Benjamin de Callatay committed Apr 22, 2011
0 parents commit d0221e4ce325cfa173ff36c8bd83f45b62409093
Showing with 3,524 additions and 0 deletions.
  1. BIN .DS_Store
  2. +8 −0 .classpath
  3. +17 −0 .project
  4. +12 −0 .settings/org.eclipse.jdt.core.prefs
  5. BIN bin/AudioData.class
  6. BIN bin/AudioServer.class
  7. BIN bin/BonjourEmitter.class
  8. BIN bin/RTSPPacket.class
  9. BIN bin/RTSPResponder.class
  10. BIN bin/Rplay.class
  11. BIN bin/UDPDelegate.class
  12. BIN bin/UDPListener.class
  13. BIN bin/com/beatofthedrum/alacdecoder/AlacContext.class
  14. BIN bin/com/beatofthedrum/alacdecoder/AlacDecodeUtils.class
  15. BIN bin/com/beatofthedrum/alacdecoder/AlacFile.class
  16. BIN bin/com/beatofthedrum/alacdecoder/AlacInputStream.class
  17. BIN bin/com/beatofthedrum/alacdecoder/AlacUtils.class
  18. BIN bin/com/beatofthedrum/alacdecoder/ChunkInfo.class
  19. BIN bin/com/beatofthedrum/alacdecoder/DecodeResult.class
  20. BIN bin/com/beatofthedrum/alacdecoder/Defines.class
  21. BIN bin/com/beatofthedrum/alacdecoder/DemuxResT.class
  22. BIN bin/com/beatofthedrum/alacdecoder/DemuxUtils.class
  23. BIN bin/com/beatofthedrum/alacdecoder/LeadingZeros.class
  24. BIN bin/com/beatofthedrum/alacdecoder/MyStream.class
  25. BIN bin/com/beatofthedrum/alacdecoder/QTMovieT.class
  26. BIN bin/com/beatofthedrum/alacdecoder/SampleDuration.class
  27. BIN bin/com/beatofthedrum/alacdecoder/SampleInfo.class
  28. BIN bin/com/beatofthedrum/alacdecoder/StreamUtils.class
  29. BIN bin/com/beatofthedrum/alacdecoder/WavWriter.class
  30. +9 −0 src/AudioData.java
  31. +115 −0 src/AudioServer.java
  32. +69 −0 src/BonjourEmitter.java
  33. +86 −0 src/RTSPPacket.java
  34. +300 −0 src/RTSPResponder.java
  35. +37 −0 src/Rplay.java
  36. +7 −0 src/UDPDelegate.java
  37. +37 −0 src/UDPListener.java
  38. +24 −0 src/com/beatofthedrum/alacdecoder/AlacContext.java
  39. +1,020 −0 src/com/beatofthedrum/alacdecoder/AlacDecodeUtils.java
  40. +62 −0 src/com/beatofthedrum/alacdecoder/AlacFile.java
  41. +32 −0 src/com/beatofthedrum/alacdecoder/AlacInputStream.java
  42. +332 −0 src/com/beatofthedrum/alacdecoder/AlacUtils.java
  43. +11 −0 src/com/beatofthedrum/alacdecoder/ChunkInfo.java
  44. +10 −0 src/com/beatofthedrum/alacdecoder/DecodeResult.java
  45. +17 −0 src/com/beatofthedrum/alacdecoder/Defines.java
  46. +45 −0 src/com/beatofthedrum/alacdecoder/DemuxResT.java
  47. +890 −0 src/com/beatofthedrum/alacdecoder/DemuxUtils.java
  48. +18 −0 src/com/beatofthedrum/alacdecoder/LeadingZeros.java
  49. +19 −0 src/com/beatofthedrum/alacdecoder/MyStream.java
  50. +25 −0 src/com/beatofthedrum/alacdecoder/QTMovieT.java
  51. +18 −0 src/com/beatofthedrum/alacdecoder/SampleDuration.java
  52. +18 −0 src/com/beatofthedrum/alacdecoder/SampleInfo.java
  53. +168 −0 src/com/beatofthedrum/alacdecoder/StreamUtils.java
  54. +118 −0 src/com/beatofthedrum/alacdecoder/WavWriter.java
BIN .DS_Store
Binary file not shown.
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="lib" path="/Users/bencall/Downloads/commons-codec-1.5/commons-codec-1.5.jar"/>
+ <classpathentry kind="lib" path="/Users/bencall/Downloads/bcprov-jdk16-146.jar"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>Rplay</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
@@ -0,0 +1,12 @@
+#Wed Apr 20 12:55:36 CEST 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,9 @@
+/**
+ * C struct to java
+ * @author bencall
+ *
+ */
+public class AudioData {
+ public int ready;
+ public short data;
+}
@@ -0,0 +1,115 @@
+/**
+ * The class that process audio data
+ * @author bencall
+ *
+ */
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.ServerSocket;
+
+import com.beatofthedrum.alacdecoder.*;
+
+public class AudioServer implements UDPDelegate{
+ // Constantes
+ public static final int BUFFER_FRAMES = 512;
+
+ // Variables d'instances
+ int[]fmtp; // Sound infos
+ AudioData[] audioBuffer; // Buffer audio
+ DatagramSocket sock, csock;
+
+ public AudioServer(byte[] aesiv, byte[] aeskey, int[] fmtp, int controlPort, int timingPort){
+ this.fmtp = fmtp;
+ this.initDecoder();
+ this.initBuffer();
+ this.initRTP();
+ }
+
+ public int getServerPort() {
+ return sock.getLocalPort();
+ }
+
+ private void initRTP(){
+ int port = 6000;
+ while(true){
+ try {
+ sock = new DatagramSocket(port);
+ csock = new DatagramSocket(port+1);
+ } catch (IOException e) {
+ port = port + 2;
+ continue;
+ }
+ break;
+ }
+
+ UDPListener l1 = new UDPListener(sock, this);
+ UDPListener l2 = new UDPListener(csock, this);
+ }
+
+ private void initDecoder(){
+// int frameSize = fmtp[1];
+// int samplingRate = fmtp[11];
+ int sampleSize = fmtp[3];
+ if (sampleSize != 16){
+ return;
+ }
+
+ AlacFile alac = AlacDecodeUtils.create_alac(sampleSize, 2);
+ alac.setinfo_max_samples_per_frame = 3;
+ alac.setinfo_7a = fmtp[2];
+ alac.setinfo_sample_size = sampleSize;
+ alac.setinfo_rice_historymult = fmtp[4];
+ alac.setinfo_rice_initialhistory = fmtp[5];
+ alac.setinfo_rice_kmodifier = fmtp[6];
+ alac.setinfo_7f = fmtp[7];
+ alac.setinfo_80 = fmtp[8];
+ alac.setinfo_82 = fmtp[9];
+ alac.setinfo_86 = fmtp[10];
+ alac.setinfo_8a_rate = fmtp[11];
+ }
+
+ private void initBuffer(){
+ audioBuffer = new AudioData[BUFFER_FRAMES];
+ }
+
+ public void packetReceived(DatagramSocket socket, DatagramPacket packet) {
+ int type = packet.getData()[1] & ~0x80;
+ if (type == 0x60 || type == 0x56) { // audio data / resend
+ byte[] pktp = packet.getData();
+ if(type==0x56){
+ for(int i=0; i<pktp.length-4; i++){
+ pktp[i] = packet.getData()[i+4];
+ }
+
+ short seqno = pktp[2];
+ this.putPacketInBuffer(seqno, pktp);
+ }
+
+ }
+ }
+
+ private void putPacketInBuffer(short seqno, byte[] data){
+
+ }
+
+ private void alac_decrypt(){
+// unsigned char packet[MAX_PACKET];
+// assert(len<=MAX_PACKET);
+//
+// unsigned char iv[16];
+// int i;
+// memcpy(iv, aesiv, sizeof(iv));
+// for (i=0; i+16<=len; i += 16)
+// AES_cbc_encrypt((unsigned char*)buf+i, packet+i, 0x10, &aes, iv, AES_DECRYPT);
+// if (len & 0xf)
+// memcpy(packet+i, buf+i, len & 0xf);
+//
+// int outsize;
+//
+// decode_frame(decoder_info, packet, dest, &outsize);
+//
+// assert(outsize == FRAME_BYTES);
+ }
+}
@@ -0,0 +1,69 @@
+import com.apple.dnssd.DNSSD;
+import com.apple.dnssd.DNSSDException;
+import com.apple.dnssd.DNSSDRegistration;
+import com.apple.dnssd.DNSSDService;
+import com.apple.dnssd.RegisterListener;
+import com.apple.dnssd.TXTRecord;
+
+/**
+ * Emetteur Bonjour pour qu'iTunes detecte la borne airport
+ * Needs Bonjour for Windows (apple.com)
+ * @author bencall
+ *
+ */
+
+public class BonjourEmitter implements RegisterListener{
+ DNSSDRegistration r;
+
+ public BonjourEmitter(String name, String identifier, int port) throws DNSSDException{
+ TXTRecord txtRecord = new TXTRecord( );
+ txtRecord.set("txtvers", "1");
+ txtRecord.set("pw", "false");
+ txtRecord.set("sr", "44100");
+ txtRecord.set("ss", "16");
+ txtRecord.set("ch", "2");
+ txtRecord.set("tp", "UDP");
+ txtRecord.set("sm", "false");
+ txtRecord.set("sv", "false");
+ txtRecord.set("ek", "1");
+ txtRecord.set("et", "0,1");
+ txtRecord.set("cn", "0,1");
+ txtRecord.set("vn", "3");
+
+ // Il faut un serial bidon pour se connecter
+ if (identifier == null){
+ identifier = "";
+ for(int i=0; i<6; i++){
+ identifier = identifier + Integer.toHexString((int) (Math.random()*255)).toUpperCase();
+ }
+ }
+
+ // Zeroconf registration
+ r = DNSSD.register(0, 0, identifier+"@"+name, "_raop._tcp", null, null, port, txtRecord, this);
+
+ }
+
+ /**
+ * Stop service publishing
+ */
+ public void stop(){
+ r.stop();
+ }
+
+ /**
+ * Registration failed
+ */
+ public void operationFailed(DNSSDService service, int errorCode) {
+ System.out.println("Registration failed " + errorCode);
+ }
+
+ /**
+ * Confirmation that registration is ok
+ */
+ // Display registered name on success
+ public void serviceRegistered(DNSSDRegistration registration, int flags, String serviceName, String regType, String domain){
+ System.out.println("Registered Name : " + serviceName);
+ System.out.println(" Type : " + regType);
+ System.out.println(" Domain: " + domain);
+ }
+}
@@ -0,0 +1,86 @@
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Extracts informations from RTSP Header
+ * @author bencall
+ *
+ */
+public class RTSPPacket {
+ private String req;
+ private String directory;
+ private String rtspVersion;
+ private String content;
+ private Vector<String> headers;
+ private Vector<String> headerContent;
+ private String rawPacket;
+
+ public RTSPPacket(String packet){
+ // Init arrays
+ headers = new Vector<String>();
+ headerContent = new Vector<String>();
+ rawPacket = packet;
+
+ // If packet completed
+ // First line
+ Pattern p = Pattern.compile("^(\\w+)\\W(.+)\\WRTSP/(.+)\r\n");
+ Matcher m = p.matcher(packet);
+ if(m.find()){
+ req = m.group(1);
+ directory = m.group(2);
+ rtspVersion = m.group(3);
+ }
+
+ // Header fields
+ p = Pattern.compile("^([\\w-]+):\\W(.+)\r\n", Pattern.MULTILINE);
+ m = p.matcher(packet);
+ while(m.find()){
+ headers.add(m.group(1));
+ headerContent.add(m.group(2));
+ }
+
+ // Content if present or null if not
+ p = Pattern.compile("\r\n\r\n(.+)", Pattern.DOTALL);
+ m = p.matcher(packet);
+ if(m.find()){
+ content = m.group(1).trim();
+ if(content.isEmpty()){
+ content = null;
+ }
+ }
+ }
+
+ public String getRawPacket(){
+ return rawPacket;
+ }
+
+ public String getContent(){
+ return content;
+ }
+
+ public String getReq(){
+ return req;
+ }
+
+ public String getVersion(){
+ return rtspVersion;
+ }
+
+ public String getDirectory(){
+ return directory;
+ }
+
+ public int getCode(){
+
+ return 200;
+ }
+
+ public String valueOfHeader(String headerName){
+ int i = headers.indexOf(headerName);
+ if (i==-1){
+ return null;
+ }
+ return headerContent.elementAt(i);
+ }
+}
Oops, something went wrong.

0 comments on commit d0221e4

Please sign in to comment.