Versions Compared

Key

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

概要

Kollus 전용플레이어에서 재생을 할때 고객사에서 정의한 URL을 호출Security Playerで再生する際に顧客側で指定したURLを呼出す(Callback)하는 기능을 정의한 문서입니다.機能を説明します。Agentインストール型及びモバイルPlayerアプリ, Player SDKの使用が前提になります。

Expire option

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

設定項目のdata-typeや値が範囲から外れた場合、エンドユーザーのコンテンツの利用に問題が発生する可能性があります。また、誤った設定値による使用回数の過剰などを回収する方法はありませんので設定に注意してください。

  • Expire date : 컨텐츠 만료 시간再生有効期限
    • data-type : integer, unixtime stamp
    • 컨텐츠 재생이 만료될 시간

      컨텐츠 재생이 만료될 시간

      コンテンツの有効期限(再生可能期限)
      • 終了日(日時)ex) 2014. 3. 3. 5시 45분 30초   5時 45分 30秒 GMT → 1393825531
      • 0 : unlimited (무제한無制限)최대값
      • : 2029년 12월 31일 23시 59분 59초 最大値 : 2029年 12月 31日 23時 59分 59秒 (1893455999)

Play callback

Play callback(이하 콜백)을 사용하기 위해서는 CMS의 관리 화면에서 관리자 이상의 권한을 소유한 로그인 계정으로 채널 속성에 Play 콜백 항목에 고객사에서 콜백을 응답받기 위해 정의된 URL을 등록하셔야 합니다.

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

주의:

  1. 고객사의 회원 아이디를 포함한 미디어 토큰(Media token)을 생성하여 요청된 경우에 Play 콜백이 호출됩니다. (미디어 토큰 생성은 별도 문서를 참고해 주십시오.)
  2. Play 콜백 URL이 응답하지 않으면 재생 되지 않습니다.
  3. Play 콜백은 다운로드된 콘텐츠에 대한 DRM 콜백과 다르게 동작합니다. 다운로드된 콘텐츠는 Play 콜백이 아닌 DRM 콜백으로 동작하게 됩니다. 필요에 따라 Play 콜백과 DRM 콜백 URL을 동일하게 등록하면 다운로드와 스트리밍시에 재생에 대한 응답을 동일하게 받으실 수 있습니다.

Callback flow

Image Removed

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

callbackを使用するにはチャンネル編集ページの運用ポリシー、Play Callback項目にCallbackを受け取るURLを事前に登録する必要があります。

チャンネルにPlay Callbackを指定するとこのチャンネルから再生される全てのコンテンツはCallbackに対したレスポンスが確認されてから再生されるため、Callback URLは常にレスポンスができる状態を維持する必要があります。

注意:

  1. 顧客側のユーザID(サービスに登録された会員が特定できる情報)を含むメディアトークン(Media token)を生成してリクエストするとPlay Callbackが呼出されます。(メディアトークンの生成は別途文書を参考にしてください。)
  2. Play Callback URLからレスポンスがないと再生されません。
  3. Play Callbackはダウンロードされたコンテンツ(DRM Callback)とは動作が異なります。ダウンロードされたコンテンツはPlay Callbackではなく、DRM Callbackが適用されます。必要に応じてPlay CallbackとDRM Callbackに同一なURLを指定する場合、ストリーミングとダウンロードに対してのレスポンスを同時に受け取ることができます。

Callback flow

Image Added

  1. 配信チャンネルにPlay CallbackのURL設定します。Kollus mobile player가
  2. Media token을 생성하여 다운로드를 요청합니다.

    • Kollus crypt SDK를 이용해 Media token을 생성합니다.
    •  を顧客のPlay Callback サーバーとする
  3. Media tokenを生成して再生(ダウンロード)をリクエストします。
    • Kollus crypt SDKを使ってMedia tokenを生成します。
  4. Kollus Security playerがhttp://www.foo.com/auth.php 에 다음의 정보를 POST 전송 합니다. に以下の情報をPOST転送します。
    • kind : 1, 3
    • client_user_id : 고객사 회원 아이디ユーザID(サービス会員情報)
      • Media token 생성시 포함된 아이디입니다.生成の際に含まれたID
    • player_id : 고객사 회원이 가지고 있는 단말 아이디ユーザのデバイス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파라미터 값을 사용합니다.再生するコンテンツキー
      • チャンネルに登録されたコンテンツのメディアコンテンツキー(ユニーク)
      • 同じコンテンツを複数のチャンネルに登録する場合、それぞれのmedia_content_keyは全て異なります。
    1. 顧客のPlay Callbackサーバーは転送された上記の情報に基づいて以下のjson フォーマットのdataを次の方式に合わせてHttp Bodyに転送します。(顧客が認証データをPlayerに転送する全てのデータは必ずinteger型で転送しなければなりません。)
      • 対応方式
        • Kollus crypt SDKで暗号化して転送
        • JWT Encodeして転送、アルゴリズムはHS256のみ対応しており、jsonフォーマットのdataをJWTのpayloadに追加してEncodingします。ヘッダーに指定された *ユーザーキー(X-KOLLUs-USERKEY)"を共に転送します。secret keyはCallbackリクエストの際に転送するcustom_keyパラメータ値を使用します。

Response JSON spec.

Json TagDescription
expiration_dateunixtime stamp (만료될 시간의 unixtime 有効期限終了日のunixtime stamp)
최대값 : 2029년 12월 31일 23시 59분 59초 最大値 : 2029年 12月 31日 23時 59分 59秒 (1893455999)
result반환 결과가 정상인 경우 1, 비정상인 경우 0을 반환하도록 합니다.結果が正常の場合は1、異常の場合は0をリターンする。
content_expiredDRM 컨텐츠를 강제로 expire 시킵니다.コンテンツを強制的にexpireします。

Callback Kind

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

콘텐츠의 Expire 정보를 요청하는 경우

Callbackが呼出される状況は以下の三つのケースになります。

コンテンツのExpire情報をリクエストする場合 (kind:1)

Request
구분区分Description
POSTHttp POST로 요청합니다. (parameter가 아닙니다.POSTでリクエスト (parameterではない)
kind1
client_user_id고객사 사용자 IDユーザーID, media_token 생성시 사용된 client生成に使用されたclient_user_id와 동일합니다.idと同一です。
player_id고객사 사용자가 가지고 있는 단말의 아이디ユーザーのデバイスID
hardware_id단말의 hardware 아이디デバイスのhardware ID (PC, 입력값이 있으면入力内容がある場合)
device_name고객사 사용자가 가지고 있는 단말의 모델명ユーザーデバイスのモデル名
media_content_keyKollus 컨텐츠 unique key再生するコンテンツのメディアコンテンツキー
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9VideoGatewayの呼出に使用されたuservalue0~9)
  • uservalues sample
    • uservalues={"uservalue0":"강의코드01商品種類コード01","uservalue1":"상품코드02商品名コード02","uservalue9":" 생성코드03生成コード03"}
    • VideoGateway(v.krjp.kollus.com)호출시 사용된 uservalue0~9 정보를 함께 전달 받습니다.の呼出に使用されたuservalue0~9 情報が一緒にリターンされます。
Response
카테고리カテゴリ구분区分Description
Data(int) expiration_date만료될 시간의 unixtime 有効期限終了日のunixtime stamp
최대값 : 2029년 12월 31일 23시 59분 59초 最大値 : 2029年 12月 31日 23時 59分 59秒 (1893455999)

(int) result0 (비정상エラー), 1 (정상正常)

(string) messageresult == 0 (비정상)의 경우 message를 추가하면 지정 한 메시지가 표출됩니다.
PC 플레이의 경우 재생 URL에 loadcheck=0 파라미터를 추가 해 주셔야 지정 한 메시지가 표출됩니다.エラー)の場合、messageを追加すると状況に合うメッセージが表示されます。
  • PCで再生する場合、再生URLにloadcheck=0 パラメータを追加する必要があります。
    EX. http://v.krjp.kollus.com/{미디어 컨텐츠 키メディアコンテンツキー}?loadcheck=0

(int) vmcheck0 (사용안함使用しない), 1 (사용함使用する, default) virtural machine 체크 여부, PCvirtual machineの確認有無、PC(v3)용에서만 사용 가능のみ使用可能

(array)
play_section{
start_time,
end_time
}
미리 보기 구간 초로 구분プレビュー区間、秒単位で区分(end_time이 start_time 보다 커야 한다timeをstart_timeより大きく指定)

(int) disable_tvout0 (tvout 차단 안함遮断なし), 1 (tvout 차단) 이 항목이 없으면 채널에 있는 disable_tvout정책이 적용됩니다.遮断) ここで指定しなかった場合、チャンネルポリシーのdisable_tvoutポリシーが適用されます。

(int)
expiration_playtime
이 항목이 없거나 0이면 재생 시간을 사용하지 않고 0보다 크면 해당 값의 초만큼만 재생 후 종료합니다.空白または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 콜백에 대한 응답을 확인 후에 재생을 시작합니다.注意) Play Callbackに対したレスポンスが確認されてから再生が始まります。レスポンスがなければ再生できません。

Request
구분区分Description
POSTHttp POST로 요청합니다. (parameter가 아닙니다.POSTでリクエスト (parameterではない)
kind3
client_user_id고객사 사용자 IDユーザーID, media_token 생성시 사용된 client生成に使用されたclient_user_id와 동일합니다.idと同一です。
player_id고객사 사용자가 가지고 있는 단말의 아이디ユーザーのデバイスID
device_name고객사 사용자가 가지고 있는 단말의 모델명ユーザーデバイスのモデル名
media_content_keyKollus 컨텐츠 unique key再生するコンテンツのメディアコンテンツキー
uservaluesJSON format (VideoGateway 호출시 사용된 uservalue0~9VideoGatewayの呼出に使用されたuservalue0~9)
Response
카테고리カテゴリ구분区分Description
data(int) content_expired0 (재생가능再生可能), 1 (재생 제한再生不可)
재생을 차단합니다. DRM 콜백과 동일한 스펙 유지를 위해 동일한 항목으로 유지됩니다.再生を遮断します。DRM Callbackと同一な仕様を維持するため同一項目で管理されます。

(int) result0 (비정상エラー), 1 (정상正常)
0 인 경우 재생되지 않습니다. 이때 conent_expired가 1이어도 expire가 수행되지 않습니다.0の場合再生されません。たとえconent_expiredが1になっていてもexpireが適用されません。

(string) messageresult == 0 (비정상エラー)의 경우나 content_expired이 1(재생 제한)의 경우 message를 추가하면 지정 한 메시지가 표출됩니다.
PC 플레이의 경우 재생 URL에 loadcheck=0 파라미터를 추가 해 주셔야 지정 한 메시지가 표출됩니다.の場合、またはcontent_expiredが1(再生不可)の場合にmessageを追加すると内容に合わせてメッセージが表示されます。
  • PCで再生する場合、再生URLにloadcheck=0 パラメータを追加する必要があります。
    EX. http://v.krjp.kollus.com/{미디어 컨텐츠 키メディアコンテンツキー}?loadcheck=0
exp(int) expiration_date사용 가능 시간 使用可能期限 unixtime stamp(옵션オプション)
최대값 : 2029년 12월 31일 23시 59분 59초 最大値 : 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일 자정 종료コンテンツ有効期限 : 2014年 6月 10日 24:00まで
    • 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입니다. から1402444800値を変更することができます。※UTC基準(GMTではない)
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商品種類コード01","uservalue1":"상품코드02商品名コード02","uservalue9":" 생성코드03生成コード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商品種類コード01","uservalue1":"상품코드02商品名コード02","uservalue9":" 생성코드03生成コード03"}
response
Code Block
languagejs
themeMidnight
{
    “data” : {
        "content_expired": 1,
        "result": 1
    },
    "exp" : 1477558242
}

Code sample

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

以下のように顧客のDBが構成されていると想定したサンプルコードになります。

Image Added

PHP sample
Code Block
languagejs
themeMidnight
<?php
    /**
    * PHP Version : 5.4 above
    * by yupmin
    */
    include "./config.php";
    
    // 주의注意 : kind가 1일때 자동으로 expiration_date가 생성되는 샘플 페이지입니다. 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를 통해 암호화시킴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로nullで初期化
초기화 한다.     PreparedStatement pstmt = null;
    ResultSet rs = null;
    JSONObject jsonobj = new JSONObject();
	try {
        String url = "jdbc:mysql://localcost:3306/kollus_base";
        String id = "test"; // 사용자ユーザアカウントID
계정         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을 미리 컴파일한다.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