Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Audio Streaming - Getting Static Noise on AudioTrack

I have a streaming server running on localhost. When I try to stream audio from it from my Android application. I'm getting static noise most of the time (The kind you get on radio). Sometimes the complete audio is static noise, sometimes a part of it, and sometimes the audio plays just fine, so I'm not sure what's going wrong.

Here's the streaming code from my android application:

new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        try {
                            URI uri = URI.create("http://192.168.1.6:5000/api/tts");
                            HttpURLConnection urlConnection = (HttpURLConnection) uri.toURL().openConnection();
                            urlConnection.setRequestMethod("POST");
                            urlConnection.setRequestProperty("Content-Type", "application/json");
                            urlConnection.setRequestProperty("x-access-token", credentials.getAccessToken());
                            urlConnection.setRequestProperty("Accept", "*");
                            urlConnection.setDoInput(true);
                            urlConnection.setDoOutput(true);
                            urlConnection.connect();
                            OutputStreamWriter osw = new OutputStreamWriter(urlConnection.getOutputStream());
                            String body = "{\"text\": \"" + text + "\", \"ttsLang\": \"" + language + "\"}";
                            Log.d("TTS_HTTP", body);
                            osw.write(body);
                            osw.flush();
                            osw.close();
                            Log.d("TTS_OUT", credentials.getAccessToken());
                            Log.d("TTS_OUT", urlConnection.getResponseCode() + " " + urlConnection.getResponseMessage());

                            // define the buffer size for audio track
                            int SAMPLE_RATE = 16000;
                            int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
                                    AudioFormat.ENCODING_PCM_16BIT);
                            if (bufferSize == AudioTrack.ERROR || bufferSize == AudioTrack.ERROR_BAD_VALUE) {
                                bufferSize = SAMPLE_RATE * 2;
                            }
                            bufferSize *= 2;

                            AudioTrack audioTrack = new AudioTrack(
                                    AudioManager.STREAM_MUSIC,
                                    SAMPLE_RATE,
                                    AudioFormat.CHANNEL_OUT_MONO,
                                    AudioFormat.ENCODING_PCM_16BIT,
                                    bufferSize*2,
                                    AudioTrack.MODE_STREAM);
                            byte[] buffer = new byte[bufferSize];
                            InputStream is = urlConnection.getInputStream();
                            int count;

                            audioTrack.play();
                            while ((count = is.read(buffer, 0, bufferSize)) > -1) {
                                Log.d("TTS_COUNT", count + "");
                                audioTrack.write(buffer, 0, count);
                            }
                            is.close();
                            audioTrack.stop();
                            audioTrack.release();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();

Please help me to fix the code to solve the problem. I'm not able to hear the sound properly as I described before.

Also, the server response is fine since I'm able to save it to a file using Python code. The saved file is being played just fine.

>>> import requests
>>> import wave
>>> with wave.open("output.wav", "wb") as f:
...   f.setframerate(16000)  # 16khz
...   f.setnchannels(1)  # mono channel
...   f.setsampwidth(2)  # 16-bit audio
...   res = requests.post("http://192.168.1.6:5000/api/tts", headers={"x-access-token": token}, json={"text": "Hello, would you like to have some tea", "ttsLang": "en-us"}, stream=True)
...   for i in res.iter_content(chunk_size=16*1024):
...     f.writeframes(i)
...

Update: Writing the inputstream to file and then playing from file to audiotrack works just fine...

like image 932
Asym Avatar asked Mar 05 '23 01:03

Asym


1 Answers

Finally, I fixed the problem. It turns out that AudioTrack does not like inconsistent amounts of data being written to it and causes static noise due to it. This was the byte count sequence that was being written to AudioTrack before, that was causing the problem 1248, 3439, 5152, 5152, 3834, ... , 823 (Inconsistent). So, I looked at the readFully method of DataInputStream and used it and that fixed the static noise problem. The byte count sequence now looked like 5152,5152,5152, ..., 5152 (Consistent). But now the problem was to read the left-over bytes that were being skipped due to EOFException. So I had to implement my own methods to fix that.

public class TTSInputStream extends DataInputStream {
    public TTSInputStream(InputStream in) {
        super(in);
    }

    public final int readFullyUntilEof(byte b[]) throws IOException {
        return readFullyUntilEof(b, 0, b.length);
    }

    public final int readFullyUntilEof(byte b[], int off, int len) throws IOException {
        if (len < 0)
            throw new IndexOutOfBoundsException();
        int n = 0;
        while (n < len) {
            int count = in.read(b, off + n, len - n);
            if (count < 0)
                break;
            n += count;
        }
        return n;
    }
}

My final code now looks like this:

new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        try {
                            URI uri = URI.create("http://192.168.1.6:5000/api/tts");
                            HttpURLConnection urlConnection = (HttpURLConnection) uri.toURL().openConnection();
                            urlConnection.setRequestMethod("POST");
                            urlConnection.setRequestProperty("Content-Type", "application/json");
                            urlConnection.setRequestProperty("x-access-token", credentials.getAccessToken());
                            urlConnection.setRequestProperty("Accept", "*");
                            urlConnection.setChunkedStreamingMode(bufferSize);
                            urlConnection.setDoInput(true);
                            urlConnection.setDoOutput(true);
                            urlConnection.connect();
                            OutputStreamWriter osw = new OutputStreamWriter(urlConnection.getOutputStream());
                            String body = "{\"text\": \"" + text + "\", \"ttsLang\": \"" + language + "\"}";
                            Log.d("TTS_HTTP", body);
                            osw.write(body);
                            osw.flush();
                            osw.close();
                            Log.d("TTS_OUT", credentials.getAccessToken());
                            Log.d("TTS_OUT", urlConnection.getResponseCode() + " " + urlConnection.getResponseMessage());

                            // define the buffer size for audio track
                            int SAMPLE_RATE = 16000;
                            int bufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
                                    AudioFormat.ENCODING_PCM_16BIT);
                            if (bufferSize == AudioTrack.ERROR || bufferSize == AudioTrack.ERROR_BAD_VALUE) {
                                bufferSize = SAMPLE_RATE * 2;
                            }
                            bufferSize *= 2;
                            TTSInputStream bis = new TTSInputStream(urlConnection.getInputStream());
                            AudioTrack audioTrack = new AudioTrack(
                                    AudioManager.STREAM_MUSIC,
                                    SAMPLE_RATE,
                                    AudioFormat.CHANNEL_OUT_MONO,
                                    AudioFormat.ENCODING_PCM_16BIT,
                                    bufferSize * 2,
                                    AudioTrack.MODE_STREAM);
                            byte[] buffer = new byte[bufferSize];
                            audioTrack.play();
                            int count;
                            while ((count = bis.readFullyUntilEof(buffer)) > 0) {
                                Log.d("TTS_COUNT", "Read " + count + " bytes.");
                                audioTrack.write(buffer, 0, buffer.length);
                            }
                            bis.close();
                            audioTrack.stop();
                            audioTrack.release();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
        ).start();

Now my audio is playing well without any static noises. Hope this helps someone else having the same problem as me.

like image 77
Asym Avatar answered Mar 15 '23 22:03

Asym