OSDN Git Service

original
[gb-231r1-is01/GB_2.3_IS01.git] / cts / apps / CtsVerifier / src / com / android / cts / verifier / audioquality / Utils.java
diff --git a/cts/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/Utils.java b/cts/apps/CtsVerifier/src/com/android/cts/verifier/audioquality/Utils.java
new file mode 100644 (file)
index 0000000..885e18c
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audioquality;
+
+import android.content.Context;
+import android.media.AudioFormat;
+import android.media.AudioTrack;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * File and data utilities for the Audio Verifier.
+ */
+public class Utils {
+    public static final String TAG = "AudioQualityVerifier";
+    public static final ByteOrder BYTE_ORDER = ByteOrder.LITTLE_ENDIAN;
+
+    /**
+     *  Time delay.
+     *
+     *  @param ms time in milliseconds to pause for
+     */
+    public static void delay(int ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException e) {}
+    }
+
+    public static String getExternalDir(Context context, Object exp) {
+        checkExternalStorageAvailable();
+        // API level 8:
+        // return context.getExternalFilesDir(null).getAbsolutePath();
+        // API level < 8:
+        String dir = Environment.getExternalStorageDirectory().getAbsolutePath();
+        dir += "/Android/data/" + exp.getClass().getPackage().getName() + "/files";
+        checkMakeDir(dir);
+        return dir;
+    }
+
+    private static void checkExternalStorageAvailable() {
+        String state = Environment.getExternalStorageState();
+        if (!Environment.MEDIA_MOUNTED.equals(state)) {
+            // TODO: Raise a Toast and supply internal storage instead
+        }
+    }
+
+    private static void checkMakeDir(String dir) {
+        File f = new File(dir);
+        if (!f.exists()) {
+            f.mkdirs();
+        }
+    }
+
+    /**
+     * Convert a string (e.g. the name of an experiment) to something more suitable
+     * for use as a filename.
+     *
+     * @param s the string to be cleaned
+     * @return a string which is similar (not necessarily unique) and safe for filename use
+     */
+    public static String cleanString(String s) {
+        StringBuilder sb = new StringBuilder();
+        for (char c : s.toCharArray()) {
+            if (Character.isWhitespace(c)) sb.append('_');
+            else if (Character.isLetterOrDigit(c)) sb.append(c);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Convert a sub-array from bytes to shorts.
+     *
+     * @param data array of bytes to be converted
+     * @param start first index to convert (should be even)
+     * @param len number of bytes to convert (should be even)
+     * @return an array of half the length, containing shorts
+     */
+    public static short[] byteToShortArray(byte[] data, int start, int len) {
+        short[] samples = new short[len / 2];
+        ByteBuffer bb = ByteBuffer.wrap(data, start, len);
+        bb.order(BYTE_ORDER);
+        for (int i = 0; i < len / 2; i++) {
+            samples[i] = bb.getShort();
+        }
+        return samples;
+    }
+
+    /**
+     * Convert a byte array to an array of shorts (suitable for the phone test
+     * native library's audio sample data).
+     *
+     * @param data array of bytes to be converted
+     * @return an array of half the length, containing shorts
+     */
+    public static short[] byteToShortArray(byte[] data) {
+        int len = data.length / 2;
+        short[] samples = new short[len];
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        bb.order(BYTE_ORDER);
+        for (int i = 0; i < len; i++) {
+            samples[i] = bb.getShort();
+        }
+        return samples;
+    }
+
+    /**
+     * Convert a short array (as returned by the phone test native library)
+     * to an array of bytes.
+     *
+     * @param samples array of shorts to be converted
+     * @return an array of twice the length, broken out into bytes
+     */
+    public static byte[] shortToByteArray(short[] samples) {
+        int len = samples.length;
+        byte[] data = new byte[len * 2];
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        bb.order(BYTE_ORDER);
+        for (int i = 0; i < len; i++) {
+            bb.putShort(samples[i]);
+        }
+        return data;
+    }
+
+    /**
+     * Scale the amplitude of an array of samples.
+     *
+     * @param samples to be scaled
+     * @param db decibels to scale up by (may be negative)
+     * @return the scaled samples
+     */
+    public static short[] scale(short[] samples, float db) {
+        short[] scaled = new short[samples.length];
+        // Convert decibels to a linear ratio:
+        double ratio = Math.pow(10.0, db / 20.0);
+        for (int i = 0; i < samples.length; i++) {
+            scaled[i] = (short) (samples[i] * ratio);
+        }
+        return scaled;
+    }
+
+    /**
+     * Read an entire file into memory.
+     *
+     * @param filename to be opened
+     * @return the file data, or null in case of error
+     */
+    private static byte[] readFile(String filename) {
+        FileInputStream fis;
+        try {
+            fis = new FileInputStream(filename);
+        } catch (FileNotFoundException e1) {
+            return null;
+        }
+
+        File file = new File(filename);
+        int len = (int) file.length();
+        byte[] data = new byte[len];
+
+        int pos = 0;
+        int bytes = 0;
+        int count;
+        while (pos < len) {
+            try {
+                count = fis.read(data, pos, len - pos);
+            } catch (IOException e) {
+                return null;
+            }
+            if (count < 1) return null;
+            pos += count;
+        }
+
+        try {
+            fis.close();
+        } catch (IOException e) {}
+        return data;
+    }
+
+    /**
+     * Read an entire file from an InputStream.
+     * Useful as AssetManager returns these.
+     *
+     * @param stream to read file contents from
+     * @return file data
+     */
+    public static byte[] readFile(InputStream stream) {
+        final int CHUNK_SIZE = 10000;
+        ByteArrayBuilder bab = new ByteArrayBuilder();
+        byte[] buf = new byte[CHUNK_SIZE];
+        int count;
+        while (true) {
+            try {
+                count = stream.read(buf, 0, CHUNK_SIZE);
+            } catch (IOException e) {
+                return null;
+            }
+            if (count == -1) break; // EOF
+            bab.append(buf, count);
+        }
+        return bab.toByteArray();
+    }
+
+    /**
+     * Save binary (audio) data to a file.
+     *
+     * @param filename to be written
+     * @param data contents
+     */
+    public static void saveFile(String filename, byte[] data) {
+        try {
+            FileOutputStream fos = new FileOutputStream(filename);
+            fos.write(data);
+            fos.close();
+        } catch (IOException e) {
+            Log.e(TAG, "Error writing to file " + filename);
+        }
+    }
+
+    /**
+     * Push an entire array of audio data to an AudioTrack.
+     *
+     * @param at destination
+     * @param data to be written
+     * @return true if successful, or false on error
+     */
+    public static boolean writeAudio(AudioTrack at, byte[] data) {
+        int pos = 0;
+        int len = data.length;
+        int count;
+
+        while (pos < len) {
+            count = at.write(data, pos, len - pos);
+            if (count < 0) return false;
+            pos += count;
+        }
+        at.flush();
+        return true;
+    }
+
+    /**
+     * Determine the number of audio samples in a file
+     *
+     * @param filename file containing audio data
+     * @return number of samples in file, or 0 if file does not exist
+     */
+    public static int duration(String filename) {
+        File file = new File(filename);
+        int len = (int) file.length();
+        return len / AudioQualityVerifierActivity.BYTES_PER_SAMPLE;
+    }
+
+    /**
+     * Determine the number of audio samples in a stimulus asset
+     *
+     * @param context to look up stimulus
+     * @param stimNum index number of this stimulus
+     * @return number of samples in stimulus
+     */
+    public static int duration(Context context, int stimNum) {
+        byte[] data = AudioAssets.getStim(context, stimNum);
+        return data.length / AudioQualityVerifierActivity.BYTES_PER_SAMPLE;
+    }
+
+    public static void playRawFile(String filename) {
+        byte[] data = readFile(filename);
+        if (data == null) {
+            Log.e(TAG, "Cannot read " + filename);
+            return;
+        }
+        playRaw(data);
+    }
+
+    public static void playStim(Context context, int stimNum) {
+        Utils.playRaw(getStim(context, stimNum));
+    }
+
+    public static byte[] getStim(Context context, int stimNum) {
+        return AudioAssets.getStim(context, stimNum);
+    }
+
+    public static byte[] getPinkNoise(Context context, int ampl, int duration) {
+        return AudioAssets.getPinkNoise(context, ampl, duration);
+    }
+
+    public static void playRaw(byte[] data) {
+        Log.i(TAG, "Playing " + data.length + " bytes of pre-recorded audio");
+        AudioTrack at = new AudioTrack(AudioQualityVerifierActivity.PLAYBACK_STREAM, AudioQualityVerifierActivity.SAMPLE_RATE,
+                AudioFormat.CHANNEL_OUT_MONO, AudioQualityVerifierActivity.AUDIO_FORMAT,
+                data.length, AudioTrack.MODE_STREAM);
+        writeAudio(at, data);
+        at.play();
+    }
+
+    /**
+     * The equivalent of a simplified StringBuilder, but for bytes.
+     */
+    public static class ByteArrayBuilder {
+        private byte[] buf;
+        private int capacity, size;
+
+        public ByteArrayBuilder() {
+            capacity = 100;
+            size = 0;
+            buf = new byte[capacity];
+        }
+
+        public void append(byte[] b, int nBytes) {
+            if (nBytes < 1) return;
+            if (size + nBytes > capacity) expandCapacity(size + nBytes);
+            System.arraycopy(b, 0, buf, size, nBytes);
+            size += nBytes;
+        }
+
+        public byte[] toByteArray() {
+            byte[] result = new byte[size];
+            System.arraycopy(buf, 0, result, 0, size);
+            return result;
+        }
+
+        private void expandCapacity(int min) {
+            capacity *= 2;
+            if (capacity < min) capacity = min;
+            byte[] expanded = new byte[capacity];
+            System.arraycopy(buf, 0, expanded, 0, size);
+            buf = expanded;
+        }
+    }
+}