Notice
Recent Posts
Recent Comments
Link
투케이2K
192. (TWOK/UTIL) [Web/JavaScript] [기능 보완] 자바스크립트 AWS Kvs HLS 뷰어 Viewer 비디오 스트림 영상 재생 수행 유틸 - 재시도 적용 본문
투케이2K 유틸파일
192. (TWOK/UTIL) [Web/JavaScript] [기능 보완] 자바스크립트 AWS Kvs HLS 뷰어 Viewer 비디오 스트림 영상 재생 수행 유틸 - 재시도 적용
투케이2K 2026. 6. 7. 14:45728x90
반응형
[설 명]
프로그램 : Web / JavaScript
설 명 : [Web/JavaScript] [기능 보완] 자바스크립트 AWS Kvs HLS 뷰어 Viewer 비디오 스트림 영상 재생 수행 유틸 - 재시도 적용

[소스 코드]
-----------------------------------------------------------------------------------------
[사전 설명 및 설정 사항]
-----------------------------------------------------------------------------------------
- 개발 환경 : Web
- 개발 기술 : JavaScript / AWS / Kvs / HLS / Viewer
- 사전) 👉 비디오 스트림 간략 설명 정리 :
>> 비디오 스트림은 라이브 비디오 및 기타 시간이 인코딩된 데이터를 캡처하고, 선택적으로 저장하고, 실시간, 배치 혹은 애드혹 형식으로 데이터의 소비를 가능하게 할 수 있도록 해 주는 리소스입니다
>> 일반적인 구성에서는 Kinesis 비디오 스트림은 데이터를 푸시해 주는 생산자가 하나만 있습니다 (실시간 스트리밍 데이터를 밀어 넣어주는 하드웨어 기기)
- 사전) 👉 HLS 개념 설명 :
>> HTTP 라이브 스트리밍으로 인터넷을 통해 소비자에게 미디어 콘텐츠를 제공하는 데 사용되는 스트리밍 프로토콜입니다
>> HLS 는 Apple 장치에서 지원하는 유일한 형식입니다
>> 미디어는 h.264 또는 h.265 인코딩된 비디오를 포함해야 하며 AAC 인코딩된 오디오는 선택 사항입니다
>> 미디어 타입 유효한 값의 예로는 "video/h264" 및 "video/h264,audio/aac" 가 있습니다
- 사전) 👉 PlaybackMode 설명 :
>> 라이브, 라이브 재생 또는 아카이브된 온디맨드 데이터를 검색할지 여부입니다
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
[소스 코드]
-----------------------------------------------------------------------------------------
<!DOCTYPE HTML>
<html lang="ko">
<head>
<title>javaScriptTest</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 반응형 구조 만들기 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<!-- 내부 CSS 스타일 지정 -->
<style>
html, body {
width: 100%;
height: 100%;
margin : 0 auto;
padding : 0;
border : none;
background-color: #666;
}
#container_remoteView {
width: 100%;
height: 98%;
margin: 0 auto;
position: relative;
top: 1%;
}
#remoteView {
width: 100%;
height: 100%;
margin: 0 auto;
background-color: #666;
}
</style>
<!-- [CDN 주소 설정] -->
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.js"></script>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1560.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<!-- <script src="../Desktop/aws-sdk-2.1560.0.min.js"></script> -->
<!-- <script src="../Desktop/hls.js"></script> -->
<!-- [자바스크립트 코드 지정] -->
<script>
// --------------------------------------------------------------------------------------------------------------
// 🟦 [전역 변수 선언]
var remotePlayTimer = null;
var remotePlayFlag = false;
var remotePlayCount = 0;
var remoteSrcArray = [];
var kinesisVideoClient = null;
var localStream = null; // 마스터 카메라 영상 스트림
var region = 'ap-northeast-1'; // [AWS 리전]
var accessKeyId = 'AK..7Q'; // [IAM 액세스 키]
var secretAccessKey = 'Zz..xj'; // [IAM 시크릿 키]
var streamName = 'DEVICE_1'; // [스트림 명칭]
var hlsStreamType = 'LIVE_REPLAY'; // ✅ [스트리밍 타입] : LIVE or LIVE_REPLAY
var remoteView = null;
var retryCnt = 0;
// --------------------------------------------------------------------------------------------------------------
// 🟦 [html 최초 로드 및 이벤트 상시 대기 실시]
window.onload = async function() {
console.log("[window onload] : [start]");
// -----------------------------------------
// [JSON 데이터 삽입 수행] : 하드 코딩
// -----------------------------------------
var webJson = {
region : region,
accessKeyId : accessKeyId,
secretAccessKey : secretAccessKey,
streamName : streamName,
hlsStreamType : hlsStreamType
};
setSystem(JSON.stringify(webJson)); // [Web 자체 데이터 생성 호출]
};
// --------------------------------------------------------------------------------------------------------------
// 🟦 [AWS KVS HLS 비디오 재생 관련 : getDataEndpoint]
async function setSystem(jsonData){
console.log("[setSystem] : 웹 데이터 전달 받음 : ", JSON.stringify(jsonData));
try {
// -----------------------------------------
// [json 데이터 파싱 수행 실시]
// -----------------------------------------
var jsonObject = JSON.parse(jsonData);
var parse_region = String(jsonObject.region); // [AWS 리전]
var parse_accessKeyId = String(jsonObject.accessKeyId); // [IAM 액세스 키]
var parse_secretAccessKey = String(jsonObject.secretAccessKey); // [IAM 시크릿 키]
var parse_streamName = String(jsonObject.streamName); // [비디오 스트림 명칭]
var parse_hlsStreamType = String(jsonObject.hlsStreamType); // [비디오 스트림 타입]
console.log("");
console.log("=========================================");
console.log("[setSystem] : 데이터 파싱 정보");
console.log("-----------------------------------------");
console.log("[region] : " + parse_region);
console.log("-----------------------------------------");
console.log("[accessKeyId] : " + parse_accessKeyId);
console.log("-----------------------------------------");
console.log("[secretAccessKey] : " + parse_secretAccessKey);
console.log("-----------------------------------------");
console.log("[streamName] : " + parse_streamName);
console.log("-----------------------------------------");
console.log("[hlsStreamType] : " + parse_hlsStreamType);
console.log("=========================================");
console.log("");
// -----------------------------------------
// [비디오 플레이 컴포넌트 지정 및 이벤트 지정]
// -----------------------------------------
remoteView = document.getElementById("remoteView");
remoteView.muted = true; // ✅ 음소거 설정 : 웹 자바스크립트 : NotAllowedError 조치
remoteView.autoplay = true;
remoteView.controls = true; // 컨트롤 박스 표시
//remoteView.onload = (event) => {};
//remoteView.onchange = (event) => {};
remoteView.onerror = (event) => {
console.error("[setSystem] : [remoteView] : 원격 비디오 뷰 컴포넌트 : onerror");
};
/*
remoteView.onwaiting = (event) => { // [디바이스 스트리밍 송출 종료 시 로딩 프로그레스를 돌리기 위해 주석]
console.log("[setSystem] : [remoteView] : 원격 비디오 뷰 컴포넌트 : onwaiting");
};
// */
remoteView.onpause = (event) => {
console.error("[setSystem] : [remoteView] : 원격 비디오 뷰 컴포넌트 : onpause");
};
remoteView.onplaying = (event) => {
console.warn("[setSystem] : [remoteView] : 원격 비디오 뷰 컴포넌트 : onplaying");
};
// video.onplay = (event) => {};
// -----------------------------------------
// [타이머를 반복 돌리며 실시간 해상도 변경 감지]
// -----------------------------------------
var lastWidth = 0;
var lastWidth = 0;
setInterval(() => {
console.log('>>>>>>>>>>>>>>>>>> [check setInterval running] >>>>>>>>>>>>>>>>>>');
const currentWidth = remoteView.videoWidth;
const currentHeight = remoteView.videoHeight;
// 해상도가 변경되었을 때만 로그 출력
if (currentWidth !== lastWidth || currentHeight !== lastHeight) {
console.log('[setInterval : resolution] : ', currentWidth + 'x' + currentHeight);
lastWidth = currentWidth;
lastHeight = currentHeight;
var msg = "\n" + "[디바이스 기기] : [비디오 해상도 정보 확인]" + "\n";
msg += "\n" + "[Resolution] : " + currentWidth + 'x' + currentHeight + "\n";
console.warn("[setSystem] : [Resolution] : ", msg);
}
}, 2000); // 2초마다 확인
// -----------------------------------------
// [KVS 클라이언트 생성]
// -----------------------------------------
/*
kinesisVideoClient = new AWS.KinesisVideo({
region,
accessKeyId,
secretAccessKey,
correctClockSkew: true,
});
// */
AWS.config.update({
region: parse_region,
accessKeyId: parse_accessKeyId,
secretAccessKey: parse_secretAccessKey
});
kinesisVideoClient = new AWS.KinesisVideo({
correctClockSkew: true,
});
console.log("");
console.log("=========================================");
console.log("[setSystem] : [KinesisVideo] : 비디오 재생 및 정보 관련 객체 초기화 수행");
console.log("=========================================");
console.log("");
// -----------------------------------------
// [KVS 스트림 엔드포인트 가져오기]
// -----------------------------------------
kinesisVideoClient.getDataEndpoint({
StreamName: parse_streamName,
APIName: 'GET_HLS_STREAMING_SESSION_URL' // ✅ HLS 세션 URL 가져오기 타입 지정
}, function(err, response){
if (err){
console.error("");
console.error("=========================================");
console.error("[setSystem] : [getDataEndpoint] : ❌ 예외 상황 발생");
console.error("-----------------------------------------");
console.error("[ERROR] : ", err.message);
console.error("=========================================");
console.error("");
return;
}
console.log("");
console.log("=========================================");
console.log("[setSystem] : [getDataEndpoint] : response 확인");
console.log("-----------------------------------------");
console.log(JSON.stringify(response));
console.log("=========================================");
console.log("");
const endpoint = response.DataEndpoint;
if (endpoint != null && endpoint != '' && endpoint != 'undefined'){
getLiveHLSUrl(parse_region, endpoint, parse_accessKeyId, parse_secretAccessKey, parse_streamName, parse_hlsStreamType);
}
else {
console.error("[setSystem] : [Error] : ❌ DataEndpoint Is Null");
}
});
}
catch (exception) {
console.error("[setSystem] : [Exception] : ❌ 예외 상황 발생 : ", exception.message);
}
};
// --------------------------------------------------------------------------------------------------------------
// 🟦 [AWS KVS HLS 비디오 재생 관련 : 엔드포인트를 기반으로 HLS 세션 URL 가져오기 및 HLS 뷰어 재생]
async function getLiveHLSUrl(region, endpoint, accessKeyId, secretAccessKey, streamName, hlsStreamType) {
console.log("");
console.log("=========================================");
console.log("[getLiveHLSUrl] : HLS 뷰어 재생 Url 확인 및 비디오 플레이 수행");
console.log("-----------------------------------------");
console.log("[endpoint] : " + endpoint);
console.log("-----------------------------------------");
console.log("[region] : " + region);
console.log("-----------------------------------------");
console.log("[accessKeyId] : " + accessKeyId);
console.log("-----------------------------------------");
console.log("[secretAccessKey] : " + secretAccessKey);
console.log("-----------------------------------------");
console.log("[streamName] : " + streamName);
console.log("-----------------------------------------");
console.log("[hlsStreamType] : " + hlsStreamType);
console.log("=========================================");
console.log("");
try {
// -----------------------------------------
// [엔드포인트를 기반으로 HLS 세션 URL 가져오기]
// -----------------------------------------
const kinesisVideoArchivedMedia = new AWS.KinesisVideoArchivedMedia({
region: region,
endpoint: endpoint,
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey
});
//const startTimestamp = new Date(Date.now() - 30 * 1000); // 과거 : 30초전
//const startTimestamp = new Date(Date.now() - 60 * 1000); // 과거 : 1분전
//const startTimestamp = new Date(Date.now() - 3 * 60 * 60 * 1000); // 과거: 3시간 전
//const startTimestamp = new Date(Date.now() - 24 * 60 * 60 * 1000); // 과거: 24시간 전
//const endTimestamp = new Date(); // 현재
//const endTimestamp = new Date(Date.now() + 60 * 1000); // 미래 : 1분후
var params = null;
if (hlsStreamType.indexOf("LIVE_REPLAY") >= 0){ // ✅ LIVE_REPLAY
console.log("[getLiveHLSUrl] : LIVE_REPLAY");
var startTimestamp = null;
if (hlsStreamType.indexOf("-24") >= 0){ // LIVE_REPLAY (-24)
startTimestamp = new Date(Date.now() - 24 * 60 * 60 * 1000); // 과거: 24시간 전
}
else { // LIVE_REPLAY (Default)
startTimestamp = new Date(Date.now() - 30 * 1000); // 과거 : 30초전
}
params = {
StreamName: streamName,
PlaybackMode: 'LIVE_REPLAY', // 이전 데이터 부터 재생을 하므로 끊김 최소화 : AWS 콘솔 대시보드도 동일 설정
HLSFragmentSelector: {
FragmentSelectorType: 'SERVER_TIMESTAMP', // SERVER_TIMESTAMP 또는 PRODUCER_TIMESTAMP
TimestampRange: {
StartTimestamp: startTimestamp,
//EndTimestamp: endTimestamp // 디바이스가 올린 영상 종료까지 출력 위해 주석 : 주석하지 않으면 시작 ~ 종료 범위까지의 영상만 재생 됨
}
}
}
}
else { // ✅ LIVE
console.log("[getLiveHLSUrl] : LIVE");
params = {
StreamName: streamName,
PlaybackMode: 'LIVE', // 가장 최신만 재생 (지연 최소, 끊김 위험 높음)
HLSFragmentSelector: {
FragmentSelectorType: 'SERVER_TIMESTAMP', // SERVER_TIMESTAMP 또는 PRODUCER_TIMESTAMP
}
}
}
kinesisVideoArchivedMedia.getHLSStreamingSessionURL( params , function(err, response){
if (err){
console.error("");
console.error("=========================================");
console.error("[getLiveHLSUrl] : [getHLSStreamingSessionURL] : ❌ 예외 상황 발생");
console.error("-----------------------------------------");
console.error("[ERROR] : ", err.message);
console.error("=========================================");
console.error("");
// [1번 더 재시도 수행]
if (retryCnt < 6){
retryCnt ++; // 카운트 증가
console.error("[getLiveHLSUrl] : [Error] : 타이머 대기 및 재시도 수행 : ", retryCnt);
// ✅ 5초 (5000ms) 대기 후 함수 실행
setTimeout(() => {
getLiveHLSUrl(region, endpoint, accessKeyId, secretAccessKey, streamName, hlsStreamType);
}, 5000);
}
else {
// -----------------------------------------
// [에러 알림]
// -----------------------------------------
var errMsg = err.message;
if (errMsg.indexOf("No fragments found in the stream for the streaming request") >= 0){
errMsg += "\n\n" + "현재 재생 되고 있는 스트리밍이 없습니다. 스트리밍 재생 여부를 다시 확인해주세요." + "\n";
}
console.error("[getLiveHLSUrl] : [Error] : ", errMsg);
return;
}
}
console.log("");
console.log("=========================================");
console.log("[getLiveHLSUrl] : [getHLSStreamingSessionURL] : response 확인");
console.log("-----------------------------------------");
console.log(JSON.stringify(response));
console.log("=========================================");
console.log("");
const hlsUrl = response.HLSStreamingSessionURL;
if (hlsUrl != null && hlsUrl != '' && hlsUrl != 'undefined'){
Hls.DefaultConfig.debug = true; // 디버깅 로그 출력
if (Hls.isSupported()){ // Hls 지원 여부 확인
const hls = new Hls(); // Default
/*
const hls = new Hls({ // Custom
liveSyncDuration: 1, // 재생지점 - LIVE edge 거리 (초 단위)
liveMaxLatencyDuration: 2,
//maxLiveSyncPlaybackRate: 1.5,
//enableWorker: true,
lowLatencyMode: true, // 중요 : Live HLS 지연 없이 재생 (PlaybackMode: 'LIVE')
//backBufferLength: 15,
//maxBufferLength: 5, // 초 단위 : 최대 버퍼 길이
//maxBufferSize: 10* 1000 * 1000, // 10MB // 바이트 단위 : 메모리 제한
maxBufferHole: 0.1,
});
// */
hls.loadSource(hlsUrl);
hls.attachMedia(remoteView);
// [비디오 AutoPlay 설정으로 주석 처리]
/*
hls.on(Hls.Events.MANIFEST_PARSED, function(){
remoteView.play();
console.log("[getLiveHLSUrl] : [getHLSStreamingSessionURL] : Hls 스트리밍 재생 수행");
});
// */
hls.on(Hls.Events.ERROR, function(event, data){
console.error("");
console.error("=========================================");
console.error("[getLiveHLSUrl] : [getHLSStreamingSessionURL] : ❌ Hls.Events.ERROR");
console.error("-----------------------------------------");
console.error("[ERROR] : ", JSON.stringify(data));
console.error("-----------------------------------------");
console.error("[data.type] : ", data.type);
console.error("-----------------------------------------");
console.error("[data.details] : ", data.details);
console.error("-----------------------------------------");
console.error("[data.fatal] : ", data.fatal);
console.error("=========================================");
console.error("");
// [에러 분기 처리 시 사용]
// if (data.details === 'bufferStalledError'){ }
// if (data.details === 'bufferStalledError'){ }
});
}
else {
console.error("[getLiveHLSUrl] : [Error] : ❌ Hls.isSupported False");
}
}
else {
console.error("[getLiveHLSUrl] : [Error] : ❌ HLSStreamingSessionURL Is Null");
}
})
}
catch (exception) {
console.error("[getLiveHLSUrl] : [Exception] : ❌ 예외 상황 발생 : ", exception.message);
}
};
// --------------------------------------------------------------------------------------------------------------
</script>
</head>
<body>
<!-- 🟦 [컨테이너 생성] -->
<div id="container_remoteView">
<video autoplay="true" id="remoteView"></video>
</div>
</body>
</html>
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
[참고 사이트]
-----------------------------------------------------------------------------------------
▶️ [Web/JavaScript] AWS Kvs HLS 뷰어 Viewer 비디오 스트림 영상 재생 수행
https://kkh0977.tistory.com/8269
https://blog.naver.com/kkh0977/224004858035
▶️ [Aws Kinesis Video Streams] Aws KVS 비디오 스트림 , 신호 전송 채널 차이점 설명 정리
https://kkh0977.tistory.com/7956
https://blog.naver.com/kkh0977/223854439046?trackingCode=blog_bloghome_searchlist
▶️ [Aws Kvs HSL 비디오 스트림 녹화 영상 관련 학습 정리]
https://kkh0977.tistory.com/7967
https://blog.naver.com/kkh0977/223855980812?trackingCode=blog_bloghome_searchlist
▶️ [자바스크립트 AWS Kvs HLS 비디오 스트림 채널 생성 수행 - createStream]
https://kkh0977.tistory.com/8276
https://blog.naver.com/kkh0977/223916957964
▶️ [자바스크립트 AWS Kvs HLS 비디오 스트림 채널 삭제 수행 - deleteStream]
https://kkh0977.tistory.com/8098
https://blog.naver.com/kkh0977/223918327833
▶️ [JavaScript] The FragmentSelector is required for LIVE_REPLAY PlaybackMode
https://kkh0977.tistory.com/8256
https://blog.naver.com/kkh0977/223997369730?trackingCode=blog_bloghome_searchlist
▶️ [JavaScript] No fragments found in the stream for the streaming request
https://kkh0977.tistory.com/8257
https://blog.naver.com/kkh0977/223997383598?trackingCode=blog_bloghome_searchlist
-----------------------------------------------------------------------------------------
728x90
반응형
'투케이2K 유틸파일' 카테고리의 다른 글
Comments
