Blog

Android: Saving a sound file to SD from resource and setting as ringtone

Quite a few people have been asking how to save a file to the SD card in order to register it as a ringtone. The following example creates a function that will save a resource to the SD card (ie: from R.raw.soundfile to /sdcard/media/audio/ringtones/soundfile.ogg) and register it as a ringtone.

I have split this example into two parts, the first part goes through the code a section at a time with a brief explanation of what it does, the second half is just the code that you can copy and paste and then edit to your hearts content.

Parts

We first setup our function to return a boolean depicting if we have failed or if we are successful. We accept in an integer which corresponds to the raw sound file.

public boolean saveas(int ressound){

}

So this function would be called in the following fashion:

saveas(R.raw.soundfile);

or utilising its boolean return:

if (saveas(R.raw.soundfile)){
// Code if successful
}
else
{
// Code if unsuccessful
}

The following chunk of code creates an inputstream from the raw sound resource and loads it into a buffer. We add in the mandatory try/catch clause around these operations and return false if an exception is raised (to indicate failure to the rest of our program and to prevent trying to continue act upon this sound).

 byte[] buffer=null;
 InputStream fIn = getBaseContext().getResources().openRawResource(ressound);
 int size=0;

 try {
  size = fIn.available();
  buffer = new byte[size];
  fIn.read(buffer);
  fIn.close();
 } catch (IOException e) {
  // TODO Auto-generated catch block
  return false;
 }

The following saves the buffer to a file on the SD card. It first ensures the folder exists and if not it is created. Then as before the writing operations are surrounded with try/catches

 String path="/sdcard/media/audio/ringtones/";
 String filename="examplefile"+".ogg";

 boolean exists = (new File(path)).exists();
 if (!exists){new File(path).mkdirs();}

 FileOutputStream save;
 try {
  save = new FileOutputStream(path+filename);
  save.write(buffer);
  save.flush();
  save.close();
 } catch (FileNotFoundException e) {
  // TODO Auto-generated catch block
  return false;
 } catch (IOException e) {
  // TODO Auto-generated catch block
  return false;
 }    

The following code sends an intent to tell the Media Scanner that we have added a new file, and sets up its properties in the media database:

 sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+path+filename)));

 File k = new File(path, filename);

 ContentValues values = new ContentValues();
 values.put(MediaStore.MediaColumns.DATA, k.getAbsolutePath());
 values.put(MediaStore.MediaColumns.TITLE, "exampletitle");
 values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/ogg");
 values.put(MediaStore.Audio.Media.ARTIST, "cssounds ");
 values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
 values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
 values.put(MediaStore.Audio.Media.IS_ALARM, true);
 values.put(MediaStore.Audio.Media.IS_MUSIC, false);

 //Insert it into the database
 this.getContentResolver().insert(MediaStore.Audio.Media.getContentUriForPath(k.getAbsolutePath()), values);

Final code
Putting all this code together gives us our final functions:

public boolean saveas(int ressound){
 byte[] buffer=null;
 InputStream fIn = getBaseContext().getResources().openRawResource(ressound);
 int size=0;

 try {
  size = fIn.available();
  buffer = new byte[size];
  fIn.read(buffer);
  fIn.close();
 } catch (IOException e) {
  // TODO Auto-generated catch block
  return false;
 }

 String path="/sdcard/media/audio/ringtones/";
 String filename="examplefile"+".ogg";

 boolean exists = (new File(path)).exists();
 if (!exists){new File(path).mkdirs();}

 FileOutputStream save;
 try {
  save = new FileOutputStream(path+filename);
  save.write(buffer);
  save.flush();
  save.close();
 } catch (FileNotFoundException e) {
  // TODO Auto-generated catch block
  return false;
 } catch (IOException e) {
  // TODO Auto-generated catch block
  return false;
 }    

 sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+path+filename)));

 File k = new File(path, filename);

 ContentValues values = new ContentValues();
 values.put(MediaStore.MediaColumns.DATA, k.getAbsolutePath());
 values.put(MediaStore.MediaColumns.TITLE, "exampletitle");
 values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/ogg");
 values.put(MediaStore.Audio.Media.ARTIST, "cssounds ");
 values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
 values.put(MediaStore.Audio.Media.IS_NOTIFICATION, true);
 values.put(MediaStore.Audio.Media.IS_ALARM, true);
 values.put(MediaStore.Audio.Media.IS_MUSIC, false);

 //Insert it into the database
 this.getContentResolver().insert(MediaStore.Audio.Media.getContentUriForPath(k.getAbsolutePath()), values);


 return true;
}

Comments, suggestions etc. are always welcome. Hope this has been helpful.

65 Comments

  1. mrj05hua

    Ok but how do i implement that I understand slightly how to declare them globaly but then how do i make the saveas pick from them. I am stuck at those two parts. All your help is and will continue to be greatly appreciated.

  2. mrj05hua

    so i declared them globally as
    int[] soundids = {R.raw.sound1, R.raw.sound2, R.raw.sound3};
    that part works but how do i function call into them in the save as or play feature? Is there a link I missed I will gladly do whatever research you send me too.

  3. mrj05hua

    I have gotten some of the code compiled and changed, I got it to pass an integer to the save as functions, it even saves the number of the resource id. But has some debugging errors, how can i get to use the name. Or am I going in the wrong direction.

    I passed the int as
    int[ ] soundid ={raw files, raw file, raw file};
    int j = 0;

    then in the button clicks it assigns the int to the corresponding number. But in the saveas it saves the resource location IE 2693889.mp3. How can I change this.

  4. mat

    Just make a matching string array.

    String[] name ={ “Sound 1”, “Sound name 2”, “Chainsaw!”};
    int[] sounds = {R.raw.sound1, R.raw.sound2, R.raw.chainsaw};

    then just have saveas(0); using the passed integer to correspond to the name and sound in the arrays.

  5. satish

    hi i tried this code. this code doesnt shows any error when i run this program. but it does not set it as a ringtone i dont know y…if save as true i have user the toast. but the toast itslf is not being displayed . pls help me i need this code working becase i need to submit my project

  6. mrj05hua

    @mat how do you assign an integer to that specific spot of the string or int arrays. I say a few ways to code it but I keep messing it up.

  7. mrj05hua

    nevermind lol figured it out thank you so so much!!!!!

  8. Tommy

    @mrJ05hua I am encountering the same problem you were and I can not figure it out. After googling I found this site. How did you set up the call of your arrays in the function that saves the file, well chooses the file the save? I know this is old but hey maybe you will reply 🙂 Thanks.

  9. Fernando Boaglio

    Excellent post, help me a lot!

  10. Patry

    Hi,

    I have a problem related to that but in a differente way. I am trying to do a recorder player in Android. I got the file “example.3gp” in the SD card but then, I would like to give an option to discard or save the sound with a different name. Is there any idea of that? How can I use just the example.3gp as a temporal var?

    Thanks in advance.

  11. pozycjonowanie warszawa

    I am thankful that I found this blog , exactly the right information that I was searching for! .

  12. John

    I implemented your code, very helpful thanks!!!!!
    After that i added ringtonemanager to set it as a ringtone.
    But on a android 2.3.3 device it will not work.
    I posted my question on stackoverflow.

    If you have time, could you take a look at it?

    http://stackoverflow.com/questions/10105877/ringtone-set-as-silent-on-android-2-3-but-works-on-4-0-3

  13. […] ringtone to sdcard:http://www.stealthcopter.com/blog/2010/01/android-saving-a-sound-file-to-sd-from-resource-and-settin… This is asking for a specific folder name on sd card. How do I know if card exists.. and what […]

  14. site

    Why use Hostgator Web Hosting to host your website.
    Host gator also provide set up of worth additional companies cost-free to all their buyers.
    The over two million domains hosted by Host –
    Gator make up approximately 1% of the world.

  15. rowery Giant

    Strona świadczy o ciekawych wydarzeniach, zapraszam do rozmowy

Leave a Comment

Your email address will not be published. Required fields are marked *