MediaPlayer cant play audio files from program data folder? - android

When i record my audio from MIC and store file in /data/data/..... why
MediaPlayer can't play this file ? If i change destination to /
sdcard/..... - all works great. I do something wrong ? I not found
limitation for MediaPlayer. Device - Samsung T959 (Galaxy S)
Thanks, i hope anybody know solution....

i had the same issues... whenever i used setDataSource with filepaths, it would not work; kept getting IOException.
changing my code to use setDataSource(FileDescriptor) does work... and with this i don't have to copy the files to SDCard or anything like that.
So, with a simple File object, create a new FileInputStream and pass the actual file descriptor as data source as in:
setDataSource((new FileInputStream(myFileInstance)).getFD());
creating an input stream pulls the file data into memory and thereby addresses /data/data access violations.

Better practice is to close the stream, like this:
FileInputStream stream = new FileInputStream(path);
mediaPlayer.setDataSource(stream.getFD());
stream.close();
Even better from Kotlin:
mediaPlayer.setDataSource(
FileInputStream(path).use { it.fd }
)
It is noted in the documentation of the method:
android.media.MediaPlayer.setDataSource(FileDescriptor fd)
Sets the data source (FileDescriptor) to use. It is the caller's
responsibility to close the file descriptor. It is safe to do so as
soon as this call returns.

use MediaPlayer.setDataSource(FileDescriptor fd)

Try setting ContentValues and to store some standard meta-data properties. Then using a ContentResolver to set the meta-data and Uri to the file.
see: http://developer.android.com/guide/topics/media/index.html
"Example: Audio Capture Setup and Start", then try changing Uri base to your /data/data/-filename.

Due to the Android security model, MediaPlayer haven't enough rights. It can access SD card, but can't access another places with out permissions.
As so, setDataSource(...) can thrown SecurityException and I think it's happening.
You can play this file next ways:
copy it to temp dir and play;
copy it to temp dir and play;
copy it to sdcard;
read it fully to memory and try play via stream.

Related

How can I write a public file for my service to pick up on Android?

I have two parts to this question: 1) what is the best solution to my need, and 2) how do I do this?
1) I have a client app which sends bundles to a service app. the bundles can break the limit on bundle size, so I need to write the actual request out and read it in on the service side. Because of this, I can't write to my private internal storage. I've used these pages heavily, and haven't had luck: http://developer.android.com/guide/topics/data/data-storage.html
http://developer.android.com/training/basics/data-storage/files.html
My current understanding is that my best path is to use this to get a public dir:
File innerDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
I then add in my filename:
String fileName = String.valueOf(request.timestamp + "_avoidRoute"+count+++".ggr");
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
fos.write(routeString.getBytes());
fos.close();
When I try to write this to disk I get the error
java.lang.IllegalArgumentException: File /storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr contains a path separator
Of course it does - I need it to have a path. I've searched online for solutions to this error which tell me to us FileOutputStream to write a full path. I did, but while my app doesn't error and appears to create the file, I'm also not able to view it on my phone in Windows Explorer, leading me to believe that it is creating a file with private permissions. So this brings me to my post and two questions:
1) Is there a different approach I should be trying to take to share large amounts of data between my client and service apps?
2) If not, what am I missing?
Thanks all for reading and trying to help!
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
This is not an appropriate use of Context's openFileOutput() method as that does not take a full path, but rather a filename within an app's private storage area.
If you are going to develop a full path yourself, as you have, then use
fos = new FileOutputStream(fullPath)
The Sharing permission setting is not applicable to the External Storage, though you will need a manifest permission to write (and implicitly read) on your creator, and the one for reading on your consumer.
Or, instead of constructing a full path, you could use your private storage with a filename and Context.MODE_WORLD_WRITEABLE (despite the being deprecated as an advisory) and pass the absolute path of the result to the other app to use with new FileInputStream(path).
Or you could use any of the other data interchange methods - content providers, local sockets, etc.

Can one retrieve data from a MediaPlayer's stream?

If I were to stream some sort of media to a MediaPlayer, is there any way I could copy it before/as/after it is played? For instance, if I were to stream a YouTube clip, is it possible to save that clip as it is being played?
Edit:
(Ocelot's answer made me realise how localised this question is).
What I am looking to do is copy the stream of a MediaPlayer already in progress (be it youtube or music stream). I want to be able to be notified when a new stream starts and ends. So far the only thing I found (for the latter) that is even remotely close it the broadcast string ACTION_AUDIO_BECOMING_NOISY but that doesn't really do anything for what I need. I there any way to do this?
I haven't tested this, and it looks like quite a bit of work, but here is what I would try:
Create a subclass of Socket. In this class, you can handle all byte reads, and save the stream locally or do whatever you want with it
Create your own content provider, which you can use to pass URIs to your media player, in your own format. Example: mystream://youtube.com/watch?v=3Rhy37u
In your content provider, override the openFile method and in it, open your own socket, and create a ParcelFileDescriptor with it.
Now, simply passing the new format url to your mediaplayer should make all streams go through your Socket, where you can save your data.
one way is to first find out where the video is in the server for exmaple in youtube with simple regex like this :
Regex("(?<=&t=)[^&]*").Match(file).Value;
you could retrieve url to the video and then download it like
public static void Download(string videoID, string newFilePath)
{
WebClient wc = new WebClient();
string file = wc.DownloadString(string.Format("http://www.youtube.com/watch?v={0}", videoID));
string t = new Regex("(?<=&t=)[^&]*").Match(file).Value;
wc.DownloadFile(string.Format("http://www.youtube.com/get_video?t={0}=&video_id={1}",t,videoID), newFilePath);
}
it's c# code but you could easily convert it to java.
#zrgiu
I tried to go with this solution, but the MediaPlayer retrieves a FileDescriptor from the URI, so sadly no http URL can be passed like this.
I also found another solution, it suggests to create a local ProxyServer on your device to serve files from the internet, it should be possible to also save the files streamed via the proxy.

how to play midi file in android use fmod

I am trying to play midi file using fmod. But there is an error says that :a resource that the plugin requires cannot be found,(ie the DLS file for MIDI playback)
I have searched results for problems like this,and referred to the fmod.h files. It seems that I need a file named "gs_instrument.dls" but I cannot find it in my mac as well as the android simulator filesystem. I have also searched the resources in the web,no result either.
So what should I do if I want to play midi file in android using fmod.
Hope you can help me!
Thanks!
I don't know about fmod, but Android can play MIDI files right out of the box. Here's a simplified version of what works for me:
MediaPlayer mediaPlayer = new MediaPlayer();
File f = [... my MIDI file ...];
FileInputStream fis = new FileInputStream(f);
FileDescriptor fd = fis.getFD();
mediaPlayer.setDataSource( fd );
mediaPlayer.prepare();
mediaPlayer.start();
You specify the location of the DLS file with the dlsname member of the FMOD_CREATESOUNDEXINFO structure passed into System::createSound.
You must provide the actual file yourself and put it on the sdcard so you can pass in the location of it. On Windows the default DLS file is located at "C:\Windows\System32\drivers\gm.dls" or "C:\Windows\System32\drivers\etc\gm.dls". Alternatively on Mac it is located at "/System/Library/Components/CoreAudio.component/Contents/Resources/gs_instruments.dls". This being said I cannot speak to the legality of using these files in an Android project, you may need to source your own "free" dls file from somewhere else.
You can use like this. You can call following method where you want to play midi file.
public void myRingCtone()
{
Uri path = Uri.parse("android.resource://com.PackageName/raw/MIDI_RingToneName");
RingtoneManager.setActualDefaultRingtoneUri(getApplicationContext(),
RingtoneManager.TYPE_RINGTONE, path);
Log .i("TESTT", "Ringtone Set to Resource: "+ path.toString());
RingtoneManager.getRingtone(getApplicationContext(), path).play();
}

Android Assets-Folder: it takes always the first file by alphabetical order

I'm new in Java/Android programming, so please have patience with me.
I try to play a mp3 which is locate und the assets folder. I know there is another way with the /res/raw/ folder, but use the assets-folder because later I'll try to access the file by String.
This code works to play a mp3-file:
try
{
MediaPlayer mp = new MediaPlayer();
FileDescriptor sfd = getAssets().openFd("song.mp3").getFileDescriptor();
mp.setDataSource(sfd);
mp.prepare();
mp.start();
}
catch(Exception e) {}
Now the problem: In the same assets-folder is another mp3 file stored. Though I specify the name of the mp3 to use it take the one which comes first in alphabet. E.g. the other file is named "music.mp3" it plays this one. Renaming it to "worldmusic.mp3" it will play "song.mp3". Rerename "worldmusic.mp3" back to "music.mp3" it will take this mp3 again. Another test: Renaming "song.mp3" to something other so the application can find whats specify by the code above will result that no song is played. So this means the songname have to exist, although it take arbitrary the song first in alphabet.
I'm testing with the AVD emulator of eclipse. But I think the behaviour would be the same on a real device.
Have someone an idea about this problem?
I don't believe using FileDescriptor is the right way to do this. Try using .create() and a Uri instead:
MediaPlayer mp = MediaPlayer.create(getBaseContext(), songUri);
mp.start();
Not sure why, but the URI syntax doesn't seem to work for the assets. Try getting the AssetFileDescriptor instead, as answered in the related question:
Play audio file from the assets directory

Feeding data from memory to MediaPlayer

Scenario:
Have encrypted mp3 files in my .apk. Need to decrypt and send to MediaPlayer object.
Problem:
After I read the files and decrypt them, how do I get MediaPlayer to play them ?
Now. MediaPlayer has 4 versions of setDataSource().
setDataSource(String path)
setDataSource(FileDescriptor fd)
setDataSource(FileDescriptor fd, long offset, long length)
setDataSource(Context context, Uri uri)
None of which are ideal for the situation. Guess ideal would be to give MediaPlayer an InputStream ?
Possible solutions:
Write decrypted data to file play
that file. A lot of IO overhead.
Create a dummy http server
(ServerSocket ?) and pass the url to
MediaPlayer. Again, messy. Am I
even allowed to create a socket.
Does anyone have a better solution ?
byte[] callData = ...;
String base64EncodedString = Base64.encodeToString(callData, Base64.DEFAULT);
try
{
String url = "data:audio/amr;base64,"+base64EncodedString;
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
mediaPlayer.start();
}
catch(Exception ex){
...
}
If you don't need all the functionality in MediaPlayer, I recommend trying AudioTrack. It's meant for basically what you describe. Unfortunately, MediaPlayer doesn't take an AudioTrack in its constructor, so the best solution in that case is to include a dummy Http server that sends your data back from a URL (which is what the Android 1.0 release notes recommends).
I'm not a 100% sure, but I don't think you have any other option than to temporarily save the the decrypted file before playing it.
This question is kind of similar, but I don't think you use the easy solution suggested there since you have an encrypted file. There is also provided a link to a tutorial for Custom Audio Streaming with MediaPlayer, but it seems like their solution also use a temporary file.

Categories

Resources