8

We have recently been receiving reports of audio not playing in our Android apps, on the Samsung Galaxy S4. The app is fine on other devices.

The audio is streamed using the MediaPlayer. It is saved locally using the Android Socket method.

The warning in the Logcat is caused by:

try {
    byte[] buffer = httpString.toString().getBytes();
    int readBytes = -1;
    Log.d(LOG_TAG, "writing to client");
    client.getOutputStream().write(buffer, 0, buffer.length);

    // Start streaming content.
    byte[] buff = new byte[1024 * 64];
    while (isRunning && (readBytes = data.read(buff, 0, buff.length)) != -1) {
        client.getOutputStream().write(buff, 0, readBytes);
    }
}

The stack trace is as follows:

D/StreamProxy(3913): downloaded
D/StreamProxy(3913): downloading...
D/StreamProxy(3913): reading headers
D/StreamProxy(3913): headers done HTTP/1.0 200 OK
D/StreamProxy(3913): Content-Type: audio/mpeg
D/StreamProxy(3913): 
D/StreamProxy(3913): writing to client
W/StreamProxy(3913): Broken pipe.
W/StreamProxy(3913): java.net.SocketException: sendto failed: EPIPE (Broken pipe)
W/StreamProxy(3913):    at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:506)
W/StreamProxy(3913):    at libcore.io.IoBridge.sendto(IoBridge.java:475)
W/StreamProxy(3913):    at java.net.PlainSocketImpl.write(PlainSocketImpl.java:507)
W/StreamProxy(3913):    at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:46)
W/StreamProxy(3913):    at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:269)
W/StreamProxy(3913):    at com.gm.mobile.util.StreamProxy.processRequest(StreamProxy.java:234)
W/StreamProxy(3913):    at com.gm.mobile.util.StreamProxy.run(StreamProxy.java:123)
W/StreamProxy(3913):    at java.lang.Thread.run(Thread.java:856)
W/StreamProxy(3913): Caused by: libcore.io.ErrnoException: sendto failed: EPIPE (Broken pipe)
W/StreamProxy(3913):    at libcore.io.Posix.sendtoBytes(Native Method)
W/StreamProxy(3913):    at libcore.io.Posix.sendto(Posix.java:151)
W/StreamProxy(3913):    at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
W/StreamProxy(3913):    at libcore.io.IoBridge.sendto(IoBridge.java:473)
W/StreamProxy(3913):    ... 6 more
E/(3913): client closing
D/StreamProxy(3913): Proxy interrupted. Shutting down.

The stream plays when I comment out the proxy code, however, it starts playing for a second, then starts buffering for 2-3 seconds, before resuming.

Any solutions would be greatly accepted.

I have found similar issues, but they have not been solved:

Community
  • 1
  • 1
SteveEdson
  • 2,485
  • 2
  • 28
  • 46
  • I've been having the same issue. No solution yet though :( – Nick May 13 '13 at 14:21
  • At least I'm not the only one. Have you got any further than I have? Anything you can share that would help solve the issue? – SteveEdson May 13 '13 at 14:42
  • Unfortunately not. I dont even have an S4 to test on. I've seen this on a few other devices besides the S4 but haven't been able to pinpoint the issue. I will update here if I find anything. – Nick May 13 '13 at 22:54
  • Do you have an S4 to test on? If so try sending "HTTP/1.0 206 OK" as the status line and see if that works. Or potentially "HTTP/1.0 206 Partial Content". – Nick May 13 '13 at 23:19
  • A co-worker has an S4 so I am able to test a little bit. I was kind of hoping for a solution that doesn't involve changing stuff on the server. The app works fine on other devices, and the URL can vary, so its not a suitable option for me personally. If I get chance, I will try it though, would be interested to see if it makes a difference. – SteveEdson May 14 '13 at 09:18
  • You dont necessarily have to change it on the server. After you get the request back from the server, you can alter the headers to be whatever you want before you send them back into the media player. – Nick May 14 '13 at 14:20
  • Is the issues still persist , while using byte[] buff = new byte[1024]; Actually I worked on different video streaming apps , and make sure ServerSocket is also having the same buffer sync .So, as to have well channelization, and avoid connection reset by peer(due to pipe-lining multiple messages in some device as per the resources). In my case it was not working on certain chinese tablets with lower buffer read capabilities . – Arpit Garg May 21 '13 at 09:19
  • @Nick, changing the status line had no effect unfortunately. Thanks Arpit, I'll give this a go and report back. – SteveEdson May 21 '13 at 09:46

2 Answers2

4

I've finally figured out the issue that was causing this. As expected, the media player was doing range requests in an attempt to find the id3 information. On other phones simply setting the header status line to HTTP/1.0 206 OK would prevent the media player from performing such range requests. However, for some odd reason, this is not true on the S4 (thanks Samsung!).

So in order to fix it, you will just need to handle these range requests. In my case I was only calling socket.accept() one time. I changed this to be performed in a loop while isRunning is true in my run() function. This way, when a new request is done, it is handled properly. A chopped-down version of my code looks like this...

public void run() {

    while (isRunning) {

        client = socket.accept();

        HttpResponse cloudResponse = startCloudRequest();
        sendDataToMediaPlayer(cloudResponse);

    }
}

Hope this helps.

Nick
  • 6,375
  • 5
  • 36
  • 53
0

Broken Pipe usually occurs when the other side has closed the connection on you. Make sure you are proxying the headers correctly and then putting in the two newlines before throwing in the body. Something you are feeding the other end is likely prompting a socket close.... This only happens on S4? Are you sending the content length?

Aditya Nagrath
  • 421
  • 2
  • 8
  • Yes this only happens on the galaxy S4, no issues on hundreds of other devices. AFAIK the content length is 0 because it is a live stream which theoretically never ends. – SteveEdson May 23 '13 at 14:08
  • I send the content length in the header. If you do not, the media player will not know how long the song is and therefore wont show the duration. This is most likely happening (although I cant confirm) because the media player is doing a range request and not getting the right information back afterwards. However, I dont know how to stop this range request (sending http1.0 works on all other phones). Ive also seen this on certain versions of the Note 2 and the LG Optimus G. – Nick Jun 03 '13 at 00:07