views:

49

answers:

2

I am trying to implement a threaded circular buffer with PipedInputStream & PipedOutputStream but it is locking everytime when I get to mHead.write in the Decoder runnable. I thought there was no chance for deadlocks when using separate threads.

    private class DecoderTask implements Runnable{

    @Override
    public void run() {
        while(!mStop){
            try {
                    Log.d(TAG,"trying to write");
        mHead.write(decode( 0, 1000));
            mHead.flush();
            Log.d(TAG,"Decoded");
            } catch (DecoderException e) {
                Log.e(TAG,e.toString());
            } catch (IOException e) {
                Log.e(TAG,e.toString());
            }
        }
    }

}
private class WriteTask implements Runnable{

    @Override
    public void run() {
        while(!mStop){
            try {
                                 Log.d(TAG,"trying to read");
                 int read = mTail.read(mByteSlave, 0, mByteSlave.length);
                 mAudioTrack.flush();
                                 mAudioTrack.write(mByteSlave,0,read);
                                 Log.d(TAG,"read");                 
            } catch (IOException e) {
                Log.e(TAG,e.toString());
            }
        }
    }

}


//in some function
mTail = new PipedInputStream();
mHead = new PipedOutputStream(mTail);
mByteSlave = new byte[BUF];
mT1 = new Thread(new DecoderTask(), "Reader");
mT2 = new Thread(new WriteTask(), "Writer");
mT1.start();
mT2.start();
return;

edit: here is the full source for my service http://pastie.org/1179792

logcat prints out :

trying to read
trying to write

A: 

The program doesn't block, it's just very very slow and inefficient. It uses 100% CPU. The problem is if (mTail.available() >= mByteSlave.length) - this will return false in most cases, and so you get a busy loop in this thread. If you can get rid of this, do it. Then this problem is solved. If you can't, it gets more complicated...

There is another problem: PipedInputStream.read returns an int. You need to use:

int len = mTail.read(mByteSlave, 0, mByteSlave.length);
mAudioTrack.write(mByteSlave, 0, len);

Other than that, I couldn't find anything wrong in this code. My complete test case looks like this:

import java.io.*;
public class Test2 {
    PipedOutputStream mHead;
    PipedInputStream mTail;
    byte[] mByteSlave = new byte[1024];
    boolean mStop;
    public static void main(String... ar) throws Exception {
        new Test2().run();
    }
    void run() throws Exception {
        mTail = new PipedInputStream();
        mHead = new PipedOutputStream(mTail);
        Thread mT1 = new Thread(new DecoderTask(), "Reader");
        Thread mT2 = new Thread(new WriteTask(), "Writer");
        mT1.start();
        mT2.start();
    }
    class DecoderTask implements Runnable {
        public void run() {
            while (!mStop) {
                try {
                    mHead.write(new byte[3000]);
                    mHead.flush();
                    System.out.println("decoded 3000");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    class WriteTask implements Runnable {
        public void run() {
            while (!mStop) {
                try {
                    int len = mTail.read(mByteSlave, 0, mByteSlave.length);
                    if (len < 0) break; // EOF
                    // mAudioTrack.write(mByteSlave, 0, len);
                    // mAudioTrack.flush();
                    System.out.println("written " + len);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
Thomas Mueller
Still not working I edited my code above to reflect what I have now, log output says: trying to write trying to read and then nothing, its blocking on the read and the write.
schwiz
The problem was what you pointed out, as well as write(byte[]) is not defined by PipedOutputStream so it doesn't work, you have to use the (byte[], int, int) one
schwiz
This doesnt work like I thought it did, once I read the data from the the mTail how to I clear out the data, it reads the same data over and over again.
schwiz
You don't need to clear the data, you just need to make sure you don't write the same data over and over again into mAudioTrack and mHead. I updated the code: you need to use the "len" when writing to the audio: mAudioTrack.write(mByteSlave, 0, len); - also I added EOF detection: if (len < 0) break - so you could also get rid of if (!mStop) in the WriteTask, but you need to close mHead.
Thomas Mueller
can't get rid of mStop this is for an internet radio stream so there is never an EOF. Is there a better class to use for this type of situation?
schwiz
mStop is OK. The question is, of course, if it's possible to just directly write to the mAudioTrack after decoding.
Thomas Mueller
The decode library gives me the wrong byte order so I need to have sort of a double buffer one decoded, and one decoded with the right byte order.
schwiz
A: 

Just get rid of the test involving available(). The read will block anyway, and you have nothing better to do when there is no data.

EJP