---
source_path: "api/sample/android/SnsrStreamAudioDeviceAndroid.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/android/SnsrStreamAudioDeviceAndroid/"
---

# SnsrStreamAudioDeviceAndroid.java

This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) implementation for Android.
It provides a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) adapter for [Android Audio][AudioRecord].

**Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider)

## Code

Available in this TrulyNatural SDK installation at
_~/Sensory/TrulyNaturalSDK/7.9.0-pre.0/sample/android/misc/SnsrStreamAudioDeviceAndroid.java_

**SnsrStreamAudioDeviceAndroid.java:**

```java
/* Sensory Confidential
 * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/
 *
 * Android AudioRecord to read-only SnsrStream adapter.
 *------------------------------------------------------------------------------
 */

package com.sensory.speech.snsr;

import java.io.IOException;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioSource;

import com.sensory.speech.snsr.SnsrStream;

/*
 * Implements the SnsrStream.Provider interface for live audio.
 *
 * Create a new SnsrStream instance with:
 * SnsrStream a = SnsrStream.fromProvider(new SnsrStreamAudioDeviceAndroid(16000),
 *                                        SnsrStreamMode.READ);
*/
class SnsrStreamAudioDeviceAndroid implements SnsrStream.Provider {
    private static final String TAG = "SnsrStreamAudioDeviceAndroid";
    private static final int CHANNELS = AudioFormat.CHANNEL_IN_MONO;
    private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    private int mSource = AudioSource.VOICE_RECOGNITION;
    /* Use an audio buffer that is at least this long */
    private static final int MIN_BUFFER_SIZE_MS = 1000;
    private AudioRecord mAudio;
    private int mBufferSize;
    private int mSampleRate;

    /**
     * Static constructor.
     * @param[in] sampleRate the sample rate. Use 16000.
     */
    public SnsrStreamAudioDeviceAndroid(int source, int sampleRate) {
        double minBufferSize = (double)sampleRate * MIN_BUFFER_SIZE_MS / 1000;
        mBufferSize =
          AudioRecord.getMinBufferSize(sampleRate, CHANNELS, ENCODING);
        if (mBufferSize < minBufferSize) {
          mBufferSize =
            mBufferSize * (int)Math.ceil(minBufferSize / mBufferSize);
        }
        mSampleRate = sampleRate;
        mSource = source;
    }

    /**
     * Static constructor with VOICE_RECOGNITION source.
     * @param[source] recording source.
     * @param[in] sampleRate the sample rate. Use 16000.
     */
    public SnsrStreamAudioDeviceAndroid(int sampleRate) {
      this(AudioSource.VOICE_RECOGNITION, sampleRate);
    }

    @Override
    public long onOpen() throws IOException {
        mAudio = new AudioRecord(mSource, mSampleRate,
                                 CHANNELS, ENCODING, mBufferSize);
        if (mAudio == null ||
            mAudio.getState() != AudioRecord.STATE_INITIALIZED) {
          mAudio = null;
          throw new IOException("Could not initialize audio device at " +
                                mSampleRate + " Hz.");
        }
        try {
          mAudio.startRecording();
        } catch (IllegalStateException e) {
          mAudio = null;
          throw new IOException(e.toString());
        }
        return OK;
    }

    @Override
    public long onClose() throws IOException {
        try {
            mAudio.stop();
        } catch (IllegalStateException e) {
          // ignore
        }
        mAudio.release();
        mAudio = null;
        return OK;
    }

    @Override
    public void onRelease() {
        if (mAudio != null) mAudio.release();
        mAudio = null;
    }

    @Override
    public long onRead(byte[] buffer) throws IOException {
      int read = mAudio.read(buffer, 0, buffer.length);
      if (Thread.interrupted()) return INTERRUPTED;
      if (read == AudioRecord.ERROR_BAD_VALUE) return INVALID_ARG;
      else if (read < 0) return ERROR;
      return read;
    }

    @Override
    public long onWrite(byte[] buffer) throws IOException {
      return NOT_IMPLEMENTED;
    }
}

```

<!-- Reference definitions from includes/links.md -->
[AudioRecord]: https://developer.android.com/reference/android/media/AudioRecord "Android AudioRecord class"

<!-- Abbreviation definitions from includes/abbreviations.md -->
*[API]: Application Programming Interface
*[SDK]: Software Development Kit
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
