-->

Android Play PCM byte array from Converted from Ba

2019-01-29 02:58发布

问题:

As the very long title suggests, I'm having trouble playing the audio from a audio that I send over the network through PubNunb. What I do is I send the audio while recording from AudioRecord using this code:

 AudioConfig audioConfig = getValidSampleRates(AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
    buffer = new byte[audioConfig.getBufferSize()];

    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, audioConfig.getSampleSize(), AudioFormat.CHANNEL_IN_MONO, AUDIO_FORMAT, audioConfig.getBufferSize());

Recorded data is sent when the user holds the button down:

   private class RecorderRunnable implements Runnable {
    @Override
    public void run() {
        while(mRecording) {
            Log.d("RECORDER_STATE", "Recording LOOP");
            recorder.read(buffer, 0, buffer.length);

            String base64EncodedBuffer = Base64.encodeToString(buffer, Base64.NO_WRAP);

            pubnub.publish(MainActivity.CHANNEL_ID, base64EncodedBuffer, new Callback() {
                @Override
                public void successCallback(String channel, Object message) {
                    super.successCallback(channel, message);
                }
            });
        }
    }
}

Receive code:

       @Override
                    public void successCallback(String channel, final Object message) {


                        byte[] decodedBase64 = Base64.decode(message.toString(), Base64.NO_WRAP);

                        speaker.write(decodedBase64, 0, decodedBase64.length);
                    }

Issue: I get the audio, but I get sounds that are really slow. "Hello" would sound like: "Hee-*static*-ll-*static*-oo"

To rule out possible causes, I tried immediately playing the audio like this (without the network):

 while(mRecording) {
            Log.d("RECORDER_STATE", "Recording LOOP");
            recorder.read(buffer, 0, buffer.length);

            String base64EncodedBuffer = Base64.encodeToString(buffer, Base64.NO_WRAP);

            byte[] decodedBase64 = Base64.decode(base64EncodedBuffer, Base64.NO_WRAP);

            speaker.write(decodedBase64, 0, decodedBase64.length);
        }

(Note: I did the convert to base64 and back to byte array on purpose.)

The result for the code above (directly playing it after recording) is pretty good. So I'm wondering what I'm doing wrong when handling it over the network.

Any suggestion is appreciated. Thank you.

Edit: 08/28/2015 Found a good explanation for this here. But now the question is, what's the best way of handling network jitter/buffering and packetloss using my current implementation.

回答1:

pubnub delivers data through tcp (not udp). http://www.pubnub.com/knowledge-base/discussion/263/does-pubnub-support-the-udp-protocol

There should be no need to handle packet loss in your application.

You may need to handle jitter by creating a buffer of some sort. Since there would be no rigid realtime constraint, I will discuss an approach rather than pasting code.

You can make a buffer using a queue. I suggest having two threads. One for your reader (your player) and one for writer (the network stream). Let the writer queue up some data (maybe a few seconds of data) before letting the reader read. On paper, with a very simply proof of concept, you should not have issues with simultaneous reads and writes since the writer is writing to the end of the queue and the reader is reading at the beginning of the queue.

Think of it as a bucket that is halfway full. You pour water in and let water leak out at the same rate.