Android Question MediaPlayerStream with creds for basic auth?

miker2069

Active Member
Licensed User
Longtime User
I'm trying to stream just the audio from an IP camera. The camera I'm using (Amcrest) publishes the URL for the audio stream as:

http://ip/cgi-bin/audio.cgi?action=getAudio&httptype=singlepart&channel=1

I can put that in a browser and it pops up a basic url auth dialog and after entering creds it works. Unfortunately I tried the format:

http://user:password@ip/cgi-bin/audio.cgi?action=getAudio&httptype=singlepart&channel=1

Which doesn't seem to seemless auth in a browser. VLC (VideoLan app) seems to do a better job at it though - and I assume it's parsing it out and handling the auth behind the scenes.


The MediaPlayerStream type of the Audio library doesn't seem to have a way to pass in or set creds for basic auth on a URL. I took a long shot and maybe thought if I authenticated with an HTTPJob first then that would work - it didn't :) (thought I'd try anyway).

So is there anyway to authenticate against the streaming server and use MediaPlayerStream?

I guess as a harder workaround would be to get the raw bytes (the IP camera can encode as AAC or G.711A or PCM - my particular camera only supports the first 2 though). The web service returns:

HTTP Code:
20 0 OK
Content Type: Audio/G.711A
Body:
<Audio data>
<Audio data>

Saw I guess I could use that and pipe it to an AudioStreamer? I was hoping for a slightly easier solution. Also I need to see if audiostream supports AAC or G.711A encoding.

Any insight is appreciated.

Thank You!
 

moster67

Expert
Licensed User
Longtime User
It was a long time ago I did this but maybe you need to encode it...
If I recall correctly, you can use StringUtils to encode it.
 
Upvote 0

miker2069

Active Member
Licensed User
Longtime User
So I gave expoplayer a whirl. I based my code attempt office this stack overflow post on authenticating streams in exoplayer (found here). After some time I came up with the following inline java. Th idea (so I thought) was to base64 encode the username and password, and pass that string *and* the ref to the SimpleExoPlayer instace from b4a to my inline java. In that routine it would setup the authorization header, and then associate it with a data source. Theoretically it should connect the stream url, authenticate, and then I should be able to return back to b4a and play it. Here's my code:

B4X:
#If JAVA

import anywheresoftware.b4a.keywords.B4AApplication;
import anywheresoftware.b4a.objects.SimpleExoPlayerWrapper;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.LoopingMediaSource;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.util.Util;
import android.net.Uri;

public String FirstMethod(String encoded, anywheresoftware.b4a.objects.SimpleExoPlayerWrapper exoplayer) {

   // encrypt Authdata
    //byte[] toEncrypt = (username + ":" + password).getBytes();
    //String encoded = android.util.Base64.encodeToString(toEncrypt, Base64.DEFAULT);
   
    String ua = Util.getUserAgent(this, "exoplayer2example");
           
    DefaultHttpDataSourceFactory dataSourceFactory = new DefaultHttpDataSourceFactory(ua);
    DefaultHttpDataSource source = new DefaultHttpDataSource(ua,null);
    dataSourceFactory.setDefaultRequestProperty("Authorization","Basic "+encoded);
   
    ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
    MediaSource videoSource = new ExtractorMediaSource(Uri.parse("http://10.0.0.111/cgi-bin/audio.cgi?action=getAudio&httptype=singlepart&channel=1"), dataSourceFactory,extractorsFactory, null, null);
    final LoopingMediaSource loopingSource = new LoopingMediaSource(videoSource);
   
    exoplayer.Prepare(videoSource);
   
   return ua;
   

}
#End If


For the moment, I hard coded the url to the ip camera audio stream inside the java routine.

I setup my SimpleExoPlayer and my encoded username/password (I just hacked up the exoplayer example) and pass everything up to my routine like so:

B4X:
Dim s As String = NativeMe.RunMethod("FirstMethod",Array(encoded_creds,player1))
   
    Log("ret: " & s) 'will print Hello World!
    Activity.LoadLayout("1")
    SimpleExoPlayerView1.Player = player1

Actually it *seemed* to attempt to authenticate as now I see 401 auth errors thrown from DefaultHttpDataSourceFactory in the log. After looking at a successful auth in my browser in fidler, I realize that my camera requires digest authentication and not basic (which is what I was using because I copied from the stackoverflow example). Digest auth is a different beast altogether - I'm sure it's doable, it's just not trivial (I haven't searched the forum yet to see if anyone has manually setup the digest auth header - there is java code out there so I know I could probably adapt that). Anyway, that's as far as I got with the exoplayer approach. Seems like auth won't be trivial at all (plus I'm not totally up to speed on the best way to setup inline java so I know my code is very crude).

Apparently this is a fairly frequently appearing question and some of the other alternatives suggested using a WebView and just hide it if you're just streaming audio. I tested that as well and that was very simple (after overriding the UserNameandPassword WebView event). It worked well. I don't know how much control I'll have over volume or muting or anything like that, but for now that works. I plan on trying to get digest auth working since I think I got pretty far with the exoplayer approach.

I figured I share my progress so far in case anyone comes across the need for authenticated audio/video streams on android. Any comments or pointers would be greatly appreciated.
 
Upvote 0
Top