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을 등록하셔야 합니다.
Play 콜백이 정의되지 않은 채널은 콜백의 응답과 관계없이 재생을 진행합니다. 콜백이 정의된 채널을 통해 서비스되는 콘텐츠는 콜백에 대한 응답을 확인 후 재생하기 때문에 고객사에서 정의한 콜백 URL은 항상 응답상태를 유지하셔야 원활한 서비스를 받으실 수 있습니다.
주의:
- 고객사의 회원 아이디를 포함한 미디어 토큰(Media token)을 생성하여 요청된 경우에 Play 콜백이 호출됩니다. (미디어 토큰 생성은 별도 문서를 참고해 주십시오.)
- Play 콜백 URL이 응답하지 않으면 재생 되지 않습니다.
- Play 콜백은 다운로드된 콘텐츠에 대한 DRM 콜백과 다르게 동작합니다. 다운로드된 콘텐츠는 Play 콜백이 아닌 DRM 콜백으로 동작하게 됩니다. 필요에 따라 Play 콜백과 DRM 콜백 URL을 동일하게 등록하면 다운로드와 스트리밍시에 재생에 대한 응답을 동일하게 받으실 수 있습니다.
Callback flow
채널에 Play 콜백 URL을 설정합니다.
- ex> http://www.foo.com/auth.php 가 고객사 Play 콜백 서버인 경우
Media token을 생성하여 다운로드를 요청합니다.
- Kollus crypt SDK를 이용해 Media token을 생성합니다.
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는 모두 다르게 생성됩니다.
고객사 Play 콜백 서버는 전달 받은 위 정보를 바탕으로 다음의 json 포멧의 data를 아래의 방식 중에서 하나로 Http Body에 전송합니다.
(고객사가 인증 정보를 플레이어로 전달할 때 모든 데이터의 자료형은 반드시 기술된대로 integer 형이여야만 합니다.)
- 지원하는 방식
- Kollus crypt SDK를 이용해 암호화하여 전송합니다.
- JWT Encode하여 전송합니다. 알고리즘은 HS256만 지원하며 secret키는 콜백 요청 시 넘겨주는 custom_key파라미터 값을 사용합니다.
- 지원하는 방식
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) |
- 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) result | 0 (비정상), 1 (정상) | |
(string) message | 0 (비정상)의 경우 message를 추가하면 상황에 따른 메시지가 표시됩니다. | |
(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보다 크면 해당 값의 초만큼만 재생 후 종료합니다. | |
exp | (int) | 사용 가능 시간 unixtime stamp(옵션) |
Example
{ “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 |
---|---|
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 | 0 (비정상), 1 (정상) 0 인 경우 재생되지 않습니다. 이때 conent_expired가 1이어도 expire가 수행되지 않습니다. | |
(string) message | 0 (비정상)의 경우나 content_expired이 1(재생 제한)의 경우 message를 추가하면 상황에 따른 메시지가 표시됩니다. | |
exp | (int) expiration_date | 사용 가능 시간 unixtime stamp(옵션) 최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999) |
Example
{ “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
{ “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
{ “data” : { "content_expired": 1, "result": 1 }, "exp" : 1477558242 }
Code sample
다음과 같은 고객사의 DB가 구성된 것으로 고려되어 샘플이 구성되어있습니다.
PHP sample
<?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
<%@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-jsp
https://github.com/kollus-service/kollus-drm-callback-php
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)을 설정해야 합니다.
채널에 DRM 콜백 URL을 설정하면 컨텐츠를 다운로드하는 시점에 채널에 설정된 DRM 콜백 URL을 호출하여 반환된 값을 DRM 정책으로 사용하게 됩니다. 이때 다운로드되는 DRM 정책 정보는 JWT Encode 되어 Http Body에 반환 되어야 합니다.
주의:
- DRM 콜백 URL이 응답하지 않으면 다운로드가 되지 않습니다.
- 알고리즘은 HS256만 지원을 하며 Http 헤더에 지정된 헤더(X-KOLLUS-USERKEY)의 값으로 “사용자키"를 함께 전송해야 합니다.
Callback flow
채널에 DRM 콜백 URL을 설정합니다.
- ex> http://www.foo.com/auth.php 가 고객사 인증 DRM 서버인 경우
JSON 데이터를 생성 후 JWT로 인코딩 한다.
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는 모두 다르게 생성됩니다.
- session_key : 플레이어에서 생성한 요청 확인용 세션키
고객사 DRM 인증서버는 전달받은 위 정보를 바탕으로 다음의 json 포멧의 data를 JWT의 payload 에 추가하여 Encoding 하고 헤더에 지정된 “시용자키(X-KOLLUS-USERKEY)"를 함께 전송합니다.
(고객사가 인증 정보를 플레이어로 전달할 때 모든 데이터의 자료형은 반드시 기술된대로 integer 형이여야만 합니다.)
Response JSON spec.
Json Tag | Description |
---|---|
expiration_date | unixtime stamp (만료될 시간의 unixtime stamp) 최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999) |
expiration_count | 재생 제한 횟수 |
expiration_playtime | 재생시간 제한 |
result | 반환 결과가 정상인 경우 1, 비정상인 경우 0을 반환하도록 합니다. |
content_expired | DRM 콘텐츠를 강제로 expire 시킵니다. |
content_delete | DRM 콘텐츠를 강제 삭제 합니다. |
content_expire_reset | expire 콘텐츠를 복구합니다. |
session_key | * v1.6 이후 Callback v2에서 적용됩니다. kind3의 요청으로 content_expire_reset 작업시 Request에 포함된 session_key를 Response에 포함시켜야 합니다. |
media_content_key | Kollus 컨텐츠 Unique Key |
kind | 요청에 대한 구분 |
device_name 추가 설명
Andoid
안드로이드 어플 개발시 사용되는 Build.DEVICE, Build.MODEL을 /(슬래쉬)로 구분한 문자열로 만들어 사용합니다.
- Build.DEVICE+”/”+Build.MODEL
- 단말기의 특성에 따라 해당 정보는 NULL로 표시될 수 있습니다.
iOS
iOS의 경우 iOS에서 제공하는 device-name을 사용합니다.
Device Type | Product Name |
---|---|
iPhone1,1 | iPhone |
iPhone1,2 | iPhone 3G |
iPhone2,1 | iPhone 3GS |
iPhone3,1 | iPhone 4 (GSM) |
iPhone3,3 | iPhone 4 (CDMA) |
iPhone4,1 | iPhone 4S |
iPhone5,1 | iPhone 5 (A1428) |
iPhone5,2 | iPhone 5 (A1429) |
iPhone5,3 | iPhone 5c (A1456/A1532) |
iPhone5,4 | iPhone 5c (A1507/A1516/A1529) |
iPhone6,1 | iPhone 5s (A1433/A1453) |
iPhone6,2 | iPhone 5s (A1457/A1518/A1530) |
iPhone7,1 | iPhone 6 Plus |
iPhone7,2 | iPhone 6 |
iPhone8,1 | iPhone 6s |
iPhone8,2 | iPhone 6s Plus |
iPhone8,4 | iPhone SE |
iPhone9,1 | iPhone 7 (A1660/A1779/A1780) |
iPhone9,2 | iPhone 7 Plus (A1661/A1785/A1786) |
iPhone9,3 | iPhone 7 (A1778) |
iPhone9,4 | iPhone 7 Plus (A1784) |
iPhone10,1 | iPhone 8 (A1863/A1906) |
iPhone10,2 | iPhone 8 Plus (A1864/A1898) |
iPhone10,3 | iPhone X (A1865/A1902) |
iPhone10,4 | iPhone 8 (A1905) |
iPhone10,5 | iPhone 8 Plus (A1897) |
iPhone10,6 | iPhone X (A1901) |
iPad1,1 | iPad |
iPad2,1 | iPad 2 (Wi-Fi) |
iPad2,2 | iPad 2 (GSM) |
iPad2,3 | iPad 2 (CDMA) |
iPad2,4 | iPad 2 (Wi-Fi, revised) |
iPad2,5 | iPad mini (Wi-Fi) |
iPad2,6 | iPad mini (A1454) |
iPad2,7 | iPad mini (A1455) |
iPad3,1 | iPad (3rd gen, Wi-Fi) |
iPad3,2 | iPad (3rd gen, Wi-Fi+LTE Verizon) |
iPad3,3 | iPad (3rd gen, Wi-Fi+LTE AT&T) |
iPad3,4 | iPad (4th gen, Wi-Fi) |
iPad3,5 | iPad (4th gen, A1459) |
iPad3,6 | iPad (4th gen, A1460) |
iPad4,1 | iPad Air (Wi-Fi) |
iPad4,2 | iPad Air (Wi-Fi+LTE) |
iPad4,3 | iPad Air (Rev) |
iPad4,4 | iPad mini 2 (Wi-Fi) |
iPad4,5 | iPad mini 2 (Wi-Fi+LTE) |
iPad4,6 | iPad mini 2 (Rev) |
iPad4,7 | iPad mini 3 (Wi-Fi) |
iPad4,8 | iPad mini 3 (A1600) |
iPad4,9 | iPad mini 3 (A1601) |
iPad5,1 | iPad mini 4 (Wi-Fi) |
iPad5,2 | iPad mini 4 (Wi-Fi+LTE) |
iPad5,3 | iPad Air 2 (Wi-Fi) |
iPad5,4 | iPad Air 2 (Wi-Fi+LTE) |
iPad6,3 | iPad Pro (9.7 inch) (Wi-Fi) |
iPad6,4 | iPad Pro (9.7 inch) (Wi-Fi+LTE) |
iPad6,7 | iPad Pro (12.9 inch, Wi-Fi) |
iPad6,8 | iPad Pro (12.9 inch, Wi-Fi+LTE) |
iPad6,11 | iPad 9.7-Inch 5th Gen (Wi-Fi Only) |
iPad6,12 | iPad 9.7-Inch 5th Gen (Wi-Fi/Cellular) |
iPad7,1 | iPad Pro (12.9 inch, A1670) |
iPad7,2 | iPad Pro (12.9 inch, A18219) |
iPad7,3 | iPad Pro (10.5 inch, A1701) |
iPad7,4 | iPad Pro (10.5 inch, A1709) |
iPad7,5 | iPad (6th gen, A1893) |
iPad7,6 | iPad (6th gen, A1954) |
iPod1,1 | iPod touch |
iPod2,1 | iPod touch (2nd gen) |
iPod3,1 | iPod touch (3rd gen) |
iPod4,1 | iPod touch (4th gen) |
iPod5,1 | iPod touch (5th gen) |
iPod7,1 | iPod touch (6th gen) |
Callback kind
DRM callback이 호출되는 상황은 아래 3가지 경우입니다.
DRM 컨텐츠의 Expire 정보를 요청하는 경우 (kind:1)
Request
구분 | Description |
---|---|
POST | Http POST로 요청합니다. (parameter가 아닙니다.) |
kind | 1 |
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) |
- 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) result | 0 (비정상), 1 (정상) 0 인 경우 다운로드 되지 않습니다. 0 인 경우 재요청되지 않습니다. | |
(string) message | 0 (비정상)의 경우 message를 추가하면 상황에 따른 메시지가 표시됩니다. | |
(int) expiration_refresh_popup | 만료후 갱신 여부 팝업 표시 0 인 경우 표시하지 않음 (기본값) 1 인 경우 DRM 만료후 갱신이 필요할때 사용자 확인을 받는 팝업을 표시합니다. | |
(int) disable_tvout | 0 (tvout 차단 안함), 1 (tvout 차단) 이 항목이 없으면 채널에 있는 disable_tvout정책이 적용됩니다. |
Example
{ “data” : { "expiration_date": 1402444800, "expiration_count": 10, "result": 1 } }
DRM 컨텐츠의 Download가 100% 완료된 경우 (kind:2)
주의) 반드시 응답해야 하며, Block 상태로 통신합니다.
Request
구분 | Description |
---|---|
POST | Http POST로 요청합니다. (parameter가 아닙니다.) |
kind | 2 |
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
카테고리 | 구분 | Descriptsion |
---|---|---|
data | (int) expiration_date | 만료될 시간의 unixtime stamp 해당 항목이 있으면 kind1의 값을 대체합니다. 최대값 : 2029년 12월 31일 23시 59분 59초 (1893455999) |
(int) content_delete | 0 (삭제하지 않음), 1 (다운로드 받은 파일 삭제) 다운로드된 컨텐츠를 요청에 의해 삭제하는 옵션입니다. | |
(int) result | 0 (비정상), 1 (정상) 0 인 경우 추가 작업은 없습니다. 0 인경우 추가 옵션은 무시됩니다. 0 인 경우 재요청되지 않습니다. | |
(string) message | 0 (비정상)의 경우나 content_delete이 1(다운로드 받은 파일 삭제) 시 message를 추가하면 상황에 따른 메시지가 표시됩니다. |
Example
{ “data” : { "content_delete": 1, "result": 1 } }
DRM 컨텐츠를 재생하는 경우 (kind:3)
주의) v1.6 이후 재생시 네트워크 통신이 가능한 경우 전송되며 요청 실패시 네트워크 통신이 가능할 때 재 전송 됩니다.
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 |
start_at | unixtimestamp (localtime) - 전송 요청 시간 |
uservalues | JSON format (VideoGateway 호출시 사용된 uservalue0~9) |
Response
카테고리 | 구분 | Description |
---|---|---|
data | (int) content_expired | 0 (재생가능), 1 (재생 제한) 다운로드 컨텐츠를 강제로 expire 시킵니다. 필요시 content_expire_reset 옵션으로 다시 복구 할 수 있습니다. * expired 컨텐츠는 0(재생가능)으로 응답해도 재생되지 않습니다. |
(int) result | 0 (비정상), 1 (정상) 0 인 경우 재생되지 않습니다. 0 인 경우 추가 옵션은 무시됩니다. 0 인 경우 재요청되지 않습니다. | |
(string) message | 0 (비정상)의 경우나 content_expired이 1(재생 제한) 시 message를 추가하면 상황에 따른 메시지가 표시됩니다. |
Example
{ “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
{ “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
{ “data” : { "result": 1 } }
DRM Callback 신규 버전 v2
이전 1.4까지 제공되던 kind1, kind2, kind3의 호출이 한번의 호출로 통합되어 호출되는 버전으로 변경됩니다. 이전 버전은 사용자의 사용자의 빈번한 호출에 대응하기 용이하지 않다는 다수 고객사의 요청에 따라 추가 되었습니다. 편의상 새로운 버전을 v2로 이전버전을 v1으로 합니다.
Reuest
구분 | Description |
---|---|
POST | Http POST로 요청합니다. (parameter가 아닙니다.) |
items | JsonArray로 구성된 string 입니다. |
items 항목은 kind1, kind2, kind3의 데이터를 모두 포함한 호출이 될 수 있습니다.
items (JsonArray)
kind1, kind2
구분 | Description |
---|---|
kind | 1,2 |
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) |
kind3
구분 | Description |
---|---|
kind | 3 |
session_key | content_expire_reset 요청시 동일한 session_key를 확인합니다. |
client_user_id | 고객사 사용자 ID, media_token 생성시 사용된 client_user_id와 동일합니다. |
player_id | 고객사 사용자가 가지고 있는 단말의 아이디 |
hardware_id | 단말의 hardware 아이디(PC, 입력값이 있으면) |
device_name | 고객사 사용자가 가지고 있는 단말의 모델명 |
media_content_key | Kollus 컨텐츠 unique key |
start_at | unixtimestamp (localtime) - 전송 요청 시간 |
uservalues | JSON format (VideoGateway 호출시 사용된 uservalue0~9) |
content_expired | 만료된 컨텐츠 확인 flag( 1 : 만료, 0 : 재생가능) |
reset_req | 일괄갱신 요청인지 판단( 0 (default), 1 : 일괄갱신) |
Items Sample
[ { "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) kind | O | 1 |
(string) media_content_key | O | Kollus 컨텐츠 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) result | O | 0 (비정상), 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) kind | O | 2 |
(string) media_content_key | O | Kollus 컨텐츠 Unique Key |
(int) content_delete | 0 (삭제하지 않음), 1 (다운로드 받은 파일 삭제) 다운로드된 컨텐츠를 요청에 의해 삭제하는 옵션입니다. | |
(string) message | 0 (비정상)의 경우나 content_delete이 1(다운로드 받은 파일 삭제)시 message를 추가하면 상황에 따른 메시지가 표시됩니다. | |
(int) result | O | 0 (비정상), 1 (정상) 0 인 경우 추가 작업은 없습니다. 0 인 경우 추가 옵션은 무시됩니다. 0 인 경우 재 요청되지 않습니다. |
kind3
구분 | 필수 | Description |
---|---|---|
(int) kind | O | 3 |
(string) session_key | content_expire_reset 요청시 session_key 확인합니다. | |
(string) media_content_key | O | Kollus 컨텐츠 Unique Key |
(int) start_at | O | Request에 포함된 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) result | O | 0 (비정상), 1 (정상) 0 인 경우 재생되지 않습니다. 0 인 경우 추가 옵션은 무시됩니다. 0 인 경우 재 요청되지 않습니다. |
(string) message | 0 (비정상), content_expired이 1(재생 제한) 또는 content_delete이 1(다운로드 받은 파일 삭제) 시 message를 추가하면 상황에 따른 메시지가 표시됩니다. | |
(int) check_abuse | DRM kind3 항상 물어보기(0 : 안함(기본값), 1: 체크) |
Response Example
{ “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으로 변경하여 반환하도록 추가 되었습니다.
플레이어에 JWT Token으로 반환하는 경우에 지정된 헤더에 사용자키를 포함 시켜 전송해야 합니다.
HTTP/1.1 200 OK Date: Fri, 14 Oct 2016 04:12:46 GMT Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Connection: keep-alive X-Kollus-UserKey: 0993d76eb424a72f2005b874ac49405d44a6c Content-Encoding: gzip
지정된(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를 이용하여 사용자키를 함께 전송해주셔야 합니다.
(예시) php
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
<?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);
샘플코드
LMS
Kollus에서 제공하는 Callback 정보는 플랫폼에서 전달하는 내용과 플레이어에서 전달하는 내용으로 구분될 수 있습니다. 플레이어에서 전달하는 정보는 사용자가 컨텐츠를 이용한 정보를 활용할 수 있도록 관련 정보를 지정된 Url에 전달하는 기능입니다. 진도율을 전송할때 응답을 확인하지 않습니다. 단, 네트워크 오류인 경우 해당 데이터를 보관후 재 전송 가능할때 재 전송됩니다. 해당 기능을 사용하기 위해서는 Kollus에 접속하여 관련 정보를 설정하시면 Video-gateway를 통해 관련 내용이 전달되어 재생과 관련된 정보를 전달합니다.
Callback process
재생 정보를 전달 받는 흐름을 설명합니다.
- Kollus 설정에서 관련 정보 요청을 설정합니다.
- Kollus는 컨텐츠 배포 단위인 채널 마다 다양한 옵션을 지정할 수 있습니다.
- 배포하는 채널마다 지정된 데이터 수집이 가능합니다.
- 동영상 재생을 위해 Video-gateway를 호출하면 컨텐츠 재생을 위한 다양한 정보를 플레이어 전달하게 되며, 이때 재생과 관련된 정보를 전달할 설정을 함께 전달합니다.
- 재생 정보를 활용하기 위해 설정한 Url에 관련 정보를 전달합니다.
- 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}의 경우 개인정보에 해당하는 요소로 필요한 경우 별도 협의해 주십시오.
Option | FlashPlayer | KollusPlayer(PC) | KollusPlayer(Monlie) |
---|---|---|---|
{MAC} | X | X | X |
{IP} | X | X | X |
{CLIENT_USER_ID} | O | O | O |
{START_AT} | O | O | O |
{BLOCK_CNT} | O | O | O |
{PLAY_TIME} | O | O | O |
{PLAYTIME_PERCENT} | O | O | O |
{DURATION} | O | O | O |
{MEDIA_CONTENT_KEY} | O | O | O |
{ENCODING_PROFILE_KEY} | O | O | O |
{PLAY_BLOCK_JSON} | O | O | O |
{BLOCK_PLAY_1} ~ | O | O | O |
{BLOCK_TIME_1} ~ | O | O | O |
{LAST_PLAY_AT} | O | O | O |
{HOST_NAME} | O | O | O |
{PLAYER_ID} | X(kfp) | O | O |
{PLAYLIST_SKIP} | X | O | O |
{USERVALUE0} ~ | O | O | O |
{JSON_DATA} | O | O | O |
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
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
● 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 파일이 있어야 합니다.
<?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 생성 규칙은 아래와 같습니다.
hash_1 = md5 ( post-data ) hash_2 = md5 ( hash_1 + service_account ) ← + 문자 포함 hash_2값을 post data의 hash 파라메터의 값으로 전송합니다.
전송되는 Post 데이터 예시
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