Add WHIP settings for simulcast and authentication to demo app

This commit is contained in:
Sangwon Oh
2025-02-12 15:46:36 +09:00
parent b9dc45ae20
commit bcbe6f9a72
2 changed files with 77 additions and 32 deletions

View File

@ -159,7 +159,6 @@
<span> <span>
WebRTC Input WebRTC Input
</span> </span>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-info">Beta</span>
</a> </a>
</li> </li>
</ul> </ul>
@ -554,18 +553,6 @@
<!-- linked in --> <!-- linked in -->
<a class="btn btn-floating m-1" class="" role="button" target="_blank" <a class="btn btn-floating m-1" class="" role="button" target="_blank"
href="https://www.linkedin.com/company/airensoft"><i class="fab fa-linkedin-in"></i></a> href="https://www.linkedin.com/company/airensoft"><i class="fab fa-linkedin-in"></i></a>
<!-- Facebook -->
<a class="btn btn-floating m-1" class="" role="button" target="_blank"
href="https://www.facebook.com/airensoft/"><i class="fab fa-facebook-f"></i></a>
<!-- Twitter -->
<a class="btn btn-floating m-1" class="" role="button" target="_blank"
href="https://twitter.com/AirenSoft"><i class="fab fa-twitter"></i></a>
<!-- Instagram -->
<a class="btn btn-floating m-1" class="" role="button" target="_blank"
href="https://www.instagram.com/airensoft"><i class="fab fa-instagram"></i></a>
</div> </div>
</div> </div>
</section> </section>

View File

@ -117,7 +117,6 @@
<span> <span>
WebRTC Input WebRTC Input
</span> </span>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-info">Beta</span>
</a> </a>
</li> </li>
</ul> </ul>
@ -127,7 +126,7 @@
<div class="input-group"> <div class="input-group">
<div class="form-outline flex-grow-1"> <div class="form-outline flex-grow-1">
<input type="text" id="webRtcUrlInput" class="form-control bg-white" /> <input type="text" id="webRtcUrlInput" class="form-control bg-white" />
<label class="form-label" for="webRtcUrlInput">WebRTC input URL</label> <label class="form-label" for="webRtcUrlInput">WebRTC ingress URL</label>
</div> </div>
<button id="streamingButton" class="btn btn-primary px-2 px-md-4" type="button"> <button id="streamingButton" class="btn btn-primary px-2 px-md-4" type="button">
Start Start
@ -199,6 +198,35 @@
</div> </div>
</div> </div>
<div class="col-12">
<ul class="list-group">
<li class="list-group-item bg-light">
<h5 class="mb-0 fs-6">WHIP settings</h5>
</li>
<li class="list-group-item">
<div class="row">
<div class="col-lg-6 border-start border-2 mb-3 mb-lg-0">
<h6>Simulcast</h6>
<fieldset>
<label for="numberOfLayersInput">Number of layers</label>
<input id="numberOfLayersInput" type="number" class="form-control streamingConfigSelect mb-2"
placeholder="Not set">
</fieldset>
</div>
<div class="col-lg-6 border-start border-2 mb-3 mb-lg-0">
<h6>Authentication</h6>
<fieldset>
<label for="bearerTokenInput">Bearer token</label>
<input id="bearerTokenInput" type="text" class="form-control streamingConfigSelect mb-2"
placeholder="Token">
</fieldset>
</div>
</div>
</li>
</ul>
</div>
<div class="col-12"> <div class="col-12">
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item bg-light"> <li class="list-group-item bg-light">
@ -231,8 +259,7 @@
<label for="videoPreferredCodecSelect">Preferred video codec</label> <label for="videoPreferredCodecSelect">Preferred video codec</label>
<select id="videoPreferredCodecSelect" class="form-control streamingConfigSelect mb-2"> <select id="videoPreferredCodecSelect" class="form-control streamingConfigSelect mb-2">
<option selected value="">Not Set</option> <option value="H264" selected>H264 (default)</option>
<option value="H264">H264</option>
<option value="VP8">VP8</option> <option value="VP8">VP8</option>
</select> </select>
</fieldset> </fieldset>
@ -318,17 +345,9 @@
</div> </div>
<div class="col-md-5 col-lg-4 ml-lg-0 text-center text-md-end"> <div class="col-md-5 col-lg-4 ml-lg-0 text-center text-md-end">
<!-- Facebook --> <!-- linked in -->
<a class="btn btn-floating m-1" class="" role="button" target="_blank" <a class="btn btn-floating m-1" class="" role="button" target="_blank"
href="https://www.facebook.com/airensoft/"><i class="fab fa-facebook-f"></i></a> href="https://www.linkedin.com/company/airensoft"><i class="fab fa-linkedin-in"></i></a>
<!-- Twitter -->
<a class="btn btn-floating m-1" class="" role="button" target="_blank"
href="https://twitter.com/AirenSoft"><i class="fab fa-twitter"></i></a>
<!-- Instagram -->
<a class="btn btn-floating m-1" class="" role="button" target="_blank"
href="https://www.instagram.com/airensoft"><i class="fab fa-instagram"></i></a>
</div> </div>
</div> </div>
</section> </section>
@ -340,7 +359,8 @@
<script src="https://cdn.jsdelivr.net/npm/underscore@1.12.0/underscore-min.js"></script> <script src="https://cdn.jsdelivr.net/npm/underscore@1.12.0/underscore-min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js" <script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"
integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI=" crossorigin="anonymous"></script> integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/ovenlivekit@1.1.0/dist/OvenLiveKit.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/ovenlivekit@1.4.0/dist/OvenLiveKit.min.js"></script>
<script> <script>
@ -403,6 +423,9 @@
let testPlaybackButtonArea = $('#testPlaybackButtonArea'); let testPlaybackButtonArea = $('#testPlaybackButtonArea');
let playStreamButton = $('#playStreamButton'); let playStreamButton = $('#playStreamButton');
let bearerTokenInput = $('#bearerTokenInput');
let numberOfLayersInput = $('#numberOfLayersInput');
let savedWebRtcUrl = localStorage.getItem('savedWebRtcUrl'); let savedWebRtcUrl = localStorage.getItem('savedWebRtcUrl');
let savedVideoSource = localStorage.getItem('savedVideoSource'); let savedVideoSource = localStorage.getItem('savedVideoSource');
let savedVideoResolution = localStorage.getItem('savedVideoResolution'); let savedVideoResolution = localStorage.getItem('savedVideoResolution');
@ -410,6 +433,9 @@
let savedVideoFrame = localStorage.getItem('savedVideoFrame'); let savedVideoFrame = localStorage.getItem('savedVideoFrame');
let savedAudioSource = localStorage.getItem('savedAudioSource'); let savedAudioSource = localStorage.getItem('savedAudioSource');
let savedBearerToken = localStorage.getItem('savedBearerToken');
let savedNumberOfLayersInput = localStorage.getItem('savedNumberOfLayersInput');
let ovenLiveKitVersion = $('#ovenLiveKitVersion'); let ovenLiveKitVersion = $('#ovenLiveKitVersion');
ovenLiveKitVersion.text(OvenLiveKit.getVersion()); ovenLiveKitVersion.text(OvenLiveKit.getVersion());
@ -417,10 +443,26 @@
webRtcUrlInput.val(savedWebRtcUrl); webRtcUrlInput.val(savedWebRtcUrl);
} }
if (savedBearerToken) {
bearerTokenInput.val(savedBearerToken);
}
if (savedNumberOfLayersInput) {
numberOfLayersInput.val(savedNumberOfLayersInput);
}
webRtcUrlInput.on('change', function () { webRtcUrlInput.on('change', function () {
localStorage.setItem('savedWebRtcUrl', $(this).val()); localStorage.setItem('savedWebRtcUrl', $(this).val());
}); });
bearerTokenInput.on('change', function () {
localStorage.setItem('savedBearerToken', $(this).val());
});
numberOfLayersInput.on('change', function () {
localStorage.setItem('savedNumberOfLayersInput', $(this).val());
});
videoSourceSelect.on('change', function () { videoSourceSelect.on('change', function () {
localStorage.setItem('savedVideoSource', $(this).val()); localStorage.setItem('savedVideoSource', $(this).val());
@ -750,13 +792,16 @@
$('#errorText').html('Web Socket is closed. ' + reason); $('#errorText').html('Web Socket is closed. ' + reason);
} }
if (type === 'ice') { if (type === 'ice') {
$('#errorText').html('Peer Connection is closed. State: ' + input.peerConnection.iceConnectionState); if (input && input.peerConnection) {
$('#errorText').html('Peer Connection is closed. State: ' + input.peerConnection.iceConnectionState);
}
} }
}, },
iceStateChange: function (state) { iceStateChange: function (state) {
iceStateSpan.text(state); iceStateSpan.text(state);
if (state === 'connected') { if (state === 'connected') {
testPlaybackButtonArea.show(); testPlaybackButtonArea.show();
errorTextSpan.text('');
} }
} }
} }
@ -805,13 +850,27 @@
connectionConfig.preferredVideoFormat = videoPreferredCodecSelect.val(); connectionConfig.preferredVideoFormat = videoPreferredCodecSelect.val();
} }
if (bearerTokenInput.val()) {
connectionConfig.httpHeaders = {
'Authorization': 'Bearer ' + bearerTokenInput.val()
};
}
if (numberOfLayersInput.val()) {
connectionConfig.simulcast = [];
for (let i = 0; i < parseInt(numberOfLayersInput.val()); i++) {
connectionConfig.simulcast.push({});
}
}
input.startStreaming(webRtcUrlInput.val(), connectionConfig); input.startStreaming(webRtcUrlInput.val(), connectionConfig);
} }
} }
function stopStreaming() { function stopStreaming() {
if (input) { if (input && streamingStarted) {
input.stopStreaming(); input.stopStreaming();
} }
@ -835,7 +894,6 @@
} }
streamingButton.on('click', function () { streamingButton.on('click', function () {
if (!streamingStarted) { if (!streamingStarted) {
@ -989,7 +1047,7 @@
errorMessage = error.toString(); errorMessage = error.toString();
} }
$('#errorText').text(errorMessage); errorTextSpan.text(errorMessage);
}); });
function initDemo() { function initDemo() {