Utilizzando un flusso arbitrario come sorgente per MediaPlayer
-
26-10-2019 - |
Domanda
Vorrei utilizzare un InputStream arbitrario come origine dati per un oggetto MediaPlayer.
La ragione di questo è che l'InputStream sto utilizzando è in realtà un autorizzato connessione HTTPS a una risorsa multimediale su un server remoto. Passando l'URL in questo caso, ovviamente, non funzionerà come è necessaria un'autenticazione. Posso però fare l'autenticazione separatamente e ottenere un InputStream alla risorsa -? Problema è che cosa devo fare una volta l'ho
ho pensato alla possibilità di utilizzare un named pipe e passando la sua FileDescriptor al metodo setDataResource di MediaPlayer. C'è un modo per creare named pipe in Android (senza l'utilizzo di NDK)?
Ogni altro suggerimento è il benvenuto.
Soluzione 2
Un'altra soluzione potrebbe essere quella di avviare un server proxy HTTP su localhost. Il lettore multimediale si connetterà a questo server con setDataSource (contesto Context, Uri uri). Questa soluzione funziona meglio rispetto al precedente e non causa la riproduzione per problema tecnico.
Altri suggerimenti
Credo di aver trovato una soluzione. Vi sarei grato se gli altri che sono interessati avrebbero cercato questo da soli e riferire i risultati con i loro modelli di dispositivi e la versione SDK.
ho visto i messaggi simili che direttamente a questo, ma ho pensato di postare comunque dal momento che è più recente e sembra funzionare su versioni più recenti del SDK - finora funziona sul mio Nexus One con sistema operativo Android 2.3.6 <. / p>
La soluzione si basa sulla bufferring flusso di input in un file locale (ho questo file sulla memoria esterna, ma probabilmente sarà possibile posizionarlo sul stoccaggio intenal pure) e fornendo descrittore di file per l'istanza MediaPlayer.
I seguenti viene eseguito in una modalità doInBackground di qualche AsyncTask che fa AudioPlayback:
@Override
protected
Void doInBackground(LibraryItem... params)
{
...
MediaPlayer player = new MediaPlayer();
setListeners(player);
try {
_remoteStream = getMyInputStreamSomehow();
File tempFile = File.createTempFile(...);
tempFile.deleteOnExit();
_localInStream = new FileInputStream(tempFile);
_localOutStream = new FileOutputStream(tempFile);
int buffered = bufferMedia(
_remoteStream, _localOutStream, BUFFER_TARGET_SIZE // = 128KB for instance
);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource(_localInStream.getFD());
player.prepareAsync();
int streamed = 0;
while (buffered >= 0) {
buffered = bufferMedia(
_remoteStream, _localOutStream, BUFFER_TARGET_SIZE
);
}
}
catch (Exception exception) {
// Handle errors as you see fit
}
return null;
}
I bufferMedia metodo buffer nBytes byte o fino al raggiungimento della fine dell'input:
private
int bufferMedia(InputStream inStream, OutputStream outStream, int nBytes)
throws IOException
{
final int BUFFER_SIZE = 8 * (1 << 10);
byte[] buffer = new byte[BUFFER_SIZE]; // TODO: Do static allocation instead
int buffered = 0, read = -1;
while (buffered < nBytes) {
read = inStream.read(buffer);
if (read == -1) {
break;
}
outStream.write(buffer, 0, read);
outStream.flush();
buffered += read;
}
if (read == -1 && buffered == 0) {
return -1;
}
return buffered;
}
Il metodo setListeners imposta gestori per vari eventi MediaPlayer. La più importante è quella del OnCompletionListener che viene richiamato quando la riproduzione è stata completata. In caso di svuotamento del buffer (a causa, per esempio, connessione temporanea di rete lenta) il giocatore raggiungerà la fine del file locale e di transito per lo Stato PlaybackCompleted. Mi identifico quelle situazioni confrontando il posizione _localInStream contro la dimensione del flusso di ingresso. Se la posizione è più piccolo, quindi la riproduzione è ora davvero completata e I ha ripristinato il MediaPlayer:
private
void setListeners(MediaPlayer player)
{
// Set some other listeners as well
player.setOnSeekCompleteListener(
new MediaPlayer.OnSeekCompleteListener()
{
@Override
public
void onSeekComplete(MediaPlayer mp)
{
mp.start();
}
}
);
player.setOnCompletionListener(
new MediaPlayer.OnCompletionListener()
{
@Override
public
void onCompletion(MediaPlayer mp)
{
try {
long bytePosition = _localInStream.getChannel().position();
int timePosition = mp.getCurrentPosition();
int duration = mp.getDuration();
if (bytePosition < _track.size) {
mp.reset();
mp.setDataSource(_localInStream.getFD());
mp.prepare();
mp.seekTo(timePosition);
} else {
mp.release();
}
} catch (IOException exception) {
// Handle errors as you see fit
}
}
}
);
}