0

I want to write an app that plays progressively-downloaded audio from a remote http source through the standard Android mediaplayer, but I want to save a copy of the audio file to the SD card as well. This has proved to be a hard problem:

1) We pass a uri to the media player and are then "cut out of the loop" during playback, because mediaplayer talks directly to the remote thereby not having access to the bytes being played

2) There doesn't seem to be an option for Android to write downloaded bits to disk, nor a callback to access downloaded data

3) While it's possible embed a webserver into our app (see nanohttpd), and then pass a localhost uri into mediaplayer, this seems like a horrible kludge

Am I missing a simpler way? This must be a solved problem?!

Edit: Perhaps a simpler question: if I have a buffer in memory that contains music, can I play it? It seems ridiculous that I have to write it to disk or use a web server to get the mediaplayer to play it.

Fixee
  • 1,581
  • 2
  • 15
  • 25

1 Answers1

1

Yes, there is a way to do this. Create a local proxy server and connect the MediaPlayer to that. See my answer here for a little more detail.

Edit: After looking at this on my PC instead of my phone, I noticed you mention embedding a server in your app. If done properly, it is lightweight and straightforward. And it will give you access to the raw data. I don't think it is a "kludge" at all.

Community
  • 1
  • 1
Dave
  • 4,282
  • 2
  • 19
  • 24
  • You have to man-in-the-middle your own app.. I'd call that a kludge. It also adds latency and complexity. And, as a security concern, it opens a port on your device that anyone can suck music out of (this is especially a concern since the proxy would be decrypting encrypted files from its doc root and then serving plaintext music to the mediaplayer). I appreciate the reply, Dave, but I'm going to see if I can find another way. Perhaps via OpenSL ES's api. – Fixee Sep 09 '13 at 05:22
  • Suit yourself. But... 1) Using NIO, latency is negligible to non-existent in my experience. 2) I fail to see the security concern, particularly since you intend to write to the world-readable SD card. If you design the proxy, you can restrict access and serve secure media as necessary. In the end, it's just a workaround given the available API. My concerns are more for video, though, so I haven't explored the OpenSL option. I'd be interested to see what you come up with. Good luck! – Dave Sep 09 '13 at 07:01
  • I'll write ciphertext to the SD. How are you suggesting to restrict access to the proxy? (I know one way, but I'd love to hear what you're thinking when you say this.) – Fixee Sep 09 '13 at 22:34
  • I have another suggestion first. Depending on if you need seek capability and possibly what type of media you intend to consume, you can use a pipe. Your client feeds the pipe (and whatever else you would like), and the media player simply reads as if it's a file. I've only tested this with my hardware vendor's hacked player, but I would bet it works with standard Android as well. – Dave Sep 10 '13 at 01:14
  • I had read in the Droid MediaPlayer docs that the filedescriptor has to be seekable (they specifically warned against using pipes). Perhaps you're right that if the player doesn't seek pipes might still work, but ours does seek. Still, it's a clever idea! I just wish we could extend FileDescriptor and this would all be easy... but that is a final class in Java. Gosling sabotaged me 20 years ago... nice going man. – Fixee Sep 10 '13 at 01:22
  • To be honest, I'm confused as to what scenario you are worried about with the proxy. Simply refusing connections from anything other than local ip limits attacks to apps on the same device. But really, nothing is being written to a socket by the local proxy that wasn't being sent the same way from the remote host. Any security concerns that exist for one exist for both. – Dave Sep 10 '13 at 01:29
  • You read encrypted music from the remote, then decrypt in my app and play the music. The problem is, `mediaplayer` won't let you play the decrypted buffer, and writing it to disk puts plaintext on the SD. Feeding `mediaplayer` via a socket lets any app on the device pull plaintext as well. So how does one ensure that only the "authorized" invocation of `mediaplayer` reads from your proxy? I think the best idea is to use a temp key embedded in the URI. Not ideal, but the problem is not easily solved here. – Fixee Sep 10 '13 at 03:08
  • I thought to use a key in the URI as well, so yeah that's one way to restrict requests. I was also thinking to use a secure proxy, but a little googling makes me think the media player may not cooperate without some coercion. If your media is so sensitive you think someone will root their phone and put a packet sniffer on it, I guess the proxy isn't an easy out after all. If I come up with something more clever, I'll be sure to put it here for posterity. – Dave Sep 10 '13 at 11:20