Spela upp mp3 i asset-mappen med MediaPlayer?

Diskussion i 'Frågor, support och diskussion' startad av Danneman101, 20 aug 2009.

  1. Danneman101

    Danneman101 Kid Droid Medlem

    Blev medlem:
    18 aug 2009
    Inlägg:
    69
    Mottagna gillanden:
    0

    MINA ENHETER

    Jag har en basic kod som ska spela upp en mp3 (mySound.mp3 som ligger i assets-foldern).

    Jag försöker använda mig av MediaPlayer-klassen.

    Trots att jag inte kan hitta något fel så får jag inget ljud.

    Kod:
    package com.myApp;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.webkit.WebView;
    import android.media.MediaPlayer;
    import android.net.Uri;
    import java.io.*;
    
    import com.myApp.R.id;
    
    
    public class myApp extends Activity 
    {
        // Init:    MediaPlayer
        MediaPlayer mp;
       
        
        @Override
        public void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            mp = new MediaPlayer();
            try
            {
            	mp.setDataSource("file:///android_asset/mySound.mp3");
            	mp.prepare();
            	mp.start();
            }
            catch(Exception e) {}
        }
    }
    
    Det borde ju vara klockrent.


    Jag har även testat att placera mp3-filen i res-mappen och sedan använda följande kod:
    Kod:
    package com.myApp;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.webkit.WebView;
    import android.media.MediaPlayer;
    import android.net.Uri;
    import java.io.*;
    
    import com.myApp.R.id;
    
    
    public class myApp extends Activity 
    {
        // Init:    MediaPlayer
        MediaPlayer mp;
       
        
        @Override
        public void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            mp = new MediaPlayer();
            mp = MediaPlayer.create(getBaseContext(), R.raw.mySound); 
            mp.start();
        }
    }
    
    Denna kod kan jag dock inte använda av den anledningen att det finns ett par hundra ljudfiler och hittills har jag inte hittat en metod för att byta ut "mySound" mot en variabel med namnet på aktuell ljudfil. Följande kodstycke fungerar alltså inte:

    Kod:
    String soundName = "mySound2";
    String param2 = "R.raw." + soundName;
    mp = MediaPlayer.create(getBaseContext(), param2); 
    

    Alltså, det borde ju vara en enkel grej tycker man att dynamiskt spela upp ljud i Android, så det är väl någon liten struntsak som jag inte fattat. Ser ni vad? :)
     
  2. doep

    doep Kid Droid Medlem

    Blev medlem:
    14 aug 2009
    Inlägg:
    98
    Mottagna gillanden:
    0

    MINA ENHETER

    Första kod-exemplet bör fungera fint.. dock vet jag inte om URLen är korrekt. Ska det verkligen stå "file://"?
    Vad säger logcat?
    Prova att utöka MediaPlayer.OnErrorListener och lyssna efter error.
     
  3. Danneman101

    Danneman101 Kid Droid Medlem

    Blev medlem:
    18 aug 2009
    Inlägg:
    69
    Mottagna gillanden:
    0

    MINA ENHETER

    Jag får inga felmeddelanden, så jag förmodar att (som du är inne på) det har att göra med söksträngen.

    Men strängen till filer i asset-foldern ska vara som den är enligt ett antal källor, och mina strängar till html-filer för webview'n har precis samma prefix, nämligen:

    file:///android_asset/

    Så jag är helt förbluffad. Detta borde ju vara solklart, men ändå inte.

    Har det möjligtvis att göra med åtkomsttillstånd av olika typer av filer i asset-foldern? html-filer däri koms åt utan problem via webview'n, men samma regler kanske inte gäller per default för mediaplayern och mp3-filer?
     
  4. PatrikS

    PatrikS Senior Droid Medlem

    Blev medlem:
    29 jun 2009
    Inlägg:
    1 123
    Mottagna gillanden:
    65

    MINA ENHETER

    Du sväljer ju precis alla exceptions som kommer där... om du steppar genom koden med F6 vart hamnar du då?

    Ett tips är att åtminstone skriva


    Kod:
    
    
    catch(Exception e) {
             android.util.Log.v("com.myapp",e.getMessage());
    }
    
    
    
     
  5. Danneman101

    Danneman101 Kid Droid Medlem

    Blev medlem:
    18 aug 2009
    Inlägg:
    69
    Mottagna gillanden:
    0

    MINA ENHETER

    Jag testade att skriva som du rekommenderade, men jag är så ny i eclipse att jag inte hittar logg-filen :o Har sökt i eclipse, projects, och sdk-mapparna efter "log", men inget som uppdaterats nyligen...

    [edit]
    Hittar iofs Window -> Show view -> error log, vilket jag förmodar är det som gäller. Den visar dock inget felmeddelande alls.
     
    Last edited: 21 aug 2009
  6. nazurro

    nazurro Baby Droid Medlem

    Blev medlem:
    12 aug 2009
    Inlägg:
    28
    Mottagna gillanden:
    0

    MINA ENHETER

    Nu har jag inte kodat själv (än) men har kikat i docsen och devguiden.

    För assets tolkar jag det som att det krävs klassen AssetManager:

    http://developer.android.com/reference/android/content/res/AssetManager.html. Du kör väl open() och använder inputströmmen och läser bytes.

    För resources:

    MediaPlayer mp = MediaPlayer.create(context, R.raw.mysoundfile);
    mp.start();

    För andra filer på disk eller URL:ar:

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

    PatrikS Senior Droid Medlem

    Blev medlem:
    29 jun 2009
    Inlägg:
    1 123
    Mottagna gillanden:
    65

    MINA ENHETER

    Det finns ett "logcat"-fönster längst ner till höger.

    Allt du behöver göra är att först starta din applikation i debug-läge.
    Och sen längst upp till höger finns ett antal flikar, en av dom heter "DEBUG" välj den så kommer du in i den vy som passar bäst när du ska köra programmet i debugläge.

    Finns den inte så trycker du på det lilla fönstret med ett gult kryss på och lägger till debug-view.
     
  8. doep

    doep Kid Droid Medlem

    Blev medlem:
    14 aug 2009
    Inlägg:
    98
    Mottagna gillanden:
    0

    MINA ENHETER

    Slå om till debug-view i eclipse och leta upp logcat fönstret. Där borde stå en del intressant.

    Kan dock inte säga exakt hur just nu eftersom jag skriver på telefonen.
     
  9. doep

    doep Kid Droid Medlem

    Blev medlem:
    14 aug 2009
    Inlägg:
    98
    Mottagna gillanden:
    0

    MINA ENHETER

    Med debug-view menar jag Debug perspektivet (hittar du längst upp till höger). Och LogCat hittar du i menyn under Window/Show view/LogCat.
     
  10. Danneman101

    Danneman101 Kid Droid Medlem

    Blev medlem:
    18 aug 2009
    Inlägg:
    69
    Mottagna gillanden:
    0

    MINA ENHETER

    nazurro:

    Tydligen gör det ingen skillnad att importera android.content.res.*;

    Och det är precis den kod du tar upp som jag försöker få bukt med. Den första fungerar, medan den andra gör det inte (då är som sagt PATH_TO_FILE utbytt mot "file:///android_asset/mySound.mp3").


    PatrikS/deop:

    Jasså, det var en helt ny vy :)

    Och mycket riktigt dök det upp tre errors relaterade till MediaPlayer och MediaPlayerService:

    1) MediaPlayerService: Couldnt open fd for content://settings/system/notification_sound
    2) MediaPlayer: Unable to create media player
    4) MediaPlayer: error (1, -4)

    Även ett fel som verkar vara relevant dök upp strax innan rad 4 ovan:
    3) PlayerDriver: Command PLAYER_SET_DATA_SOURCE completed with an error or info PVMFErrNotSupported

    Men detta säger tyvärr inte mig så mycket... Någon som har bättre koll på errorlogs-mumbojumbo? :confused:


    Felmeddelandena (radnr) hör ihop med koden på följande sätt:
    Kod:
    // Rad 1
    (vet ej)
    
    // Rad 2
    mp = new MediaPlayer();
    
    // Rad 3-4
    catch(Exception e) {
            android.util.Log.v("com.androidspanishcourse", e.getMessage());
    }
    
     
    Last edited: 21 aug 2009
  11. doep

    doep Kid Droid Medlem

    Blev medlem:
    14 aug 2009
    Inlägg:
    98
    Mottagna gillanden:
    0

    MINA ENHETER

    Jag antar att du har provat relativa sökvägar också?
    typ om filen ligger i assets/audio/mysound.mp3:
    Kod:
    mp.setDataSource("audio/mysound.mp3");
    mp.prepare();
    mp.start();
    
    Detta hade varit min första gissning att man borde skriva. "file://" använder man ju mest i browsers.
    Jag har använt MediaPlayern en hel del och den brukar inte krångla så mycket, men jag har mest använt http-adresser.
     
  12. Danneman101

    Danneman101 Kid Droid Medlem

    Blev medlem:
    18 aug 2009
    Inlägg:
    69
    Mottagna gillanden:
    0

    MINA ENHETER

    Jodå, det var också min första gissning. Dock funkar det inte heller.

    Nä, det lutar mer och mer åt att göra en groteskt stor lista med funktioner i stil med:
    Kod:
            public void PlaySound_Ljud1()
            {
                mp = new MediaPlayer();
                mp = MediaPlayer.create(getBaseContext(), R.raw.Ljud1);
                mp.start();        
            }
    
    // osv
    
            public void PlaySound_Ljud1000()
            {
                mp = new MediaPlayer();
                mp = MediaPlayer.create(getBaseContext(), R.raw.Ljud1000);
                mp.start();        
            }
    
    Urk, vilket tidskrävande jobb!

    Dessutom är jag lite orolig för att jag inte releasar mediaspelaren efter varje användning när jag har så många ljud.

    Men sätter jag en mp.release() efter start() så spelar inte ljudet alls.

    Någon tanke om hur detta bäst löses?
    Finns det kanske någon funktion som väntar tills ljudet spelat klart innan nästa kodrad (dvs. release()) kan köras?
     
  13. doep

    doep Kid Droid Medlem

    Blev medlem:
    14 aug 2009
    Inlägg:
    98
    Mottagna gillanden:
    0

    MINA ENHETER

    Du måste använda MediaPlayer.OnCompletionListener för att veta när ljudet har spelat klart. Du kan inte vänta i en rad i koden eftersom du kommer att få en timeout efter 10-15 sekunder (såvida du inte kör i en annan tråd). Förslagsvis så sätter du upp någon typ av kösystem som sätter igång nästa spår när MediaPlayer.OnCompletionListener körs.
     
  14. Danneman101

    Danneman101 Kid Droid Medlem

    Blev medlem:
    18 aug 2009
    Inlägg:
    69
    Mottagna gillanden:
    0

    MINA ENHETER

    Men hur viktigt är det att lösgöra resurserna i detta exemplet? Jag räknar med kanske 50 ljud per applikation, mellan 1-10 sekunder vardera. Rimligtvis används kanske alla dessa en gång under en sittning innan programmet stängs ned och resurserna lösgörs av sig självt. Borde inte det vara tillräckligt?
     
  15. doep

    doep Kid Droid Medlem

    Blev medlem:
    14 aug 2009
    Inlägg:
    98
    Mottagna gillanden:
    0

    MINA ENHETER

    Som de står i dokumentationen så BÖR man anropa release() för att frigöra resurser. Jag kan inte se något annat sätt hur du ska kunna spela upp nästa ljud om du inte använder dig av MediaPlayer.OnCompletionListener.
    Ska du bara spela upp alla ljuden i en följd eller ska du göra något annat mellan varje ljud också?
     
  16. PatrikS

    PatrikS Senior Droid Medlem

    Blev medlem:
    29 jun 2009
    Inlägg:
    1 123
    Mottagna gillanden:
    65

    MINA ENHETER

    Nu vet jag att du bara labbar lite, men du bör verkligen inte spela upp ljudet i main-tråden i din applikation, precis som doep säger så bör du skriva en egen klass som ärver Thread eller implementerar runnable.
    I den klassen kör du den här koden.
    Jag är inte 100 på hur det _ska_ vara i android, men den klassen hade jag iaf instanserat på att lyssna på en fifo som du puttar in "ljuden som skall spelas".
    Detta behöver kanske vara synchronized jag vet inte vad det gör för prestandan i android.
    Någon annan som vet hur man gör detta bäst?
     
  17. Danneman101

    Danneman101 Kid Droid Medlem

    Blev medlem:
    18 aug 2009
    Inlägg:
    69
    Mottagna gillanden:
    0

    MINA ENHETER

    doep:
    Jag ska köra dem en och en, och göra grejer emellan. De anropas genom en knapptryckning i en webview.

    PatrikS:
    Trådning är något jag aldrig arbetat med förut, men har hört att det är enkelt att använda i java. Räcker det med att en klass ärver Thread för att den ska köras i en egen tråd, eller behövs ytterligare kodning?


    [edit]
    Jag fick dessutom ett tips i ett annat forum att använda AssetManager för att få ett sk. AssetFileDescriptor-objekt med vägen till ljudfilen, och till sist passa in den som parameter i mediaplayerns setDataSource()-funktion.
    Kod:
            AssetManager assetManager = null; 
            try{ 
               assetManager.openFd("file:///android_asset/mySound.mp3"); 
            } catch (Exception e) {}      
            
            AssetFileDescriptor assetFileDescriptor = null; 
            assetFileDescriptor.getFileDescriptor();        
                      
            mp = new MediaPlayer(); 
            try { 
               mp.[color=red][b]setDataSource[/b][/color](assetFileDescriptor); 
               mp.prepare(); 
               mp.start(); 
            }  catch(Exception e) { } 
    
    Men det känns som jag snubblar på målsnöret trots allt plitande för den rödmarekerade koden genererar följande error:
    "The method setDataSource(String) in the type MediaPlayer is not applicable for the arguments (AssetFileDescriptor)".

    Detta trots att jag specifikt valt den "setDataSource"-funktion med FileDescriptor och inte String när ide'n presenterade alternativen (Ctrl + space).

    Någon tanke om det?
     
    Last edited: 22 aug 2009
  18. gunnar-medial

    gunnar-medial Youth Droid Medlem

    Blev medlem:
    22 jun 2009
    Inlägg:
    137
    Mottagna gillanden:
    3

    MINA ENHETER

    param2 skall vara en int, dvs du kan t ex skapa en array
    av integers som refererar till ljudresurserna:

    int[] sounds = { R.raw.sound1, R.raw.sound2, }; // Und so weiter

    och sedan använder du t ex sounds[n] som värde för param2.

    Värt att tänka på: "When done with the MediaPlayer, you should call release(), to free the resources. If not released, too many MediaPlayer instances will result in an exception."
     
    Last edited: 9 dec 2009