venerdì 27 gennaio 2017

AudioRecord su Android

Per registrare i dati raw dal microfono di Android e' necessario utilizzare AudioRecord (non MediaRecord)

quello che viene riportato in calce e' il codice per utilizzare questa libreria (e' un copia/incolla da piu' fonti...di mio non c'e' praticamente niente se non il fatto di avere messo insieme i pezzi per farlo funzionare da Android 6 in poi)

Un paio di trucchi: non e' sufficiente aggiungere i permessi di accedere al microfono (RECORD AUDIO) dentro al file  Manifest ma devono essere anche esplicitamente i permessi a livello di codice (la funzione requestRecordAudioPermission)

i dati vengono inseriti in un buffer per poi essere post processati e sono in formato di short signed (32768/-32767)


------------------------------

public class MainActivity extends AppCompatActivity {

    private Button play;
    final int SAMPLE_RATE = 8000;
    boolean mShouldContinue;
    String LOG_TAG = "Audio";
    private Button stop;


    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        requestRecordAudioPermission();

        play = (Button) findViewById(R.id.button);
        stop = (Button) findViewById(R.id.button2);

      
        play.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View view) {
                mShouldContinue = true;
                recordAudio();
            }
        });

        stop.setOnClickListener(new View.OnClickListener() {
            @Override            public void onClick(View view) {
                mShouldContinue = false;
            }
        });

    }


    private void requestRecordAudioPermission() {
        //check API version, do nothing if API version < 23!        int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        if (currentapiVersion > android.os.Build.VERSION_CODES.LOLLIPOP){

            if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {

                // Should we show an explanation?                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.RECORD_AUDIO)) {

                    // Show an expanation to the user *asynchronously* -- don't block                    // this thread waiting for the user's response! After the user                    // sees the explanation, try again to request the permission.
                } else {

                    // No explanation needed, we can request the permission.
                    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECORD_AUDIO}, 1);
                }
            }
        }
    }

    @Override    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case 1: {
                // If request is cancelled, the result arrays are empty.                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the                    // contacts-related task you need to do.                    Log.d("Activity", "Granted!");

                } else {

                    // permission denied, boo! Disable the                    // functionality that depends on this permission.                    Log.d("Activity", "Denied!");
                    finish();
                }
                return;
            }

            // other 'case' lines to check for other            // permissions this app might request        }
    }

    synchronized void recordAudio() {
        new Thread(new Runnable() {
            @Override            public void run() {
                Log.d(LOG_TAG, "Start ");

                android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);

                // buffer size in bytes                int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
                        AudioFormat.CHANNEL_IN_MONO,
                        AudioFormat.ENCODING_PCM_16BIT);
                Log.d(LOG_TAG, "Buffer Size " + Integer.toString(bufferSize));

                if (bufferSize == AudioRecord.ERROR || bufferSize == AudioRecord.ERROR_BAD_VALUE) {
                    bufferSize = SAMPLE_RATE * 2;
                }

                short[] audioBuffer = new short[bufferSize / 2];

                AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC,
                        SAMPLE_RATE,
                        AudioFormat.CHANNEL_IN_MONO,
                        AudioFormat.ENCODING_PCM_16BIT,
                        bufferSize);

                if (record.getState() != AudioRecord.STATE_INITIALIZED) {
                    Log.e(LOG_TAG, "Audio Record can't initialize!");
                    return;
                }
                record.startRecording();

                Log.v(LOG_TAG, "Start recording");

                long shortsRead = 0;
                while (mShouldContinue) {
                    int numberOfShort = record.read(audioBuffer, 0, audioBuffer.length);
                    shortsRead += numberOfShort;



                    for(int i = 0; i < numberOfShort; i++){
                        Log.d(LOG_TAG,String.valueOf(audioBuffer[i]));                    }

                }

                record.stop();
                record.release();

                Log.v(LOG_TAG, String.format("Recording stopped. Samples read: %d", shortsRead));

            }
        }).start();
    }
}