Question

Je voudrais utiliser un InputStream arbitraire en tant que source de données pour un objet MediaPlayer.

La raison est que le InputStream je me sers est en fait une connexion HTTPS autorisé à une ressource multimédia sur un serveur distant. En passant l'URL dans ce cas ne fonctionne évidemment pas comme une authentification est requise. Je peux cependant faire l'authentification séparément et obtenir un InputStream à la ressource - problème est que dois-je faire une fois que je l'ai

je pensais à la possibilité d'utiliser un tube nommé et passant son FileDescriptor à la méthode setDataResource de MediaPlayer. Est-il possible de créer des canaux nommés dans Android (sans utiliser NDK)?

Toute autre suggestion est la bienvenue.

Était-ce utile?

La solution 2

Une autre solution serait de démarrer un serveur HTTP proxy sur localhost. Le lecteur multimédia se connecte à ce serveur avec setDataSource (contexte de contexte, Uri uri). Cette solution fonctionne mieux que la précédente et ne provoque pas la lecture de pépin.

Autres conseils

Je crois que je l'ai trouvé une solution. Je vous serais reconnaissant si d'autres qui sont intéressés tenteraient de leur propre chef et rendre compte des résultats avec leurs modèles de périphériques et la version SDK.

J'ai vu des postes similaires qui dirigent à cela, mais je pensais que je posterais toute façon car il est plus récent et semble fonctionner sur les versions plus récentes du SDK - jusqu'à présent, il fonctionne sur mon Nexus One sous Android 2.3.6 <. / p>

La solution repose sur bufferring le flux d'entrée dans un fichier local (je ce fichier sur le stockage externe, mais il sera probablement possible de le placer sur le stockage intenal ainsi) et en fournissant le descripteur de ce fichier à l'instance MediaPlayer.

Les pistes suivantes dans une méthode doInBackground de certains AsyncTask qui fait 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;
}

Les tampons de méthode bufferMedia nBytes octets ou jusqu'à ce que soit atteinte la fin de l'entrée:

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;
}

La méthode setListeners définit des gestionnaires pour divers événements MediaPlayer. Le plus important est le OnCompletionListener qui est appelée lorsque la lecture est terminée. Dans le cas de (buffer underrun en raison, par exemple, la connexion réseau lente temporaire), le joueur atteindra la fin du fichier local et de transit à l'état PlaybackCompleted. J'identifie les situations en comparant la la position de _localInStream contre la taille du flux d'entrée. Si la position est plus petite, puis la lecture est vraiment terminée et réinitialiser le 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
                }
            }
        }
    );
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top