StarPlayerFramework

목적

StarPlayerFramework와 Sample App는 StarPlayerPlus App기반으로 제작되었으며 StarPlayer+의 기능을 Framework 형태로 사용할 수 있도록 지원합니다.

요구사항

  • iOS(iPhone, iPad)버전 10.x 이상
  • [x86_64, i386, arm_v7, arm64] 아키텍처를 지원하며 시뮬레이터 사용시 i386은 원활한 작동이 안될 수 있으니 x86_64 또는 arm64 사용을 권장합니다.
  • StarPlayerFramework는 라이센스를 발급 받아야 사용할 수 있습니다. 라이센스는 (주)액시스소프트에 문의하여 발급을 받아 주시기 바랍니다.

빌드셋팅

  • StarPlayerFramework는 Bitcode를 지원하지 않기 때문에 프로젝트>Build Setting에서 ‘Enable Bitcode'의 값을 'No'로 설정해 주세요. bitcode_setting
  • ScmsUrl 또는 EventUrl의 프로토콜이 http형식이면 원활한 서버 통신을 위해 프로젝트>info.plist에 'App Transport Security Settings’ 항목을 추가해줘야 합니다. (StarPlayerFramework 내부에서 Scms 연결 및 학습이력(event)전송을 처리하고 있습니다.) http_setting
  • SampleStarPlayer 프로젝트와 같이 첨부된 StarPlayer.framework 또는 StarPlayer.xcframework를 프로젝트에 추가해 줍니다. framework_setting

라이센스 인증

플레이어를 사용하기 위해서는 라이센스 인증이 반드시 필요합니다.

  • 전역 함수를 통해 StarPlayerView 객체를 생성하지 않고도 라이센스 인증을 선행할 수 있습니다.
/**
 * 라이센스 인증 요청 (서버)
 * @note
 * 라이센스 인증 완료후 플레이어의 온/오프라인 재생 가능
 * 라이센스 인증을 선행하지 않으면 플레이어 재생을 할 수 없음
 * @param license 라이센스
 * @param completion 결과 콜백, 실패시 StarPlayerError return
 */
+ (void)authTheLicenseAtServer:(NSString *)license completion:(void(^)(BOOL isSuccess, StarPlayerError* error))completion;
//라이센스 인증
StarPlayerLicense.authTheLicense(atServer: license){ isSuccess, error in
    //결과 처리
}
  • StarPlayerView 객체를 생성하여 플레이어 오픈시 라이센스 인증을 진행할 수 있습니다.
/**
 * 플레이어 open
 * @note
 * 플레이어 실행에 필요한 준비작업 (라이센스 검증 등)
 * 기존에 라이센스 인증을 완료한 상태라면 다운로드된 미디어 파일은 오프라인에서도 재생가능 (스트리밍 재생은 해당x)
 * 온라인 상태에서는 서버에 라이센스 인증을 요청하여 상태를 갱신함
 * StarPlayerLicense class의 authTheLicenseAtServer 호출의 선행 없이도 해당 함수의 호출로 플레이어 재생 가능
 *
 * 라이센스 검증 실패 : 에러 발생 (playerEventOccurred)
 * 라이센스 검증 성공 : OpenStateIdle -> OpenStateReady 상태 변경
 * @see starPlayerView:playerEventOccurred:withEventMethod:
 * @see StarPlayerError
 * @param license 라이센스 코드*/
- (void)open:(NSString *_Nonnull)license;


let license = "발급 받은 라이센스키"
player.open(license)    //플레이어 오픈

만약 라이센스 인증에 문제가 있다면 StarPlayerErrorCode를 참고 바랍니다.

[오프라인 재생]

최초 한번 라이센스 인증에 성공하면 다운로드된 영상에 한하여 오프라인 재생을 할 수 있게 됩니다.

SCMS

지정된 별도의 서버에서 사용자의 접속과 금지 행위를 실시간으로 감지하는 기능을 하며 플레이어 사용중 차단될 이유가 발생했다면 ‘starPlayerView:playerScmsBlockOccurred:’ 델리게이트를 통해 확인할 수 있고 클라이언트 측에서 사용자 제한 기능을 직접 구현할 수 있습니다.

  • ‘mirroringGuardEnabled'를 통해 미러링 및 화면 캡쳐 차단 여부를 설정할 수 있습니다. (화면캡쳐방지 기능은 OS 13이상부터 사용가능)

    /**
    * 미러링 가드 사용 여부
    * @note
    * 플레이어가 중지 상태(PlayerStateStopped) 일 때 변경 가능 */
    @property (nonatomic, readwrite) BOOL mirroringGuardEnabled;
    
  • StarPlayerScmsBlock 델리게이트

/**
 * 플레이어 SCMS Block 발생
 * @param info block정보 */
- (void)starPlayerView:(StarPlayerView *_Nonnull)view playerScmsBlockOccurred:(StarPlayerScmsBlock*_Nullable)info;
  • StarPlayerScmsBlockCode

  • 라이브스트리밍(HLS)의 경우 scms 연결은 지원하나 전송량이나 파일 사이즈는 0으로 전송합니다.

EVENT(학습이력)

별도의 서버에 플레이어 라이프 사이클에 맞게 'beginContent’, ‘playingContent’, ‘endContent’ 3가지 method 형식으로 이벤트를 전송합니다. 이벤트 기능을 사용하기 위해서는 ‘eventEnabled’ 값이 ‘true'이고 라이센스 서버에 EventUrl이 등록돼 있어야 합니다. 'starPlayerView:playerEventOccurred:withEventMethod:’ 델리게이트를 통해 이벤트 서버 전송 결과를 확인할 수 있습니다. 학습이력 데이터 세부 내용은 스타플레이어 연동 가이드 문서를 참고해 주시기를 바랍니다.

이벤트 설명
beginContent playState가 ‘PlayerStateReadyToPlay’ 상태일 때 전송(영상 시작)
playingContent 영상 재생중에는 ‘eventPlayingContentInterval’ 시간 간격으로 전송 (default : 3분) 또는 일시정지(pause) 상태로 변경될 때 전송
endContent playState가 ‘PlayerStateStopped’ 상태일 때 전송 (영상 정지 또는 재생완료)
  • 이벤트 활성화 여부
/**
 * 플레이어 학습이력 이벤트 전송 활설화 여부
 * @note 플레이어가 중지 상태(PlayerStateStopped) 일 때 변경 가능
 * @see eventPlayingContentInterval  */
@property (nonatomic, readwrite) BOOL eventEnabled;
  • 이벤트 전송 간격(단위:초)
/**
 * playing_content(Event) 전송 interval
 * @note
 * 단위 : sec
 * default : 180초
 * 플레이어가 재생중 일 때만 이벤트 스케줄러가 동작
 * 플레이어가 중지 상태(PlayerStateStopped) 일 때 변경 가능
 * @see eventEnabled */
@property (nonatomic, readwrite) uint16_t eventPlayingContentInterval;
  • 이벤트 전송 델리게이트
/**
 * 플레이어 Event 발생
 * @param response 결과
 * @param method 이벤트  (bengin_content, playing_content, end_content)
 * @see eventEnabled */
- (void)starPlayerView:(StarPlayerView *_Nonnull)view playerEventOccurred:(NSDictionary*_Nullable)response withEventMethod:(NSString*_Nonnull)method;

위의 ‘starPlayerView:playerEventOccurred:withEventMethod:requestParameters:error:’ 델리게이트를 통해 이벤트 서버 전송 결과를 확인할 수 있습니다.

미전송 EVENT

이벤트 서버 또는 통신의 문제로 전송에 실패한 학습 이력 데이터를 SDK 내부에 미전송 데이터로 분류하여 저장하게 됩니다. 미전송 데이터는 playState가 ‘PlayerStateReadyToPlay’ 상태일 때 일괄 재전송하게 되고 전송에 성공하면 저장된 데이터는 삭제합니다.

/**
 * 미전송 데이터 개수 조회
 * @note 플레이어가 재생 준비가 되었을 경우 작동 (OpenStateReady) */
- (int)selectMissedEventDataCount;

/**
 * 미전송 이벤트 데이터 전체 삭제
 * @note
 * 미전송 데이터가 전송이 안되고 많이 쌓여 있을 경우 부하가 발생할 수 있으므로 삭제할 수 있는 함수 제공
 * 플레이어가 재생 준비가 되었을 경우 동작 (OpenStateReady) */
- (void)deleteAllMissedEventData;

추가적으로 미전송 데이터 개수를 조회할 수 있는 함수와 삭제 함수를 제공하고 있습니다.

기본플레이어 & 서브플레이어

내부적으로 기본플레이어와 서브플레이어 두가지 코어로 작동하고 있으며 ‘basicPlayerEnable’ 변수로 플레이어를 선택할 수 있습니다. 권장은 기본플레이어 입니다. 추후 해당 기능은 삭제 될 수 있습니다.

  • 기본플레이어 : PIP(Picture In Picture)기능을 사용할 수 있으며 오디오싱크(currentAudioDelay) 기능을 사용할 수 없습니다. HLS 라이브 또는 스트리밍을 지원합니다.
  • 서브플레이어 : PIP(Picture In Picture)기능을 사용할 수 없으며 오디오싱크(currentAudioDelay) 기능을 사용할 수 있습니다.

플레이어 State

플레이어의 실시간 상태 정보를 변수나 델리게이트를 통해 확인할 수 있습니다.

  • 플레이어 상태 변수
@property (nonatomic, readonly) StarPlayerOpenState openState;      //플레이어 준비 상태
@property (nonatomic, readonly) StarPlayerPlayState playState;      //플레이어 재생 상태
/**
 * 플레이어  준비 상태 변경
 * @param openState 플레이어 준비 상태 (idle, ready)
 * @see StarPlayerOpenState*/
- (void)starPlayerView:(StarPlayerView *_Nonnull)view openStateChanged:(StarPlayerOpenState)openState;
/**
 * 플레이어  재생 상태 변경
 * @param playState 플레이어 재생 상태
 * @see StarPlayerPlayState*/
- (void)starPlayerView:(StarPlayerView *_Nonnull)view playStateChanged:(StarPlayerPlayState)playState;

StarPlayerViewDelegate

플레이어의 재생정보, 상태, SCMS, EVENT, 에러등의 정보를 확인할 수 있는 인터페이스 입니다.

StarPlayerContentModel

플레이어 재생에 필요한 데이터 Model Class 입니다. 플레이어 객체 생성 후 ‘setPlayerContentModel'에 미디어 데이터를 설정해 줘야 영상을 재생할 수 있습니다. contentUrl, originalUrl, contentId, userId, referer 정보는 필수로 입력해 주세요.

  • 설정 방법
let contentModel = StarPlayerContentModel()
contentModel.contentUrl = ""       //재생할 컨텐츠 URL(CDN 또는 Local URL)
contentModel.originalUrl = ""      //실제 원본 컨텐츠가 저장된 CDN URL (Event, SCMS 전송에 필요)
contentModel.contentId = ""        //컨텐츠 아이디 (Event, SCMS 전송에 필요)
contentModel.userId = ""           //User 아이디 (Event, SCMS 전송에 필요)
contentModel.referer = ""          //referer (컨텐츠 보안용)
contentModel.spkId = ""            //prepackaging(AxDRM) 된 파일들은 spkId 필요(SPK 파일 decrypt)
contentModel.watchedPlayTime = 0   //누적 시청 시간(동영상 PlayerDuration을 초과할 수 없음), Event 시간 계산에 사용
contentModel.beginTime = 0   //이어보기 (재생 시작 위치)

player.setPlayerContentModel(contentModel)
  • StarPlayerContentModel
  • 재생중 컨텐츠 정보를 변경하려면 플레이어를 stop 시킨후 setPlayerContentModel에 컨텐츠 정보를 다시 설정해 주세요.

PIP(PictureInPicture)

기본플레이어(basicPlayerEnabled = true)만 PIP 기능을 제공하며 iOS 9.0이상부터 지원이 가능합니다.

  • PictureInPicture 사용 방법
//PIP 시작 및 정지
if(player.isPictureInPictureSupported && player.isPictureInPicturePossible) {
    if player.isPictureInPictureActive {
        player.stopPictureInPicture()
    } else {
        player.startPictureInPicture()
    }
}

//PIP용 자막 추가하기
func starPlayerViewWillStartPicture(inPicture view: StarPlayerView) {
    player.setupSubtitleView(inPIP: pipSubtitleView)    //PIP용 전용 SubtitleView 추가 -> StarPlayerSubtitleView
}
  • PictureInPicture 델리게이트
/**
 * PictureInPicture will start
 * @note playing_content 이벤트 전송*/
- (void)starPlayerViewWillStartPictureInPicture:(StarPlayerView *_Nonnull)view;

/**
 * PictureInPicture will stop
 * @note playing_content 이벤트 전송*/
- (void)starPlayerViewWillStopPictureInPicture:(StarPlayerView *_Nonnull)view;

/**
 * PictureInPicture did start */
- (void)starPlayerViewDidStartPictureInPicture:(StarPlayerView *_Nonnull)view;
/**
 * PictureInPicture did stop */
- (void)starPlayerViewDidStopPictureInPicture:(StarPlayerView *_Nonnull)view;

/**
 * PictureInPicture 중지, 사용자 인터페이스 복귀
 * @note playing_content 이벤트 전송*/
- (void)starPlayerViewRestoreUserInterfaceForPictureInPictureStop:(StarPlayerView *_Nonnull)view;

/**
 * PictureInPicture start failed */
- (void)starPlayerViewFailedToStartPictureInPictureWithError:(NSString *_Nullable)description;

HLS 스트리밍

현재 SDK 구조상 기본적으로 url 확장자가 'm3u8’ 또는 ‘m3u'이어야만 HLS Content로 인식하고 있습니다. 만약 재생해야 할 HLS content url 이 위의 조건에 부합하지 않는다면 StarPlayerContentModel의 isHlsStreaming 값을 'true'로 설정해 주세요.

[제한사항]

  • hls 재생은 기본플레이어에서만 지원 가능합니다.
  • 라이브 스트리밍에서는 구간반복, 배속 기능을 사용할 수 없습니다.

  • hls delegate

/**
 * 로드된 HLS stream list 정보
 * @note
 * HLS MasterPlaylist의 #EXT-X-STREAM-INF 태그 정보를 담은 배열
 * @param streamList stream list */
- (void)starPlayerView:(StarPlayerView *_Nonnull)view loadedHlsStreamList:(NSArray<StarPlayerHLSStream*>*_Nonnull)streamList;

/**
 * 로드된 stream 정보
 * @note
 * 'auto' 모드 일 경우 네트워크 환경에 따라 stream이 변경됨
 * @param stream 로드된 stream */
- (void)starPlayerView:(StarPlayerView *_Nonnull)view loadedHlsStream:(StarPlayerHLSStream*_Nonnull)stream;

/**
 * 로드된 HLS Alternative Media List
 * @note
 * Media의 종류는 Audio, Video 두가지가 존재
 * HLS MasterPlaylist에서  #EXT-X-MEDIA 태그 정보를 담은 배열
 * @param mediaList alternative media list
 */
- (void)starPlayerView:(StarPlayerView *_Nonnull)view loadedHlsAlternativeMediaList:(NSArray<StarPlayerHLSAlternativeMedia*>*_Nonnull)mediaList;
/**
 * HLS MasterPlaylist stream 중에서 하나의 stream만 선택하여 영상 재생
 * @param stream 선택하여 재생할 stream
 */
- (void)selectHLSVideoStream:(StarPlayerHLSStream *_Nonnull)stream;

/**
 * HLS '자동' 모드 활성화
 * @note
 * xStream list가 2개 이상 존재하면 자동 모드 활성화
 * @return 활성화 성공 여부 (이미 활성화 되어 있거나 활성화 할 수 없는 환경이면 return 'NO')
 */
- (BOOL)activateHlsAutoStream;
/**
 * HLS MasterPlaylist Alternative Media중에 하나의 Media를 선택하여 비디오 또는 Audio를 변경
 * @note
 * Media의 종류는 Audio, Video 두가지가 존재
 * Media는 MasterPlaylist에서 #EXT-X-MEDIA 태그에 해당함
 */
- (void)selectHLSAlternativeMedia:(StarPlayerHLSAlternativeMedia *_Nonnull)media;

다운로드

고객사마다 CDN의 접근 방식이 상이하기 때문에 현재 다운로드 기능은 따로 제공되고 있지 않고 해당 기능은 클라이언트 측에서 직접 구현을 해야하는 부분입니다.

Axissoft에서 제공하는 CDN을 사용할 경우 아래의 Request 정보로 서비스에 접근하면 됩니다.

let range = String(format: "bytes=%llu-", dataOffset)
또는 
let range = String(format: "bytes=%llu-%llu", dataOffset, fileSize)

request.addValue("no-cache, no-store, no-transform", forHTTPHeaderField: "Cache-Control")
request.addValue("발급 받은 referer 정보", forHTTPHeaderField:"Referer")
request.addValue("", forHTTPHeaderField: "Accept")
request.addValue("StarPlayer/1.0", forHTTPHeaderField: "User-Agent")
request.addValue("Close", forHTTPHeaderField: "Connection")
request.addValue(range, forHTTPHeaderField: "Range")
request.addValue(StarPlayerUtils.generateXStreamingCheckSum(range), forHTTPHeaderField: "X-Streaming-Checksum")
request.addValue("CDN 도메인", forHTTPHeaderField: "X-Streaming-Domain")
request.addValue("임의의 세션값", forHTTPHeaderField: "X-Streaming-Session")

  • User-Agent : 'StarPlayer’ 단어가 반드시 포함돼야 합니다.
  • Referer : 발급 받은 referer 정보
  • X-Streaming-Checksum :StarPlayerUtils.generateXStreamingCheckSum 함수를 통해 생성 가능 합니다.
  • X-Streaming-Domain : CDN 도메인
  • X-Streaming-Session : 임의의 세션값
  • Range : 다운로드 영역 또는 구간
  • Accept : 필드는 추가하되 값은 공백 처리

StarPlayerPackager

byteArray 형태의 영상 데이터를 DRM 암호화 파일로 변환해주는 기능입니다. 다운로드 데이터 패키징 용도로 사용해 주세요. 단, 이미 DRM으로 패키징 된 파일에는 해당하지 않습니다.

  • DRM Packager 객체 생성 및 open
let spkPackager: StarPlayerPackager = StarPlayerPackager()
let filePath: String = "저장된 파일 경로 또는 저장할 파일 경로"
var dataOffset: CUnsignedLongLong?  //저장된 데이터 현재 위치
dataOffset = spkPackager?.open(withPath: URL(string: filePath))   //StarPlayer Packager open(저장된 파일이 없은 경우 값은 0, 이전에 저장했던 데이터가 있다면 값은 파일 offset)


/**
 * File packager open
 * @note
 * 영상 파일 drm 적용 용도
 * file packaging이 완료되면 close 함수를 호출 해야함
 * @param fileSavePath 파일 저장 경로 (경로+파일명)
 * @return 파일 데이터 offset (파일 데이터가 없을 경우 0), 파일 offset 정보로 이어 받기 가능
 */
- (unsigned long long)openWithPath:(NSURL*)fileSavePath;

  • DRM Packager 데이터 쓰기(Append), 이전에 받았던 파일의 dataOffset 정보를 알고 있다면 이어받기 가능
spkPackager?.dataPackagingAndAppend(data, offset: dataOffset!)  //데이터 DRM & 쓰기

/**
 * File packaging(DRM) &  append
 * @param data packaging 할 데이터
 * @param offset 데이터 offset(파일 이어받기 가능)
 */
- (void)dataPackagingAndAppend:(NSData*)data offset:(unsigned long long)offset;
  • DRM Packager 닫기(close), DRM 패키징 작업이 다 끝났다면 반드시 close 함수를 호출
spkPackager?.close()

DRM 영상 실행 방법

spkid로 DRM 패키징된 다운로드 영상이나 스트리밍 영상은 플레이어 재생전 StarPlayerContentModel에서 spkId를 설정해 줘야 영상을 재생할 수 있습니다.

StarPlayerError

플레이어 초기화,라이센스 인증,재생중 발생하는 에러는 ‘starPlayerView:errorOccurred:’ 델리게이트를 통해 확인할 수 있습니다.

  • StarPlayerError 델리게이트
/**
 * 플레이어 에러 발생
 * @param error 에러 내용 */
- (void)starPlayerView:(StarPlayerView *_Nonnull)view errorOccurred:(StarPlayerError *_Nonnull)error;

StarPlayerSubtitleView(자막)

영상의 경과 시간에 맞춰 자막 텍스트를 View에 출력해 줍니다. 지원하는 파일 형식은 smi, srt, web vtt 입니다.

  • 자막 초기화 및 설정
subtitle.datasource = self                      //자막 Datasource
subtitle.setFontSize(20)                        //자막 폰트 크기 설정
subtitle.setFontColor("#FFFFFF")                //자막 폰트 색상 설정, Hex(RGB)
subtitle.setVerticalAlign(.alignBottom)         //자막 수직 정렬 모드 설정(top, center, bottom)

subtitle.setContentUrl(URL(string: subtitleUrl), asLanguage: "en")  //자막 content url 및 언어셋팅
  • 자막 Datasource
//플레이어 시간으로 자막 싱크 맞추기
func displayTimeFor(in view: StarPlayerSubtitleView?) -> TimeInterval {
        return (player?.playerCurrentTime ?? 0.0) / Double(getTimeScale())
}

  • 자막 시작
subtitle.start() //자막 시작
  • 자막 일시정지
subtitle.pause() //자막 일시정지
  • 자막 정지
subtitle.stop() //자막 정지
  • 자막 초기화
subtitle.clearOfSubtitleText() //화면에 표시된 자막 텍스트 클리어
  • 수학 수식 텍스트 : KaTex 라이브러리에서 지원하는 문자열 포맷을 입력해야 하며 수식은 구분자 ‘$$'로 텍스트를 감싸야 합니다. KaTex 0.16.9 버전과 호환되며 필요한 수식은 KaTex documentation을 참고해 주세요.

  • 자막 텍스트 입력 예시

//일반 텍스트 입력
"안녕하세요. 만나서 반갑습니다!!!"

//수식 텍스트 입력
"$$c = \pm\sqrt{a^2 + b^2}$$"

//일반 + 수식 텍스트 입력
"a보다 b가 크면 $$\sqrt{a}$$보다 $$\sqrt{b}$$가 큽니다. 

StarPlayerSliderView(슬라이더)

  • 슬라이더 설정
playerSlider.delegate = self                    //슬라이더 델리게이터
playerSlider.setProgressViewHeight(2.0)         //슬라이더 높이 설정

playerSlider.setPlayDuration(totalTime)  //동영상 재생 가능 시간 slider에 set
  • 슬라이더 구간반복
playerSlider.setRepeatMode(isSelected)      //슬라이더 구간반복 모드
  • 슬라이더 초기화
playerSlider.resetSliderProgress()

워터마크

  • 설정
player.watermarkEnabled = true      //워터마크 사용설정

let contentModel = StarPlayerContentModel()
//워터마크 텍스트
contentModel.wmText = "watermark"
contentModel.wmTextSize = 10
contentModel.wmTextColor = "#43ff64c2"        //Hex(RGBA)

//워터마크 이미지
contentModel.wmImage = imgData  //워터마크 이미지(NSData)

//워터마크 정렬
contentModel.wmVerticalAlign = "WatermarkAlign.RANDOM" //[WatermarkAlign.Top, WatermarkAlign.BOTTOM, WatermarkAlign.CENTER, WatermarkAlign.RANDOM] 
contentModel.wmHorizontalAlign = "WatermarkAlign.RANDOM" //[WatermarkAlign.LEFT, WatermarkAlign.RIGHT, WatermarkAlign.CENTER, WatermarkAlign.RANDOM] 

//플레이어 컨텐츠 정보 설정
player.setPlayerContentModel(contentModel)

기타

워터마크, 슬라이더, 자막, starPlayerHandlePan는 원활한 프레임워크 연동 또는 테스트를 위해 기본적으로 지원하는 부가 기능들입니다. 해당 API들은 커스텀을 지원하지 않으며 기능 이슈에 대해 보증을 하지 않습니다. 기능 추가 및 고도화, 커스텀 UI등이 필요하시다면 직접 해당 기능들을 구현하시기를 바랍니다.

그리고 해당 가이드에 설명 안 된 기능들은 SampleStarPlayerSwift를 참고 해 주시기를 바랍니다.

버전 & 생성일

  • 버전 : 1.5.0
  • 생성 : 2023/09/25 (1.3.2)
  • 수정 : 2024/05/22 (1.4.0)
  • 수정 : 2024/06/11 (1.5.0)

License

License는 (주)액시스소프트에서 가지고 있습니다. 폐사의 승인 없이 본 내용의 전부 또는 일부에 대한 복사, 전재, 배포, 사용을 금합니다.