4

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

1 Answer 1

3

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;
}
Sign up to request clarification or add additional context in comments.

1 Comment

thanks, it works. Maybe useful to others: 1. Dispose WebClient is ok. 2. the stream created by OpenRead should not be Disposed which makes sense since it is streaming. Not sure whether we need and where to dispose it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.