Using Android MediaPlayer to play sound.

Hi all, I'm trying to use the code posted here by yelele_brother to play sound in Android mode. (Code posted below for ease of reference.)

It is currently throwing an error that the getAssets(); method does not exist. I checked the Media Player reference here and can't see a getAssets() method. So since this method is no longer available, my question is: How do I make this code work? I've tried looking for ApWidgets but the google code page is shutdown, Cassette doesn't work for me and there appear to be few other solutions as far as I can find.

    import android.media.*;
    import android.content.res.*;
    void setup()
    {
      size(10,10,P2D);
      try {
        MediaPlayer snd = new MediaPlayer();
        AssetManager assets = this.getAssets();
        AssetFileDescriptor fd = assets.openFd("test.mp3");
        snd.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
        snd.prepare();
        snd.start();
      }
      catch (IllegalArgumentException e) {
        e.printStackTrace();
      }
      catch (IllegalStateException e) {
        e.printStackTrace();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }

Answers

  • From this next post: https://forum.processing.org/two/discussion/12819/how-do-i-get-sound-to-play-on-the-phone

    It seems you need to add these lines:

    import android.content.Context; Context context;

    And to add this change :

    AssetFileDescriptor fd = context.getAssets().openFd("your.mp3");//which is in the data folder

    Let us know if this fix your problem.

    Kf

  • This stopped the errors but when I compile and it is sent to the phone, it tries to launch and says "SketchName has stopped working."

    Phone tested was a Samsung Galaxy 7. Other programs work fine on the phone.

    Neither the code above or below work, they both get this error.

    I did try just having the snd.prepare(); & snd.play(); in the setup and this doesn't work either.

    main:

    import android.media.*;
    import android.content.res.*;
    import android.content.Context;
    
    MediaPlayer snd = new MediaPlayer();
    //AssetManager assets = this.getAssets();
    AssetFileDescriptor fd;
    Context context;
    Button bPlay;
    
    void setup()
    {
      colorMode(HSB);
      size(800, 800);
      try {
    
        fd = context.getAssets().openFd("Ni-"+(int)random(1, 22)+".mp3");
        snd.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
      }
      catch (IllegalArgumentException e) {
        e.printStackTrace();
      }
      catch (IllegalStateException e) {
        e.printStackTrace();
      } 
      catch (IOException e) {
        e.printStackTrace();
      }
    
      bPlay = new Button(width/2, height/2, 500, color(0, 125, 255));
    }
    
    void draw()
    {
      background(210);
      bPlay.draw();
      textSize(30);
      textAlign(CENTER);
      fill(0, 21, 75);
      text("Press for replacement", width/2, height/2);
    }
    
    void mousePressed()
    {
      if (bPlay.buttonCheck()) {
        bPlay.c = color(0, 125, 220);
        try {
          snd.prepare();
          snd.start();
          fd = context.getAssets().openFd("Ni-"+(int)random(1, 22)+".mp3");
          snd.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
    
        }
        catch (IllegalArgumentException e) {
          e.printStackTrace();
        }
        catch (IllegalStateException e) {
          e.printStackTrace();
        } 
        catch (IOException e) {
          e.printStackTrace();
        }
        //fd = context.getAssets().openFd("Ni-"+(int)random(1, 22)+".mp3");
      }
    }
    
    void mouseReleased()
    {
      bPlay.c = color(0, 125, 255);
    }
    

    Button class:

    class Button
    {
      int x, y, w, h, r;
      color c;
    
      Button(int x, int y, int w, int h, color c) //rectangular buttons
      {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.c = c;
      }
      Button(int x, int y, int r, color c) //circular buttons
      {
        this.x = x;
        this.y = y;
        this.r = r;
        this.c = c;
      }
    
      void draw()
      {
        ellipseMode(CENTER);
        noStroke();
        fill(c);
        rect(x, y, w, h);
        ellipse(x, y, r, r);
      }
    
      boolean buttonCheck()
      {
        boolean result = false;
        float disX = x - mouseX;
        float disY = y - mouseY;
        if (sqrt(sq(disX) + sq(disY)) < r/2) result = true;
        return result;
      }
    }
    
  • All references to

    context.getAssets()...

    needs to be replaced with

    this.getActivity().getApplicationContext().getAssets()...
    

    Kf

  • edited November 2016

    Error: the function "getActivity()" does not exist.

  • edited November 2016

    It worked for me. What Processing version are you using and OS? Also include

    import android.content.Context;
    import android.app.Activity;
    

    Kf

  • edited November 2016

    Processing 3.2.3

    Windows 10 + anniversary update

    already had import android.content.Context;

    added import android.app.Activity; no change.

  • @SnailPropulsionLabs===

    just changing some imports, some lines of code as you are in a fragment, using only 1 mp3 in order to simplify, and adding the onStop() , onPause() etc methods which are mandatory when using an instance of media player. Of course the .mp3 has to be in the data folder. The code below works, tested SonyXperiaZ3 and nexus tablet.

        import android.media.MediaPlayer;
        import  android.content.res.Resources;
        import android.content.res.AssetFileDescriptor;
        import android.content.res.AssetManager;
        import android.content.Context;
        import android.app.Activity;
    
        MediaPlayer snd = new MediaPlayer();
        //AssetManager assets = this.getAssets();
        AssetFileDescriptor fd;
        Context context;
        Button bPlay;
        Activity act;
    
        void setup()
        {
          colorMode(HSB);
          size(800, 800);
          act = this.getActivity();
          context = act.getApplicationContext();
          try {
    
            fd = context.getAssets().openFd("some.mp3");
            snd.setDataSource(fd.getFileDescriptor(),fd.getStartOffset(), fd.getLength());
          }
          catch (IllegalArgumentException e) {
            e.printStackTrace();
          }
          catch (IllegalStateException e) {
            e.printStackTrace();
          } 
          catch (IOException e) {
            e.printStackTrace();
          }
    
          bPlay = new Button(width/2, height/2, 500, color(0, 125, 255));
        }
    
        void draw()
        {
          background(210);
          bPlay.draw();
          textSize(30);
          textAlign(CENTER);
          fill(0, 21, 75);
          text("Press for replacement", width/2, height/2);
        }
    
        void mousePressed()
        {
          if (bPlay.buttonCheck()) {
            bPlay.c = color(0, 125, 220);
            try {
              snd.prepare();
              snd.start();
              //fd = context.getAssets().openFd("Ni-"+(int)random(1, 22)+".mp3");
              //snd.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
    
            }
            catch (IllegalArgumentException e) {
              e.printStackTrace();
            }
            catch (IllegalStateException e) {
              e.printStackTrace();
            } 
            catch (IOException e) {
              e.printStackTrace();
            }
            //fd = context.getAssets().openFd("Ni-"+(int)random(1, 22)+".mp3");
          }
        }
    
        void mouseReleased()
        {
          bPlay.c = color(0, 125, 255);
    
        }
    
        void onPause(){
          super.onPause();
          if(snd!=null){
    
            snd.release();
            snd= null;
          }
        }
    
        void onStop(){
          super.onStop();
          if(snd!=null){
    
            snd.release();
            snd= null;
          }
    
        }
    
    
        void onDestroy(){
           super.onDestroy();
          if(snd!=null){
    
            snd.release();
            snd= null;
          }
        }
    
    
        ////////////
    
        class Button
        {
          int x, y, w, h, r;
          color c;
    
          Button(int x, int y, int w, int h, color c) //rectangular buttons
          {
            this.x = x;
            this.y = y;
            this.w = w;
            this.h = h;
            this.c = c;
          }
          Button(int x, int y, int r, color c) //circular buttons
          {
            this.x = x;
            this.y = y;
            this.r = r;
            this.c = c;
          }
    
          void draw()
          {
            ellipseMode(CENTER);
            noStroke();
            fill(c);
            rect(x, y, w, h);
            ellipse(x, y, r, r);
          }
    
          boolean buttonCheck()
          {
            boolean result = false;
            float disX = x - mouseX;
            float disY = y - mouseY;
            if (sqrt(sq(disX) + sq(disY)) < r/2) result = true;
            return result;
          }
        }
    
  • Still throwing "The function "getActivity()" does not exist" on line 19. What on earth is wrong with my setup if this works for both of you guys?

  • I might have asked you before, maybe it was another post. Could you install the ketai library and run one of their examples, like the one with the video camera or the sensor one? I just want to test if your Android SDK is setup properly. Have you run any other sketch in your device before?

    These details could help in figuring it out what is happening.

    Kf

  • yes i've run selfmade apps on this device previously.

    installed ketai, ran the gettingstartedcamera example. It loaded a landscape screen with a small grey box, then gave the "appname has stopped working error", tried the accelerometer example, same error.

    So i've got the sdk installed incorrectly?

  • You can copy and paste the error you get from the console in Processing. Just select the text and use the keys ctrl+c to copy and paste in the forum by pressing ctrl+v.

    Do the examples come with the sketch's size defined in setup? If not add fullScreen();

    By the way, a quicker test to test your android mode is to run something similar to the following lines, which do not depend on external libraries. The code below is not tested, so they might have minor typos.

    Kf:

    int x,y;  //Position of last mouseClicked()
    
    void setup(){
      fullScreen();
      Orientation(PORTRAIT);
      noStroke();
    } 
    void draw(){
      background(0);
    
      //NEXT if clause is for a blinking effect
      fill(255,0,0);
      if(frameRate%100>60) 
        ellipse(width/2,height*0.8,width/10,height/10);
    
      //Draws an ellipse in the last registered mouse position
      fill(255);
      ellipse(x,y,width/6,height/6);
    
    }
    
    void keyPressed(){
    
       x=mouseX;
       y=mouseY;
    }
    
  • @snailpropulsionlabs=== it happens (processing bug??) that it fires an error with "this.getactivity()" but it compiles; have you tried?

  • edited December 2016

    Just for knowledge's sake, the console says that the sdk version is: Android SDK Tools Revision 25.2.3

    @kfrajer: The code you gave compiled, black screen with white ellipse in top left corner, I suppose it should follow my touch inputs but I didn't have time to try (not my phone).

    Also, the ketai camera example compiled and didn't crash this time, didn't display an image from the camera as I imagine it is supposed to, but not crashing is a step in the right direction.

    @akenaton: Yes and it gave this error:

        1. ERROR in C:\Users\Rowan\AppData\Local\Temp\android4038316879264140021sketch\src\processing\test\nireplacement_androidmediaplayeriii\NiReplacement_AndroidMediaPlayerIII.java (at line 44)
            act = this.getActivity();
                       ^^^^^^^^^^^
        The method getActivity() is undefined for the type NiReplacement_AndroidMediaPlayerIII
        ----------
        1 problem (1 error)
    
        BUILD FAILED
        C:\Users\Rowan\AppData\Local\Temp\android4038316879264140021sketch\build.xml:15: The following error occurred while executing this line:
        C:\Users\Rowan\AppData\Local\Temp\android4038316879264140021sketch\build.xml:28: Compile failed; see the compiler error output for details.
    
        Total time: 1 second
    

    here's the first part of the xml file it refers to:

        <?xml version="1.0" encoding="UTF-8"?>
        <project name="NiReplacement_AndroidMediaPlayerIII" default="help">
          <property file="local.properties" />
          <property file="ant.properties" />
          <property environment="env" />
          <condition property="sdk.dir" value="${env.ANDROID_HOME}">
               <isset property="env.ANDROID_HOME" />
          </condition>
          <property name="jdt.core" value="E:\Tools, Utilities unt Programs\Programming\Processing\processing-3.2.3\tools/../modes/java/mode/org.eclipse.jdt.core.jar" />
          <property name="jdtCompilerAdapter" value="E:\Tools, Utilities unt Programs\Programming\Processing\processing-3.2.3\tools/../modes/java/mode/jdtCompilerAdapter.jar" />
          <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />
          <mkdir dir="bin" />
          <echo message="${build.compiler}" />
            <target name="-compile" depends="-pre-build, -build-setup, -code-gen, -pre-compile">
                <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
                    <path id="project.javac.classpath">
                        <path refid="project.all.jars.path" />
                        <path refid="tested.project.classpath" />
                        <path path="${java.compiler.classpath}" />
                    </path>
                    <javac encoding="${java.encoding}"
                            source="${java.source}" target="${java.target}"
                            debug="true" extdirs="" includeantruntime="false"
                            destdir="${out.classes.absolute.dir}"
                            bootclasspathref="project.target.class.path"
                            verbose="${verbose}"
                            classpathref="project.javac.classpath"
                            fork="${need.javac.fork}">
                        <src path="${source.absolute.dir}" />
                        <src path="${gen.absolute.dir}" />
                        <compilerarg line="${java.compilerargs}" />
                        <compilerclasspath path="${jdtCompilerAdapter};${jdt.core}" />
                    </javac>
                    <if condition="${build.is.instrumented}">
                        <then>
                            <echo level="info">Instrumenting classes from ${out.absolute.dir}/classes...</echo>
                            <getemmafilter
    
  • @SnailPropulsionLabs

    I made a small mistake in my example code. Instead of keyPressed() use mousePressed(). The first function will not work on Android as you will need a keyboard.

    void mouysePressed(){
        x=mouseX;
       y=mouseY;
    }
    

    A white circle in the corner, yes, that sound about right. I believe mousePressed events will be interpreted as touch events in Android. With the above modification, every time you touch the screen on your device, the white circle will move to that touch point. I can say from what you describe about this small simple program that Android mode is working in Processing :)>-

    All my code testing has been done using API 23 and Processing 3.1.2

    Another suggestion. You are trying to get the reference to your current activity to access your files. To work around your problem, can you try accessing your file using

    dataPath("your_file_name.mp3");

    instead of

    fd = context.getAssets().openFd("some.mp3");
    snd.setDataSource(fd.getFileDescriptor()
    

    Make sure your mp3 file is inside your data folder in your current sketch folder. This is a way to work around but I am not sure it will work.

    Kf

  • edited December 2016

    yup, your program works @kfrajer.

    Though the datapath("file_path.mp3") didn't solve the issue. I'm gonna lose my mind, it works for you guys but not here. Still just getting the Android error of "Sorry, appname has stopped working." Useful descriptive error messages from android.

    As per the error in line 28 of the xml file above, what is javac.fork and could this be the source of my issues? What is it skipping on line 15?

  • @snailPropulsionLabs===

    the error in .xml is when compiling so i dont understand: does it compiles or no??? you are speaking about crashing at run time, which means that the app was compiled and installed... btw: try to save as changing your app name which seems rather weird....

  • Answer ✓

    @SnailPropulsionLabs

    This next post could be relevant. Try and see if it solves anything: https://forum.processing.org/two/discussion/19458/0255-the-method-oncreate-bundle-is-undefined-for-the-type-papplet#latest

    I can't reproduce your error so I can help anymore. Maybe create a new post in the forum to see how to install Processing with a previous version of Android mode. Also I suggest running API23 instead of 21.

    Doing a light browsing, calls to getActivity has changed before in Processing. I do not know much about what changes are implemented so my suggestions are just things I will do. I understand your frustration. Maybe you should text @codeanticode. I think he is in this forum or try stackoverflow.

    Kf

  • edited December 2016

    @kfrajer, turns out using API23 got things to launch in the emulator.

    @akenaton, your code from Nov 30 works for me now.

    New question in this vein (that's why it's not in a new thread)

    How can I make this play a different sound on each press of the button? It only plays the first sound it loads (even if the fd = context.getAssets().openFd("Ni-1.mp3"); is also present in the mousePressed method ) and if I try and make it load a random sound from the data folder It either doesn't go or just sits silent.

  • Answer ✓

    This is a previous code adapted to play a random filename. You need to have 5 sound files inside the data folder stored under the Sound folder. This is using the cassette library from Processing's library manager.

    Kf

    import ketai.sensors.*;
    
    import android.os.Environment;
    import cassette.audiofiles.SoundFile; 
    
    
    import android.view.WindowManager;
    import android.view.WindowManager.LayoutParams;
    
    
    int globalProxCtr=0;
    
    int seln=1;
    int CM_STD_WAIT=100;
    int holdCtr=0;//CM_STD_WAIT;
    
    
    SoundFile music; 
    Boolean isPlaying=false;
    int fileN;
    
    // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
    
    void settings() {
      fullScreen();
    }
    
    
    void setup() {  
    
      selectionUpdate(1);    
    
      orientation(LANDSCAPE);  
      stroke(0, 255, 0);
      strokeWeight(2);
      noFill();
      textAlign(CENTER, CENTER);
      textSize(36);
      smooth();
      noStroke();
      frameRate(30);
    
      rectMode(CORNER);
      ellipseMode(CENTER);
    }
    
    // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
    
    void draw() { 
      background(92);
    
      if (isPlaying) {
        fill(255,20,20);
        //noStroke();
        ellipse(width/2,height/2,width*0.3,height*0.3);
      }
    
      if (holdCtr>0) {    
        fill(#FFFF00);
        //stroke(0, 255, 0);
        rect(width/2 -100, 0.15*height -15, 100*2, 15*2);
        fill(250,220,25);    
        text("Playing a random sound " + fileN + "\nThis message will disappear in "+ int(holdCtr/30), width/2, 0.05*height); 
        holdCtr--;
      }
    }
    
    
    // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
    
    public void mousePressed() {
    
      if (isPlaying) {
        music.stop();  
        isPlaying=false;
        holdCtr=0;
      } else {    
        selectionUpdate(int(random(4))+1);
        //music.loop();
        music.play();
        isPlaying=true;
    
        holdCtr=CM_STD_WAIT;
      }
    } 
    
    
    // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    
    
    void selectionUpdate(int s) {
    
      String cm_audiofile="sound/default.mp3";  //Default case 
      fileN=s;
    
      switch(s) {
    
      case 1:
        cm_audiofile="sound/snd01.amr";
        break;
    
      case 2:
        cm_audiofile="sound/snd02.amr"; 
        break;
    
      case 3:
        cm_audiofile="sound/snd03.amr";     
        break;
    
      case 4:
        cm_audiofile="sound/button-3.mp3";
        break;
      }
    
      music = new SoundFile(this, cm_audiofile);
    }  
    
  • edited December 2016

    It works and plays the sounds i've put in there but it only plays 7 times and then just plays silence. Any variation I have tried has similar results, 7 times and silence thereafter.

    In the console, it is outputting

    debug: No event method

    every time I click, this is during the times the sound plays and those when it doesn't.

Sign In or Register to comment.