Search code examples
androidxamarin.androidandroid-mediaplayer

Android MediaPlayer can't SetDataSource()


I'm trying to set the data source for a media player, but it keeps throwing this exception.

java.io.IOException: setDataSourceFD failed

Where am I going wrong?

java.io.IOException: setDataSourceFD failed.: status=0x80000000
    at android.media.MediaPlayer._setDataSource(Native Method)
    at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1025)
02-05 11:11:37.664 I/mono-stdout(19741):   at Android.Runtime.JNIEnv.CallVoidMethod (IntPtr jobject, IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00063] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.10.2-branch/4b53fbd0/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:507 
    at futurestate.audiobook.droid.ui.views.home.HomeView.n_onCreate(Native Method)
    at futurestate.audiobook.droid.ui.views.home.HomeView.onCreate(HomeView.java:31)
    at android.app.Activity.performCreate(Activity.java:5231)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
    at android.app.ActivityThread.access$800(ActivityThread.java:135)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5017)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
    at

Here's my code. The Player.SetDataSource() is the failing line.

if (Player == null)
{
    try
    {
        var expansionFile = ApkExpansionSupport.GetApkExpansionZipFile(Application.Context, 1, 0);
        var entry = expansionFile.GetEntry(FileName);

        // I can see all entries with the line below. 
        // Therefore the above code can reach into the obb and see the contents.
        // var entries = expansionFile.GetAllEntries();

        var pfd = ParcelFileDescriptor.Open(new File(entry.ZipFileName), ParcelFileMode.ReadOnly);
        var afd = new AssetFileDescriptor(pfd, entry.FileOffset, entry.FileSize);
        var fd = afd.FileDescriptor;

        Player = new MediaPlayer();
        Player.Reset();
        Player.SetWakeMode(Application.Context, WakeLockFlags.Partial);
        Player.Looping = false;

        Player.SetDataSource(fd, afd.StartOffset, afd.Length);
        Player.Prepare();
    }
    catch (Exception ex)
    {
        Console.Out.WriteLine(ex.Message);
        Console.Out.WriteLine(ex.Source);
        Console.Out.WriteLine(ex.InnerException);
        Console.Out.WriteLine(ex.StackTrace);
    }

    SeekTo(_startingPointMsec);
    DurationMsec = (Player.Duration);
}

Solution

  • Well, I suppose I don't know if I should feel stupid or plain mad. The whole problem with my approach was due to the fact that Microsoft's idea of "NoCompression" is a little askew.

    note: the code in the question works and is correct"

    The problem comes out of the fact that I was using Powershell to automate the creation of my .obb file. The script was leveraging System.IO.Compression, and when I set the System.IO.Compression.CompressionLevel to NoCompression, it still mangled my obb file.

    I fired up my console and installed 7zip (ps: rocks.)

    > cinst 7zip
    

    and recreated the obb file using the Store mode, and everything worked.

    enter image description here

    Now that this is figured out, here's our PowerShell build script

    function Invoke-CreateExpansionApk
    {
        param(
            [Parameter(Position=0, HelpMessage="Type of apk to create: main|patch")]
            [ValidateSet('main','patch')]
            [System.String]$Type = 'main',
            [Parameter(Position=1, Mandatory=$true, HelpMessage="Must be the same name as your Play Store App")]
            [System.String]$ApkName,
    
            [Parameter(Position=2, Mandatory=$true)]
            [System.String]$SourceDir,
            [Parameter(Position=3, Mandatory=$true)]
            [System.String]$OutputDir,
            [Parameter(Position=4)]
            [System.Double]$Version = 1
        )
        $PRIVATE:bundleVersion = $Version
    
        $PRIVATE:fileName = "$OutputDir\$Type.$bundleVersion.$ApkName.obb"
    
        $pwd = Get-ModuleDirectory
        set-alias sz $pwd\7za.exe
        sz a -tzip $fileName $SourceDir -mx0
    }