web-dev-qa-db-fra.com

Android - Lecture de mp3 à partir de byte []

J'ai mon fichier mp3 en byte [] (téléchargé depuis un service) et j'aimerais le lire sur mon appareil de la même manière que vous pouvez lire des fichiers:

MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
mp.prepare();
mp.start();

Mais je n'arrive pas à trouver un moyen de le faire. Cela ne me dérangerait pas de sauvegarder le fichier sur le téléphone, puis de le lire. Comment puis-je lire le fichier ou le télécharger puis le lire?

29
kape123

D'accord, merci à vous tous, mais j'avais besoin de lire des fichiers MP3 à partir d'octets [], ainsi que de Webservice .NET (vous ne souhaitez pas stocker des fichiers MP3 générés dynamiquement sur le serveur).

En fin de compte - il y a un certain nombre de "pièges" pour jouer en simple mp3 ... voici du code pour ceux qui en ont besoin:

private MediaPlayer mediaPlayer = new MediaPlayer();
private void playMp3(byte[] mp3SoundByteArray) {
    try {
        // create temp file that will hold byte array
        File tempMp3 = File.createTempFile("kurchina", "mp3", getCacheDir());
        tempMp3.deleteOnExit();
        FileOutputStream fos = new FileOutputStream(tempMp3);
        fos.write(mp3SoundByteArray);
        fos.close();

        // resetting mediaplayer instance to evade problems
        mediaPlayer.reset();

        // In case you run into issues with threading consider new instance like:
        // MediaPlayer mediaPlayer = new MediaPlayer();                     

        // Tried passing path directly, but kept getting 
        // "Prepare failed.: status=0x1"
        // so using file descriptor instead
        FileInputStream fis = new FileInputStream(tempMp3);
        mediaPlayer.setDataSource(fis.getFD());

        mediaPlayer.prepare();
        mediaPlayer.start();
    } catch (IOException ex) {
        String s = ex.toString();
        ex.printStackTrace();
    }
}

EDIT: J'ai écrit cette réponse il y a plus de 4 ans - évidemment, beaucoup de choses ont changé depuis. Voir le commentaire de Justin sur la façon de réutiliser l'instance de MediaPlayer. De plus, je ne sais pas si .deleteOnExit () fonctionnera pour vous maintenant - n'hésitez pas à suggérer des améliorations afin que les fichiers temporaires ne s'empilent pas.

73
kape123

J'ai trouvé une solution facile en encodant mon fichier MP3 en Base64 (je reçois déjà les données encodées d'un service API Restful), puis en créant un objet URL. Je l'ai testé sous Android 4.1.

public void PlayAudio(String base64EncodedString){
        try
        {
            String url = "data:audio/mp3;base64,"+base64EncodedString; 
            MediaPlayer mediaPlayer = new MediaPlayer();
            mediaPlayer.setDataSource(url);
            mediaPlayer.prepare();
            mediaPlayer.start();
        }
        catch(Exception ex){
            System.out.print(ex.getMessage());
        }
    }
9
Max Vargas

À partir d'Android MarshMellow (version 23), une nouvelle API rendra cela possible.

MediaPlayer.setDataSource (Android.media.MediaDataSource)

Vous pouvez fournir une implémentation personnalisée de MediaDataSource et encapsuler un octet []. Une implémentation de base donnée ci-dessous.

import Android.annotation.TargetApi;
import Android.media.MediaDataSource;
import Android.os.Build;
import Java.io.IOException;


@TargetApi(Build.VERSION_CODES.M)
public class ByteArrayMediaDataSource extends MediaDataSource {

    private final byte[] data;

    public ByteArrayMediaDataSource(byte []data) {
        assert data != null;
        this.data = data;
    }
    @Override
    public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
        System.arraycopy(data, (int)position, buffer, offset, size);
        return size;
    }

    @Override
    public long getSize() throws IOException {
        return data.length;
    }

    @Override
    public void close() throws IOException {
        // Nothing to do here
    }
}
6
krishnakumarp

Pas sûr des bytearrays/bytestreams, mais si vous avez une URL du service, vous pouvez essayer de définir la source de données sur un URI réseau en appelant 

setDataSource(Context context, Uri uri)

Voir la Documentation API .

5
Yoni Samlan

mauvais code:

 MediaPlayer mp = new MediaPlayer();
 mp.setDataSource(PATH_TO_FILE);
 mp.prepare();
 mp.start();

CODE CORRECT:

 MediaPlayer mp = new MediaPlayer();
 mp.setDataSource(PATH_TO_FILE);
 mp.setOnpreparedListener(this);
 mp.prepare();

//Implement OnPreparedListener 
OnPrepared() {
    mp.start();
 }

voir les démonstrations de l'API ..

1
subbarao

Si vous ciblez l'API 23 et supérieure, créez une classe comme celle-ci.

class MyMediaDataSource(val data: ByteArray) : MediaDataSource() {

override fun readAt(position: Long, buffer: ByteArray, offset: Int, size: Int): Int {

    if (position >= data.size) return -1 // -1 indicates EOF 

    val endPosition: Int = (position + size).toInt()
    var size2: Int = size
    if (endPosition > data.size)
        size2 -= endPosition - data.size

    System.arraycopy(data, position.toInt(), buffer, offset, size2)
    return size2
}

override fun getSize(): Long {
    return data.size.toLong()
}

override fun close() {}

}

et utiliser comme ça 

val mediaSource = MyMediaDataSource(byteArray)
MediaPlayer().apply {
    setAudioStreamType(AudioManager.STREAM_MUSIC)
    setDataSource(mediaSource)
    setOnCompletionListener { release() }
    prepareAsync()
    setOnPreparedListener { start() }
}

crédits à la réponse de krishnakumarp ci-dessus et à cet article

0
Dan Alboteanu