Our Live View Local API provides endpoint that allow you to stream live video from the cameras. In this end-to-end example, we walk you through the steps.
Prerequisites
To use this endpoint, you'll need:
- A valid Lumana api key.
- A camera id.
Generating a Lumana API key:
There are two options to generate Lumana API key:
- In the platform go to: Organizations Settings -> API Keys -> Generate Key.
- Via the Lumana API:
$ curl --location 'https://access.lumana.ai/v1/api-key' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "api-key-name",
"expiresIn": 30,
"email": "your-email",
"password": "your-password"
,"orgId": "your-org-id"
}'
Getting camera id
You can get cameraId by using the API or by going to the platform -> Edit camera -> Camera Id
Getting Lumana Live View Local HLS URL:
First, we will get the url path that point to the HLS manifest file:
curl --request GET \
--url 'https://access.lumana.ai/v1/live-view/cameras/<cameraId>/local/start?resolution=<resolution>' \
--header 'accept: application/json' \
--header 'authorization: Bearer <api-key>'
Response example:
{
"edgeId": <edgeId>,
"cameraId": <cameraId>,
"cameraStatus": true,
"resolution": 1,
"errorCode": 0,
"url": "streams/mq/<edgeId>/<cameraId>/video/manifest.m3u8",
"id": "12493484-9479-43fd-8f24-7aae4623522f"
}
Then, we will get the url host prefix:
curl --request GET \
--url 'https://access-dev.lumana.ai/v1/local-network-configuration?cameraIds=<cameraId>' \
--header 'accept: application/json' \
--header 'authorization: Bearer <api-token>'
Response example:
[
{
"eth0": "https://<edgeId>-eth0.lumixai.com/edgeid/getedgeid",
"eth0Base": "https://<edgeId>-eth0.lumixai.com",
"edgeId": <edgeId>,
"cameraId": <cameraId>
}
]
Finally, we can construct the full url from the two responses:
Host prefix: https://<edgeId>-eth0.lumixai.com
Stream URL: /streams/<edgeId>/<cameraId>/video/manifest.m3u8
The full URL would be: https://<edgeId>-eth0.lumixai.com/streams/<edgeId>/<cameraId>/video/manifest.m3u8
Stream local live view from camera:
Once you have the url you should start streaming in the first 90 seconds as the session will be invalid due to inactivity timeout. You can stream the video from the camera using this player example.
Enter the playback url obtained from the previous request and play the video.
<!DOCTYPE html>
<html lang="en">
<script src="https://cdn.jsdelivr.net/npm/livekit-client/dist/livekit-client.umd.min.js"></script>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Live View Player</title>
<style>
/* General styles */
body {
margin: 0;
font-family: Arial, sans-serif;
background-color: #121212;
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
padding: 20px;
box-sizing: border-box;
}
/* Video container */
#video-container {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 50vh; /* Adjusted height for better fit */
background-color: #000;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
margin-bottom: 50px; /* Increased space between video and controls */
}
video {
width: 80%;
max-width: 800px;
border-radius: 10px;
}
/* Controls container */
#controls {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-width: 620px;
}
/* Token input styling */
#token-input, #url-input {
width: 100%;
height: 50px;
font-size: 18px;
padding: 10px;
border-radius: 5px;
border: 2px solid #333;
background-color: #1e1e1e;
color: #fff;
margin-bottom: 10px; /* Space between input fields */
box-sizing: border-box;
}
/* Connect button styling */
#connect-btn {
width: 100%;
height: 60px;
font-size: 20px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
margin-top: 10px; /* Space between button and inputs */
}
#connect-btn:hover {
background-color: #0056b3;
}
</style>
<h1>Live View Player</h1>
</head>
<body>
<!-- Controls container -->
<div id="controls">
<input type="text" id="url-input" value="https://stream.lumana.ai" placeholder="Live View URL">
<input type="text" id="token-input" placeholder="Live View Token">
<button id="connect-btn">Connect</button>
</div>
<!-- Video container -->
<div id="video-container">
<video id="video-player" autoplay playsinline></video>
</div>
</body>
<script type="module">
async function connectToLiveView() {
const liveViewURL = document.getElementById('url-input').value;
const token = document.getElementById('token-input').value;
if (!liveViewURL || !token) {
alert('Please enter both Live View URL and Token');
return;
}
try {
const room = new LivekitClient.Room({
// automatically manage subscribed video quality
adaptiveStream: true,
// default capture settings
videoCaptureDefaults: {
resolution: LivekitClient.VideoPresets.h720.resolution,
},
});
room.prepareConnection(liveViewURL, token);
// set up event listeners
room.on(LivekitClient.RoomEvent.TrackSubscribed, handleTrackSubscribed)
.on(LivekitClient.RoomEvent.TrackUnsubscribed, handleTrackUnsubscribed)
.on(LivekitClient.RoomEvent.Disconnected, handleDisconnect)
.on(LivekitClient.RoomEvent.LocalTrackUnpublished, handleLocalTrackUnpublished);
// connect to room
await room.connect(liveViewURL, token);
console.log('connected to room', room.name);
function handleTrackSubscribed(track, publication, participant) {
console.log('handleTrackSubscribed', track.kind);
if (track.kind === LivekitClient.Track.Kind.Video) {
const videoElement = document.getElementById('video-player');
track.attach(videoElement);
}
}
function handleTrackUnsubscribed(track, publication,participant) {
track.detach().forEach(element => element.remove());
}
function handleLocalTrackUnpublished(publication, participant) {
// when local tracks are ended, update UI to remove them from rendering
publication.track.detach();
}
function handleDisconnect() {
console.log('disconnected from room');
}
} catch (error) {
console.error('Error connecting to Live View:', error);
alert(`Failed to connect ${JSON.stringify({liveViewURL, token}, null, 2)}` );
}
}
document.getElementById('connect-btn').addEventListener('click', connectToLiveView);
</script>
</body>
</html>