blob: 34655022952d3926a1c60c7b4652731a1f54af89 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.positioning;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;
public class UltrasoundGenerator {
private static final int FREQUENCY = 20000;
private static final int AMPLITUDE = 32767;
// Duration of the tone in seconds
private static final int DURATION = 1;
private static final int STEP_AMOUNT = 100;
private static final int BYTES_PER_SAMPLE = 2;
private static final int LOOP_COUNT = 10;
private static final int SAMPLE_RATE = AudioTrack.getNativeOutputSampleRate(
AudioTrack.MODE_STATIC);
private static final byte[] SOUND_BYTES = createSoundArray(FREQUENCY);
private static final String TAG = UltrasoundGenerator.class.getSimpleName();
private AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT,
SAMPLE_RATE *STEP_AMOUNT * 2 * DURATION, AudioTrack.MODE_STATIC);
UltrasoundGenerator() {
setAudioTrack();
}
public long playUltrasound() {
long startTime = System.nanoTime();
audioTrack.play();
return startTime;
}
public void stopUltrasound() {
if (audioTrack != null && audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
audioTrack.pause();
audioTrack.flush();
audioTrack.release();
}
}
private void setAudioTrack() {
int bytes = audioTrack.write(SOUND_BYTES, 0, SOUND_BYTES.length);
if (AudioTrack.ERROR_INVALID_OPERATION == bytes || AudioTrack.ERROR_BAD_VALUE == bytes) {
Log.d(TAG, "Failed writing to the audioTrack " + bytes);
}
audioTrack.setLoopPoints(0, SAMPLE_RATE * DURATION, LOOP_COUNT);
audioTrack.setNotificationMarkerPosition(SOUND_BYTES.length / 2);
audioTrack.setPlaybackPositionUpdateListener(
new AudioTrack.OnPlaybackPositionUpdateListener() {
@Override
public void onMarkerReached(AudioTrack track) {
Log.d(TAG, "Ultrasound sent at " + System.nanoTime());
}
@Override
public void onPeriodicNotification(AudioTrack track) {
}
});
}
/**
* Create a 16-bit PCM sinusoidal tone.
*
* @return A byte array containing the encoded tone.
*/
private static byte[] createSoundArray(double frequencyHz) {
int numSamples = DURATION * SAMPLE_RATE;
byte[] soundBytes = new byte[BYTES_PER_SAMPLE * numSamples];
double[] sampleTones = new double[numSamples];
for (int i = 0; i < numSamples; i++) {
sampleTones[i] = Math.sin(2 * Math.PI * (i / (SAMPLE_RATE / frequencyHz)));
}
int idx = 0;
for (final double dVal : sampleTones) {
final short val = (short) ((dVal * AMPLITUDE));
soundBytes[idx++] = (byte) (val & 0x00ff);
soundBytes[idx++] = (byte) ((val & 0xff00) >>> 8);
}
return soundBytes;
}
}