There are a couple of things you could try here. A lot of server side technologies (including .NET and Java) are much stricter about what they consider to be valid JSON than Javascript is. Many have been adapted from earlier tech like SOAP that relied on validated XML and consider JSON to be a similar strict set of rules.
Also, the API you're connecting to was probably written by specialist embedded camera firmware engineers who've never written code for the web before. They're used to C++ and Java, which are a lot less forgiving than JS.
Firstly their API specifies that they expect the HTTP headers to be:
Content-Type: application/json;charset=utf-8
Accept: application/json
However, in the screenshot you're sending:
Content-Type: text/plain;charset=utf-8
This tells the server that the content you're sending is text, not JSON. Even though they only expect JSON that will cause a lot of out-of-the-box server side JSON implementations to fail.
The next thing to try is that a lot of JSON parsers that aren't actually Javascript add some quite specific rules to what they consider to be valid JSON.
You're sending:
{name:camera._getLivePreview, parameters:{sessionId:SID_0001}}
This is valid JS, but not actually valid JSON by the strict XML-like rules because they expect everything to be quoted (the only value types you don't quote are booleans and numbers).
So try:
{
"name": "camera._getLivePreview",
"parameters": {
"sessionId": "SID_0001"
}
}
If you look at their getting started guide they format every request in this way - quote the properties and quote the values.
One way to ensure that you get this stricter JSON is to build your request JS object and then use JSON.stringify
to set the body of the request, like this:
const content = {name:'camera._getLivePreview', parameters:{sessionId:'SID_0001'}};
const response = await fetch('.../osc/commands/execute', {
method: 'POST',
body: JSON.stringify(content),
headers:{ 'Content-Type': 'application/json' }
});
Finally what you're getting back is a video stream - support for this in fetch
is fairly bleeding edge and basically missing from XMLHttpRequest
. The server is going to keep sending you content and you keep piping it to something that can render it, and if you stop you'll see that target_closed
error.
You need to keep iterating through the stream:
// Get the fetch response as a stream
const reader = await response.body.getReader();
// Async loop the stream
let chunk = await reader.read();
while (chunk && !chunk.done) {
for (let index = 0; index < chunk.value.length; index++) {
// parse the response in chunks
}
chunk = await reader.read();
}
There are plenty of JS MJPEG implementations already out there, here's a fairly simple one
camera.startSession
? Otherwise that could be the reason. Also the name probably should becamera.getLivePreview
without the underscore. – Didi<img>
tag or anImage
object and put the URL in thesrc
parameter. That's how I used to access to MJPEG streams a few years ago. With that, the browser takes care of splitting the multipart headers and updates the image when a full frame is available. This used to work with very old browsers, so I guess support is still there. If later you need to convert it from spherical to view it, you can access the image from WebGL, I guess. – Derwin