urlreader
urlreader

Reputation: 6605

Stream Audio directly from an url to Web Browser in C# & ASP.NET MVC?

I'm using ASP.NET MVC and C# for a project.

One task is: when a user clicks on a link, it needs get the id from the link, then use this link to generate an external link, which is a audio file, then play it in web browser (not save as file).

The current solution is: download the audio file from the external link, get the bytes, then put it in the response as audio/wav

public async Task<HttpResponseMessage> StreamAudioAsync(string id)
{
    var response = Request.CreateResponse(HttpStatusCode.Moved);
    var data = GetAudio(id);

    if (data != null && data.Length > 0)
    {
        response.StatusCode = HttpStatusCode.OK;
        response.Content = new ByteArrayContent(data);
        response.Content.Headers.ContentType = new MediaTypeHeaderValue("audio/wav");
    }

    return response;
}

private byte[] GetAudio(string id)
{
    string accessKey = Cp.Service.Settings.AccessKey;
    string secretAccessKey = Cp.Service.Settings.SecretAccessKey;

    string url = string.Format("https://....../......php?access_key={0}&secret_access_key={1}&action=recording.download&format=mp3&sid={2}", accessKey, secretAccessKey, id);

    byte[] data = null;

    try
    {
        using (var wc = new System.Net.WebClient())
        {
            data = wc.DownloadData(url);
        }
    }
    catch //(Exception ex)
    {
        //forbidden, proxy issues, file not found (404) etc
        //ms = null;
    }

    return data;
}

This will download the audio data first. Is there a way to stream the audio stream from the url directly to the response? so that, the server will not hold the data bytes[] in memory? Sometimes, the data size is huge.

Thanks

Upvotes: 4

Views: 4558

Answers (1)

Lance U. Matthews
Lance U. Matthews

Reputation: 16596

There are two places in your code where you are working with byte arrays.

WebClient.DownloadData returns the entire remote resource as a byte[]. If you instead used WebClient.OpenRead (i.e. wc.OpenRead(url);) you get a Stream through which to read the remote resource.

Further, you are instantiating a ByteArrayContent to provide the audio data to your remote client. I see there is also a StreamContent class with which you can specify a Stream to send to the remote client.

This is untested and I'm not sure if disposing the WebClient before response.Content is consumed will be problematic, or if/how/where the Stream returned by wc.OpenRead(url) should be explicitly disposed, but this should give you the idea...

public async Task<HttpResponseMessage> StreamAudioAsync(string id)
{
    var response = Request.CreateResponse(HttpStatusCode.Moved);

    response.StatusCode = HttpStatusCode.OK;
    using (var wc = new System.Net.WebClient())
    {
        string accessKey = Cp.Service.Settings.AccessKey;
        string secretAccessKey = Cp.Service.Settings.SecretAccessKey;
        string url = string.Format("https://....../......php?access_key={0}&secret_access_key={1}&action=recording.download&format=mp3&sid={2}", accessKey, secretAccessKey, id);

        response.Content = new StreamContent(wc.OpenRead(url));
    }
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("audio/wav");

    return response;
}

Upvotes: 3

Related Questions