Skip to content

P2P設定

P2pConfig をインスタンス化します:

swift
let config = P2pConfig()
objective-c
P2pConfig* config = [P2pConfig defaultConfiguration];

該当するフィールドを上書きします:

フィールドデフォルト値説明
trackerZoneTrackerZone.Europetrackerサーバーアドレスの所在国の列挙値。China、Europe、HongKong、USA に分かれます
debugBoolfalseログを出力するかどうか
logLevelLogLevel.WARNログ出力のレベル(VERBOSE, DEBUG, INFO, WARN, ERROR)
iceServers[IceServer][IceServer(url: "stun:stun.l.google.com:19302"), IceServer(url: "stun:global.stun.twilio.com:3478?transport=udp")]Stunサーバーの設定に使用
announceString?niltrackerサーバーのアドレス
diskCacheLimitUInt2000 * 1024 * 1024VODモードでP2Pがディスクキャッシュする最大データ量(0に設定するとディスクキャッシュを無効化できます)
memoryCacheCountLimitUInt20P2Pがメモリキャッシュする最大ファイル数
p2pEnabledBooltruep2p engineを有効化・無効化
localPortHlsUInt0HLSストリーミング再生用ローカルプロキシサーバーのポート番号。デフォルトはランダムポート
customLabelString?${platform}-$ユーザー定義のカスタムラベル。管理パネルで分布図を確認できます
maxPeerConnectionsInt25最大接続ノード数
startFromSegmentOffsetUInt3trackerサービスへのリクエストを開始するsegmentオフセット
useHttpRangeBooltrue可能な場合にHttp Rangeリクエストを使用して、p2pダウンロードのタイムアウトによる残りのデータを補完
useStrictHlsSegmentIdBoolfalseデフォルトのシーケンス番号ベースの代わりに、urlベースのSegmentIdを使用
httpHeadersHls[String : String]?niltsおよびm3u8をリクエストする際のHTTPリクエストヘッダーを設定
sharePlaylistBoolfalsem3u8ファイルのP2P伝送を許可するかどうか
prefetchOnlyBoolfalseプリフェッチ方式のみでP2Pダウンロードを行う
logPersistentBoolfalseログを外部ストレージに永続化するかどうか。デフォルトのパスは Library/Caches/p2pengine.log

P2pEngine

P2pEngine を初期化します:

swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    P2pEngine.setup(token: YOUR_TOKEN)
    return true
}
objective-c
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [P2pEngine setupWithToken:YOUR_TOKEN config:NULL];
    return YES;
}

YOUR_TOKEN はユーザーを識別するための文字列です。管理パネルから取得したtokenに置き換えてください。元の再生アドレス(m3u8)を P2pEngine に渡すことで、ローカル再生アドレスを取得できます:

swift
let parsedUrl = P2pEngine.shared.parseStreamUrl(ORIGINAL_URL)
objective-c
NSString *parsedUrl = [[P2pEngine sharedInstance] parseStreamUrl:ORIGINAL_URL];

ソースの切り替え

プレイヤーが新しい再生アドレスに切り替える際は、新しい再生アドレス(m3u8)を P2pEngine に渡すだけで、新しいローカル再生アドレスを取得できます:

swift
let newParsedURL = P2pEngine.shared.parseStreamUrl(NEW_ORIGINAL_URL)
objective-c
NSString *newParsedURL = [[P2pEngine sharedInstance] parseStreamUrl:NEW_ORIGINAL_URL];

P2Pの停止

現在再生中の動画のP2P伝送を停止しますが、ローカルプロキシは停止しません:

swift
override func viewDidDisappear(_ animated: Bool) {
    P2pEngine.shared.stopP2p()
}
objective-c
- (void)viewDidDisappear:(BOOL)animated {
    [P2pEngine.sharedInstance stopP2p];
}

実行時に動的にP2Pを無効化

次のメディアファイルを再生する際に反映されます

swift
P2pEngine.shared.disableP2p()
objective-c
[P2pEngine.sharedInstance disableP2p];

実行時に動的にP2Pを有効化

次のメディアファイルを再生する際に反映されます

swift
P2pEngine.shared.enableP2p()
objective-c
[P2pEngine.sharedInstance enableP2p];

P2Pとローカルプロキシの停止

現在再生中の動画のP2P伝送とローカルプロキシを停止します:

swift
P2pEngine.shared.shutdown()
objective-c
[P2pEngine.sharedInstance shutdown];

ローカルプロキシの再起動

swift
P2pEngine.shared.startLocalServer()
objective-c
[P2pEngine.sharedInstance startLocalServer];

P2P統計

P2pStatisticsMonitor を通じてP2Pダウンロード情報を監視します:

swift
let monitor = P2pStatisticsMonitor()
P2pEngine.shared.p2pStatisticsMonitor = monitor
objective-c
P2pStatisticsMonitor* monitor = [[P2pStatisticsMonitor alloc] initWithQueue:dispatch_get_main_queue()];
P2pEngine.shared.p2pStatisticsMonitor = monitor;

コールバック関数内で p2pDownloadedp2pUploadedhttpDownloadedpeersserverConnected などを取得します:

swift
monitor.onPeers = { peers in
}
monitor.onP2pUploaded = { value in
}
monitor.onP2pDownloaded = { value, speed in
}
monitor.onHttpDownloaded = { value in
}
monitor.onServerConnected = { connected in
}
objective-c
monitor.onPeers = ^(NSArray<NSString *> * _Nonnull peers) {
};
monitor.onP2pUploaded = ^(NSInteger value) {
};
monitor.onP2pDownloaded = ^(NSInteger value, NSInteger speed) {
};
monitor.onHttpDownloaded = ^(NSInteger value) {
};
monitor.onServerConnected = ^(BOOL connected) {
};

WARNING

ダウンロード・アップロードデータ量の単位はKBです。

高度な使い方

プレイヤー情報のコールバック

ライブ配信モードでは、P2P効果を高めるために、PlayerInteractor プロトコルを実装する方法で、現在の再生時刻からバッファ先端までの時間間隔をp2p engineにコールバックすることを推奨します。

swift
class ViewController: UIViewController {
...
P2pEngine.shared.playerInteractor = self
...
}
extension ViewController : PlayerInteractor {
    func onBufferedDuration() -> TimeInterval {
        let currentTime = CMTimeGetSeconds(self.avplayer.currentTime())
        var bufferedDuration: Double = 0.0
        let timeRanges = self.avplayer.currentItem!.loadedTimeRanges
        for value in timeRanges {
            let timeRange = value.timeRangeValue
            let start = CMTimeGetSeconds(timeRange.start)
            let end = start + CMTimeGetSeconds(timeRange.duration);
            if (currentTime >= start && currentTime <= end) {
                bufferedDuration = end - currentTime;
                break;
            }
        }
        return bufferedDuration;
    }
}
objective-c
@interface ViewController () <PlayerInteractor>
...
P2pEngine.shared.playerInteractor = self;
...
#pragma mark - **************** PlayerInteractor ****************
-(NSTimeInterval)onBufferedDuration {
    NSTimeInterval currentTime = CMTimeGetSeconds([self.player currentTime]);
    NSTimeInterval bufferedDuration = 0;
    for (NSValue *value in [[self.player currentItem] loadedTimeRanges]) {
        CMTimeRange timeRange = [value CMTimeRangeValue];
        NSTimeInterval start = CMTimeGetSeconds(timeRange.start);
        NSTimeInterval end = start + CMTimeGetSeconds(timeRange.duration);
        if (currentTime >= start && currentTime <= end) {
            bufferedDuration = end - currentTime;
            break;
        }
    }
    return bufferedDuration;
}

VODモードでは、動画の長さが比較的大きい場合があり、ノードのマッチング時に再生時刻が近いノードを優先的にマッチングできればP2P効果の向上に役立ちます。この機能を実現するには、SDK側でプレイヤーの現在の再生時刻を取得する必要があります:

swift
class ViewController: UIViewController {
...
P2pEngine.shared.playerInteractor = self
...
}
extension ViewController : PlayerInteractor {
    func onCurrentPosition() -> TimeInterval {
        return CMTimeGetSeconds(self.avplayer.currentTime())
    }
}
objective-c
@interface ViewController () <PlayerInteractor>
...
P2pEngine.shared.playerInteractor = self;
...
- (NSTimeInterval)onCurrentPosition {
    return CMTimeGetSeconds([self.player currentTime]);
}

動的なm3u8パスの問題を解決する

一部のストリーミング配信事業者のm3u8は動的に生成されており、ノードごとにm3u8のアドレスが異なります。例えばexample.com/clientId1/streamId.m3u8とexample.com/clientId2/streamId.m3u8のようになります。本プラグインはデフォルトでm3u8のアドレス(クエリパラメータを除いたもの)をchannelIdとして使用します。このような場合、実際に同じライブ配信/動画を視聴しているノードを同じチャンネルに配置するために、共通のchannelIdを構築する必要があります。

swift
let videoId = extractVideoIdFromUrl(url: orginalUrl)                      // extractVideoIdFromUrl は自身で定義する必要があり、url内の動画IDを抽出して結果として返すことができます
let parsedUrl = P2pEngine.shared.parseStreamUrl(orginalUrl, videoId: videoId)
objective-c
NSString *videoId = [Utils extractVideoIdFromUrl:originalUrl];            // extractVideoIdFromUrl は自身で定義する必要があり、url内の動画IDを抽出して結果として返すことができます
NSURL *parsedUrl = [[P2pEngine sharedInstance] parseStreamUrl:originalUrl videoId:videoId];

HTTPリクエストヘッダーの設定

不正リンク防止や統計上の必要性から、一部のHTTPリクエストに User-Agent などのヘッダー情報を追加する必要がある場合、httpHeaders で設定できます:

swift
p2pConfig.httpHeadersHls = ["User-Agent": "XXX"]
objective-c
p2pConfig.httpHeadersHls = @{@"User-Agent":@"XXX"};

実行時に動的に設定することもできます:

swift
P2pEngine.shared.setHttpHeadersForHls(headers: ["User-Agent": "XXX"])
objective-c
[P2pEngine.shared setHttpHeadersForHlsWithHeaders: @{@"User-Agent": @"XXX"}];

AirPlayモードのサポート

SwarmCloudは現時点でAirPlayに対応していませんが、AirPlayを使用していない時のみローカルプロキシを使うことで制約を回避できます:

objective-c
if (/* player is in AirPlay mode */) {
    // set URL to original version
   [player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:original]];
} else {
    // airplay stopped - set URL to result of parseStreamURL
   [player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:rewritten]];
}

対応するHLSメディアファイルの拡張

デフォルトでは".ts"などの一般的な拡張子を持つファイルのみに対応しています。".image"のような拡張子に対応させたい場合は、以下の設定が必要です:

swift
let config = P2pConfig()
config.hlsMediaFiles = ["ts", "image"]
P2pEngine.shared.setup(token: YOUR_TOKEN, config: config)
objective-c
P2pConfig *config = [P2pConfig defaultConfiguration];
config.hlsMediaFiles = @[@"ts", @"image"];
[[P2pEngine sharedInstance] setupWithToken:YOUR_TOKEN config:config];

通常、HLSメディアファイルは".xx"のような拡張子で終わりますが、例外的に他の任意の文字で終わる場合もあります。ローカルプロキシがこれらの拡張子を認識できるようにするには、以下の設定が必要です:

swift
class ViewController: UIViewController {
...
P2pEngine.shared.hlsInterceptor = self
...
}
extension ViewController : HlsInterceptor {
    func isMediaSegment(url: String) -> Bool {
        return mediaFileRegex.match(url)
    }
}
objective-c
@interface ViewController () <HlsInterceptor>
...
P2pEngine.shared.hlsInterceptor = self;
...
#pragma mark - **************** HlsInterceptor ****************
- (BOOL)isMediaSegmentWithUrl:(NSString *)url {
    return [mediaFileRegex match:url];
}

特定のセグメントファイルを除外する

特定のセグメントファイル、例えばSSAI(Server Side Ad Insertion)によって生成されたユーザー固有のセグメントをP2Pに参加させたくない場合があります。このような場合、segmentBypass 関数を利用してフィルタリングできます:

swift
class ViewController: UIViewController {
...
P2pEngine.shared.hlsInterceptor = self
...
}
extension ViewController : HlsInterceptor {
    func shouldBypassSegment(url: String) -> Bool {
        return isSSAISegment(url)
    }
}
objective-c
@interface ViewController () <HlsInterceptor>
...
P2pEngine.shared.hlsInterceptor = self;
...
#pragma mark - **************** HlsInterceptor ****************
- (BOOL)shouldBypassSegment:(NSString *)url {
    return [Utils isSSAISegment:url];
}

m3u8ファイルのインターセプト

SDKはm3u8の内容を解析する必要があるため、暗号化されたm3u8を使用している場合は、インターセプターで内容をインターセプトし、標準的なm3u8ファイルを返す必要があります:

swift
class ViewController: UIViewController {
...
P2pEngine.shared.hlsInterceptor = self
...
}
extension ViewController : HlsInterceptor {
    func interceptPlaylist(data: Data, url: String) -> Data {
        return handlePlaylist(data, url)
    }
}
objective-c
@interface ViewController () <HlsInterceptor>
...
P2pEngine.shared.hlsInterceptor = self;
...
#pragma mark - **************** HlsInterceptor ****************
- (NSData *)interceptPlaylistWithData:(NSData *)data url:(NSString *)url {
    return [Utils handlePlaylistWithData:data url:url];
}

プレイヤーのカクつき統計

SwarmCloudの管理パネルではクライアントの平均カクつき率を監視できます。プレイヤーでカクつきが発生した際にSDKへ報告するだけで済みます:

swift
NotificationCenter.default.addObserver(self, selector: #selector(handleItemPlayBackStall), name: NSNotification.Name.AVPlayerItemPlaybackStalled, object: player.currentItem)

@objc func handleItemPlayBackStall() {
    P2pEngine.shared.notifyPlaybackStalled()
}
objective-c
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleItemPlayBackStall) name:AVPlayerItemPlaybackStalledNotification object:self.playerVC.player.currentItem];

- (void)handleItemPlayBackStall {
    [P2pEngine.sharedInstance notifyPlaybackStalled];
}

粤ICP备18075581号