I need to play live audio stream, actually it is radio. The problem is that I also need to manage 20 minute buffer for streaming. As far as I understand it's not easy to implement with android.
Firstly I checked MediaPlayer, but it doesn't provide any methods for buffer management. In fact you even can't set buffer size directly.
Secondly I tried to manage buffer using local files: progressively download the stream to a temporary files and switch them. But when you want to switch to following file (change datasource in MediaPlayer), audio is not played continuously. You can hear short interruptions.
The last idea is to use stream proxy. Usually it is used for playing streams in Android versions below 8. In stream proxy you create ServerSocket, read from audio stream and write to player. So actually I can manage buffering there. I can cache stream and write to MediaPlayer whatever I want. But. It doesn't work with Android 8.
I got exception: Connection reset by peer java.net.SocketException: Connection reset by peer. MediaPlayer 8 doesn't want to read data from socket.
Thus I have two questions: 1) What other way to implement stream buffering? 2) how to adapt StreamProxy for android 8?
Any ideas are appreciated.
Thanks
If you're accessing the internet via Wi-Fi, constant buffering may mean that you don't have a strong connection to the network. Moving closer to the signal source or removing barriers between you and the signal can improve signal strength. Try loading other media to test your connection.
Buffering refers to downloading a certain amount of data before starting to play the video. Two common reasons for buffering are 1) your internet connection is too slow to stream a video in real time, and 2) the speed at which your router sends the video to all your internet-connected devices is too slow.
A buffer is a small area of memory which must be filled before the player begins playback of music. It represents a few seconds' worth of sound. It is intended to provide a more comfortable listening experience by avoiding small audible breaks in the stream, which would lead to unpleasant, jerky sound.
I use the same StreamProxy that guys used for NPR project - https://code.google.com/p/npr-android-app/source/browse/Npr/src/org/npr/android/news/StreamProxy.java
So it gets original audio stream:
String url = request.getRequestLine().getUri();
HttpResponse realResponse = download(url);
...
InputStream data = realResponse.getEntity().getContent();
And writes from this stream to client socket:
byte[] buff = new byte[1024 * 50];
while (isRunning && (readBytes = data.read(buff, 0, buff.length)) != -1) {
client.getOutputStream().write(buff, 0, readBytes);
}
(You can get whole code from the link above.)
And finally how they initialize the player (PlaybackService):
if (stream && sdkVersion < 8) {
if (proxy == null) {
proxy = new StreamProxy();
proxy.init();
proxy.start();
}
String proxyUrl = String.format("http://127.0.0.1:%d/%s", proxy.getPort(), url);
playUrl = proxyUrl;
}
...
mediaPlayer.setDataSource(playUrl);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.prepareAsync();
So they check SDK version. But if I omit this check and use proxy for SDK 8 as well I get an exception. It is strange that MediaPlayer even doesn't try to read the stream:
12-30 15:09:41.576: DEBUG/StreamProxy(266): downloading...
12-30 15:09:41.597: DEBUG/StreamProxy(266): reading headers
12-30 15:09:41.597: DEBUG/StreamProxy(266): headers done
12-30 15:09:41.647: DEBUG/StreamProxy(266): writing to client
12-30 15:09:41.857: INFO/AwesomePlayer(34): mConnectingDataSource->connect() returned - 1007
12-30 15:09:41.857: ERROR/MediaPlayer(266): error (1, -1007)
12-30 15:09:41.867: ERROR/MediaPlayer(266): Error (1,-1007)
12-30 15:09:41.867: WARN/AudioService(266): onError(1, -1007)
12-30 15:09:41.867: WARN/AudioService(266): MediaPlayer refused to play current item. Bailing on prepare.
12-30 15:09:41.867: WARN/AudioService(266): onComplete()
12-30 15:09:42.097: ERROR/StreamProxy(266): Connection reset by peer
java.net.SocketException: Connection reset by peer
at org.apache.harmony.luni.platform.OSNetworkSystem.writeSocketImpl(Native Method)
at org.apache.harmony.luni.platform.OSNetworkSystem.write(OSNetworkSystem.java:723)
at org.apache.harmony.luni.net.PlainSocketImpl.write(PlainSocketImpl.java:578)
at org.apache.harmony.luni.net.SocketOutputStream.write(SocketOutputStream.java:59)
at com.skyblue.service.media.StreamProxy.processRequest(StreamProxy.java:204)
at com.skyblue.service.media.StreamProxy.run(StreamProxy.java:103)
at java.lang.Thread.run(Thread.java:1096)
It seems that MediaPlayer became more clever. And If i pass such url "http://127.0.0.1:%d/%s"
it wants to get not only bytes but "full" http responce.
Also I wonder if there any other ways implement buffering? As I know the MediaPlayer consumes only files and urls. Solution with files doesn't work. So I have to use socket for stream transmitting.
Thanks
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With