Ich schreibe eine Anwendung zum Abspielen von Audio vom Remote-Server. Ich habe verschiedene Möglichkeiten versucht, Streaming-Audio zu implementieren, aber alle sind nicht gut genug für mich. Das ist, was ich versucht habe:Best Practices für Audio-Streaming
Naive von Mediaplayer mit
Etwas wie:
MediaPlayer player = new MediaPlayer();
player.setDataSource(context, Uri.parse("http://whatever.com/track.mp3"));
player.prepare();
player.start();
(oder prepareAsync
, egal)
Aber Standard MediaPlayer
ist ziemlich instabil, wenn die Fern spielen Inhalt. Es fällt oft ab oder stoppt die Wiedergabe und ich kann das nicht verarbeiten. Auf der anderen Seite möchte ich Media Caching implementieren. Ich habe jedoch keine Möglichkeit gefunden, gepufferten Inhalt vom MediaPlayer zu holen, um ihn irgendwo auf dem Gerät zu speichern.
Implementierung eigene Puffer
Dann wurde es eine Idee Mediendatei von Chunks herunterladen, um sie in einer lokalen Datei kombinieren und diese Datei spielen. Das Herunterladen der gesamten Datei kann wegen schlechter Verbindung langsam sein, daher ist es in Ordnung, zunächst genug Stück herunterzuladen, dann die Wiedergabe zu starten und das Herunterladen und Anhängen der lokalen Datei fortzusetzen. Außerdem erhalten wir Caching-Funktionalität.
Klingt wie ein Plan, aber es hat nicht immer funktioniert. Es funktioniert perfekt auf HTC Sensation XE, aber nicht auf 4.1 Tablet-Wiedergabe gestoppt nach Abschluss dieses ersten Stück. Weiß nicht, warum ist das so. Ich habe question darüber gefragt, aber keine Antworten erhalten.
Verwendung von zwei Mediaplayers
Ich habe zwei Mediaplayer-Instanzen erstellt und versucht, sie einander zu machen ändern. Die Logik ist folgende:
- starten Anfangsstück Medien
- Download Wenn es heruntergeladen haben, starten Sie die Wiedergabe über currentMediaPlayer. Der Rest der Medien weiterhin Download
- Wenn heruntergeladen Stück fast gespielt wird (1 sec vor Ende), bereiten secondaryMediaPlayer mit der gleichen Quelldatei
- 261 ms vor dem Abgang von currentMediaPlayer (wie es bei der Wiedergabe angehängt wurde) - es pausiert , starte sekundär, setze sekundär als aktuell, plane die Vorbereitung des nächsten sekundären Spielers.
Die Quelle:
private static final String FILE_NAME="local.mp3";
private static final String URL = ...;
private static final long FILE_SIZE = 7084032;
private static final long PREPARE_NEXT_PLAYER_OFFSET = 1000;
private static final int START_NEXT_OFFSET = 261;
private static final int INIT_PERCENTAGE = 3;
private MediaPlayer mPlayer;
private MediaPlayer mSecondaryPlayer;
private Handler mHandler = new Handler();
public void startDownload() {
mDownloader = new Mp3Downloader(FILE_NAME, URL, getExternalCacheDir());
mDownloader.setDownloadListener(mInitDownloadListener);
mDownloader.startDownload();
}
private Mp3Downloader.DownloadListener mInitDownloadListener = new Mp3Downloader.DownloadListener() {
public void onDownloaded(long bytes) {
int percentage = Math.round(bytes * 100f/FILE_SIZE);
// Start playback when appropriate piece of media downloaded
if (percentage >= INIT_PERCENTAGE) {
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath());
mPlayer.prepare();
mPlayer.start();
mHandler.postDelayed(prepareSecondaryPlayerRunnable, mPlayer.getDuration() - PREPARE_NEXT_PLAYER_OFFSET);
mHandler.postDelayed(startNextPlayerRunnable, mPlayer.getDuration() - START_NEXT_OFFSET);
} catch (IOException e) {
Log.e(e);
}
mDownloader.setDownloadListener(null);
}
}
};
// Starting to prepare secondary MediaPlayer
private Runnable prepareSecondaryPlayerRunnable = new Runnable() {
public void run() {
mSecondaryPlayer = new MediaPlayer();
try {
mSecondaryPlayer.setDataSource(mDownloader.getDownloadingFile().getAbsolutePath());
mSecondaryPlayer.prepare();
mSecondaryPlayer.seekTo(mPlayer.getDuration() - START_NEXT_OFFSET);
} catch (IOException e) {
Log.e(e);
}
}
};
// Starting secondary MediaPlayer playback, scheduling creating next MediaPlayer
private Runnable startNextPlayerRunnable = new Runnable() {
public void run() {
mSecondaryPlayer.start();
mHandler.postDelayed(prepareSecondaryPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - PREPARE_NEXT_PLAYER_OFFSET);
mHandler.postDelayed(startNextPlayerRunnable, mSecondaryPlayer.getDuration() - mPlayer.getCurrentPosition() - START_NEXT_OFFSET);
mPlayer.pause();
mPlayer.release();
mPlayer = mSecondaryPlayer;
}
};
Again - Töne, wie ein Plan funktioniert, aber nicht perfekt. Die Momente des Wechselns von MediaPlayern sind durchaus hörbar. Hier habe ich entgegengesetzte Situation: auf 4.1 Tablet ist es ok, aber auf HTC Sensation gibt es deutliche Verzögerungen.
Ich habe auch versucht, verschiedene Download-Techniken zu implementieren. Ich habe Download von 10Kb Chunks und von MP3-Frames implementiert. Ich weiß es nicht genau, aber es scheint, dass im Falle von MP3-Frames suchen und besser arbeiten. Aber es ist nur ein Gefühl, ich weiß keine Erklärung.
StreamingMediaPlayer
Ich sah mehrmals auf dieses Wort während googeln und fand diese Implementierung: https://code.google.com/p/mynpr/source/browse/trunk/mynpr/src/com/webeclubbin/mynpr/StreamingMediaPlayer.java?r=18
Es wird eine Lösung jeder benutzen?
Wenn ja, ist es traurig, denn es funktioniert auch nicht gut für mich. Und ich sehe keine neuen Ideen in der Umsetzung.
Also, die Frage
Wie implementiere ihr Audio-Streaming in Ihren Anwendungen? Ich glaube nicht, dass ich die einzige Person bin, die solche Probleme hatte. Es sollte einige gute Praktiken geben.
Sehr nette Frage ... Es nervt mich auch für die letzten 2 Wochen ... Aber ich brauche es für Video-Streaming von einem Gerät zum anderen ... –
für Audio-Streaming sollten Sie Ihre eigenen benutzerdefinierten Player mit Android-Diensten verwenden –
Gute Frage ... Leider ist der MediaPlayer von Android einer der schlechtesten Softwares, die je geschrieben wurden. – StackOverflowed