투케이2K

990. (Android/Java) [간단 소스] 안드로이드 Aws Kvs HLS 비디오 스트리밍 정보 확인에 필요한 getHLSStreamingSessionURL 호출 수행 본문

Android

990. (Android/Java) [간단 소스] 안드로이드 Aws Kvs HLS 비디오 스트리밍 정보 확인에 필요한 getHLSStreamingSessionURL 호출 수행

투케이2K 2025. 5. 23. 19:35

[개발 환경 설정]

개발 툴 : AndroidStudio

개발 언어 : Java / Kotlin

 

[소스 코드]

// --------------------------------------------------------------------------------------
[개발 및 테스트 환경]
// --------------------------------------------------------------------------------------

- 언어 : Java / Kotlin

- 개발 툴 : AndroidStudio

- 기술 구분 : Aws / Kvs / Kinesis Video Streams

// --------------------------------------------------------------------------------------






// --------------------------------------------------------------------------------------
[사전) 필요 설정 정리] : build.gradle 의존성 부여
// --------------------------------------------------------------------------------------

// [AWS] : [target 31 이상 의존성]
implementation 'com.amazonaws:aws-android-sdk-kms:2.57.0'
implementation 'com.amazonaws:aws-android-sdk-s3:2.57.0'
implementation 'com.amazonaws:aws-android-sdk-iot:2.57.0'
implementation 'com.amazonaws:aws-android-sdk-mobile-client:2.57.0'
implementation 'com.amazonaws:aws-android-sdk-kinesisvideo:2.57.0'

// --------------------------------------------------------------------------------------





// --------------------------------------------------------------------------------------
[소스 코드]
// --------------------------------------------------------------------------------------

// -----------------------------------------------------------------------------------------
// TODO [SEARCH FAST] : [디바이스] : KVS HLS 스트리밍 재생 URL 확인
// -----------------------------------------------------------------------------------------
// TODO 참고 : 해당 코드를 호출 하기 전에 스트리밍이 재생되고 있어야합니다 (스트리밍 재생 없을 시 404 : No fragments found in the stream for the streaming request)
// -----------------------------------------------------------------------------------------
// [호출 소스 코드]
// -----------------------------------------------------------------------------------------
/*
try {

    C_Aws_Kvs_Module.getKvsHlsStreamPlayUrl(A_Intro.this, C_Aws_Kvs_Module.ACCESS_KEY, C_Aws_Kvs_Module.SECRET_KEY, C_Aws_Kvs_Module.REGION, "DEVICE_1")
            .subscribeOn(AndroidSchedulers.mainThread()) // [Observable (생성자) 로직을 IO 스레드에서 실행 : 백그라운드]
            .observeOn(Schedulers.io()) // [Observer (관찰자) 로직을 메인 스레드에서 실행]
            .subscribe(new Observer<String>() { // [Observable.create 타입 지정]
                @Override
                public void onSubscribe(@NonNull Disposable d) {
                }

                @Override
                public void onNext(@NonNull String value) {
                    S_Log._W_("AWS KVS HLS 스트리밍 재생 URL 확인 :: onNext", new String[]{String.valueOf(value)});
                }

                @Override
                public void onError(@NonNull Throwable e) {
                    S_Log._E_("AWS KVS HLS 스트리밍 재생 URL 확인 :: onError", new String[]{String.valueOf(e.getMessage())});
                }

                @Override
                public void onComplete() {
                }
            });

}
catch (Exception e) {
    S_Log._printStackTrace_(null, S_FinalData.LOG_BUG_STATE, null, e);
}
*/
// -----------------------------------------------------------------------------------------
public static String getKvsHlsStreamPlayUrl_Error_Message = "";

public static Observable<String> getKvsHlsStreamPlayUrl(Context mContext, String ACCESS_KEY, String SECRET_KEY, String REGION, String STREAM_NAME) {
    S_Log._D_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 URL 확인", new String[]{
            "ACCESS_KEY :: " + String.valueOf(ACCESS_KEY),
            "SECRET_KEY :: " + String.valueOf(SECRET_KEY),
            "REGION :: " + String.valueOf(REGION),
            "STREAM_NAME :: " + String.valueOf(STREAM_NAME),
    });

    // [로직 처리 실시]
    return Observable.create(subscriber -> {
        try {

            // [에러 메시지 초기화]
            getKvsHlsStreamPlayUrl_Error_Message = "";


            // [인풋 데이터 널 체크 수행]
            if (mContext != null
                    && C_Util.stringNotNull(ACCESS_KEY) == true
                    && C_Util.stringNotNull(SECRET_KEY) == true
                    && C_Util.stringNotNull(REGION) == true
                    && C_Util.stringNotNull(STREAM_NAME) == true){

                // --------------------------------------------------------
                // TODO [HTTP 요청 처리 Thread 정의]
                // --------------------------------------------------------
                new Thread(){
                    @Override
                    public void run(){

                        // --------------------------------------------------------
                        // TODO [AWS 자격 증명 설정]
                        // --------------------------------------------------------
                        AWSCredentials credentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);


                        // --------------------------------------------------------
                        // TODO [AWSKinesisVideoClient 생성]
                        // --------------------------------------------------------
                        AWSKinesisVideo awsKinesisVideoClient = new AWSKinesisVideoClient(credentials);

                        if (C_Util.stringNotNull(REGION) == true){ // TODO [리젼 정보 설정]
                            //awsKinesisVideoClient.setRegion(Region.getRegion("ap-northeast-1"));
                            awsKinesisVideoClient.setRegion(Region.getRegion(REGION));
                        }

                        S_Log._D_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 데이터 엔트포인트 정보 요청 수행", new String[]{
                                "getAWSAccessKeyId :: " + String.valueOf(credentials.getAWSAccessKeyId()),
                                "getAWSSecretKey :: " + String.valueOf(credentials.getAWSSecretKey()),
                        });


                        // --------------------------------------------------------
                        // TODO [GetDataEndpointRequest 객체 생성 : KVS]
                        // --------------------------------------------------------
                        GetDataEndpointRequest dataEndPointRequest = new GetDataEndpointRequest()
                                .withStreamName(STREAM_NAME) // 스트림 이름 설정
                                .withAPIName(APIName.GET_HLS_STREAMING_SESSION_URL); // TODO API 이름 설정 (GET_HLS_STREAMING_SESSION_URL)


                        // [로직 처리 수행]
                        try {

                            // --------------------------------------------------------
                            // TODO [GetDataEndpointResult 확인]
                            // --------------------------------------------------------
                            GetDataEndpointResult result = awsKinesisVideoClient.getDataEndpoint(dataEndPointRequest);


                            // [getDataEndpoint 출력]
                            String dataEndpoint  = result.getDataEndpoint();


                            // [dataEndpoint 변수 체크]
                            if (C_Util.stringNotNull(dataEndpoint)){
                                S_Log._W_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 데이터 엔트포인트 정보 확인 성공", new String[]{String.valueOf(dataEndpoint)});

                                // --------------------------------------------------------
                                // TODO [Http 요청에 필요한 Body 선언]
                                // --------------------------------------------------------
                                JSONObject payload = new JSONObject();
                                payload.put("StreamName", STREAM_NAME);
                                payload.put("PlaybackMode", "LIVE");

                                byte[] contentBytes = payload.toString().getBytes("UTF-8");

                                RequestBody requestBody = RequestBody.create(payload.toString(), MediaType.parse("application/json"));


                                // --------------------------------------------------------
                                // TODO [AWS Signature V4 서명 적용]
                                // --------------------------------------------------------
                                // import com.amazonaws.DefaultRequest;
                                // import com.amazonaws.Request;
                                // --------------------------------------------------------
                                // import okhttp3.Request;
                                // import okhttp3.RequestBody;
                                // import okhttp3.Response;
                                // import okio.BufferedSink;
                                // --------------------------------------------------------
                                S_Log._D_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 AWS Signature V4 헤더 서명 수행 실시", null);

                                Request<?> signRequest = new DefaultRequest<>("kinesisvideo");

                                signRequest.setHttpMethod(HttpMethodName.POST);
                                signRequest.setEndpoint(new URI(dataEndpoint)); // TODO [DataEndpoint 적용]
                                signRequest.setEncodedResourcePath("/getHLSStreamingSessionURL"); // TODO [Path 설정 : 해당 값 추가 중요]

                                signRequest.addHeader("Host", new URI(dataEndpoint).getHost()); // TODO [호스트 지정]
                                signRequest.addHeader("Content-Length", String.valueOf(contentBytes.length)); // TODO [Body Length]
                                signRequest.addHeader("Content-Type", "application/json"); // TODO [Body 에서 지정한 MediaType 타입]

                                signRequest.setContent(new ByteArrayInputStream(contentBytes)); // TODO [Body Data]
                                // --------------------------------------------------------
                                AWS4Signer signer = new AWS4Signer();

                                signer.setServiceName("kinesisvideo");
                                signer.setRegionName(REGION);

                                signer.sign(signRequest, credentials); // TODO [Sign 인증 수행]
                                // --------------------------------------------------------


                                // --------------------------------------------------------
                                // TODO [서명된 헤더들을 okhttp 헤더에 반영]
                                // --------------------------------------------------------
                                Headers.Builder okHttpHeaders = new Headers.Builder();
                                for (Map.Entry<String, String> entry : signRequest.getHeaders().entrySet()) {
                                    okHttpHeaders.add(entry.getKey(), entry.getValue());
                                    S_Log.w("KWON_TWOK", ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Okhttp Header Insert :: " + String.valueOf(entry.getKey()) + " :: " + String.valueOf(entry.getValue()) + " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                                }


                                // --------------------------------------------------------
                                // TODO [okhttp Request 빌더 생성]
                                // --------------------------------------------------------
                                String streamUrl = dataEndpoint + "/getHLSStreamingSessionURL";

                                okhttp3.Request request = new okhttp3.Request.Builder()
                                        .url(streamUrl) // TODO [최종 요청 URL]
                                        .headers(okHttpHeaders.build()) // TODO [Signature V4 인증 헤더 값 추가]
                                        .post(requestBody) // TODO [실시간 스트리밍 데이터 업로드 Body 추가 : writeTo]
                                        .build();


                                // --------------------------------------------------------
                                // TODO [OkHttp 클라이언트 설정 (HTTP/2 지원)]
                                // --------------------------------------------------------
                                OkHttpClient client = new OkHttpClient.Builder()
                                        .protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
                                        .retryOnConnectionFailure(true)
                                        .build();


                                // --------------------------------------------------------
                                // TODO [로그 출력]
                                // --------------------------------------------------------
                                S_Log._D_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 요청 수행", new String[]{
                                        "method :: " + String.valueOf(request.method()),
                                        "url :: " + String.valueOf(request.url().toString()),
                                        "headers :: " + String.valueOf(request.headers().toString()),
                                        "body :: " + String.valueOf(payload),
                                });


                                // --------------------------------------------------------
                                // TODO [HTTP 요청 및 응답 확인]
                                // --------------------------------------------------------
                                //try (Response response = client.newCall(request).execute()) {
                                try (Response response = client.newCall(request).execute()) {

                                    String responseHeaders = response.headers().toString();
                                    int responseCode = response.code();
                                    String responseData = new String(response.body().bytes(), "UTF-8");

                                    if (responseCode >= 200 && responseCode < 300){ // TODO [정상 응답]
                                        S_Log._W_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 응답 결과", new String[]{
                                                "responseHeaders :: " + String.valueOf(responseHeaders),
                                                "responseCode :: " + String.valueOf(responseCode),
                                                "responseData :: " + String.valueOf(responseData),
                                        });

                                        if (subscriber != null && subscriber.isDisposed() == false){
                                            subscriber.onNext(responseData);
                                            subscriber.onComplete();
                                        }
                                    }
                                    else { // TODO [에러 응답]
                                        S_Log._E_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 요청 에러", new String[]{
                                                "responseHeaders :: " + String.valueOf(responseHeaders),
                                                "responseCode :: " + String.valueOf(responseCode),
                                                "responseData :: " + String.valueOf(responseData),
                                        });

                                        // [에러 메시지 삽입]
                                        getKvsHlsStreamPlayUrl_Error_Message = C_Format.form_message(new String[]{
                                                "CODE :: " + C_Util.getSourceCodeLine(),
                                                "MESSAGE :: " + "[재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 응답 정보 확인이 필요합니다.",
                                                "RESPONSE_HEADERS :: " + String.valueOf(responseHeaders),
                                                "RESPONSE_CODE :: " + String.valueOf(responseCode),
                                                "RESPONSE_DATA :: " + String.valueOf(responseData),
                                        });

                                        if (subscriber != null && subscriber.isDisposed() == false){
                                            subscriber.onError(new Throwable(getKvsHlsStreamPlayUrl_Error_Message));
                                            subscriber.onComplete();
                                        }
                                    }

                                } catch (IOException e) {
                                    e.printStackTrace();

                                    S_Log._D_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 요청 실패", new String[]{
                                            "IOException :: " + String.valueOf(e.getMessage()),
                                    });

                                    // [에러 메시지 삽입]
                                    getKvsHlsStreamPlayUrl_Error_Message = C_Format.form_message(new String[]{
                                            "CODE :: " + C_Util.getSourceCodeLine(),
                                            "MESSAGE :: " + "[재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 요청 중 문제가 발생했습니다.",
                                            "EXCEPTION :: " + String.valueOf(e.getMessage())
                                    });

                                    if (subscriber != null && subscriber.isDisposed() == false){
                                        subscriber.onError(new Throwable(getKvsHlsStreamPlayUrl_Error_Message));
                                        subscriber.onComplete();
                                    }

                                }

                            }
                            else {
                                S_Log._E_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 요청 실패", new String[]{ "Error :: getDataEndpoint Is Null" });

                                // [에러 메시지 삽입]
                                getKvsHlsStreamPlayUrl_Error_Message = C_Format.form_message(new String[]{
                                        "CODE :: " + C_Util.getSourceCodeLine(),
                                        "MESSAGE :: " + "[재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 요청 중 문제가 발생했습니다.",
                                        "Error :: getDataEndpoint Is Null"
                                });

                                if (subscriber != null && subscriber.isDisposed() == false){
                                    subscriber.onError(new Throwable(getKvsHlsStreamPlayUrl_Error_Message));
                                    subscriber.onComplete();
                                }
                            }

                        } catch (Exception es) {
                            es.printStackTrace();
                            S_Log._E_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 요청 실패", new String[]{ "Exception :: " + String.valueOf(es.getMessage()) });

                            // [에러 메시지 삽입]
                            getKvsHlsStreamPlayUrl_Error_Message = C_Format.form_message(new String[]{
                                    "CODE :: " + C_Util.getSourceCodeLine(),
                                    "MESSAGE :: " + "[재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 HTTP 요청 중 문제가 발생했습니다.",
                                    "EXCEPTION :: " + String.valueOf(es.getMessage())
                            });

                            if (subscriber != null && subscriber.isDisposed() == false){
                                subscriber.onError(new Throwable(getKvsHlsStreamPlayUrl_Error_Message));
                                subscriber.onComplete();
                            }

                        }

                    }
                }.start();

            }
            else {
                S_Log._E_(ACTIVITY_NAME + " :: getKvsHlsStreamPlayUrl :: [재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 에러", new String[]{"Input Data Is Null (ACCESS_KEY, SECRET_KEY, REGION, STREAM_NAME)"});

                // [에러 메시지 삽입]
                getKvsHlsStreamPlayUrl_Error_Message = C_Format.form_message(new String[]{
                        "CODE :: " + C_Util.getSourceCodeLine(),
                        "EXPLANATION :: " + "[재생 정보] :: KVS HLS 스트리밍 재생 URL 확인에 필요한 필수 값을 확인해주세요.",
                        "ERROR :: Input Data Is Null (ACCESS_KEY, SECRET_KEY, REGION, STREAM_NAME)"
                });

                if (subscriber != null && subscriber.isDisposed() == false){
                    subscriber.onError(new Throwable(getKvsHlsStreamPlayUrl_Error_Message));
                    subscriber.onComplete();
                }

            }

        }
        catch (Exception e){
            S_Log._printStackTrace_(null, S_FinalData.LOG_BUG_STATE, null, e);

            // [에러 메시지 삽입]
            getKvsHlsStreamPlayUrl_Error_Message = C_Format.form_message(new String[]{
                    "CODE :: " + C_Util.getSourceCodeLine(),
                    "EXPLANATION :: " + "[재생 정보] :: KVS HLS 스트리밍 재생 URL 확인 중 예외 상황이 발생했습니다.",
                    "EXCEPTION [2] :: " + String.valueOf(e.getMessage())
            });

            if (subscriber != null && subscriber.isDisposed() == false){
                subscriber.onError(new Throwable(getKvsHlsStreamPlayUrl_Error_Message));
                subscriber.onComplete();
            }

        }
    });
}

// --------------------------------------------------------------------------------------





// --------------------------------------------------------------------------------------
[참고 사이트]
// --------------------------------------------------------------------------------------

[kvs (Kinesis Video Streams) , HLS (HTTP 라이브 스트리밍) 설명 및 정리]

https://blog.naver.com/kkh0977/223724719256?trackingCode=blog_bloghome_searchlist


[AWS 사이트 주요 질문 정리 사이트]

https://aws.amazon.com/ko/kinesis/video-streams/faqs/


[Aws Kvs 실시간 영상 업로드 위한 엔드포인트 정보 확인 - GetDataEndpointRequest]

https://blog.naver.com/kkh0977/223855177383

// --------------------------------------------------------------------------------------
 
반응형
Comments