jPlayer songs not loading correctly using MVC meth

2019-04-07 10:36发布

问题:

If I use mp3: "/Music/StreamUploadedSongs/1" in the following code:

var player = new $("#jquery_jplayer_1").jPlayer({
        ready: function () {
            $(this).jPlayer("setMedia", {
                mp3: "/Music/StreamUploadedSongs/1",
            });
        },
        cssSelectorAncestor: "#jp_container_1",
        swfPath: "~Scripts/Jplayer/jquery.jplayer.swf",
        useStateClassSkin: true,
        autoBlur: false,
        keyEnabled: true        
        }
});

Here is what it looks like, you can see jplayer isn't moving the times correctly (they are overlapping) and also the seek/play bar doesn't work although the song can still be played:

Html Markup: <audio id="jp_audio_0" preload="metadata" src="http://localhost:6060/Music/StreamUploadedSongs/1"></audio>

Music Controller:

public ActionResult StreamUploadedSongs(int id)
{
        byte[] song = db.UploadedSongs.Where(x => x.Id == id).FirstOrDefault().SongBytes;
        return File(song, "audio/*");
}

If i change the mp3 property to this instead: mp3: "http://www.jplayer.org/audio/mp3/TSP-01-Cro_magnon_man.mp3" then it works perfectly.

var player = new $("#jquery_jplayer_1").jPlayer({
    ready: function () {
        $(this).jPlayer("setMedia", {
            mp3: "http://www.jplayer.org/audio/mp3/TSP-01-Cro_magnon_man.mp3",
        });
    },
    cssSelectorAncestor: "#jp_container_1",
    swfPath: "~Scripts/Jplayer/jquery.jplayer.swf",
    useStateClassSkin: true,
    autoBlur: false,
    keyEnabled: true        
    }

});

Here is what it looks like, working properly, the seek/play bar works and jplayer has moved the time to the correct positions:

Html Markup: <audio id="jp_audio_0" preload="metadata" src="http://www.jplayer.org/audio/mp3/TSP-01-Cro_magnon_man.mp3"></audio>

I have other jPlayers on other pages and its the exact same with them too.

Edit: Just tried this:

 public string StreamUploadedSongs(int id)
    {
      string filePath = Server.MapPath(Url.Content("~/Content/TSP-01-Cro_magnon_man.mp3"));

       return filePath; 
    }

I put the mp3 file in that directory but it doesn't play at all now. If I paste this into url http://localhost:6060/Music/StreamUploadedSongs/1034" it just returns I:\Users\UserName\Desktop\MusicSite\MusicSite\MusicSite\Content\TSP-01-Cro_magnon_man.mp3 instead of playing the song.

回答1:

Here is problem, Google chrome and Ipad (i think?) require support for content-range requests. You are loading entire song, you need to load parts of it. If you load mozzila firefox you see your way works but google chrome it doesn't. This also happens with HTML5 audio.

As default ASP doesn't support it, you have to add it manually. That's why it works when using URL link and not when selecting from DB.

 public FileStreamResult StreamUploadedSongs(int id)
    {
        byte[] song = db.UploadedSongs.Where(x => x.Id == id).FirstOrDefault().SongBytes;
        long fSize = song.Length;
        long startbyte = 0;
        long endbyte = fSize - 1;
        int statusCode = 200;
        if ((Request.Headers["Range"] != null))
        {
            //Get the actual byte range from the range header string, and set the starting byte.
            string[] range = Request.Headers["Range"].Split(new char[] { '=', '-' });
            startbyte = Convert.ToInt64(range[1]);
            if (range.Length > 2 && range[2] != "") endbyte = Convert.ToInt64(range[2]);
            //If the start byte is not equal to zero, that means the user is requesting partial content.
            if (startbyte != 0 || endbyte != fSize - 1 || range.Length > 2 && range[2] == "")
            { statusCode = 206; }//Set the status code of the response to 206 (Partial Content) and add a content range header.                                    
        }
        long desSize = endbyte - startbyte + 1;
        //Headers
        Response.StatusCode = statusCode;

        Response.ContentType = "audio/mp3";
        Response.AddHeader("Content-Accept", Response.ContentType);
        Response.AddHeader("Content-Length", desSize.ToString());
        Response.AddHeader("Content-Range", string.Format("bytes {0}-{1}/{2}", startbyte, endbyte, fSize));

        //Data
        var stream = new MemoryStream(song, (int)startbyte, (int)desSize);

        return new FileStreamResult(stream, Response.ContentType);
    }


回答2:

As you have your songs in a database I have assumed you will want to create and return a File.

If this is not the case let me know and I can add a file path method instead.

I had to adapt your client code slightly:

View

<script type="text/javascript" src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jplayer/2.9.2/jplayer/jquery.jplayer.min.js"></script>
<script type="text/javascript">

    $(function () {

        var player = new $("#jquery_jplayer_1").jPlayer({
            ready: function () {
                $(this).jPlayer("setMedia", {
                    mp3: "/Music/StreamUploadedSongs/1",
                });
            },
            cssSelectorAncestor: "#jp_container_1",
            swfPath: "~Scripts/Jplayer/jquery.jplayer.swf",
            useStateClassSkin: true,
            autoBlur: false,
            keyEnabled: true
            //} deleted this extra bracket
        });

    });

</script>

<div id="jquery_jplayer_1"></div>
<div id="jp_container_1">
    <a href="#" class="jp-play">Play</a>
    <a href="#" class="jp-pause">Pause</a>
</div>

Simply wrapped a doc ready and deleted an extra bracket.

Controller

public ActionResult StreamUploadedSongs(int id)
{
    //byte[] song = db.UploadedSongs.Where(x => x.Id == id).FirstOrDefault().SongBytes;
    var song = System.IO.File.ReadAllBytes(@"C:\Foo.mp3");
    return File(song, "audio/mp3");
}

I had to specify the MIME type, if I left it as "audio/*" the browser simply downloaded the file rather than playing it.

You can test this yourself by directly navigating to the controller action, wiht a mime type specified it will display the default player rather than downloading the file.

I'd suggest reading the mime type from your song instead, rather than hardcoding the way I have i.e.

public ActionResult StreamUploadedSongs(int id)
{
    byte[] song = db.UploadedSongs.Where(x => x.Id == id).FirstOrDefault().SongBytes;

    return File(song, "audio/" + song.MimeType);
}