Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Cleaning. A bug sometimes appear when changing song.

  • Loading branch information...
commit ff718a7440e49df9bd88a09552d2d8ee018a085e 1 parent 8720594
@bencall authored
View
250 src/AudioBuffer.java
@@ -0,0 +1,250 @@
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.beatofthedrum.alacdecoder.AlacDecodeUtils;
+
+/**
+ * A ring buffer where every frame is decrypted, decoded and stored
+ * Basically, you can put and get packets
+ * @author bencall
+ *
+ */
+public class AudioBuffer {
+ // Constants - Should be somewhere else
+ public static final int BUFFER_FRAMES = 512; // Total buffer size (number of frame)
+ public static final int START_FILL = 282; // Alac will wait till there are START_FILL frames in buffer
+ public static final int MAX_PACKET = 2048; // Also in UDPListener (possible to merge it in one place?)
+
+ // The lock for writing/reading concurrency
+ private final Lock lock = new ReentrantLock();
+
+ // The array that represents the buffer
+ private AudioData[] audioBuffer;
+
+ // Can we read in buffer?
+ private boolean synced = false;
+
+ //Audio infos (rate, etc...)
+ AudioSession session;
+
+ // The seqnos at which we read and write
+ private int readIndex;
+ private int writeIndex;
+ private int actualBufSize; // The number of packet in buffer
+ private boolean decoder_isStopped = false; //The decoder stops 'cause the isn't enough packet. Waits till buffer is ok
+
+ // RSA-AES decryption infos
+ private SecretKeySpec k;
+ private Cipher c;
+
+ // Needed for asking missing packets
+ AudioServer server;
+
+
+ /**
+ * Instantiate the buffer
+ * @param session audio infos
+ * @param server whre to ask for resending missing packets
+ */
+ public AudioBuffer(AudioSession session, AudioServer server){
+ this.session = session;
+ this.server = server;
+
+ audioBuffer = new AudioData[BUFFER_FRAMES];
+ for (int i = 0; i< BUFFER_FRAMES; i++){
+ audioBuffer[i] = new AudioData();
+ audioBuffer[i].data = new int[session.OUTFRAME_BYTES()]; // = OUTFRAME_BYTES = 4(frameSize+3)
+ }
+ }
+
+ /**
+ * Sets the packets as not ready. Audio thread will only listen to ready packets.
+ * No audio more.
+ */
+ public void flush(){
+ for (int i = 0; i< BUFFER_FRAMES; i++){
+ audioBuffer[i].ready = false;
+ synced = false;
+ }
+ }
+
+
+ /**
+ * Returns the next ready frame. If none, waiting for one
+ * @return
+ */
+ public int[] getNextFrame(){
+ synchronized (lock) {
+ System.err.println("SEQNO: "+readIndex);
+
+ actualBufSize = writeIndex-readIndex; // Packets in buffer
+
+ if(actualBufSize<1 || !synced){ // If no packets more or Not synced (flush: pause)
+ if(synced){ // If it' because there is not enough packets
+ System.err.println("Underrun!!! Not enough frames in buffer!");
+ }
+
+ try {
+ // We say the decoder is stopped and we wait for signal
+ System.err.println("Waiting");
+ decoder_isStopped = true;
+ lock.wait();
+ decoder_isStopped = false;
+ System.err.println("re-starting");
+ readIndex++; // We read next packet
+
+ // Underrun: stream reset
+ session.resetFilter();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ // Overrunning. Restart at a sane distance
+ if (actualBufSize >= BUFFER_FRAMES) { // overrunning! uh-oh. restart at a sane distance
+ System.err.println("Overrun!!! Too much frames in buffer!");
+ readIndex = writeIndex - START_FILL;
+ }
+ // we get the value before the unlock ;-)
+ int read = readIndex;
+ readIndex++;
+
+ actualBufSize = writeIndex-readIndex;
+ session.updateFilter(actualBufSize);
+
+ AudioData buf = audioBuffer[read % BUFFER_FRAMES];
+
+ if(!buf.ready){
+ System.err.println("Missing Frame!");
+ // Set to zero then
+ for(int i=0; i<buf.data.length; i++){
+ buf.data[i] = 0;
+ }
+ }
+ buf.ready = false;
+ return buf.data;
+
+ }
+ }
+
+
+ /**
+ * Adds packet into the buffer
+ * @param seqno seqno of the given packet. Used as index
+ * @param data
+ */
+ public void putPacketInBuffer(int seqno, byte[] data){
+ // Ring buffer may be implemented in a Hashtable in java (simplier), but is it fast enough?
+ // We lock the thread
+ synchronized(lock){
+
+ if(!synced){
+ writeIndex = seqno;
+ readIndex = seqno;
+ synced = true;
+ }
+
+ @SuppressWarnings("unused")
+ int outputSize = 0;
+ if (seqno == writeIndex){ // Packet we expected
+ outputSize = this.alac_decode(data, audioBuffer[(seqno % BUFFER_FRAMES)].data); // With (seqno % BUFFER_FRAMES) we loop from 0 to BUFFER_FRAMES
+ audioBuffer[(seqno % BUFFER_FRAMES)].ready = true;
+ writeIndex++;
+ } else if(seqno > writeIndex){ // Too early, did we miss some packet between writeIndex and seqno?
+ server.request_resend(writeIndex, seqno);
+ outputSize = this.alac_decode(data, audioBuffer[(seqno % BUFFER_FRAMES)].data);
+ audioBuffer[(seqno % BUFFER_FRAMES)].ready = true;
+ writeIndex = seqno + 1;
+ } else if(seqno > readIndex){ // readIndex < seqno < writeIndex not yet played but too late. Still ok
+ outputSize = this.alac_decode(data, audioBuffer[(seqno % BUFFER_FRAMES)].data);
+ audioBuffer[(seqno % BUFFER_FRAMES)].ready = true;
+ } else {
+ System.err.println("Late packet with seq. numb.: " + seqno); // Really to late
+ }
+
+ // The number of packet in buffer
+ actualBufSize = writeIndex - readIndex;
+
+ if(decoder_isStopped && actualBufSize > START_FILL){
+ System.err.println(seqno);
+ lock.notify();
+ }
+ }
+ }
+
+
+ /**
+ * Decrypt and decode the packet.
+ * @param data
+ * @param outbuffer the result
+ * @return
+ */
+ private int alac_decode(byte[] data, int[] outbuffer){
+ byte[] packet = new byte[MAX_PACKET];
+
+ // Init AES
+ initAES();
+
+ int i;
+ for (i=0; i+16<=data.length; i += 16){
+ // Decrypt
+ this.decryptAES(data, i, 16, packet, i);
+ }
+
+ // The rest of the packet is unencrypted
+ for (int k = 0; k<(data.length % 16); k++){
+ packet[i+k] = data[i+k];
+ }
+
+ int outputsize = 0;
+ outputsize = AlacDecodeUtils.decode_frame(session.getAlac(), packet, outbuffer, outputsize);
+
+ assert outputsize==session.getFrameSize()*4; // FRAME_BYTES length
+
+ return outputsize;
+ }
+
+
+ /**
+ * Initiate the cipher
+ */
+ private void initAES(){
+ // Init AES encryption
+ try {
+ k = new SecretKeySpec(session.getAESKEY(), "AES");
+ c = Cipher.getInstance("AES/CBC/NoPadding");
+ c.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(session.getAESIV()));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Decrypt array from input offset with a length of inputlen and puts it in output at outputoffsest
+ * @param array
+ * @param inputOffset
+ * @param inputLen
+ * @param output
+ * @param outputOffset
+ * @return
+ */
+ private int decryptAES(byte[] array, int inputOffset, int inputLen, byte[] output, int outputOffset){
+ try{
+ return c.update(array, inputOffset, inputLen, output, outputOffset);
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+
+ return -1;
+ }
+
+
+
+
+}
View
302 src/AudioServer.java
@@ -10,41 +10,28 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import javax.crypto.Cipher;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-import com.beatofthedrum.alacdecoder.*;
+/**
+ * Main class that listen for new packets.
+ * @author bencall
+ *
+ */
public class AudioServer implements UDPDelegate{
// Constantes
public static final int BUFFER_FRAMES = 512; // Total buffer size (number of frame)
public static final int START_FILL = 282; // Alac will wait till there are START_FILL frames in buffer
public static final int MAX_PACKET = 2048; // Also in UDPListener (possible to merge it in one place?)
- // Variables d'instances
- private int[]fmtp; // Sound infos
- private int sampleSize;
- private int frameSize;
- private AudioData[] audioBuffer; // Buffer audio
- private boolean synced = false;
- private boolean decoder_isStopped = false; //The decoder stops 'cause the isn't enough packet. Waits till buffer is full
- private int readIndex; // audioBuffer is a ring buffer. We write at writeindex(seqno) and we read at readindex(seqno).
- private int writeIndex;
- private int actualBufSize;
+
+ // Sockets
private DatagramSocket sock, csock;
- // AES Keys
- private byte[] aesiv;
- private byte[] aeskey;
- private SecretKeySpec k;
- private Cipher c;
- //Decoder
- private AlacFile alac;
- // Ports
+
+ // client address
private InetAddress rtpClient;
- private int controlPort;
- // Mutex locks
- private final Lock lock = new ReentrantLock();
- // Audio stuff
- biquadFilter bFilter;
+
+ // Audio infos and datas
+ AudioSession session;
+ AudioBuffer audioBuf;
+
/**
* Constructor. Initiate instances vars
@@ -54,100 +41,17 @@
* @param controlPort
* @param timingPort
*/
- public AudioServer(byte[] aesiv, byte[] aeskey, int[] fmtp, int controlPort, int timingPort){
+ public AudioServer(AudioSession session){
// Init instance var
- this.fmtp = fmtp;
- this.aesiv = aesiv;
- this.aeskey = aeskey;
-
- // Ports
- this.controlPort = controlPort;
+ this.session = session;
// Init functions
- this.initDecoder();
- this.initBuffer();
+ audioBuf = new AudioBuffer(session, this);
this.initRTP();
-
- PCMPlayer player = new PCMPlayer(this);
+ PCMPlayer player = new PCMPlayer(session, audioBuf);
player.start();
}
-
- public int getFrameSize(){
- return this.frameSize;
- }
-
- public int[] getNextFrame(){
- synchronized (lock) {
- actualBufSize = writeIndex-readIndex; // Packets in buffer
- System.err.println("FILL: "+actualBufSize);
-
- if(actualBufSize<1 || !synced){ // If no packets more or Not synced (flush: pause)
- if(synced){ // If it' because there is not enough packets
- System.err.println("Underrun!!! Not enough frames in buffer!");
- }
-
- try {
- // We say the decoder is stopped and we wait for signal
- System.err.println("Waiting");
- decoder_isStopped = true;
- lock.wait();
- decoder_isStopped = false;
- System.err.println("re-starting");
- //TODO
-
- readIndex++; // We read next packet
-
- // Underrun: stream reset
- bFilter = new biquadFilter(this.sampleSize, this.frameSize); // New biquadFilter with default attribute (reset)
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- return null;
- }
-
- // Overrunning. Restart at a sane distance
- if (actualBufSize >= BUFFER_FRAMES) { // overrunning! uh-oh. restart at a sane distance
- System.err.println("Overrun!!! Too much frames in buffer!");
- readIndex = writeIndex - START_FILL;
- }
- // we get the value before the unlock ;-)
- int read = readIndex;
- readIndex++;
-
- actualBufSize = writeIndex-readIndex;
- bFilter.update(actualBufSize);
-
- AudioData buf = audioBuffer[read % BUFFER_FRAMES];
-
- if(!buf.ready){
- System.err.println("Missing Frame!");
- // Set to zero then
- for(int i=0; i<buf.data.length; i++){
- buf.data[i] = 0;
- }
- }
- buf.ready = false;
- return buf.data;
- }
- }
-
-
- public biquadFilter getFilter(){
- return bFilter;
- }
-
- /**
- * Sets the packets as not ready. Audio thread will only listen to ready packets.
- * No audio more.
- */
- public void flush(){
- for (int i = 0; i< BUFFER_FRAMES; i++){
- audioBuffer[i].ready = false;
- synced = false;
- }
- }
/**
* Return the server port for the bonjour service
@@ -180,47 +84,6 @@ private void initRTP(){
}
/**
- * Initiate the decoder
- */
- private void initDecoder(){
- frameSize = fmtp[1];
-
- sampleSize = fmtp[3];
- if (sampleSize != 16){
- System.err.println("ERROR: 16 bits only!!!");
- return;
- }
-
- alac = AlacDecodeUtils.create_alac(sampleSize, 2);
- if (alac == null){
- System.err.println("ERROR: creating alac!!!");
- return;
- }
- alac.setinfo_max_samples_per_frame = frameSize;
- 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];
- }
-
- /**
- * Initiate the ring buffer
- */
- private void initBuffer(){
- audioBuffer = new AudioData[BUFFER_FRAMES];
- for (int i = 0; i< BUFFER_FRAMES; i++){
- audioBuffer[i] = new AudioData();
- audioBuffer[i].data = new int[4*(frameSize+3)]; // = OUTFRAME_BYTES = 4(frameSize+3)
- }
- }
-
- /**
* When udpListener gets a packet
*/
public void packetReceived(DatagramSocket socket, DatagramPacket packet) {
@@ -243,56 +106,10 @@ public void packetReceived(DatagramSocket socket, DatagramPacket packet) {
pktp[i] = packet.getData()[i+12+off];
}
- this.putPacketInBuffer(seqno, pktp);
+ audioBuf.putPacketInBuffer(seqno, pktp);
}
}
- /**
- * Adds packet into the buffer
- * @param seqno seqno of the given packet. Used as index
- * @param data
- */
- private void putPacketInBuffer(int seqno, byte[] data){
- // Ring buffer may be implemented in a Hashtable in java (simplier), but is it fast enough?
- // We lock the thread
- synchronized(lock){
-
- if(!synced){
- writeIndex = seqno;
- readIndex = seqno;
- synced = true;
- }
-
-
- @SuppressWarnings("unused")
- int outputSize = 0;
- if (seqno == writeIndex){ // Packet we expected
- outputSize = this.alac_decode(data, audioBuffer[(seqno % BUFFER_FRAMES)].data); // With (seqno % BUFFER_FRAMES) we loop from 0 to BUFFER_FRAMES
- audioBuffer[(seqno % BUFFER_FRAMES)].ready = true;
- writeIndex++;
- } else if(seqno > writeIndex){ // Too early, did we miss some packet between writeIndex and seqno?
- this.request_resend(writeIndex, seqno);
- outputSize = this.alac_decode(data, audioBuffer[(seqno % BUFFER_FRAMES)].data);
- audioBuffer[(seqno % BUFFER_FRAMES)].ready = true;
- writeIndex = seqno + 1;
- } else if(seqno > readIndex){ // readIndex < seqno < writeIndex not yet played but too late. Still ok
- outputSize = this.alac_decode(data, audioBuffer[(seqno % BUFFER_FRAMES)].data);
- audioBuffer[(seqno % BUFFER_FRAMES)].ready = true;
- } else {
- System.err.println("Late packet with seq. numb.: " + seqno); // Really to late
- }
-
- // The number of packet in buffer
- actualBufSize = writeIndex - readIndex;
-
- if(decoder_isStopped && actualBufSize > START_FILL){
- System.err.println(seqno);
- lock.notify();
- //TODO
- }
- }
-
- }
/**
* Ask iTunes to resend packet
@@ -300,24 +117,17 @@ private void putPacketInBuffer(int seqno, byte[] data){
* @param first
* @param last
*/
- private void request_resend(int first, int last) {
+ public void request_resend(int first, int last) {
System.out.println("Resend Request: " + first + "::" + last);
if(last<first){
return;
}
- byte request[] = new byte[8];
- request[0] = (byte)(0x80 & 0xFF); // Header
- request[1] = (byte)((0x55|0x80) & 0xFF);
- request[2] = (byte)((1>>8) & 0xFF); // Our seqnum
- request[3] = (byte)(1 & 0xFF);
- request[4] = (byte)((first>>8) & 0xFF); // First
- request[5] = (byte)(first & 0xFF);
- request[6] = (byte)(((last-first+1)>>8) & 0xFF); // Count
- request[7] = (byte)((last-first+1) & 0xFF);
-
+ int len = last - first + 1;
+ byte[] request = new byte[] { (byte) 0x80, (byte) (0x55|0x80), 0x01, 0x00, (byte) ((first & 0xFF00) >> 8), (byte) (first & 0xFF), (byte) ((len & 0xFF00) >> 8), (byte) (len & 0xFF)};
+
try {
- DatagramPacket temp = new DatagramPacket(request, request.length, rtpClient, controlPort);
+ DatagramPacket temp = new DatagramPacket(request, request.length, rtpClient, session.getControlPort());
csock.send(temp);
} catch (IOException e) {
@@ -326,69 +136,11 @@ private void request_resend(int first, int last) {
}
-
- /**
- * Decrypt and decode the packet.
- * @param data
- * @param outbuffer the result
- * @return
- */
- private int alac_decode(byte[] data, int[] outbuffer){
- byte[] packet = new byte[MAX_PACKET];
-
- // Init AES
- initAES();
-
- int i;
- for (i=0; i+16<=data.length; i += 16){
- // Decrypt
- this.decryptAES(data, i, 16, packet, i);
- }
-
- // The rest of the packet is unencrypted
- for (int k = 0; k<(data.length % 16); k++){
- packet[i+k] = data[i+k];
- }
-
- int outputsize = 0;
- outputsize = AlacDecodeUtils.decode_frame(alac, packet, outbuffer, outputsize);
-
- assert outputsize==frameSize*4; // FRAME_BYTES length
-
- return outputsize;
- }
/**
- * Initiate the cipher
+ * Flush the audioBuffer
*/
- private void initAES(){
- // Init AES encryption
- try {
- k = new SecretKeySpec(aeskey, "AES");
- c = Cipher.getInstance("AES/CBC/NoPadding");
- c.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(aesiv));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Decrypt array from input offset with a length of inputlen and puts it in output at outputoffsest
- * @param array
- * @param inputOffset
- * @param inputLen
- * @param output
- * @param outputOffset
- * @return
- */
- private int decryptAES(byte[] array, int inputOffset, int inputLen, byte[] output, int outputOffset){
- try{
- return c.update(array, inputOffset, inputLen, output, outputOffset);
- }catch(Exception e){
- e.printStackTrace();
- }
-
- return -1;
+ public void flush(){
+ audioBuf.flush();
}
-
}
View
156 src/AudioSession.java
@@ -0,0 +1,156 @@
+import com.beatofthedrum.alacdecoder.AlacDecodeUtils;
+import com.beatofthedrum.alacdecoder.AlacFile;
+
+
+public class AudioSession {
+ private AlacFile alac;
+ private byte[] aesiv;
+ private byte[] aeskey;
+ private int controlPort;
+ private int timingPort;
+ private int frameSize;
+ private int sampleSize;
+ private int _7a;
+ private int rice_historymult;
+ private int rice_initialhistory;
+ private int rice_kmodifier;
+ private int _7f;
+ private int _80;
+ private int _82;
+ private int _86;
+ private int _8a_rate;
+ private BiquadFilter bFilter;
+
+
+ public AudioSession(byte[] aesiv, byte[] aeskey, int[] fmtp, int controlPort, int timingPort){
+ // KEYS
+ this.aesiv = aesiv;
+ this.aeskey = aeskey;
+
+ // PORTS
+ this.controlPort = controlPort;
+ this.timingPort = timingPort;
+
+ // FMTP
+ frameSize = fmtp[1];
+ _7a = fmtp[2];
+ sampleSize = fmtp[3];
+ rice_historymult = fmtp[4];
+ rice_initialhistory = fmtp[5];
+ rice_kmodifier = fmtp[6];
+ _7f = fmtp[7];
+ _80 = fmtp[8];
+ _82 = fmtp[9];
+ _86 = fmtp[10];
+ _8a_rate = fmtp[11];
+
+ initDecoder();
+ }
+
+ /**
+ * Initiate the decoder
+ */
+ private void initDecoder(){
+ if (this.getSampleSize() != 16){
+ System.err.println("ERROR: 16 bits only!!!");
+ return;
+ }
+
+ alac = AlacDecodeUtils.create_alac(this.getSampleSize(), 2);
+ if (alac == null){
+ System.err.println("ERROR: creating alac!!!");
+ return;
+ }
+ alac.setinfo_max_samples_per_frame = this.getFrameSize();
+ alac.setinfo_7a = this.get_7a();
+ alac.setinfo_sample_size = this.getSampleSize();
+ alac.setinfo_rice_historymult = this.getRiceHistoryMult();
+ alac.setinfo_rice_initialhistory = this.getRiceInitialhistory();
+ alac.setinfo_rice_kmodifier = this.getRiceKModifier();
+ alac.setinfo_7f = this.get_7f();
+ alac.setinfo_80 = this.get_80();
+ alac.setinfo_82 = this.get_82();
+ alac.setinfo_86 = this.get_86();
+ alac.setinfo_8a_rate = this.get_8a_rate();
+ }
+
+ public int OUTFRAME_BYTES(){
+ return 4*(this.getFrameSize()+3);
+ }
+
+ public AlacFile getAlac(){
+ return alac;
+ }
+
+ public void resetFilter(){
+ bFilter = new BiquadFilter(this.getSampleSize(), this.getFrameSize());
+ }
+
+ public void updateFilter(int size){
+ bFilter.update(size);
+ }
+
+ public BiquadFilter getFilter(){
+ return bFilter;
+ }
+
+ public byte[] getAESIV(){
+ return this.aesiv;
+ }
+
+ public byte[] getAESKEY(){
+ return this.aeskey;
+ }
+
+ public int getControlPort(){
+ return this.controlPort;
+ }
+
+ public int getTimingPort(){
+ return this.timingPort;
+ }
+
+ public int getFrameSize(){
+ return this.frameSize;
+ }
+
+ public int getSampleSize(){
+ return this.sampleSize;
+ }
+
+ public int get_7a(){
+ return this._7a;
+ }
+
+ public int getRiceHistoryMult(){
+ return this.rice_historymult;
+ }
+
+ public int getRiceInitialhistory(){
+ return this.rice_initialhistory;
+ }
+
+ public int get_8a_rate(){
+ return this._8a_rate;
+ }
+
+ public int get_86(){
+ return this._86;
+ }
+
+ public int get_82(){
+ return this._82;
+ }
+
+ public int get_80(){
+ return this._80;
+ }
+
+ public int get_7f(){
+ return this._7f;
+ }
+
+ public int getRiceKModifier(){
+ return this.rice_kmodifier;
+ }
+}
View
27 src/PCMPlayer.java
@@ -13,14 +13,16 @@
AudioFormat audioFormat;
Info info;
SourceDataLine dataLine;
- AudioServer server;
+ AudioSession session;
long fix_volume = 0x10000;
short rand_a, rand_b;
+ AudioBuffer audioBuf;
- public PCMPlayer(AudioServer server){
+ public PCMPlayer(AudioSession session, AudioBuffer audioBuf){
super();
- this.server = server;
-
+ this.session = session;
+ this.audioBuf = audioBuf;
+
try {
audioFormat = new AudioFormat(44100, 16, 2, true, true);
info = new DataLine.Info(SourceDataLine.class, audioFormat);
@@ -37,13 +39,13 @@ public PCMPlayer(AudioServer server){
public void run(){
while(true){
- int[] buf = server.getNextFrame();
+ int[] buf = audioBuf.getNextFrame();
if(buf==null){
continue;
}
- int[] outbuf = new int[4*(server.getFrameSize()+3)];
- int k = stuff_buffer(server.getFilter().bf_playback_rate, buf, outbuf);
+ int[] outbuf = new int[session.OUTFRAME_BYTES()];
+ int k = stuff_buffer(session.getFilter().bf_playback_rate, buf, outbuf);
byte[] input = new byte[outbuf.length*2];
@@ -53,22 +55,21 @@ public void run(){
input[j++] = (byte)(outbuf[i]);
}
- System.err.println("Play!!!");
dataLine.write(input, 0, k*4);
}
}
private int stuff_buffer(double playback_rate, int[] input, int[] output) {
- int stuffsamp = server.getFrameSize();
+ int stuffsamp = session.getFrameSize();
int stuff = 0;
double p_stuff;
- p_stuff = 1.0 - Math.pow(1.0 - Math.abs(playback_rate-1.0), server.getFrameSize());
+ p_stuff = 1.0 - Math.pow(1.0 - Math.abs(playback_rate-1.0), session.getFrameSize());
if (Math.random() < p_stuff) {
stuff = playback_rate > 1.0 ? -1 : 1;
- stuffsamp = (int) (Math.random() * (server.getFrameSize() - 2));
+ stuffsamp = (int) (Math.random() * (session.getFrameSize() - 2));
}
int j=0;
@@ -86,12 +87,12 @@ private int stuff_buffer(double playback_rate, int[] input, int[] output) {
} else if (stuff==-1) {
l-=2;
}
- for (int i=stuffsamp; i<server.getFrameSize() + stuff; i++) {
+ for (int i=stuffsamp; i<session.getFrameSize() + stuff; i++) {
output[j++] = dithered_vol(input[l++]);
output[j++] = dithered_vol(input[l++]);
}
}
- return server.getFrameSize() + stuff;
+ return session.getFrameSize() + stuff;
}
View
3  src/RTSPResponder.java
@@ -177,7 +177,8 @@ public void handlePacket(RTSPPacket packet){
}
// Launching audioserver
- serv = new AudioServer(aesiv, aeskey, fmtp, controlPort, timingPort);
+ serv = new AudioServer(new AudioSession(aesiv, aeskey, fmtp, controlPort, timingPort));
+
response.append("Transport: " + packet.valueOfHeader("Transport") + ";server_port=" + serv.getServerPort() + "\r\n");
// ??? Why ???
View
4 src/biquadFilter.java
@@ -4,7 +4,7 @@
* @author bencall
*
*/
-public class biquadFilter {
+public class BiquadFilter {
double bf_playback_rate = 1.0;
double bf_est_drift = 0.0; // local clock is slower by
biquad_t bf_drift_lpf;
@@ -18,7 +18,7 @@
private static final double CONTROL_A = (1e-4);
private static final double CONTROL_B = (1e-1);
- public biquadFilter(int sampling_rate, int frame_size){
+ public BiquadFilter(int sampling_rate, int frame_size){
this.sampling_rate = sampling_rate;
this.frame_size = frame_size;
bf_drift_lpf = biquad_lpf(1.0/180.0, 0.3);
Please sign in to comment.
Something went wrong with that request. Please try again.