Versions Compared

Key

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

Player Callback

Play

개요

Kollus 전용플레이어에서 재생을 할때 고객사에서 정의한 URL을 호출(Callback)하는 기능을 정의한 문서입니다.

Expire option

설정 항목의 data-type이나 값이 범위를 벗어나는 경우 컨텐츠 이용에 문제가 발생할 수 있으며, 잘못된 설정 값에 대한 사용 제한을 회수하는 방법은 존재하지 않습니다.

  • Expire date : 컨텐츠 만료 시간

    • data-type : integer, unixtime stamp

    • 컨텐츠 재생이 만료될 시간

      • 컨텐츠 재생이 만료될 시간

        ex) 2014. 3. 3. 5시 45분 30초 GMT → 1393825531

      • 0 : unlimited (무제한)

      • 최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)

Play callback

Play callback(이하 콜백)을 사용하기 위해서는 CMS의 관리 화면에서 관리자 이상의 권한을 소유한 로그인 계정으로 채널 속성에 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 콜백 서버인 경우
  2. Media token을 생성하여 다운로드를 요청합니다.

    • Kollus crypt SDK를 이용해 Media token을 생성합니다.
  3. 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는 모두 다르게 생성됩니다.
  4. 고객사 Play 콜백 서버는 전달 받은 위 정보를 바탕으로 다음의 json 포멧의 data를 아래의 방식 중에서 하나로 Http Body에 전송합니다.

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

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

Response JSON spec.

Json TagDescription
expiration_dateunixtime stamp (만료될 시간의 unixtime stamp)
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)
result반환 결과가 정상인 경우 1, 비정상인 경우 0을 반환하도록 합니다.
content_expiredDRM 컨텐츠를 강제로 expire 시킵니다.

Callback Kind

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

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

Request
구분Description
POSTHttp POST로 요청합니다. (parameter가 아닙니다.)
kind1
client_user_id고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.
player_id고객사 사용자가 가지고 있는 단말의 아이디
hardware_id단말의 hardware 아이디(PC, 입력값이 있으면)
device_name고객사 사용자가 가지고 있는 단말의 모델명
media_content_keyKollus 컨텐츠 unique key
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9)
  • uservalues sample
    • uservalues={"uservalue0":"강의코드01","uservalue1":"상품코드02","uservalue9":" 생성코드03"}
    • VideoGateway(v.kr.kollus.com)호출시 사용된 uservalue0~9 정보를 함께 전달 받습니다.
Response
카테고리구분Description
Data(int) expiration_date만료될 시간의 unixtime stamp
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)

(int) result0 (비정상), 1 (정상)

(string) message0 (비정상)의 경우 message를 추가하면 상황에 따른 메시지가 표시됩니다.

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

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

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

(int)
expiration_playtime
이 항목이 없거나 0이면 재생 시간을 사용하지 않고 0보다 크면 해당 값의 초만큼만 재생 후 종료합니다.
exp(int)사용 가능 시간 unixtime stamp(옵션)
Example
Code Block
languagejs
themeMidnight
{
    “data” : {
        "expiration_date": 1402444800,
        "vmcheck": 1,
        "play_section": [
            “start_time”: 0,
            “end_time” : 60
        ],
        "disable_tvout": 1,
        "expiration_playtime": 1800,
        "result": 1
    },
    “exp” : 1477558242
}

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

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

Request
구분Description
POSTHttp POST로 요청합니다. (parameter가 아닙니다.)
kind3
client_user_id고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.
player_id고객사 사용자가 가지고 있는 단말의 아이디
device_name고객사 사용자가 가지고 있는 단말의 모델명
media_content_keyKollus 컨텐츠 unique key
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9)
Response
카테고리구분Description
data(int) content_expired0 (재생가능), 1 (재생 제한)
재생을 차단합니다. DRM 콜백과 동일한 스펙 유지를 위해 동일한 항목으로 유지됩니다.

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

(string) message0 (비정상)의 경우나 content_expired이 1(재생 제한)의 경우 message를 추가하면 상황에 따른 메시지가 표시됩니다.
exp(int) expiration_date사용 가능 시간 unixtime stamp(옵션)
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)
Example
Code Block
languagejs
themeMidnight
{
    “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
request
  • URL : http://www.foo.com/auth.php

  • post data

    • kind=1

    • client_user_id=guest1

    • media_content_key=VXBW1VdY

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

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

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
languagejs
themeMidnight
{
    “data” : {
        "content_expired": 1,
        "result": 1
    },
    "exp" : 1477558242
}

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));
}

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)%>

샘플코드

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

...

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

DRM

...

개요

Kollus 모바일 다운로드 DRM을 이용해 다운로드한 컨텐츠의 ‘재생 재한 횟수’, ‘컨텐츠 만료 기간’, ‘컨텐츠 재생시간'을 설정하여 컨텐츠의 재생을 제어하는 기능을 설명하는 문서입니다. 서비스 모델에 따라 중복 제한으로 설정되어 사용될 수 있습니다.

Expire option

설정 항목의 data-type이나 값이 범위를 벗어나는 경우 컨텐츠 이용에 문제가 발생할 수 있으며, 잘못된 설정 값에 대한 사용 제한을 회수하는 방법은 존재하지 않습니다.

  • Expire count : 재생 제한 횟수

    • data-type : integer
    • range : 0 ~ 1000
    • 0 : unlimited (무제한)
  • Expire date : 컨텐츠 만료 시간

    • data-type : integer, unixtime stamp

    • 컨텐츠 재생이 만료될 시간

      • 컨텐츠 재생이 만료될 시간

        ex) 2014. 3. 3. 5시 45분 30초 GMT → 1393825531

      • 0 : unlimited (무제한)

      • 최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)

  • Expire playtime : 재생시간 제한 (배속의 경우 배속이 적용된 시간 적용)

    • data-type : integer
    • range : 0, 60 ~ 604800 (단위:초, 최소: 60초, 최대:1주일)
    • 0 : unlimited (무제한)

DRM callback

DRM 정책을 적용하기 위해서는 채널에 DRM 콜백 URL(DRM callback url)을 설정해야 합니다.

...

  1. DRM 콜백 URL이 응답하지 않으면 다운로드가 되지 않습니다.
  2. 알고리즘은 HS256만 지원을 하며 Http 헤더에 지정된 헤더(X-KOLLUS-USERKEY)의 값으로 “사용자키"를 함께 전송해야 합니다.

Callback ​flow

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

    • ex> http://www.foo.com/auth.php 가 고객사 인증 DRM 서버인 경우
  2. JSON 데이터를 생성 후 JWT로 인코딩 한다.

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

    • session_key : 플레이어에서 생성한 요청 확인용 세션키
      • kind3의 content_expire_reset 경우 요청한 session_key를 확인합니다.
      • Callback v2가 적용되는 v1.6에서 적용됩니다.
    • kind : 1 - 3
    • client_user_id : 고객사 회원 아이디
      • Media token 생성시 포함된 아이디입니다.
    • player_id : 고객사 회원이 가지고 있는 단말 아이디
    • device_name : 고객사 회원이 가지고 있는 단말명
      • 안드로이드, 아이폰에 따라 단말명이 다르게 전달됩니다.
      • 아이폰의 경우 사전에 Apple에서 정의한 문자열로 전달되며 안드로이드의 경우 ​디바이스명, ​모델명이 ​함께 ​전달됩니다. 안드로이드의 경우 해당 정보가 없을 경우 NULL을 전달 합니다.
    • media_content_key : 현재 다운로드하려는 컨텐츠 key 입니다.
      • 채널에 등록된 컨텐츠에 부여된 고유 키입니다.
      • 업로드된 컨텐츠를 여러채널에 등록하면 media_content_key는 모두 다르게 ​생성됩니다.
  4. 고객사 DRM 인증서버는 전달받은 위 정보를 바탕으로 다음의 json 포멧의 data를 JWT의 payload ​에 ​추가하여 Encoding ​하고 ​헤더에 ​지정된 “시용자키(X-KOLLUS-USERKEY)"를 함께 ​전송합니다.

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

Response JSON spec.

Json TagDescription
expiration_dateunixtime stamp (만료될 시간의 unixtime stamp)
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)
expiration_count재생 제한 횟수
expiration_playtime재생시간 제한
result반환 결과가 정상인 경우 1, 비정상인 경우 0을 반환하도록 합니다.
content_expiredDRM 콘텐츠를 강제로 expire 시킵니다.
content_deleteDRM 콘텐츠를 강제 삭제 합니다.
content_expire_resetexpire 콘텐츠를 복구합니다.
session_key* v1.6 이후 Callback v2에서 적용됩니다.
kind3의 요청으로 content_expire_reset
작업시 Request에 포함된 session_key를 Response에 포함시켜야 합니다.
media_content_keyKollus 컨텐츠 Unique Key
kind요청에 대한 구분

device_name 추가 설명

  • Andoid

    안드로이드 어플 개발시 사용되는 Build.DEVICE, Build.MODEL을 /(슬래쉬)로 구분한 문자열로 ​만들어 ​사용합니다.

    • Build.DEVICE+”/”+Build.MODEL
    • 단말기의 특성에 따라 해당 정보는 NULL로 표시될 수 있습니다.
  • iOS

    iOS의 경우 iOS에서 제공하는 device-name을 사용합니다.

...

Device TypeProduct Name
iPhone1,1iPhone
iPhone1,2iPhone 3G
iPhone2,1iPhone 3GS
iPhone3,1iPhone 4 (GSM)
iPhone3,3iPhone 4 (CDMA)
iPhone4,1iPhone 4S
iPhone5,1iPhone 5 (A1428)
iPhone5,2iPhone 5 (A1429)
iPhone5,3iPhone 5c (A1456/A1532)
iPhone5,4iPhone 5c (A1507/A1516/A1529)
iPhone6,1iPhone 5s (A1433/A1453)
iPhone6,2iPhone 5s (A1457/A1518/A1530)
iPhone7,1iPhone 6 Plus
iPhone7,2iPhone 6
iPhone8,1iPhone 6s
iPhone8,2iPhone 6s Plus
iPhone8,4iPhone SE
iPhone9,1iPhone 7 (A1660/A1779/A1780)
iPhone9,2iPhone 7 Plus (A1661/A1785/A1786)
iPhone9,3iPhone 7 (A1778)
iPhone9,4iPhone 7 Plus (A1784)
iPhone10,1iPhone 8 (A1863/A1906)
iPhone10,2iPhone 8 Plus (A1864/A1898)
iPhone10,3iPhone X (A1865/A1902)
iPhone10,4iPhone 8 (A1905)
iPhone10,5iPhone 8 Plus (A1897)
iPhone10,6iPhone X (A1901)
iPad1,1iPad
iPad2,1iPad 2 (Wi-Fi)
iPad2,2iPad 2 (GSM)
iPad2,3iPad 2 (CDMA)
iPad2,4iPad 2 (Wi-Fi, revised)
iPad2,5iPad mini (Wi-Fi)
iPad2,6iPad mini (A1454)
iPad2,7iPad mini (A1455)
iPad3,1iPad (3rd gen, Wi-Fi)
iPad3,2iPad (3rd gen, Wi-Fi+LTE Verizon)
iPad3,3iPad (3rd gen, Wi-Fi+LTE AT&T)
iPad3,4iPad (4th gen, Wi-Fi)
iPad3,5iPad (4th gen, A1459)
iPad3,6iPad (4th gen, A1460)
iPad4,1iPad Air (Wi-Fi)
iPad4,2iPad Air (Wi-Fi+LTE)
iPad4,3iPad Air (Rev)
iPad4,4iPad mini 2 (Wi-Fi)
iPad4,5iPad mini 2 (Wi-Fi+LTE)
iPad4,6iPad mini 2 (Rev)
iPad4,7iPad mini 3 (Wi-Fi)
iPad4,8iPad mini 3 (A1600)
iPad4,9iPad mini 3 (A1601)
iPad5,1iPad mini 4 (Wi-Fi)
iPad5,2iPad mini 4 (Wi-Fi+LTE)
iPad5,3iPad Air 2 (Wi-Fi)
iPad5,4iPad Air 2 (Wi-Fi+LTE)
iPad6,3iPad Pro (9.7 inch) (Wi-Fi)
iPad6,4iPad Pro (9.7 inch) (Wi-Fi+LTE)
iPad6,7iPad Pro (12.9 inch, Wi-Fi)
iPad6,8iPad Pro (12.9 inch, Wi-Fi+LTE)
iPad6,11iPad 9.7-Inch 5th Gen (Wi-Fi Only)
iPad6,12iPad 9.7-Inch 5th Gen (Wi-Fi/Cellular)
iPad7,1iPad Pro (12.9 inch, A1670)
iPad7,2iPad Pro (12.9 inch, A18219)
iPad7,3iPad Pro (10.5 inch, A1701)
iPad7,4iPad Pro (10.5 inch, A1709)
iPad7,5iPad (6th gen, A1893)
iPad7,6iPad (6th gen, A1954)
iPod1,1iPod touch
iPod2,1iPod touch (2nd gen)
iPod3,1iPod touch (3rd gen)
iPod4,1iPod touch (4th gen)
iPod5,1iPod touch (5th gen)
iPod7,1iPod touch (6th gen)

Callback ​kind

DRM callback이 호출되는 상황은 아래 3가지 경우입니다.

DRM 컨텐츠의 Expire 정보를 요청하는 경우 (kind:1)
Request
구분Description
POSTHttp POST로 요청합니다. (parameter가 아닙니다.)
kind1
client_user_id고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.
player_id고객사 사용자가 ​가지고 ​있는 ​단말의 ​아이디
device_name고객사 사용자가 가지고 있는 단말의 모델명
media_content_keyKollus 컨텐츠 unique key
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9)
  • uservalues sample
    • uservalues={"uservalue0":"강의코드01","uservalue1":"상품코드02","uservalue9":" 생성코드03"}
    • VideoGateway(v.kr.kollus.com)호출시 사용된 uservalue0~9 정보를 함께 전달 받습니다.
Response
카테고리구분Description
data(int) expiration_date만료될 시간의 unixtime stamp
최대값 : 2029년 12월 31일 23시 59분 59초
(1893455999)

(int) expiration_count재생 제한 횟수, 예) 10 ← 10번 재생 가능

(int) result0 (비정상), 1 (정상)
0 인 경우 다운로드 되지 않습니다.
0 인 경우 재요청되지 않습니다.

(string) message0 (비정상)의 경우 message를 추가하면 상황에 따른 메시지가 표시됩니다.

(int) expiration_refresh_popup만료후 갱신 여부 팝업 표시
0 인 경우 표시하지 않음 (기본값)
1 인 경우 DRM 만료후 갱신이 필요할때 사용자
확인을 받는 팝업을 표시합니다.

(int) disable_tvout0 (tvout 차단 안함), 1 (tvout 차단)
이 항목이 없으면 채널에 있는 disable_tvout정책이 적용됩니다.
Example
Code Block
languagejs
themeMidnight
{
    “data” : {
        "expiration_date": 1402444800,
        "expiration_count": 10,
   		"result": 1
    }
}

DRM 컨텐츠의 Download가 100% 완료된 경우 (kind:2)

주의) 반드시 응답해야 하며, Block 상태로 통신합니다.

Request
구분Description
POSTHttp POST로 요청합니다. (parameter가 아닙니다.)
kind2
client_user_id고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.
player_id고객사 사용자가 ​가지고 ​있는 ​단말의 ​아이디
device_name고객사 사용자가 가지고 있는 단말의 모델명
media_content_keyKollus 컨텐츠 unique key
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9)
Response
카테고리구분Descriptsion
data(int) expiration_date만료될 시간의 unixtime stamp
해당 항목이 있으면 kind1의 값을 대체합니다.
최대값 : 2029년 12월 31일 23시 59분 59초
(1893455999)

(int) content_delete0 (삭제하지 않음), 1 (다운로드 받은 파일 삭제)
다운로드된 컨텐츠를 요청에 의해 삭제하는 옵션입니다.

(int) result0 (비정상), 1 (정상)
0 인 경우 추가 작업은 없습니다.
0 인경우 추가 옵션은 무시됩니다.
0 인 경우 재요청되지 않습니다.

(string) message0 (비정상)의 경우나 content_delete이 1(다운로드 받은 파일 삭제) 시 message를 추가하면 상황에 따른 메시지가 표시됩니다.
Example
Code Block
languagejs
themeMidnight
{
    “data” : {
        "content_delete": 1,
        "result": 1
	}
}

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

주의) v1.6 이후 재생시 네트워크 통신이 가능한 경우 전송되며 요청 실패시 네트워크 통신이 가능할 때 재 전송 됩니다.

Request
구분Description
POSTHttp POST로 요청합니다. (parameter가 아닙니다.)
kind3
client_user_id고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.
player_id고객사 사용자가 가지고 있는 단말의 아이디
device_name고객사 사용자가 가지고 있는 단말의 모델명
media_content_keyKollus 컨텐츠 unique key
start_atunixtimestamp (localtime)
- 전송 요청 시간
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9)
Response
카테고리구분Description
data(int) content_expired0 (재생가능), 1 (재생 제한)
다운로드 컨텐츠를 강제로 expire 시킵니다.
필요시 content_expire_reset 옵션으로 다시 복구 할 수 있습니다.
* expired 컨텐츠는 0(재생가능)으로 응답해도 재생되지 않습니다.

(int) result0 (비정상), 1 (정상)
0 인 경우 재생되지 않습니다.
0 인 경우 추가 옵션은 무시됩니다.
0 인 경우 재요청되지 않습니다.

(string) message0 (비정상)의 경우나 content_expired이 1(재생 제한) 시 message를 추가하면 상황에 따른 메시지가 표시됩니다.
Example
Code Block
languagejs
themeMidnight
{
    “data: {
        "content_expired" : 1,
        "result": 1
	}
}

Sample

  • DRM 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입니다.
  • 컨텐츠 재생 횟수 제한 : 10회
kind1 : request expire option
request
  • URL : http://www.foo.com/auth.php
  • post data
    • kind=1
    • client_user_id=guest1
    • media_content_key=VXBW1VdY
    • uservalues={"uservalue0":"강의코드01","uservalue1":"상품코드02","uservalue9":" 생성코드03"}
response
Code Block
languagejs
themeMidnight
{
    “data” : {
        "expiration_date": 1402444800,
        "expiration_count": 10,
        "result": 1
	}
}

kind2 : ​download​ ​complete
request
  • URL : http://www.foo.com/auth.php
  • post data
    • kind=2
    • client_user_id=guest1
    • media_content_key=VXBW1VdY
    • uservalues={"uservalue0":"강의코드01","uservalue1":"상품코드02","uservalue9":" 생성코드03"}
response
Code Block
languagejs
themeMidnight
{
    “data” : {
    	"result": 1
    }
}

DRM Callback 신규 버전 v2

이전 1.4까지 제공되던 kind1, kind2, kind3의 호출이 한번의 호출로 통합되어 호출되는 버전으로 변경됩니다. ​이전 ​버전은 ​사용자의 ​사용자의 ​빈번한 ​호출에 ​대응하기 ​용이하지 ​않다는 ​다수 고객사의 요청에 따라 추가 되었습니다. 편의상 새로운 버전을 v2로 이전버전을 v1으로 합니다.

Reuest

구분Description
POSTHttp POST로 요청합니다. (parameter가 아닙니다.)
itemsJsonArray로 구성된 string 입니다.

items 항목은 kind1, kind2, kind3의 데이터를 모두 포함한 호출이 될 수 있습니다.

items (JsonArray)
kind1, kind2
구분Description
kind1,2
client_user_id고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.
player_id고객사 사용자가 가지고 있는 단말의 아이디
hardware_id단말의 hardware 아이디(PC, 입력값이 있으면)
device_name고객사 사용자가 가지고 있는 단말의 모델명
media_content_keyKollus 컨텐츠 unique key
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9)
kind3
구분Description
kind3
session_keycontent_expire_reset 요청시 동일한 session_key를 확인합니다.
client_user_id고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다.
player_id고객사 사용자가 가지고 있는 단말의 아이디
hardware_id단말의 hardware 아이디(PC, 입력값이 있으면)
device_name고객사 사용자가 가지고 있는 단말의 모델명
media_content_keyKollus 컨텐츠 unique key
start_atunixtimestamp (localtime)
- 전송 요청 시간
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9)
content_expired만료된 컨텐츠 확인 flag( 1 : 만료, 0 : 재생가능)
reset_req일괄갱신 요청인지 판단( 0 (default), 1 : 일괄갱신)
Items Sample
Code Block
languagejs
themeMidnight
[
    {
        "kind": 1,
        "media_content_key" : "XXX-MEDIA_CONTENTKEY-XXX",
        "client_user_id": "XXXXXXX",
        "player_id": "xxxxxxxxxxxxxxxx",
        "device_name": "XXXXX",
        "uservalues": {
            "uservalue0": "value0"
        }
    },
    {
        "kind": 2,
        "media_content_key" : "XXX-MEDIA_CONTENTKEY-XXX",
        "client_user_id": "XXXXXXX",
        "player_id": "xxxxxxxxxxxxxxxx",
        "device_name": "XXXXX",
        "uservalues": {
            "uservalue0": "value0"
        }
    },
    {
        "kind": 3,
        "session_key" : "XXX-SESSION_KEY-XXX", ← content_expire_reset 요청시 확인합니다.
        "media_content_key" : "XXX-MEDIA_CONTENTKEY-XXX",
        "client_user_id": "XXXXXXX",
        "player_id": "xxxxxxxxxxxxxxxx",
        "device_name": "XXXXX",
        "uservalues": {
       		"uservalue1": "value1"
        }
    }
]

Response

Array은 “data” 필드로 응답 받는다.

kind1
구분필수Description
(int) kindO1
(string) media_content_keyOKollus 컨텐츠 Unique Key
(int) expiration_date
만료될 시간의 unixtime stamp
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)
(int) expiration_count
재생 제한 횟수, 예) 10 ← 10번 재생 가능
(int) expiration_playtime
재생 시간 제한, 예) 60 ← 60초 재생 가능
(int) resultO0 (비정상), 1 (정상)
0 인 경우 다운로드 되지 않습니다.
0 인 경우 재 요청되지 않습니다.
(string) message
0 (비정상)의 경우 message를 추가하면 상황에 따른 메시지가 표시됩니다.
(int)
expiration_refresh_popup

만료후 갱신 여부 팝업 표시
0 인 경우 표시하지 않음 (기본값)
1 인 경우 DRM 만료후 갱신이 필요할때 사용자 확인을 받는
팝업을 표시합니다.
(int) vmcheck
virtual machine 체크 여부 판단, PC용
0 : check 안 함, 1 : check 함(기본값)
(int) check_abuse
DRM kind3 항상 물어보기(0 : 안함(기본값), 1: 체크)
kind2
구분필수Description
(int) kindO2
(string) media_content_keyOKollus 컨텐츠 Unique Key
(int) content_delete
0 (삭제하지 않음), 1 (다운로드 받은 파일 삭제)
다운로드된 컨텐츠를 요청에 의해 삭제하는 옵션입니다.
(string) message
0 (비정상)의 경우나 content_delete이 1(다운로드 받은 파일 삭제)시 message를 추가하면 상황에 따른 메시지가 표시됩니다.
(int) resultO0 (비정상), 1 (정상)
0 인 경우 추가 작업은 없습니다.
0 인 경우 추가 옵션은 무시됩니다.
0 인 경우 재 요청되지 않습니다.
kind3
구분필수Description
(int) kindO3
(string) session_key
content_expire_reset 요청시 session_key 확인합니다.
(string) media_content_keyOKollus 컨텐츠 Unique Key
(int) start_atORequest에 포함된 start_at
(int) content_expired
0 (재생가능), 1 (재생 제한)
다운로드 컨텐츠를 강제로 expire 시킵니다.
필요시 content_expire_reset 옵션으로 다시 복구 할 수 있습니다.
* expired 컨텐츠는 0(재생가능)으로 응답해도 재생되지 않습니다.
* 1인 경우 content_expire_reset 무시됩니다.
(int) content_delete
0 (삭제하지 않음), 1 (다운로드 받은 파일 삭제)
다운로드된 컨텐츠를 요청에 의해 삭제하는 옵션입니다.
content_expired 옵션과 상관 관계없이 해당 옵션이 존재하는 경우 삭제합니다.
(int) content_expire_reset
0 (추가 액션 없음), 1 (expired된 콘텐츠 권한 Reset)
expired된 콘텐츠 권한을 Reset 하는 옵션입니다.
(int) expiration_date
만료될 시간의 unixtime stamp
최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999)
* content_expire_reset 옵션이 1일때 재설정 됩니다.
(int) expiration_count
재생 제한 횟수, 예) 10 ← 10번 재생 가능
* content_expire_reset 옵션이 1일때 재설정 됩니다.
(int) expiration_playtime
재생 시간 제한, 예) 3600 ← 1시간(3600초) 재생 가능
* content_expire_reset 옵션이 1일때 재설정 됩니다.
(int) resultO0 (비정상), 1 (정상)
0 인 경우 재생되지 않습니다.
0 인 경우 추가 옵션은 무시됩니다.
0 인 경우 재 요청되지 않습니다.
(string) message
0 (비정상), content_expired이 1(재생 제한) 또는 content_delete이 1(다운로드 받은 파일 삭제) 시 message를 추가하면 상황에 따른 메시지가 표시됩니다.
(int) check_abuse
DRM kind3 항상 물어보기(0 : 안함(기본값), 1: 체크)
Response ​Example
Code Block
languagejs
themeMidnight
{
    “data” : [
        {
            "kind": 1,
            "media_content_key": "XXX-MEDIA_CONTENT_KEY-XXX",
            "expiration_date": 1402444800,
            "expiration_count": 10,
            "expiration_playtime": 60,
            "result": 1
        },
        {
            "kind": 2,
            "media_content_key": "XXX-MEDIA_CONTENT_KEY-XXX",
            "content_delete": 1,
            "result": 1
        },
        {
            "kind": 3,
            "session_key" : "XXX-SESSION_KEY-XXX",
            "media_content_key": "XXX-MEDIA_CONTENT_KEY-XXX",
            "start_at": 140000000,
            "content_expired": 1,
            "content_delete": 1,
            "content_expire_reset": 1,
            "expiration_date": 1402444800,
            "expiration_count": 10,
            "expiration_playtime": 3600,
            "result": 1
        }
    ]
}

JWT 지원

DRM 정책을 JWT로 반환하는 것을 지원합니다. JWT 웹사이트(https://jwt.io) 에서 공인한 라이브러리를 이용하여 생성된 Token으로 변경하여 반환하도록 추가 되었습니다.

...

지정된(X-Kollus-UserKey) 해더로 전송된 사용자키가 일치 하는 경우 플레이어에서 정상적으로 동작하게 됩니다.

JWT ​Secret,​ ​JWT​ ​사용자​ ​키

기존 사용자 키(2)키를 header에 추가하는 것 외에 추가적으로 기존의 JWT scpec에 명시되어 있는 secret key는 보안키(1)​를 ​입력해야 ​해야 ​합니다. ​고객사는 ​관련 ​정보를 ​아래와 ​같이 Kollus CMS 에서 확인 할 수 있습니다.

설정 > 서비스 계정 설정


JWT payload

각 callback의 response를 JWT playload에 담아 전송합니다.

Sample

http://jwt.io 에서 제공하는 다양한 언어로 구현된 라이브러리와 예제를 이용해 구현하도록 합니다. JWT ​스펙과 ​동일하나 ​반환되는 http ​헤더에 X-Kollus-UserKey​를 ​이용하여 ​사용자키를 함께 전송해주셔야 합니다.

...

Code Block
languagejs
themeMidnight
define('KOLLUS_KEY', '**사용자키**'); // X-Kollus-UserKey
define('JWT_KEY', '**보안키**'); // JWT 보안 키

function encode_jwt($payload, $key, $alg = 'HS256') {
    $header = array('alg' => $alg, 'typ' => 'JWT' );
    $unsignedToken = base64_encode(json_encode($header)).'.'.
    base64_encode(json_encode($payload));
    $signature = hash_hmac('sha256', $unsignedToken, $key, TRUE);
    return $unsignedToken.'.'.base64_encode($signature);
}
$payload = array(
    'data' => array(
        array(
            'kind' => 1,
            'result' =>1,
            'expiration_date' => time()+3600,
            'expiration_playtime' => 30,
            'vmcheck' => 1,
        ),
        array(
            'kind' => 2,
            'result' =>1,
            'expiration_date' => time()+3600,
            'expiration_playtime' => 30,
            'vmcheck' => 1,
        ),
        array(
            'kind' => 3,
            'result' =>1,
            'expiration_date' => time()+3600,
            'expiration_playtime' => 30,
            'vmcheck' => 1,
        ),
    ),
);

$result = encode_jwt($payload, JWT_KEY);

//header('Content-Type: application/jwt');
header('X-Kollus-UserKey: '.KOLLUS_KEY);
echo $result;

Code sample (v1.4 기준)

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

PHP ​sample

Code Block
languagejs
themeMidnight
<?php
/**
* PHP Version : 5.4 above
*/
function get_jwt($payload, $key, $alg = 'HS256')
{
	$header = array('alg' => $alg, 'typ' => 'JWT' );
	$unsignedToken = base64_encode(json_encode($header)).'.'.base64_encode(json_encode($payload));
	$signature = hash_hmac('sha256', $unsignedToken, $key, TRUE);
	return $unsignedToken.'.'.base64_encode($signature);
}

function print_kollus_jwt($data)
{
    define('KOLLUS_KEY', '**사용자키**'); // X-Kollus-UserKey
    define('JWT_KEY', '**보안키**'); // JWT 보안 키
    $payload = array( ‘data’ => $data );
    $result = encode_jwt($payload, JWT_KEY);
    //header('Content-Type: application/jwt');
    header('X-Kollus-UserKey: '.KOLLUS_KEY);
    echo $result;
}

/////////////////////////////////////////////////

include "./config.php";
// 주의 : kind가 1일때 자동으로 expiration_date가 생성되는 샘플 페이지입니다.
// 재생 제한 횟수
$_default_expiration_count = 3;
$_expired_duration = 60 * 60 * 24; // 1 day

// DB Connection
$_db_conn = mysqli_connect($_hostname, $_username, $_password);
if (!$_db_conn) {
	die('Could not connect: ' . mysql_error());
}

$_db_selected = mysqli_select_db($_database, $_db_conn);
if (!$_db_selected) {
	die ('Can\'t use database : ' . mysqli_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'",
mysqli_real_escape_string($_media_content_key, $_db_conn));
$_result = mysqli_query($_query, $_db_conn);

if ($_result) {
	$channel = mysqli_fetch_array($_result, MYSQL_ASSOC);
	if ($channel === FALSE) $channel = NULL;
} else {
	die('Invalid query: ' . mysqli_error());
}

$user = NULL;
$_query = sprintf("SELECT * FROM `users` WHERE `client_user_id` = '%s'",
mysqli_real_escape_string($_client_user_id, $_db_conn));
$_result = mysqli_query($_query, $_db_conn);
if ($_result) {
	$user = mysqli_fetch_array($_result, MYSQL_ASSOC);
	if ($user === FALSE) $user = NULL;
} else {
	die('Invalid query: ' . mysqli_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 = mysqli_query($_query, $_db_conn);
	if ($_result) {
		$channel_user = mysqli_fetch_array($_result, MYSQL_ASSOC);
		if ($channel_user === FALSE) $channel_user = NULL;
	} else {
		die('Invalid query: ' . mysqli_error());
	}
}

$_jwt_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 = mysqli_query($_query, $_db_conn);
		if (!$_result) {
			die('Invalid query: ' . mysqli_error());
		}
	} else {
        $_expiration_date = $channel_user['expiration_date'];
        $_expiration_count = $channel_user['$expiration_count'];
	}
    $_jwt_result['expiration_date'] = (int) $_expiration_date;
    $_jwt_result['expiration_count'] = (int) $_expiration_count;
	break;
case 2:
    if (!is_null($channel_user)){
        $_download_times = ++((int) $channel_user['download_times']);
        $_query = sprintf("UPDATE `channel_users` SET `download_times` = '%s', `updated_at` =
        UNIX_TIMESTAMP() WHERE id = %s", $_download_times, $channel_user['id']);
        $_result = mysqli_query($_query, $_db_conn);
  	    if (!$_result) {
    		die('Invalid query: ' . mysql_error());
   		}
        $_jwt_result['result'] = 1;
    }
	break;
case 3:
    if (!is_null($channel_user) && $channel_user['is_expired']) {
    	$_jwt_result['content_expired'] = 1;
    }
    break;
}

// DB Close
mysqli_close($_db_conn);
// 결과인 data array를 JWT로 변환하여 출력함
print_kollus_jwt($_jwt_result);

샘플코드

 DRM – dotnet

 DRM – jsp

 DRM – php

LMS

...

Kollus에서 제공하는 Callback 정보는 플랫폼에서 전달하는 내용과 플레이어에서 전달하는 내용으로 구분될 수 있습니다. 플레이어에서 전달하는 정보는 사용자가 컨텐츠를 이용한 정보를 활용할 수 있도록 관련 정보를 지정된 Url에 전달하는 기능입니다. 진도율을 전송할때 응답을 확인하지 않습니다. 단, 네트워크 오류인 경우 해당 데이터를 보관후 재 전송 가능할때 재 전송됩니다. 해당 기능을 사용하기 위해서는 Kollus에 접속하여 관련 정보를 설정하시면 Video-gateway를 통해 관련 내용이 전달되어 재생과 관련된 정보를 전달합니다.

Callback process

재생 정보를 전달 받는 흐름을 설명합니다.

  1. Kollus 설정에서 관련 정보 요청을 설정합니다.
    • Kollus는 컨텐츠 배포 단위인 채널 마다 다양한 옵션을 지정할 수 있습니다.
    • 배포하는 채널마다 지정된 데이터 수집이 가능합니다.
  2. 동영상 재생을 위해 Video-gateway를 호출하면 컨텐츠 재생을 위한 다양한 정보를 플레이어 전달하게 되며, 이때 재생과 관련된 정보를 전달할 설정을 함께 전달합니다.
  3. 재생 정보를 활용하기 위해 설정한 Url에 관련 정보를 전달합니다.
  4. Kollus는 컨텐츠 재생과 관련된 기본 정보를 수집하기 위해 관련 정보를 수집합니다.
    • 사용자 정보를 일체 포함되지 않습니다.
    • Mac Address, IP Address 개인의 위치 정보와 관련된 정보를 수집 되지 않습니다.

Customer Requirement

Kollus에서 전달하는 재생 관련 정보는 고객의 다양한 요청을 수렴하여 개발되었습니다.

  • 마지막 종료 시간
  • 컨텐츠 구간별 재생 정보
  • 사용자 정보
  • 컨텐츠 정보
  • PC 정보
  • 동영상 구간을 시스템에서 지정된 블럭으로 나누어 정보를 수집

Plugin option

  • {MAC}
    • Mac Address
    • 사용자 개인정보에 해당하여 수집을 권장하지 않습니다.
    • 고급 사용자의 경우 Mac Address를 임의로 변경할 수 있으며, 모바일 플레이어의 경우 App의 등록 제한으로 인해 지원하지 않습니다.
  • {IP} - RemoteAddress의 이슈로 지원하지 않습니다. (서버쪽에서 확인하도록합니다.)
    • 컨텐츠를 재생하는 사용자 PC의 IP Address
    • 사용자 개인정보에 해당하여 수집을 권장하지 않습니다.
    • 공유기를 사용하는 환경에서 수집 되는 IP Address는 Private 영역 IP Address 입니다. 정확한 사용자의 IP를 수집하기 위해서는 Callback을 받는 Web 서버에서 Remote_Address를 확인하는 것이 정확합니다.
  • {CLIENT_USER_ID}
    • 사용자의 User ID 입니다.
    • MediaToken 생성시 파라미터로 입력한 사용자의 ID 정보입니다. 이때 입력된 사용자 ID는 Kollus 시스템에서 관리되지 않고 사용자를 구분하는 Unique 정보로만 사용됩니다.
  • {START_AT}
    • Video-gateway를 호출한 시점의 Unixtimestamp 입니다.
    • 사용자의 컨텐츠 이용중 다수의 재생정보 전달이 발생할 수 있습니다. 동일한 요청에 같은 {START_AT} 값을 갖게 되며, 같은 시간에 다수의 이용자가 발생할 경우 Unixtimestamp 이기 때문에 중복될 수 있습니다.
    • 다운로드 컨텐츠의 경우 start_at은 컨텐츠 재생시 단말의 unixtimestamp 입니다.
  • {BLOCK_CNT}
    • Kollus에서 설정한 블럭의 개수입니다.
    • 재생 정보를 지정된 블럭 개수로 나누어 관리하며 정보 전달시 함께 포함시킬수 있습니다.
  • {PLAY_TIME}
    • 전체 재생 시간 (단위:초)
    • 배속 기능을 사용하는 경우 배속을 포함한 시간입니다. 시간 값은 누적입니다.
    • 10초간 2배속으로 재생한 경우 20초로 계산됩니다.
    • 모든 재생 시간을 포함한 시간입니다. (구간반복을 한 경우도 모두 포함됩니다.)
  • {PLAYTIME_PERCENT}
    • DURATION에 대한 전체 재생 비율 (단위:%, 정수, 절사)
    • 컨텐츠를 두번 반복해서 본 경우 200%로 계산됩니다.
  • {DURATION}
    • 컨텐츠 길이 (단위:초)
  • {MEDIA_CONTENT_KEY}
    • Kollus media_content_key
  • {ENCODING_PROFILE_KEY}
    • Kollus encoding profile key
  • {PLAY_BLOCK_JSON}
    • 데이터 포멧: JSON
    • 블럭 재생 정보
  • {BLOCK_PLAY_1}~{BLOCK_PLAY_##{BLOCK_CNT}}
    • 블럭 재생 여부
    • 재생하지 않고 Skip
    • 해당 블럭 재생 (0초 이상 재생하면 1로 설정됩니다.)
  • {BLOCK_TIME_1} ~{BLOCK_TIME_##{BLOCK_CNT}}
    • 해당 블럭을 재생한 시간입니다. (단위:초)
    • 플레이어의 배속기능을 이용해 재생한 경우 재생시간은 배속을 적용하여 계산됩니다.
    • 반복해서 3초의 범위를 갖는 블럭을 2회 재생한 경우 블럭의 재생시간은 6초입니다.
    • {DURATION}이 {BLOCK_CNT} 보다 작은 경우 {BLOCK_TIME#}의 합은 {DURATION}을 초과합니다. (각 블럭의 재생시간이 밀리초로 나오는 경우 올림하여 1초로 계산합니다.)
  • {LAST_PLAY_AT}
    • 마지막 재생 위치 (단위:초)
  • {HOST_NAME}
    • 비디오 링크 요청 도메인명
    • ex) catenoid.video.kr.kollus.com
  • {PLAYER_ID}
    • Kollus 플레이어의 고유 ID 입니다.
    • 플레이어 설치시 생성된 고유 ID 입니다.
    • 플래쉬 플레이어의 경우 kfp 라는 고유 문자열을 전송합니다.
  • {PLAYLIST_SKIP}
    • 플레이어 리스트로 재생되는 경우 컨텐츠 Skip을 한 경우에 사용됩니다.
    • 0 : 모두 재생
    • 1 : Skip
  • {USERVALUE0}~{USERVALUE9}
    • Video-gateway호출에 추가된 추가 정보 입니다.
    • ex) LCD={USERVALUE0}&UCD={USERVALUE4}
    • 영문,숫자 이외의 한글등의 문자열을 전달할 경우 웹 브라우저들의 차이점이 있기 때문에 해당 변수 전달시 UTF-8로 전달해야 합니다. (전달되는 문자열은 웹의 특성상 UrlEncode해서 전달해야 합니다.)
  • {JSON_DATA}
    • 데이터 포멧: JSON
    • 모든 재생 정보를 포함한 데이터

{PLAY_BLOCK_JSON}

  • {JSON_DATA}의 block_info 항목과 동일합니다.
  • block_info Object의 하위 노드를 포함합니다.

{JSON_DATA}

  • user_info

    • content_provider_key : 고객사 key
    • client_user_id : 사용자(고객) ID
    • player_id : 플레이어(player) ID
    • hardware_id : 플레이어(player) hardware ID, 고객 확인용
    • host_name : 비디오 링크 요청 도메인명
    • device : 디바이스명
  • content_info

    • duration : 컨텐츠 길이
    • encoding_profile : 인코딩 프로파일
    • media_content_key : 미디어 컨텐츠 키
    • channel_key : 채널키
    • real_playtime : 실제 전체 재생 시간 (단위:초)
      • 배속 기능을 사용하는 경우 배속을 포함한 시간입니다.
      • 10초간 2배속으로 재생한 경우 20초로 계산됩니다.
      • 모든 재생 시간을 포함한 시간입니다. (구간반복을 한 경우는 제외됩니다.)
    • playtime : 컨텐츠 재생 시간
    • playtime_percent : duration에 대한 전체 재생 비율
    • start_at : Video-gateway를 호출한 시점의 Unixtimestamp 입니다. 다운로드 컨텐츠의 경우 start_at은 컨텐츠 재생시 단말의 unixtimestamp 입니다.
    • last_play_at : 마지막 재생 위치 (단위:초)
  • block_info

    • block_count : 구간 횟수

    • blocks: 마일스톤 (재생시간 단위:초)

      • b0 : 블럭 재생여부 (0:재생하지 않음, 1:해당블럭 재생)

      • b1 : 0 ~ (int)

      • b2 : block_period 만큼 반복됩니다.

        ...

      • t0 : 블럭 재생시간 (단위:초)

      • t1 : 0 ~ (int)

      • t2 : block_period 만큼 반복됩니다.

        ...

      • p0 : 블럭 재생 비율 (단위:퍼센트%)

      • p1 : 0~ (int) , 블럭 재생을 반복하는 경우 100이상으로 표시됩니다.

      • p2 : block_period 만큼 반복됩니다.

    • sessions : 사용자 블럭 재생을 시간별로 관리하는 항목 (배열) 세션 데이터는 이전 데이터를 모두 누적으로 전송합니다.

      • block : 블럭 인덱스 (0부터 시작)
      • start_time : 해당 블럭을 시작한 시간 (unixtimestamp-localtime)
      • play_time : 해당 블럭 재생 시간
  • uservalues : 사용자 정의 변수, 각 변수의 전체 합은 1KB를 넘지 않도록 해야 합니다.

    • uservalue0
    • uservalue1
    • ....
    • uservalue9

Support options

플레이어별 지원 옵션을 확인할 수 있습니다. {MAC}, {IP}의 경우 개인정보에 해당하는 요소로 필요한 경우 별도 협의해 주십시오.

OptionFlashPlayerKollusPlayer(PC)KollusPlayer(Monlie)
{MAC}XXX
{IP}XXX
{CLIENT_USER_ID}OOO
{START_AT}OOO
{BLOCK_CNT}OOO
{PLAY_TIME}OOO
{PLAYTIME_PERCENT}OOO
{DURATION}OOO
{MEDIA_CONTENT_KEY}OOO
{ENCODING_PROFILE_KEY}OOO
{PLAY_BLOCK_JSON}OOO
{BLOCK_PLAY_1} ~OOO
{BLOCK_TIME_1} ~OOO
{LAST_PLAY_AT}OOO
{HOST_NAME}OOO
{PLAYER_ID}X(kfp)OO
{PLAYLIST_SKIP}XOO
{USERVALUE0} ~OOO
{JSON_DATA}OOO

Settings

Callback에 대한 설정은 채널에서 할 수 있습니다. Callback이 필요한 채널 마다 설정해야 합니다.

  • Callback URLs: 캐리지 리턴으로 각각 치환자를 포함한 URL을 등록합니다.
    • 재생정보를 다수의 시스템에서 전달 받을 수 있도록 캐리지리턴(\n)으로 구분된 다수의 callback_url 을 등록할 수 있습니다.
    • Kollus 플랫폼의 필요에 따라 URL 설정 수를 제한할 수 있습니다.
  • Format: [block_count]:[peroid]:[enable_sessions]:[callback_url]
    • 구분자 : (콜론)
    • block_count
      • 컨텐츠 재생 구간을 나누는 블럭의 수 입니다. 10으로 설정하면 컨텐츠의 길이가 300초의 경우 각 블럭은 30초로 구성됩니다.
    • peroid
      • 데이터 전송 주기
      • Callback이 전송되는 주기로 지정된 period(단위:초) 마다 호출되고 프로그램(플레이어)이 종료될 때 추가로 호출 됩니다. 단, 플래시 플레이어의 경우는 플레이어 종료시 호출되지 않습니다.
      • 플레이를 일시정시 또는 정지했을 때 추가로 호출 됩니다.
      • 단위 :초
    • enable_blocks
      • 1 이면 block_info 항목에 blocks 정보를 포함 시킵니다.
      • 0 이면 block_info 항목에 blocks 정보는 없습니다.
    • enable_sessions
      • 1 이면 block_info 항목에 sessions 정보를 포함 시킵니다.
      • 0 이면 block_info 항목에 sessions 정보는 없습니다.
    • callback_url
      • Callback Url 입니다. 컨텐츠를 재생하는 사용자 환경에서 전송하기 때문에 방화벽 환경을 고려하여 http, 80포트 사용을 권장합니다.

Callback URLs

Code Block
languagejs
themeMidnight
10:30:1:0:http://domain.com/check.asp?ip={IP}&id={CLIENT_USER_ID}&start={START_AT}&lms={
PLAY_BLOCK_JSON}&uservalue0={USERVALUE0}
20:180:0:1:http://another_domain.com/anohter_check.php?ip={IP}&id={CLIENT_USER_ID}&start={
START_AT}&lms={JSON_DATA}&uservalue0={USERVALUE0}

Plugin options

재생 정보를 전달하기 위한 옵션은 JSON 형태의 Array로 전달됩니다.

  • progress_plugin (array)
    • http://domain.com/check.asp?block_period=10&ip={IP}&id={CLIENT_USER_ID}&start={START_AT}&json_data={JSON_DATA}&uservalue0={USERVALUE0}
    • http://another_domain.com/anohter_check.php?block_period=20&ip={IP}&id={CLIENT_USER_ID}&start={START_AT}&lms={PLAY_BLOCK_JSON}&uservalue0={USERVALUE0}

Callback data sample

Code Block
languagejs
themeMidnight
● URL: http://lms.servicedomain.com/lms/register
● Method: POST
● Params:
    ● ID={CLIENT_USER_ID}
    ● MAC={MAC}
    ● LRN={USERVALUE0}
    ● LHF={USERVALUE1}
    ● IP={IP}
    ● LCD={USERVALUE2}
    ● TM={START_AT}
    ● PT={PLAY_TIME}
    ● ET={LAST_PLAT_AT}
    ● B1={BLOCK_PLAY_1}
    ● T1={BLOCK_TIME_1}
    ● ...
    ● SKIP={PLAYLIST_SKIP}
● http://lms.servicedomain.com/lms/register?ID=pobi&MAC=123456789ABCDEF&LRN=
123456789ABCDEF&LHF=1&IP=192.168.0.118&LCD=L123&UCD=U123&TM=12345678
9&PT=123456789&E T=123456789&SKIP=0&B1=1&B2=1&B3=1&B4=1&B5=1&B6=1&B7
=1&B8=1&B9=1&B10=1&T 1=123456789&T2=123456789&T3=123456789&T4=12345678
9&T5=123456789&T6=123456789&T7=123456789&T8=123456789&T9=123456789&T10
=123456789
        

Etc.

블럭개수 제한 (Limit the number of blocks)

  • 최대 100을 넘을 수 없습니다. (range: 1~100)
    • 100을 넘는 데이터가 입력되면 최대값 100으로 처리 됩니다.
    • 0으로 입력되는 경우 1로 처리 됩니다.
  • 모든 컨텐츠의 {DURATION}보다 작거나 같도록 {BLOCK_CNT}를 설정하는 것을 권장합니다. {DURATION}이 {BLOCK_CNT}보다 작은 경우 아래와 같이 처리됩니다.
    • {BLOCK_CNT}가 100일때 {DURATION}이 30이면 전송되는 블럭 정보는 30개로 조정됩니다.

Callback 호출 주기 (Callback period)

  • Callback은 시스템에 설정된 Callback Url 정보의 period 설정에 따라 호출됩니다.
  • 플레이어가 일시정지, 정지를 하는 경우도 Callback이 호출됩니다.
  • 주기적으로 호출되는 동일한 사용자의 정보는 {START_AT}, {CLIENT_USER_ID}값으로 구분하여 마지막 정보를 확인할 수 있습니다.
  • 플래시 플레이어의 경우는 플레이어 종료시 호출되지 않습니다.

USERVALUE0 ~ USERVALUE9 사용시 주의 할 점

  • 특수문자(영문,숫자이외의 모든문자:한글,한자,일어등)는 반드시 UTF-8문자열을 UrlEncode된 상태로 전달되어야 합니다.

crossdomain.xml

  • Flash Player 사용시 callback을 받을 서버(고객사)에는 crossdomain.xml 파일이 있어야 합니다.

    Code Block
    languagejs
    themeMidnight
    <?xml version="1.0"?>
    <!DOCTYPE cross-domain-policy SYSTEM
    "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
    <cross-domain-policy>
        <site-control permitted-cross-domain-policies="master-only" />
        <allow-access-from domain="*" to-ports="*" />
        <allow-http-request-headers-from domain="*" headers="*" to-ports="*" />
    </cross-domain-policy>


데이터 보안

  • LMS callback 데이터를 변조 방지를 위해 POST로 전달되는 모든 정보에 대해 Hash 를 생성하여 전달되는 Hash값과 일치하는 지 확인합니다.

    ※ Hash 생성방식에 대해 노출 우려가 있는 Flash Player, HTML5 Single Player는 제외합니다.

  • Hash 생성 규칙은 아래와 같습니다.

    Code Block
    languagejs
    themeMidnight
    hash_1 = md5 ( post-data ) 
    hash_2 = md5 ( hash_1 + service_account ) ← + 문자 포함 
    hash_2값을 post data의 hash 파라메터의 값으로 전송합니다.


  • 전송되는 Post 데이터 예시

    Code Block
    languagejs
    themeMidnight
    ID=pobi&MAC=123456789ABCDEF&LRN=123456789ABCDEF&LHF=1&IP=192.16 8.0.118&LCD=L123&UCD=U123&TM=123456789&PT=123456789&ET=123456789 &SKIP=0&B1=1&B2=1&B3=1&B4=1&B5=1&B6=1&B7=1&B8=1&B9=1&B10=1&T1= 123456789&T2=123456789&T3=123456789&T4=123456789&T5=123456789&T6=1 23456789&T7=123456789&T8=123456789&T9=123456789&T10=123456789&hash =7dec341ff384574f24c6c441b46bc9b1