1

For some reasons, I need to convert the samples of a audio into byte[] for network transmission. I found a function for short2bytearray

public static byte[] short2byte(short in) {
        byte[] ret = new byte[2];
        ret[0] = (byte) (in & 0xff);
        ret[1] = (byte) ((in >> 8) & 0xff);
        return ret;
}

because the audio keeps playing and samples are keep taking, so I save samples into a HashMap first and then open a thread to process this map.

private void convert() {
        Thread conv = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                // while (needConver) {
                Iterator<Entry<Integer, short[]>> iter = sampleBuffer
                        .entrySet().iterator();
                Log.i("Converting", "enter");
                if (iter.hasNext()) {
                    Entry<Integer, short[]> entry = iter.next();
                    //stops in here
                    byte[] converted = new byte[entry.getValue().length * 2];
                    for (short in : entry.getValue()) {
                        Admin.combineByteArray(converted, Admin.short2byte(in));
                    }
                    convertedBuffer.put(entry.getKey(), converted);
                    sampleBuffer.remove(entry.getKey());
                }
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                // }
            }

        });
        conv.start();
    }

The thread will only create once. I want it too keep tracking the sampleBuffer and convert data that stores in it. However, when I run the conversation function Admin.short2byte(in), it will output lots of information like

`03-22 14:52:48.004: D/dalvikvm(24194): GC_FOR_ALLOC freed 4096K, 50% free 8517K/16839K, paused 13ms, total 13ms`

could you please tell me why and how to fix this? thank you

7
  • You're probably getting the GC spam because you're creating a ton of small arrays, then concatenating them into a large array in the worst way possible (1 array at a time rather than a builder). Very inefficient. Rewrite short2Byte to take an array of shorts and create only a single array of bytes as output. Commented Mar 22, 2013 at 7:01
  • What error you are facing? post your complete logcat? Commented Mar 22, 2013 at 7:01
  • @kumar_android um...there are no errors, just the conversation cannot process since it seems waiting for allocate space. and I cannot post the whole log info here because there are thousands of information like 03-22 14:52:48.004: D/dalvikvm(24194): GC_FOR_ALLOC freed 4096K, 50% free 8517K/16839K, paused 13ms, total 13ms but I know it's not errors Commented Mar 22, 2013 at 7:07
  • You should not be removing entries from sampleBuffer while you are iterating through it. Also, what does Admin.combineByteArray do? Commented Mar 22, 2013 at 7:11
  • @TedHopp Admin.combineByteArray is combining two byte-arrays since the input is short[]. Also, the Audio player is keep writing samples into sampleBuffer, if I don't recreate the iterator, those new samples could be read? Commented Mar 22, 2013 at 7:21

1 Answer 1

2

There are several problems with your code. First, you are removing elements from the sampleBuffer map while you are iterating through it. I'm surprised you aren't getting an exception with that. Second, your method of building the results array is extremely inefficient and generates lots of garbage. You would be better off using a java.nio.ByteBuffer and eliminate your short2byte method. I would write your code like this:

private void convert() {
    new Thread() {
        @Override
        public void run() {
            for (Entry<Integer, short[]> entry : sampleBuffer.entrySet()) {
                short[] values = entry.getValue();
                byte[] converted = new byte[values.length * 2];
                ByteBuffer buff = ByteBuffer.wrap(converted);
                for (short in : values) {
                    buff.putShort(in);
                }
                convertedBuffer.put(entry.getKey(), converted);
            }
        }

    }.start();
}
Sign up to request clarification or add additional context in comments.

6 Comments

thank you so much Ted, but still have something that I couldn't understand. When I search the network, they said using wap() is much slower than ret[0] = (byte) (in & 0xff); this way? Also, there is a player keep putting samples into sampleBuffer, would those values be accessible?
@PandaYang - When I wrote my answer, I didn't realize that you had concurrent modifications of sampleBuffer going on. I suggest that you use a (synchronized) queue rather than a HashMap and reorganize the code accordingly. It's much better suited for what you are trying to do. As for the speed of wrap(), it is probably slower for converting a single short to bytes; however, you are converting an entire array of them. The overhead of constructing the ByteBuffer will be negligible when amortized over the entire array.
I rewrite my code use the your method, but since byte[] converted = new byte[values.length * 2]; doesn't work fine. After few conversation, it throws a error: E/dalvikvm-heap(25779): Out of memory on a 2097168-byte allocation.
I have modified it, and it seems good. use ByteBuffer.clear(). thank you so much.
@PandaYang - Glad it worked! I updated the code to include a call to clear() in case someone else wants to use this solution. Is this where you were calling it?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.