0

Not very easy to explain:

I have this app for streaming online radio. The problem was first with m3u format (which android somehow cannot normally stream like pls), so I have to parse the url with this ParserM3UToURL (that I found somewhere)... like this:

Uri u = Uri.parse(ParserM3UToURL.parse(STREAM_URL, sdkVersion, c));
player = MediaPlayer.create(c, u);

Mostly it works ok but it has one bug...

I'm testing this on two devices one old 2.2.2. (api level 17), other 4.3 (api level 23). Older device works fine. It can stream radio over wifi or mobile data, but the newer device has some problem with streaming over mobile data (on wifi it works ok). The application crashes because the parse function returns null: http://pastebin.com/ghbAqGzM

And I assume there are many more phones with 4.x than 2.x android. Which of course is very painful for me. Somehow I have to fix this.. So I really hope somebody will have some clue about this. I hope my explanation was not to confusing...

This is the ParserM3UToURL.parse() function:

public static String parse(String paramString, int sdkVersion, Context c)
{
    try
    {
      StrictModeWrapper.init(c);
      HttpURLConnection localHttpURLConnection = (HttpURLConnection)new URL(paramString).openConnection();
      InputStream localInputStream = localHttpURLConnection.getInputStream();
      BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(localInputStream));
      StringBuffer localStringBuffer = new StringBuffer();
      while (true)
      {
        String str = localBufferedReader.readLine();
        if (str == null)
        {
          localHttpURLConnection.disconnect();
          localBufferedReader.close();
          localInputStream.close();
          break;
        }
        if (str.contains("http"))
        {
          localHttpURLConnection.disconnect();
          localBufferedReader.close();
          localInputStream.close();
          return str;
        }
        localStringBuffer.append(str);
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    return null;
}
user568021
  • 1,426
  • 5
  • 28
  • 55
  • I was about to ask if you were calling the "parse" method on the Main Thread since network requests aren't allowed on the main thread but upon taking a look at the log in pastbin I realize you're working with the AsynTask. I wrote a method to solve this issue sometime ago. It works fine on all devices/os versions but it's quiet long. Can I go ahead and post it? – Nana Ghartey Jan 08 '14 at 20:07
  • Sorry I forgot about this for two days. But yes the problem is still here.. Please post the pastebin or something.. – user568021 Jan 08 '14 at 22:43
  • I've posted an answer. Try it out :-) – Nana Ghartey Jan 09 '14 at 00:20

2 Answers2

5

Below is what i worked on to stream radio (m3Urls). The example below uses a service. When the service is started, the url is parsed. Note that in the onPostExecute, parsed file is prepared. Once the file is prepared(completed buffering), the file is played/started and stopped upon completion.

  public class BackgroundRadioService extends Service implements
        OnCompletionListener, OnPreparedListener{
     MediaPlayer mediaPlayer;


@Override
public void onCreate() {

    mediaPlayer = new MediaPlayer();
    mediaPlayer.setOnCompletionListener(this);
    mediaPlayer.setOnPreparedListener(this);

}

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
              parseM3uUrlAndPrepare("http://listen.radionomy.com/andalousse.m3u");
    return START_STICKY;
    }



  private void parseM3uUrlAndPrepare(final String url){

AsyncTask<String, Integer, String> asyn = new  AsyncTask<String, Integer, String>(){

        HttpClient httpClient;
        HttpGet getRequest;
        HttpResponse httpResponse = null;
        String filePath = "";

            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                 httpClient = new DefaultHttpClient();


                    getRequest = new HttpGet(url);

            }

        @Override
        protected String doInBackground(String... params) {

                try {
                    httpResponse = httpClient.execute(getRequest);
                } catch (ClientProtocolException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                if(httpResponse != null)
                if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                    // ERROR MESSAGE


                } else {
                    InputStream inputStream = null;
                    try {
                        inputStream = httpResponse.getEntity().getContent();
                    } catch (IllegalStateException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    } catch (IOException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    } 
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                    String line;
                    try {
                        while ((line = bufferedReader.readLine()) != null) {
                            //Log.v("PLAYLISTLINE", "ORIG: " + line);
                            if (line.startsWith("#")) { // Metadata

                            } else if (line.length() > 0) {
                                filePath = "";

                                if (line.startsWith("http://")) { // Assume it's a full URL
                                    filePath = line;
                                } else { // Assume it's relative
                                    try{
                                    filePath = getRequest.getURI().resolve(line).toString();
                                    }catch(IllegalArgumentException e){

                                    }catch(Exception e){

                                    }
                                }


                            }
                        }
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            return filePath;
        }

        @Override
        protected void onPostExecute(String filePath) {
            try {
            mediaPlayer.setDataSource(filePath);
            mediaPlayer.prepareAsync(); //this will prepare file a.k.a buffering

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        }
    };          
        asyn.execute("");

}

@Override
        public void onPrepared(MediaPlayer mp) {
            // TODO Auto-generated method stub      
            mediaPlayer.start();    
}

@Override
    public void onCompletion(MediaPlayer mp) {  
        mediaPlayer.stop();
      }

}//end of Service class declaration

Note: This ignores playlists hence assumes the m3u parsed will return only one file. Let me know if you would like to handle playlists so I modify my answer :)

Nana Ghartey
  • 7,901
  • 1
  • 24
  • 26
  • I guess I don't care about playlists, I just want "the play button" to work. This code is ok, but it still crashes on g3. The problem is in onPostExecute... setDataSource... but it is a progress.. – user568021 Jan 09 '14 at 10:29
  • When debugging I get the impression, that the problem is that newer devices can't execute http request properly when on 3g. It just pisses me off when both (your code and mine) work fine with 3g or wifi on an old device but not on my Samsung Galaxy S2.. – user568021 Jan 09 '14 at 10:51
  • I think this is the same problem: http://stackoverflow.com/questions/17473617/asynctask-httppost-execute-fails-on-3g-but-works-on-wifi – user568021 Jan 09 '14 at 11:06
  • I would except your answer, because you actually improved my implementation (no need for m3u parser class), but the problem was something else - Proxies... If I disable them, it works. This took 3 days of my life...damn you android! – user568021 Jan 10 '14 at 15:09
1

I solved it thanks to this question's comments: POST request failing when in 3G

The problem was actually with proxies on 3G. So if proxies are disabled, no weird http requests.

I modified my code a little. Thanks to Nana's answer I no longer need a m3u parser. I also no longer use HttpClient but HttpURLConnection instead. So when calling URL.openConnection() I add the Proxy.NO_PROXY parameter to that function and bam!

So the solution is "use HttpURLConnection not HttpClient and add NO_PROXY parameter":

conn = (HttpURLConnection) the_url.openConnection( Proxy.NO_PROXY );
Community
  • 1
  • 1
user568021
  • 1,426
  • 5
  • 28
  • 55