web-dev-qa-db-fra.com

MediaPlayer.setDataSource (String) ne fonctionne pas avec les fichiers locaux

Je suis en mesure de lire un fichier MP3 local si j'utilise la méthode statique MediaPlayer.create (contexte, id), mais cela ne fonctionne pas si j'utilise la méthode non statique MediaPlayer.setDataSource (String). Ce qui se passe, c'est que je reçois une exception synchrone lorsque j'appelle MediaPlayer.prepare ():

prepare exceptionjava.io.IOException: Prepare failed.: status=0x1

Voici mon code (enregistrement omis):

String filename = "Android.resource://" + this.getPackageName() + "/raw/test0";

mp = new MediaPlayer();
try { mp.setDataSource(filename); } catch (Exception e) {}
try { mp.prepare(); } catch (Exception e) {}
mp.start();

Notez que je ne reçois pas d'erreur sur le fichier non trouvé ou quoi que ce soit. Le nom complet du fichier est test0.mp3 et je le place dans le répertoire/res/raw/d'Eclipse.

Je suppose que le chemin est mal défini, mais que tous les exemples que je trouve en ligne utilisent la version FileDescriptor de setDataPath au lieu de la version String de setDataPath.

EDIT: Je peux également lire un fichier MP3 local si j'utilise la méthode MediaPlayer.setDataSource (FileDescriptor) et que je place les fichiers dans le répertoire/assets/de Eclipse.

EDIT # 2: j’ai accepté la réponse selon laquelle cela n’était pas possible, mais j’ai alors réalisé que la bibliothèque que j’utilise (openFrameworks) utilise effectivement la méthode String pour charger un fichier. Vois ici: 

https://github.com/openframeworks/openFrameworks/blob/master/addons/ofxAndroid/ofAndroidLib/src/cc/openframeworks/OFAndroidSoundPlayer.Java

23
user755921

Solution alternative n ° 1: Utilisation de Resources.getIdentifier ()

Pourquoi ne pas utiliser getResources (). GetIdentifier () pour obtenir l'identifiant de la ressource et utiliser le MediaPlayer.create () statique comme d'habitude? 

public int getIdentifier (String name, String defType, String defPackage)

getIdentifier () prend votre nom de ressource (test0), votre type de ressource (brut), votre nom de package et renvoie l'identifiant de ressource réel.

 MediaPlayer mp;
 //String filename = "Android.resource://" + this.getPackageName() + "/raw/test0";
 mp=MediaPlayer.create(getApplicationContext(), getResources().getIdentifier("test0","raw",getPackageName()));
 mp.start();

J'ai testé ce code et cela fonctionne.


Update # 1:

Solution alternative n ° 2: Utiliser Uri.parse ()

J'ai aussi testé ce code et cela fonctionne aussi. Passez votre chemin de ressource en tant qu'URI à setDataSource (). Je viens d'apporter ce changement à votre code pour que cela fonctionne.

String filename = "Android.resource://" + this.getPackageName() + "/raw/test0";

mp = new MediaPlayer();
try { mp.setDataSource(this,Uri.parse(filename)); } catch (Exception e) {}
try { mp.prepare(); } catch (Exception e) {}
mp.start();


Mise à jour 2: la réponse est NON

À propos de l'appel setDataSource (String)

Après avoir vu votre commentaire, il semble que vous souhaitiez exactement que setDataSource (chaîne) soit utilisé à cette fin. Je ne comprends pas pourquoi. Mais ce que je suppose, c’est pour une raison quelconque que vous essayez d’éviter d’utiliser le "contexte". Si ce n'est pas le cas, les deux solutions ci-dessus devraient fonctionner parfaitement pour vous ou si vous essayez d'éviter le contexte, je crains que ce ne soit pas possible avec la fonction avec signature, appelez la méthode setDataSource (String). La raison est comme ci-dessous,

MediaPlayer La fonction setDataSource () propose les options suivantes, parmi lesquelles vous ne vous intéressez qu'à setDataSource (String),

 setDataSource Functions

setDataSource (String) appelle en interne la fonction setDataSource (chemin de la chaîne, clés de chaîne [], valeurs de chaîne []). Si vous pouvez vérifier sa source ,

public void setDataSource(String path)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(path, null, null);
    }

et si vous cochez le code setDataSource (chemin de la chaîne, clés [], valeurs de la chaîne []), vous verrez la condition ci-dessous filtrer le chemin en fonction de son schéma, en particulier s'il s'agit d'un schéma "fichier" qu'il appelle setDataSource (FileDescriptor) ou si scheme n'est pas "fichier", il appelle la fonction de média JNI natif. 

{
        final Uri uri = Uri.parse(path);
        final String scheme = uri.getScheme();
        if ("file".equals(scheme)) {
            path = uri.getPath();
        } else if (scheme != null) {
            // handle non-file sources
            nativeSetDataSource(
                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
                path,
                keys,
                values);
            return;
        }
        final File file = new File(path);
        if (file.exists()) {
            FileInputStream is = new FileInputStream(file);
            FileDescriptor fd = is.getFD();
            setDataSource(fd);
            is.close();
        } else {
            throw new IOException("setDataSource failed.");
        }
}

Dans le code ci-dessus, votre schéma d'URI de fichier de ressources ne sera pas nul (Android.resource: //) et setDataSource (String) tentera d'utiliser la fonction JNI native nativeSetDataSource () en pensant que votre chemin est http/https/rtsp et évidemment, cet appel échouera également sans exception, ce qui explique pourquoi votre appel à setDataSource (String) s'échappe sans exception et arrive à préparer l'appel () avec l'exception suivante. 

Prepare failed.: status=0x1

Donc, la substitution setDataSource (String) ne peut pas gérer votre fichier de ressources. Vous devez choisir un autre remplacement pour cela.

De l’autre côté, cochez setDataSource (contexte de contexte, Uri uri, en-têtes de carte) utilisé par setDataSource (contexte de contexte, Uri uri), il utilise AssetFileDescriptor, ContentResolver de votre contexte et openAssetFileDescriptor pour ouvrir l’URI ayant le succès openAssetFileDescriptor ( ) peut ouvrir votre fichier de ressources et finalement le fd résultant est utilisé pour appeler le remplacement de setDataSource (FileDescriptor).

    AssetFileDescriptor fd = null;
    try {
        ContentResolver resolver = context.getContentResolver();
        fd = resolver.openAssetFileDescriptor(uri, "r");
        //  :
        //  :
        //  :
        if (fd.getDeclaredLength() < 0) {
                setDataSource(fd.getFileDescriptor());
            } else {
                setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getDeclaredLength());
            }

Pour conclure, vous ne pouvez pas utiliser le remplacement de setDataSource (String), comme c'est le cas pour utiliser votre fichier de ressources mp3. Si vous souhaitez utiliser string pour lire votre fichier de ressources, vous pouvez utiliser la fonction statique MediaPlayer.create () avec getIdentifier () comme indiqué ci-dessus ou setDataSource (context, uri) comme indiqué dans la mise à jour # 1.

Reportez-vous au code source complet pour plus de compréhension ici: Android MediaPlayer


Update # 3:

openFrameworks setDataSource (String):

Comme je l'ai mentionné dans les commentaires ci-dessous, openFrameworks utilise le code asis Android MediaPlayer. Si vous pouvez vous référer à la ligne n ° 4,

import Android.media.MediaPlayer;

et numéro de ligne: 26, 27, 28 et 218

        player = new MediaPlayer();       //26
        player.setDataSource(fileName);   //27
        player.prepare();                 //28

        private MediaPlayer player;       //218

Donc, si vous essayez de passer ardroid.resource // + this.getPackageName () + "raw/test0" à setDataSource () à l'aide de openFrameworks, vous obtiendrez toujours la même exception que celle décrite dans Mise à jour # 2 Cela dit, j'ai juste tenté ma chance en cherchant sur Google pour vérifier ce que je disais et j'ai trouvé ceci lien vers le forum openFrameworks où l'un des développeur principal openFrameworks arturo dit: 

je ne sais pas exactement comment fonctionne mediaPlayer, mais tout est dans res/raw ou bin/data est copié dans /sdcard/cc.openframeworks.packagename

Sur la base de ce commentaire, vous pouvez essayer d'utiliser le chemin copié dans setDataSource (). L'utilisation du fichier de ressources sur setDataSource (String) de MediaPlayer n'est pas possible car il ne peut pas accepter le chemin du fichier de ressources. Veuillez noter que j'ai dit que "chemin du fichier de ressources" commençait par le schéma Android.resource // qui est en fait un emplacement de jar (dans votre apk) et non un emplacement physique. Le fichier local fonctionnera avec setDataSource (String) qui commence par le schéma file: //.

Pour vous faire comprendre clairement ce que vous essayez de faire avec un fichier de ressources, essayez d’exécuter le code ci-dessous et consultez le résultat dans logcat.

    try{
      Log.d("RESURI", this.getClass().getClassLoader().getResource("res/raw/test0").toURI().toString());
    } 
    catch(Exception e) {

    }

Vous obtiendrez le résultat comme,

jar:file:/data/app/<packagename>/<apkname>.apk!/res/raw/test0

cela signifie que le fichier de ressources auquel vous essayez d'accéder n'est pas réellement un fichier dans un chemin physique, mais un emplacement de fichier jar (dans apk) auquel vous ne pouvez pas accéder à l'aide de la méthode setDataSource (String). (Essayez d'utiliser 7Zip pour extraire votre fichier apk et vous verrez le res/raw/test0 dedans).

J'espère que cela pourra aider.

PS: Je connais sa réponse un peu longue, mais j'espère que cela l'explique en détail. Laisser les solutions alternatives en haut si cela peut aider les autres.

34
Naren Neelamegam

Le code ci-dessous fonctionne pour moi, je pense que ce code vous aidera

    player = MediaPlayer.create(this,R.raw.test0);
    player.setLooping(true); // Set looping

    player.setVolume(100,100);
    player.start();

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
player.stop();
player.release();
}
2
Ravi Vaghela

Comme le Android documentation dit

Fichiers arbitraires à enregistrer sous leur forme brute. Pour ouvrir ces ressources avec un InputStream brut, appelez Resources.openRawResource () avec le fichier ID de ressource, qui est R.raw.filename.

Toutefois, si vous avez besoin d'accéder aux noms de fichier d'origine et à la hiérarchie des fichiers, vous pouvez envisager de sauvegarder certaines ressources du répertoire assets/ (au lieu de res/raw /). Les fichiers des actifs/ne reçoivent pas d'ID de ressource, vous pouvez donc les lire uniquement à l'aide de AssetManager.

Vous devez donc utiliser un InputStream pour lire le fichier audio avant de le définir sur le lecteur multimédia.

Je vous suggère de placer le fichier audio dans le dossier assets comme vous l'avez dit

:)

2
DeKoServidoni

Lorsque vous traitez avec une ressource brute, vous devez vous fier au constructeur suivant:

public statique MediaPlayer create (contexte contextuel, int résid)

Méthode pratique pour créer un MediaPlayer pour un identifiant de ressource donné. En cas de succès, prepare () aura déjà été appelé et ne doit plus être appelé.

Le code ressemble à

mediaPlayer = MediaPlayer.create(this, R.raw.test0);
mediaPlayer.start();

N'oubliez pas d'appeler mediaPlayer.release() lorsque vous avez terminé.

( la source )

2
Sebastiano

De ici ,

Lorsque chemin fait référence à un fichier local, le fichier peut en fait être ouvert par un processus autre que l'application appelante. Cela implique que le nom du chemin doit être un chemin absolu (comme tout autre processus s'exécute avec un répertoire de travail en cours non spécifié), et que le chemin doit faire référence à un fichier lisible par tout le monde. Au lieu de cela, l'application pourrait d'abord ouvrir le fichier en lecture, puis utiliser le descripteur de fichier sous la forme setDataSource (FileDescriptor). 

Essayer,

String filePath = "path/file.mp3";
File file = new File(filePath);
FileInputStream inputStream = new FileInputStream(file);
mediaPlayer.setDataSource(inputStream.getFD());
inputStream.close();

J'espère que ça aide!

1
Akhunzaada

Vous devez utiliser setDataSource(@NonNull Context context, @NonNull Uri uri) au lieu de setDataSource(String path) 

Puisque vous voulez résoudre les ressources internes des ressources de l'application, vous devez fournir Context qui serait utilisé pour résoudre ce problème.

De plus, si vous jetez un coup d'œil à l'intérieur de ces deux méthodes, vous remarquerez qu'elles utilisent différentes stratégies pour trouver la ressource résultante.

0
Dmitry