Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Play 콜백이 정의되지 않은 채널은 콜백의 응답과 관계없이 재생을 진행합니다. 콜백이 정의된 채널을 통해 서비스되는 콘텐츠는 콜백에 대한 응답을 확인 후 재생하기 때문에 고객사에서 정의한 콜백 URL은 항상 응답상태를 유지하셔야 원활한 서비스를 받으실 수 있습니다.

주의:

  1. 고객사의 회원 아이디를 포함한 미디어 토큰(Media token)을 생성하여 요청된 경우에 Play 콜백이 호출됩니다. (미디어 토큰 생성은 별도 문서를 참고해 주십시오.)

  2. Play 콜백 URL이 응답하지 않으면 재생 되지 않습니다.

  3. Play 콜백은 다운로드된 콘텐츠에 대한 DRM 콜백과 다르게 동작합니다. 다운로드된 콘텐츠는 Play 콜백이 아닌 DRM 콜백으로 동작하게 됩니다. 필요에 따라 Play 콜백과 DRM 콜백 URL을 동일하게 등록하면 다운로드와 스트리밍시에 재생에 대한 응답을 동일하게 받으실 수 있습니다.

Callback flow

...

  1. 채널에 Play 콜백 URL을 설정합니다.

    • ex> http://www.foo.com/auth.php 가 고객사 Play 콜백 서버인 경우

Media token을 생성하여 다운로드를 요청합니다.

  1. JSON 데이터를 생성 후 JWT로 인코딩 한다.

  2. Kollus mobile player가 http://www.foo.com/auth.php 에 다음의 정보를 POST 전송 합니다.

    • kind : 1, 3

    • client_user_id : 고객사 회원 아이디

      • Media token 생성시 포함된 아이디입니다.

    • player_id : 고객사 회원이 가지고 있는 단말 아이디

    • device_name : 고객사 회원이 가지고 있는 단말명

    • media_content_key : 현재 재생하려는 콘텐츠 key 입니다.

      • 채널에 등록된 컨텐츠에 부여된 고유 키입니다.

      • 업로드된 컨텐츠를 여러채널에 등록하면 media_content_key는 모두 다르게 생성됩니다.

  3. 고객사 Play 콜백 서버는 전달 받은 위 정보를 바탕으로 다음의 json 포멧의

...

  1. data를 JWT의 payload ​에 ​추가하여 Encoding ​하고 ​헤더에 ​지정된 “시용자키(X-KOLLUS-USERKEY)"를 함께 ​전송합니다.

    (고객사가 인증 정보를 플레이어로 전달할 때 모든 데이터의 자료형은 반드시 기술된대로 integer 형이여야만 합니다.)

...

  • 지원하는 방식
    • Kollus crypt SDK를 이용해 암호화하여 전송합니다.
    • JWT Encode하여 전송합니다. 알고리즘은 HS256만 지원하며 secret키는 콜백 요청 시 넘겨주는 custom_key파라미터 값을 사용합니다.

Response JSON spec.

...

Response JSON spec.

Json Tag

Description

expiration_date

unixtime stamp (만료될 시간의 unixtime stamp)
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)

result

반환 결과가 정상인 경우 1, 비정상인 경우 0을 반환하도록 합니다.

content_expired

DRM 컨텐츠를 강제로 expire 시킵니다.

Callback Kind

Play 콜백이 호출되는 상황은 아래 3가지 경우입니다.

콘텐츠의 Expire 정보를 요청하는 경우 (kind:1)

Request

구분

Description

POST

Http POST로 요청합니다. (parameter가 아닙니다.)

kind

1

client_user_id

고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.

player_id

고객사 사용자가 가지고 있는 단말의 아이디

hardware_id

단말의 hardware 아이디(PC, 입력값이 있으면)

device_name

고객사 사용자가 가지고 있는 단말의 모델명

media_content_key

Kollus 컨텐츠 unique key

uservalues

JSON format (VideoGateway 호출시 사용된

uservalue0~9

uservalue0~999)

  • uservalues sample

    • uservalues={"uservalue0":"강의코드01","uservalue1":"상품코드02","uservalue9":" 생성코드03"}

    • VideoGateway(v.kr.kollus.com)호출시 사용된

      uservalue0~9

      uservalue0~999 정보를 함께 전달 받습니다.

Response

카테고리

구분

필수 

Description

Data

(int) expiration_date

O

만료될 시간의 unixtime stamp
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)


(int) result

O

0 (비정상), 1 (정상)


(string) message


result == 0 (비정상)의 경우 message를 추가하면

상황에 따른 메시지가 표시됩니다.

지정 한 메시지가 표출됩니다.

  • PC 플레이의 경우 재생 URL에 loadcheck=0 파라미터를 추가 해 주셔야 지정 한 메시지가 표출됩니다.
    EX. http://v.kr.kollus.com/{미디어 컨텐츠 키}?loadcheck=0


(int) vmcheck


0 (사용안함), 1 (사용함, default) virtural machine 체크 여부, PC(v3)용에서만 사용 가능

(array)
play_section{
start_time,
end_time
}미리 보기 구간 초로 구분(end_time이 start_time 보다 커야 한다)


(int) disable_tvout


0 (tvout 차단 안함), 1 (tvout 차단) 이 항목이 없으면 채널에 있는 disable_tvout정책이 적용됩니다.


(int)
expiration_playtime


이 항목이 없거나 0이면 재생 시간을 사용하지 않고 0보다 크면 해당 값의 초만큼만 재생 후 종료합니다

.

.


(int) cpcheck


0 (사용안함), 1 (사용함, default) 캡쳐프로그램 체크 여부, PC용에서만 사용 가능

exp

(int)


사용 가능 시간 unixtime stamp(옵션)

Example
Code Block
languagejsthemeMidnight
{
    “data” : {
        "expiration_date": 1402444800,
        "vmcheck": 1,
        "play_section": [
            “start_time”: 0,
            “end_time” : 60
        ],
        "disable_tvout": 1,
        "expiration_playtime": 1800,
        "result": 1
    },
    “exp” : 1477558242
}

...

Code Block

콘텐츠를 재생하는 경우 (kind:3)

주의) 콘텐츠 재생을 위해 반드시 응답해야 합니다. Play 콜백에 대한 응답을 확인 후에 재생을 시작합니다.

Request

구분

Description

POST

Http POST로 요청합니다. (parameter가 아닙니다.)

kind

3

client_user_id

고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.

player_id

고객사 사용자가 가지고 있는 단말의 아이디

device_name

고객사 사용자가 가지고 있는 단말의 모델명

media_content_key

Kollus 컨텐츠 unique key

uservalues

JSON format (VideoGateway 호출시 사용된 uservalue0~9)

Response

카테고리

구분

필수 

Description

data

(int) content_expired


0 (재생가능), 1 (재생 제한)
재생을 차단합니다. DRM 콜백과 동일한 스펙 유지를 위해 동일한 항목으로 유지됩니다.


(int) result

O

0 (비정상), 1 (정상)
0 인 경우 재생되지 않습니다. 이때 conent_expired가 1이어도 expire가 수행되지 않습니다.


(string) message


result == 0 (비정상)의 경우나 content_expired이 1(재생 제한)의 경우 message를 추가하면

상황에 따른 메시지가 표시됩니다.

지정 한 메시지가 표출됩니다.

  • PC 플레이의 경우 재생 URL에 loadcheck=0 파라미터를 추가 해 주셔야 지정 한 메시지가 표출됩니다.
    EX. http://v.kr.kollus.com/{미디어 컨텐츠 키}?loadcheck=0

exp

(int) expiration_date


사용 가능 시간 unixtime stamp(옵션)
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)

Example
Code Block
languagejsthemeMidnight
{
    “data” : {
        "content_expired": 1,
        "result": 1
    },
    "exp" : 1477558242
}


Sample

  • Play callback url

    • http://www.foo.com/auth.php

  • 컨텐츠 만료 시간 : 2014년 6월 10일 자정 종료

    • DATE (M/D/Y @ h : m : s): 6 / 10 / 2014 @ 24:0:0 UTC

    • Unix time stamp : 1402444800

    • http://www.epochconverter.com 를 이용해 1402444800 값을 변경해 볼 수 있습니다. GMT가 아닌 UTC입니다.

kind1 : request expire option

...

response
Code Block
theme
languagejsMidnight
{
    “data” : {
        "expiration_date": 1402444800,
        "result": 1
    },
    "exp" : 1477558242
}

...

Code Block
kind3 : play content (expire content)
request
  • URL : http://www.foo.com/auth.php

  • post data

    • kind=3

    • client_user_id=guest1

    • media_content_key=VXBW1VdY

    • uservalues={"uservalue0":"강의코드01","uservalue1":"상품코드02","uservalue9":" 생성코드03"}

response
Code Block
languagejsthemeMidnight
{
    “data” : {
        "content_expired": 1,
        "result": 1
    },
    "exp" : 1477558242
}

...

Code Block

Code sample

다음과 같은 고객사의 DB가 구성된 것으로 고려되어 샘플이 구성되어있습니다.

PHP sample
Code Block
languagejs
themeMidnight
<?php
    /**
    * PHP Version : 5.4 above
    * by yupmin
    */
    include "./config.php";
    
    // 주의 : kind가 1일때 자동으로 expiration_date가 생성되는 샘플 페이지입니다.
    // 재생 제한 횟수
    $_default_expiration_count = 3;
    $_expired_duration = 60 * 60 * 24; // 1 day
    // DB Connection
    $_db_conn = mysql_connect($_hostname, $_username, $_password);
    if (!$_db_conn) {
   		die('Could not connect: ' . mysql_error());
    }
    $_db_selected = mysql_select_db($_database, $_db_conn);
    if (!$_db_selected) {
    	die ('Can\'t use database : ' . mysql_error());
    }
    $_kind = isset($_POST['kind']) ? ((int) $_POST['kind']) : NULL;
    $_media_content_key = isset($_POST['media_content_key']) ? $_POST['media_content_key'] : 		NULL;
    $_client_user_id = isset($_POST['client_user_id']) ? $_POST['client_user_id'] : NULL;
    
    $channel = NULL;
    $_query = sprintf("SELECT * FROM `channels` WHERE `media_content_key` = '%s'",
   		mysql_real_escape_string($_media_content_key, $_db_conn));
    $_result = mysql_query($_query, $_db_conn);
    if ($_result) {
   		$channel = mysql_fetch_array($_result, MYSQL_ASSOC);
    	if ($channel === FALSE) $channel = NULL;
    } else {
    	die('Invalid query: ' . mysql_error());
    }
    
    $user = NULL;
    $_query = sprintf("SELECT * FROM `users` WHERE `client_user_id` = '%s'",
    	mysql_real_escape_string($_client_user_id, $_db_conn));
    $_result = mysql_query($_query, $_db_conn);
    if ($_result) {
    	$channel = mysql_fetch_array($_result, MYSQL_ASSOC);
    	if ($channel === FALSE) $channel = NULL;
    } else {
    	die('Invalid query: ' . mysql_error());
    }
    
    $channel_user = NULL;
    if (!is_null($_media_content_key) && !is_null($_client_user_id)) {
    	$_query = sprintf("SELECT * FROM `channel_users` WHERE `user_id` = '%s', `channel_id` = 			'%s'",
    	$user['id'], $channel['id']);
    	$_result = mysql_query($_query, $_db_conn);
        if ($_result) {
        	$channel_user = mysql_fetch_array($_result, MYSQL_ASSOC);
            if ($channel_user === FALSE) $channel_user = NULL;
        } else {
        	die('Invalid query: ' . mysql_error());
        }
   	}
    $_json_result = array('result' => 0);
    switch($_kind) {
    case 1:
        if (is_null($channel_user)){
            $_expiration_date = time() + $_expired_duration;
            $_expiration_count = $_default_expiration_count;
            $_query = sprintf("INSERT INTO `channel_users`(`user_id`, `channel_id`, 						`expiration_date`
                ,`expiration_count` , `created_at`, `updated_at`) VALUES('%s', '%s', '%s', '%s', 			 UNIX_TIMESTAMP(),
                UNIX_TIMESTAMP())", $user['id'], $channel['id'], $_expiration_date, 						$_expiration_count);

            $_result = mysql_query($_query, $_db_conn);
             if (!$_result) {
                die('Invalid query: ' . mysql_error());
            }
        } else {
            $_expiration_date = $channel_user['expiration_date'];
            $_expiration_count = $channel_user['$expiration_count'];
        }
        $_json_result['expiration_date'] = (int) $_expiration_date;
        $_json_result['expiration_count'] = (int) $_expiration_count;
        break;
    case 3:
    	if (!is_null($channel_user) && $channel_user['is_expired']) {
    		$_json_result['content_expired'] = 1;
    	}
    	break;
    }
    
    // DB Close
    mysql_close($_db_conn);
    
    // json_encode된 결과를 kollus_encrypt를 통해 암호화시킴
    echo kollus_encrypt(json_encode($_json_encode));
}

...

Code Block
JSP ​sample
Code Block
languagejs
themeMidnight
<%@page import="org.codehaus.jettison.json.JSONObject"%>
<%@page import="java.util.Locale"%>
<%@page import="java.util.Date"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.ArrayList"%>
<%@page import="org.codehaus.jackson.map.ObjectMapper"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.sql.*"%>
<%@ page import="test.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
    String kind_str = request.getParameter("kind");
    String media_content_key = request.getParameter("media_content_key");
    String client_user_id = request.getParameter("client_user_id");
    int kind = Integer.parseInt(kind_str);
    int _default_expiration_count = 3;
    int _expired_duration = 60 * 60 * 24; //one day
    int channel_id = 0;
    int user_id = 0;
    int channel_user_id = 0;
    int expiration_count = 0;
    int is_expired = 0;
    int download_times = 0;

    Long expiration_date = 0l;
    Connection conn = null; // null로 초기화 한다.
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    JSONObject jsonobj = new JSONObject();
	try {
        String url = "jdbc:mysql://localcost:3306/kollus_base";
        String id = "test"; // 사용자 계정
        String pw = "test"; // 사용자 계정의 패스워드
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        conn = DriverManager.getConnection(url, id, pw);
        String sql = "SELECT * FROM `channels` WHERE `media_content_key` = ? ";
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1,media_content_key);
        rs = pstmt.executeQuery();
		while(rs.next()){
			channel_id = rs.getInt("id");
		}
        rs.close();
        pstmt.close();
        sql = "SELECT * FROM `users` WHERE `client_user_id` = ?";
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1,client_user_id);
        rs = pstmt.executeQuery();
        while(rs.next()){
        	user_id = rs.getInt("id");
        }
		rs.close();
		pstmt.close();
		if (channel_id > 0 && user_id > 0) {
            sql = "SELECT * FROM `channel_users` WHERE `user_id` = ?, `channel_id` = ? ";
            pstmt = conn.prepareStatement(sql);
            pstmt.setInt(1, channel_id);
            pstmt.setInt(2, user_id);
            rs = pstmt.executeQuery();
		   while(rs.next()){
                channel_user_id = rs.getInt("id");
                expiration_date = rs.getLong("expiration_date");
                expiration_count = rs.getInt("expiration_date");
                is_expired = rs.getInt("is_expired");
                download_times = rs.getInt("download_times");
	       }	
           rs.close();
           pstmt.close();
	    }
		jsonobj.put("result", "0");
        switch(kind) {
            case 1:
                if (channel_user_id == 0) {
                    Long starttime = System.currentTimeMillis()/1000;
                    expiration_date = starttime + _expired_duration;
                    expiration_count = _default_expiration_count;
                    sql = "INSERT INTO `channel_users`(`user_id`, `channel_id`,
                    `expiration_date` ,`expiration_count` , `created_at`, `updated_at`) VALUES 						(?,?,?,?,?,?)"; // sql 쿼리
                    pstmt = conn.prepareStatement(sql); // prepareStatement에서 해당 sql을 미리 컴파일한다.

                    pstmt.setInt(1, user_id);
                    pstmt.setInt(2, channel_id);
                    pstmt.setLong(3, expiration_date);
                    pstmt.setInt(4, expiration_count);
                    pstmt.setLong(5, starttime); // 현재 날짜와 시간
                    pstmt.setLong(6, starttime); // 현재 날짜와 시간
                    pstmt.executeUpdate();
                    pstmt.close();
                 }
                 jsonobj.put("expiration_date", expiration_date);
                 jsonobj.put("expiration_count", expiration_count);
                 break;
            case 3:
                 if (channel_user_id > 0 && is_expired > 0) {
                    jsonobj.put("expiration_date", expiration_date);
                }
        }
		break;
		conn.close();
	} catch (Exception e) { // 예외가 발생하면 예외 상황을 처리한다.
		e.printStackTrace();
	}
	String sendMsg = jsonobj.toString();
	// System.out.println(sendMsg);
%>
<%= kollus_encrypt(sendMsg)%>

...

Code Block

샘플코드

https://github.com/kollus-service/kollus-playcallback-dotnet

https://github.com/kollus-service/kollus-samples-jsp

https://github.com/kollus-service/kollus-drm-callback-php

https://github.com/kollus-service/kollus-samples-php