Reputation: 321
I am trying to play a downloaded audio file and play it back in the browser from an external API.
I have a local API which is querying an external API where the file is located. My API method to get the file from the external API is:
public async Task<HttpResponseMessage> GetAudioAsync(string id)
{
using (var httpClientHandler = new HttpClientHandler())
{
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };
httpClientHandler.UseDefaultCredentials = true;
var url = "externalapi/"
using (var client = new HttpClient(httpClientHandler))
{
var result = await client.GetAsync(url);
var response = new HttpResponseMessage(HttpStatusCode.OK);
var bytes = await result.Content.ReadAsByteArrayAsync();
response.Content = new ByteArrayContent(bytes);
response.Content.Headers.ContentLength = bytes.LongLength;
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "audio.wav";
response.Content.Headers.ContentType = new MediaTypeHeaderValue("audio/wav");
return response;
}
}
}
I know that in Javascript I can set the source attribute of an audio element to playback audio. How do I take the data response from this API method and play the audio?
I've tried the following code below but I get console errors.
$.ajax({
url: 'api/' + id,
cache: false,
type: 'GET'
}).done(function (data) {
// var blob = new Blob([data], {type: 'audio/wav'});
// Creating a blob instance removes the error but the audio is not correctly loaded to the audio element. I get no playback.
document.getElementById('filename').setAttribute('src', window.URL.createObjectURL(data));
}).fail(function(error) {
console.log(error);
});
The error I get back from the browser is: ERROR TypeError: Failed to construct 'Blob': Iterator getter is not callable.
The response I get back from my local API is:
{
"version": {
"major": 1,
"minor": 1,
"build": -1,
"revision": -1,
"majorRevision": -1,
"minorRevision": -1
},
"content": {
"headers": [
{
"key": "Content-Length",
"value": [
"0"
]
},
{
"key": "Content-Disposition",
"value": [
"attachment; filename=audio.wav"
]
},
{
"key": "Content-Type",
"value": [
"application/octet-stream"
]
}
]
},
"statusCode": 200,
"reasonPhrase": "OK",
"headers": [],
"requestMessage": null,
"isSuccessStatusCode": true
}
UPDATE:
I think the issue may be that when I console.log(data) I get back an object rather than an array of bytes. That can be used to initialize a Blob object.
Upvotes: 3
Views: 4703
Reputation: 5179
You can set the audio
elements src
attribute to point directly to the ASP.NET Web API endpoint:
<audio src="http://localhost:8000/api/endpoint/callId"></audio>
If you need to set it dynamically you can do it via javascript:
function setAudioElementSource(id)
{
document.getElementById('yourAudioElement').setAttribute('src', 'http://localhost:8000/api/endpoint/callId')
}
Where endpoint
is the name of your Controller
and callId
is the id of your call.
Here is an example of my action returning the call:
[HttpGet]
public async Task<HttpResponseMessage> GetAudioAsync(
string id)
{
var url = "http://localhost:8000/api/ExternalApi";
using (var httpClientHandler = new HttpClientHandler())
{
httpClientHandler.UseDefaultCredentials = true;
using (var client = new HttpClient(httpClientHandler))
{
var result = await client.GetAsync(url);
var response = new HttpResponseMessage(HttpStatusCode.OK);
var bytes = await result.Content.ReadAsByteArrayAsync();
response.Content = new ByteArrayContent(bytes);
response.Content.Headers.ContentLength = bytes.LongLength;
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "audio.wav";
response.Content.Headers.ContentType = new MediaTypeHeaderValue("audio/wav");
return response;
}
}
}
Here is the response captured in Fiddler:
HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: audio/wav
Expires: -1
Server: Microsoft-IIS/10.0
Content-Disposition: attachment; filename=audio.wav
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcdGphYXJ0LnZhbmRlcndhbHRcZG9jdW1lbnRzXHZpc3VhbCBzdHVkaW8gMjAxNVxQcm9qZWN0c1xXZWJBcHBsaWNhdGlvbjFcV2ViQXBwbGljYXRpb24xXGFwaVxkb3dubG9hZFwxMjM=?=
X-Powered-By: ASP.NET
Date: Mon, 20 Aug 2018 09:12:45 GMT
Content-Length: 0
Content-Length is 0 as I am returning a blank byte array in my ExternalApi
method, your Content-Length header should have a value greater than 0.
If you are not getting any errors, please try a different browser, some browsers do not support playback of .wav
files
Side note:
You can also create a custom class FileResponse
that inherits from HttpResponseMessage
public class FileResponse
: HttpResponseMessage
{
public FileResponse(
byte[] fileContent
, string mediaType
, string fileName)
{
StatusCode = System.Net.HttpStatusCode.OK;
Content = new StreamContent(new MemoryStream(fileContent));
Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(mediaType);
Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = fileName };
}
}
Usage:
[HttpGet]
public async Task<HttpResponseMessage> GetAudioAsync(
string id)
{
var url = "http://localhost:8000/api/ExternalApi";
using (var httpClientHandler = new HttpClientHandler())
{
httpClientHandler.UseDefaultCredentials = true;
using (var client = new HttpClient(httpClientHandler))
{
var result = await client.GetAsync(url);
var bytes = await result.Content.ReadAsByteArrayAsync();
return new FileResponse(bytes, "audio/wav", "your-file-name.wav");
}
}
}
Upvotes: 1