/*
* Copyright (C) 2010 Google Inc.
*
* 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.ringdroid;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.util.Date;
import java.util.Random;
/**
* Some phones such as the HTC Hero and Droid Eris do not support
* MediaPlayer.setDataSource with an offset into the file, which
* Ringdroid likes to use to more precisely seek in an MP3 file.
*
* This class creates a temporary MP3 file containing silence,
* attempts to play only the last fraction of that file and then
* uses the timing information to determine if this API function
* works correctly on this particular phone.
*
* This result is then cached, so the delay only needs to happen once.
*/
public class SeekTest {
public static final String PREF_SEEK_TEST_RESULT = "seek_test_result";
public static final String PREF_SEEK_TEST_DATE = "seek_test_date";
static long before;
static long after;
static boolean CanSeekAccurately(SharedPreferences prefs) {
Log.i("Ringdroid", "Running CanSeekAccurately");
boolean result = false;
result = prefs.getBoolean(PREF_SEEK_TEST_RESULT, false);
long testDate = prefs.getLong(PREF_SEEK_TEST_DATE, 0);
long now = (new Date()).getTime();
long oneWeekMS = 1000 * 60 * 60 * 24 * 7;
if (now - testDate < oneWeekMS) {
Log.i("Ringdroid", "Fast MP3 seek result cached: " + result);
return result;
}
String filename = "/sdcard/silence" + new Random().nextLong() + ".mp3";
File file = new File(filename);
boolean ok = false;
try {
RandomAccessFile f = new RandomAccessFile(file, "r");
} catch (Exception e) {
// Good, the file didn't exist
ok = true;
}
if (!ok) {
Log.i("Ringdroid", "Couldn't find temporary filename");
return false;
}
Log.i("Ringdroid", "Writing " + filename);
try {
file.createNewFile();
} catch (Exception e) {
// Darn, couldn't output for writing
Log.i("Ringdroid", "Couldn't output for writing");
return false;
}
try {
FileOutputStream out = new FileOutputStream(file);
for (int i = 0; i < 80; i++) {
out.write(SILENCE_MP3_FRAME, 0, SILENCE_MP3_FRAME.length);
}
} catch (Exception e) {
Log.i("Ringdroid", "Couldn't write temp silence file");
try {
file.delete();
} catch (Exception e2) {}
return false;
}
try {
Log.i("Ringdroid", "File written, starting to play");
MediaPlayer player = new MediaPlayer();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
FileInputStream subsetInputStream = new FileInputStream(filename);
long start = 70 * SILENCE_MP3_FRAME.length;
long len = 10 * SILENCE_MP3_FRAME.length;
player.setDataSource(subsetInputStream.getFD(),
start,
len);
Log.i("Ringdroid", "Preparing");
player.prepare();
before = 0;
after = 0;
player.setOnCompletionListener(new OnCompletionListener() {
public synchronized void onCompletion(MediaPlayer arg0) {
Log.i("Ringdroid", "Got callback");
after = System.currentTimeMillis();
}
});
Log.i("Ringdroid", "Starting");
player.start();
for (int i = 0; i < 200 && before == 0; i++) {
if (player.getCurrentPosition() > 0) {
Log.i("Ringdroid", "Started playing after " + (i * 10) +
" ms");
before = System.currentTimeMillis();
}
Thread.sleep(10);
}
if (before == 0) {
Log.i("Ringdroid", "Never started playing.");
Log.i("Ringdroid", "Fast MP3 seek disabled by default");
try {
file.delete();
} catch (Exception e2) {}
SharedPreferences.Editor prefsEditor = prefs.edit();
prefsEditor.putLong(PREF_SEEK_TEST_DATE, now);
prefsEditor.putBoolean(PREF_SEEK_TEST_RESULT, result);
prefsEditor.commit();
return false;
}
Log.i("Ringdroid", "Sleeping");
for (int i = 0; i < 300 && after == 0; i++) {
Log.i("Ringdroid", "Pos: " + player.getCurrentPosition());
Thread.sleep(10);
}
Log.i("Ringdroid", "Result: " + before + ", " + after);
if (after > before && after < before + 2000) {
long delta = after > before? after - before: -1;
Log.i("Ringdroid", "Fast MP3 seek enabled: " + delta);
result = true;
} else {
Log.i("Ringdroid", "Fast MP3 seek disabled");
}
} catch (Exception e) {
e.printStackTrace();
Log.i("Ringdroid", "Couldn't play: " + e.toString());
Log.i("Ringdroid", "Fast MP3 seek disabled by default");
try {
file.delete();
} catch (Exception e2) {}
SharedPreferences.Editor prefsEditor = prefs.edit();
prefsEditor.putLong(PREF_SEEK_TEST_DATE, now);
prefsEditor.putBoolean(PREF_SEEK_TEST_RESULT, result);
prefsEditor.commit();
return false;
}
SharedPreferences.Editor prefsEditor = prefs.edit();
prefsEditor.putLong(PREF_SEEK_TEST_DATE, now);
prefsEditor.putBoolean(PREF_SEEK_TEST_RESULT, result);
prefsEditor.commit();
try {
file.delete();
} catch (Exception e) {}
return result;
}
static private byte SILENCE_MP3_FRAME[] = {
(byte)0xff, (byte)0xfb, (byte)0x10, (byte)0xc4, (byte)0x00,
(byte)0x03, (byte)0x81, (byte)0xf4, (byte)0x01, (byte)0x26,
(byte)0x60, (byte)0x00, (byte)0x40, (byte)0x20, (byte)0x59,
(byte)0x80, (byte)0x23, (byte)0x48, (byte)0x00, (byte)0x09,
(byte)0x74, (byte)0x00, (byte)0x01, (byte)0x12, (byte)0x03,
(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfe,
(byte)0x9f, (byte)0x63, (byte)0xbf, (byte)0xd1, (byte)0x7a,
(byte)0x3f, (byte)0x5d, (byte)0x01, (byte)0xff, (byte)0xff,
(byte)0xff, (byte)0xff, (byte)0xfe, (byte)0x8d, (byte)0xad,
(byte)0x6c, (byte)0x31, (byte)0x42, (byte)0xc3, (byte)0x02,
(byte)0xc7, (byte)0x0c, (byte)0x09, (byte)0x86, (byte)0x83,
(byte)0xa8, (byte)0x7a, (byte)0x3a, (byte)0x68, (byte)0x4c,
(byte)0x41, (byte)0x4d, (byte)0x45, (byte)0x33, (byte)0x2e,
(byte)0x39, (byte)0x38, (byte)0x2e, (byte)0x32, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
}