How To: Record Using a Microphone with the RICOH THETA Plug-in


#1

This article was originally published in Qiita by Mr. Kushimoto or Ricoh.

I edited the article and deleted some of the references to Japanese documents that we don’t have in English.

2018/10/09 Addendum: I confirmed that I can connect the speaker to THETA and play it at high volume! [Editor note: see related article]

Since the RICOH THETA V is an Android-based device, it can be expanded by installing an application. For the RICOH THETA, the application is called a plug-in.

In this article, I will show you how to record using the microphone with the THETA plug-in.

point

The points are as follows.

  • Set to record in monaural
  • Add permission to change audio settings

1. Set to record in monaural

THETA V is capable of recording 360 ° spatial sound by 4ch microphone.

When shooting movies using the Web API, you can acquire videos with spatial sounds, and you can also capture wav files of spatial sounds when shooting movies using the Camera API (For the Camera API, It is planned to be).

However, when using the standard Android API, it is not compatible with 360 ° spatial audio, so it is necessary to record in monaural.

THETA V adds some parameters to the AudioManager API.

By using the B-format Selection parameter, you can set to record in mono.

To set it to monaural, pass RicUseBFormat = false to setParameters () of AudioManager before using the microphone as below.

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audioManager.setParameters("RicUseBFormat=false");

2. Add authority to change audio settings

Since you change the audio setting using AudioManager as shown in 1, add the following authority to AndroidManifest.xml (RECORD_AUDIO is also required as it is necessary).

<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> 
<uses-permission android:name="android.permission.RECORD_AUDIO" />

Sample code

If you keep the above points, the rest is the same as general Android application development.

In this article, I tried to create a plugin to record using MediaRecorder as sample code.

The source code is at the bottom of this article.

Press the radio button to start recording, and press the wireless button again to end recording.

Recording sound can be played by pressing the shutter button.

Although you can understand when you run the sample code, the volume to be played is fairly small.

This is because the THETA V speaker is designed only to reproduce the original operation sound.

Although electronic sound can sound as it is, it is not strong for the recorded natural sound like this time, so please be careful when making plug-in with speaker.

It is like this when you move it.

Press the Wi-Fi button the side to start recording audio.

Press the Wi-Fi button again to stop recording audio

image

Playing Sound on THETA

As the THETA speaker is not intended to replay natural sounds, the speaker volume is low.

image

Although playing the sound on the THETA is soft, the sound file actually has the correct volume.

Transfer File to laptop

Playing the sound file on a laptop shows that the sound file was successfully recorded with the correct volume.

YouTube Video in Japanese

The video below is in Japanese, but you can follow along with the screenshots I put above that are in English. The main part is to listen to the sound clip from the laptop.

[Additional notes] I tried connecting a speaker to THETA

When playing with THETA, the volume was small, so I tried connecting the speaker to THETA via USB OTG.

See this article in English that describes Mr. Kushimoto’s successful use of an external speaker with the THETA to achive good sound volume.

(↓ is a link to YouTube in Japanese, but see the article above in English for the same information).

I was able to play with a loud volume!

The equipment I used this time is ↓.

  • USB DAC (USB Audio Class 1.0)
  • USB OTG adapter (converted to micro B because USB DAC was Type A)
  • Analog speaker (Built-in amplifier and battery)

In this experiment, you can play with the external speaker without changing the source code.

In other words, you can use OTG compliant USB device as it is with THETA! I understood that.

OTG USB support depends on the product. Some adapters will work and some won’t. Please experiment with each product!

Please be careful that we are not guaranteeing the operation with these equipment. Use this guide at your own responsibility

Summary

In this article, I showed you how to use a microphone with THETA.

If you keep the point unique to THETA V, you can develop it like a general Android application, so if you are an Android developer, please feel free to try it.

If you are interested in THETA plug-in development, please register with our partner program!

Please note that THETA serial number applied at the time of registration will not be subject to manufacturer support.

Source Code

This is available on GitHub or from the code listing below.

This is MainActivity.java

package com.theta360.pluginapplication;

import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.AudioSource;
import android.media.MediaRecorder.OutputFormat;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import com.theta360.pluginlibrary.activity.PluginActivity;
import com.theta360.pluginlibrary.callback.KeyCallback;
import com.theta360.pluginlibrary.receiver.KeyReceiver;
import com.theta360.pluginlibrary.values.LedColor;
import com.theta360.pluginlibrary.values.LedTarget;
import java.io.File;

public class MainActivity extends PluginActivity {

    private static final String RECORDER_TAG = "Recorder";
    private static final String PLAYER_TAG = "Player";

    private boolean isRecording = false;
    private MediaRecorder mediaRecorder;
    private String soundFilePath;

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

        soundFilePath = getFilesDir() + File.separator + "mySound.wav";

        setKeyCallback(new KeyCallback() {
            @Override
            public void onKeyDown(int keyCode, KeyEvent event) {
                if (keyCode == KeyReceiver.KEYCODE_WLAN_ON_OFF) {
                    if (!isRecording) {
                        startRecorder();
                        notificationLedBlink(LedTarget.LED7, LedColor.RED, 2000);
                    } else {
                        stopRecorder();
                        notificationLedHide(LedTarget.LED7);
                    }
                } else if (keyCode == KeyReceiver.KEYCODE_CAMERA && !isRecording) {
                    startPlayer();
                }
            }

            @Override
            public void onKeyUp(int keyCode, KeyEvent event) {
            }

            @Override
            public void onKeyLongPress(int keyCode, KeyEvent event) {
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        releaseMediaRecorder();
    }

    private void startRecorder() {
        new MediaRecorderPrepareTask().execute();
    }

    private void stopRecorder() {
        try {
            mediaRecorder.stop();
        } catch (RuntimeException e) {
            Log.d(RECORDER_TAG, "RuntimeException: stop() is called immediately after start()");
            deleteSoundFile();
        } finally {
            isRecording = false;
            releaseMediaRecorder();
        }
        Log.d(RECORDER_TAG, "Stop");
    }

    private void startPlayer() {
        File file = new File(soundFilePath);
        if (!file.exists()) {
            return;
        }
        file = null;

        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        int maxVol = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, maxVol, 0);

        MediaPlayer mediaPlayer = new MediaPlayer();
        AudioAttributes attributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build();
        try {
            mediaPlayer.setAudioAttributes(attributes);
            mediaPlayer.setDataSource(soundFilePath);
            mediaPlayer.setVolume(1.0f, 1.0f);
            mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mp.release();
                }
            });
            mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mp.start();
                }
            });
            mediaPlayer.prepare();
            Log.d(PLAYER_TAG, "Start");
        } catch (Exception e) {
            Log.e(RECORDER_TAG, "Exception starting MediaPlayer: " + e.getMessage());
            mediaPlayer.release();
            notificationError("");
        }
    }

    private boolean prepareMediaRecorder() {
        Log.d(RECORDER_TAG, soundFilePath);
        deleteSoundFile();

        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        audioManager.setParameters("RicUseBFormat=false");

        mediaRecorder = new MediaRecorder();
        mediaRecorder.setAudioSource(AudioSource.MIC);
        mediaRecorder.setOutputFormat(OutputFormat.DEFAULT);
        mediaRecorder.setAudioEncoder(AudioEncoder.DEFAULT);
        mediaRecorder.setOutputFile(soundFilePath);

        try {
            mediaRecorder.prepare();
        } catch (Exception e) {
            Log.e(RECORDER_TAG, "Exception preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        }

        return true;
    }

    private void releaseMediaRecorder() {
        if (mediaRecorder != null) {
            mediaRecorder.reset();
            mediaRecorder.release();
            mediaRecorder = null;
        }
    }

    private void deleteSoundFile() {
        File file = new File(soundFilePath);
        if (file.exists()) {
            file.delete();
        }
        file = null;
    }

    /**
     * Asynchronous task for preparing the {@link android.media.MediaRecorder} since it's a long
     * blocking operation.
     */
    private class MediaRecorderPrepareTask extends AsyncTask<Void, Void, Boolean> {

        @Override
        protected Boolean doInBackground(Void... voids) {
            if (prepareMediaRecorder()) {
                mediaRecorder.start();
                isRecording = true;
                return true;
            }
            return false;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            if (!result) {
                Log.e(RECORDER_TAG, "MediaRecorder prepare failed");
                notificationError("");
                return;
            }
            Log.d(RECORDER_TAG, "Start");
        }
    }

}