こちらのページは旧SkyWayの情報です。新しいSkyWayに関する情報はこちら

# iOS SDK

# 概要

iOSデバイス(iPhone、iPad、iPod touch)用のアプリケーションにSkyWayを実装するためのSDKです。

# SDKのダウンロード

# CocoaPodsを利用する場合

  1. Podfileに以下を追記します。

Podfile

platform :ios,'10.0'
use_frameworks!

def install_pods
  pod 'SkyWay'
end

target 'source code directory(rewrite)' do
  install_pods
end
  1. 以下のコマンドにてインストールします。
$ pod setup
$ pod install

# ファイルをダウンロードする場合

GitHubよりダウンロード

# 対応OS

  • iOS 10+
  • iPadOS 13+

# チュートリアル

iOS SDKの基本機能を利用して、1:1のシンプルなビデオ通話アプリを作成することで、iOS SDKの使い方について理解を深めます。 現在サーバに接続されているユーザーの一覧を表示し、通話相手を選び、1対1のビデオ通話を開始し、終了する機能、また着信を受け付ける機能を実装していきます。

このチュートリアルで作成するアプリは、サンプルコードとして提供している1対1のビデオ通話と同じものになります。 完成したアプリを試したい場合は、ソースコードをダウンロードし、このチュートリアルのビルド手順に沿ってビルドししてください。

SkyWayでシグナリングをして、端末間がビデオ通話で繋がる ビデオ通話のスクリーンショット

# 開発前の準備

# SkyWayのAPIキー発行

ダッシュボードへログインし、以下の3つを行います。

  1. 「新しくアプリケーションを作成する」ボタンを押す

「新しくアプリケーションを作成する」ボタン

  1. 「利用可能ドメイン」に"localhost"を追加して、「アプリケーションを作成する」を押す

「アプリケーションを作成する」を押す

  1. APIキーをコピーして保存

APIキーをコピーして保存

# 開発環境の準備

このチュートリアルでは以下の環境を前提に開発を進めます。

  • Xcode Version 12.0.1
  • 動作確認端末
    • iPhone 8(MQ7823/A)
  • iOS バージョン
    • 14.0.0
  • 開発言語
    • ObjectiveC
  • Peer認証
    • Peer認証はダッシュボードにてOFFに設定してください。

# プロジェクトの作成

チュートリアルで利用するXcodeのプロジェクトは以下のgithubリポジトリからダウンロードしてください。

# SDKをプロジェクトに追加する

SDKのバイナリファイルを配置します。
今回のチュートリアルでは、ダウンロードしたファイルを手動でプロジェクトに組込む手順を紹介します。

  1. SDKをGitHubからダウンロード
  2. ZIPファイルを解凍後、SkyWay.frameworkを、skyway-ios-sdk-tutorialディレクトリ直下に配置
  3. skyway-ios-sdk-tutorial.xcodeprojをダブルクリックしプロジェクトを開く
  4. 左ペインのファイルツリー上で右クリックしAdd File to…を選択し、先程配置したSkyWay.frameworkをファイルツリーに追加
  5. Build Phases > Embedded Frameworks にSkyWay.frameworkをドラッグアンドドロップ

SDKをプロジェクトに追加したところ

プロジェクトに含まれる主要ファイルの説明は以下のとおりです。

  • ViewController.m
    • 今回のチュートリアルで主に必要なコードを追記していくコントローラー
  • PeerListViewController.m
    • PeerID一覧を表示するUITableViewを生成するコントローラー
    • 完成版が同梱されており、今回のチュートリアルでは触れません
  • storyboard
    • 完成版が同梱されており、今回のチュートリアルで触れません

# ヘッダーファイルインポート

チュートリアルでは既に記載済みですが、ViewController.hにSDK用のヘッダーファイルを追加します。

Objective-C

#import <SkyWay/SKWPeer.h>

# SkyWayサーバへの接続

# 宣言

プログラム中で利用する定数を追記してください。
apikeyには先程ダッシュボードで発行したAPIキーを指定してください。
domainには先程ダッシュボードで指定した利用可能ドメイン名のうち一つを指定してください。

Objective-C

//
// Set your APIkey and Domain
//
static NSString *const kAPIkey = @"apikey";
static NSString *const kDomain = @"domain";

プログラム中で利用するインスタンス変数の宣言を追記してください。

  • _peer : Peerオブジェクト
  • _localStream : 自分自身のMediaStreamオブジェクト
  • _remoteStream : 相手のMediaStreamオブジェクト
  • _mediaConnection : MediaConnectionオブジェクト

Objective-C

//
// Instance declaration
//
@interface ViewController () {
    SKWPeer*			_peer;
    SKWMediaStream*		_localStream;
    SKWMediaStream*		_remoteStream;
    SKWMediaConnection*	_mediaConnection;
    
    NSString*			_strOwnId;
    BOOL				_bConnected;   
}

プロパティ宣言、そしてインスタンス変数のdealloc処理を追記してください。

  • localView : 自分自身のカメラ映像を表示するためのレンダラービューオブジェクト
  • remoteView : 相手のカメラ映像を表示するためのレンダラービューオブジェクト

Objective-C

//
// Property declaration
//
@property (weak, nonatomic) IBOutlet UILabel*   idLabel;
@property (weak, nonatomic) IBOutlet UIButton*  actionButton;
@property (weak, nonatomic) IBOutlet SKWVideo*  localView;
@property (weak, nonatomic) IBOutlet SKWVideo*  remoteView;

@end

@implementation ViewController

     :
     :

//
// dealloc
//
- (void)dealloc {
    _localStream = nil;
    _remoteStream = nil;
    _strOwnId = nil;
    _mediaConnection = nil;
    _peer = nil;
    
}

     :
     :

@end

# Peerオブジェクトの作成

viewDidLoadメソッド内に、Peerオブジェクトを作成するための処理を追記してください。
Peerオブジェクトには、SKWPeerOptionクラスを利用し、APIキー、ドメイン名、デバッグレベルを指定してください。

Objective-C

- (void)viewDidLoad {
    [super viewDidLoad];

    //
    // Initialize Peer
    //
    SKWPeerOption* option = [[SKWPeerOption alloc] init];
    option.key = kAPIkey;
    option.domain = kDomain;
    option.debug = 3;
    _peer	= [[SKWPeer alloc] initWithId:nil options:option];

Peerオブジェクトで指定可能なその他のオプションについては、APIリファレンスをご覧ください。

# 接続成功・失敗・切断時の処理

続けて、Peerオブジェクトに必要なイベントコールバックを追記してください。

# openイベント

SkyWayのシグナリングサーバと接続し、利用する準備が整ったら発火します。 SkyWayのすべての処理はこのイベント発火後に利用できるようになります。
PeerIDと呼ばれるクライアント識別用のIDがシグナリングサーバで発行され、コールバックイベントで取得できます。 PeerIDはクライアントサイドで指定することもできます。
以下の処理では、PeerIDが発行されたら、その情報をUIに表示する処理を行っています。

Objective-C

//
// Set Peer event callbacks
//

// OPEN
[_peer on:SKW_PEER_EVENT_OPEN callback:^(NSObject* obj) {
    
    // Show my ID
    _strOwnId = (NSString*) obj;
    _idLabel.text = _strOwnId;
            
}];

# カメラ映像、マイク音声の取得

openイベントのコールバック内に、カメラ映像とマイク音声を取得するための処理を追記してください。

# オプション設定

SKWMediaConstraintsクラスでカメラ映像・マイク音声取得に関するオプションを設定可能です。
ここで設定している項目の説明は以下のとおりです。

  • maxWidth: キャプチャ映像の横サイズ上限(単位:ピクセル)
  • maxHeight: キャプチャ映像の縦サイズ上限(単位:ピクセル)
  • cameraPosition: 使用するカメラの選択(ディフォルトはSKW_CAMERA_POSITION_FRONT
    • カメラポジションは前面カメラ(SKW_CAMERA_POSITION_FRONT)と背面カメラ(SKW_CAMERA_POSITION_BACK)が選択可能

これ以外の項目については、APIリファレンスをご覧ください。

Objective-C

// OPEN
[_peer on:SKW_PEER_EVENT_OPEN callback:^(NSObject* obj) {
    
     :
     :
    
    // Set MediaConstraints
    SKWMediaConstraints* constraints = [[SKWMediaConstraints alloc] init];
    constraints.maxWidth = 960;
    constraints.maxHeight = 540;
    constraints.cameraPosition = SKW_CAMERA_POSITION_FRONT;

}];        
# 取得と再生

SKWNavigatorクラスの初期化を行い、getUserMediaメソッドの引数にconstraintsを指定して実行することで、自分のカメラ映像(ローカルストリーム)が取得できます。
取得したMediaStreamオブジェクトに、addVideoRendererメソッドを利用して、ビデオレンダラー(表示用のSKWVideoオブジェクト)を割り当てます。

Objective-C

// OPEN
[_peer on:SKW_PEER_EVENT_OPEN callback:^(NSObject* obj) {
    
     :
     :
    
    // Set MediaConstraints
    
     :
     :

    // Get a local MediaStream & show it
    [SKWNavigator initialize:_peer];
    _localStream = [SKWNavigator getUserMedia:constraints];
    [_localStream addVideoRenderer:_localView track:0];

}];        

# errorイベント

何らかのエラーが発生した場合に発火します。エラーが発生したら、ログにその内容を表示できるようにします。

Objective-C

// ERROR
[_peer on:SKW_PEER_EVENT_ERROR callback:^(NSObject* obj) {
    SKWPeerError* error = (SKWPeerError*)obj;
    NSLog(@"%@",error);
    
}];

# closeイベント

Peer(相手)との接続が切れた際に発火します。チュートリアルでは特に処理は行いません。

Objective-C

// CLOSE
[_peer on:SKW_PEER_EVENT_CLOSE callback:^(NSObject* obj) {}];

# 発信・切断・着信処理

発信、切断、着信をするための処理を追記してください。

# 発信処理

相手のPeerIDを選択して発信します。

# 発信先のPeerIDを取得

actionButtonをタップし未接続状態であれば、listAllPeersメソッドを利用して接続先のPeerID一覧を取得します。 取得した一覧から自分自身のIDを削除し、PeerListViewControllerで一覧表示します。

Objective-C

//
// Action for actionButton (make/hang up a call)
//
- (IBAction)onActionButtonClicked:(id)sender {
    
    if(nil == _mediaConnection) {
        
        //
        // Select remote peer & make a call
        //
        
        // Get all IDs connected to the server
        [_peer listAllPeers:^(NSArray* aryPeers){
            NSMutableArray* maItems = [[NSMutableArray alloc] init];
            if (nil == _strOwnId) {
                 return;
            }
            
            // Exclude my own ID
            for (NSString* strValue in aryPeers) {
                if (NSOrderedSame != [_strOwnId caseInsensitiveCompare:strValue]) {
                    [maItems addObject:strValue];
                }
            }
            
            // Show IDs using UITableViewController
            PeerListViewController* vc = [[PeerListViewController alloc] initWithStyle:UITableViewStylePlain];
            vc.items = [NSArray arrayWithArray:maItems];
            vc.delegate = self;
            
            UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:vc];
            dispatch_async(dispatch_get_main_queue(), ^{
                [self presentViewController:nc animated:YES completion:nil];
            });
            
            [maItems removeAllObjects];
        
        }];
    }
         
    else {

    }
}
# 発信

PeerListViewControllerでPeerIDが選択されたら、didSelectPeerメソッドが呼ばれます。 相手のPeerID、自分自身のlocalStreamを引数にセットし発信します。
発信後は必要なイベントコールバックをセットします。
setMediaCallbacksの中身については後ほど説明します。

Objective-C


//
// Create a MediaConnection
//
- (void) didSelectPeer:(NSString *)peerId {
    _mediaConnection = [_peer callWithId:peerId stream:_localStream];
    [self setMediaCallbacks];
}

# 切断処理

相手との接続を切断します。

# MediaConnectionの切断

actionButtonをタップした際に接続中であれば、MediaConnectionオブジェクトのCloseメソッドで該当するMediaConnectionを切断し、後ほど説明するcloseRemoteStreamで必要な処理を行います。

Objective-C

//
// Action for actionButton (make/hang up a call)
//
- (IBAction)onActionButtonClicked:(id)sender {
    
    if(nil == _mediaConnection) {
        
     :
     :
         
    else {
        
        //
        // hang up a call
        //
        
        [self closeRemoteStream];
        [_mediaConnection close];
    }
}
# MediaStreamのクローズ

MediaConnectionオブジェクトのCloseメソッドが実行された後は、removeVideoRendererメソッドを利用して該当のMediaStreamに割り当てられた、ビデオレンダラーを取り外します。

Objective-C

//
// Close & release a remote MediaStream
//
- (void) closeRemoteStream {
    if(nil == _remoteStream) {
        return;
    }
    
    if(nil != _remoteView) {
        [_remoteStream removeVideoRenderer:_remoteView track:0];
    }
    
    [_remoteStream close];
    _remoteStream = nil;
}
# コールバックイベントの解放関連

MediaConnection切断時に実行するコールバックイベントの開放処理を追記してください。
尚、unsetPeerCallbacksについてはPeerオブジェクトの破棄時に利用します。 今回のチュートリアルでは、Peerオブジェクトの破棄は省略しているため未使用です。

Objective-C

//
// Unset callbacks for PEER_EVENTs
//
- (void)unsetPeerCallbacks {
    if (nil == _peer) {
        return;
    }
    
    [_peer on:SKW_PEER_EVENT_OPEN callback:nil];
    [_peer on:SKW_PEER_EVENT_CONNECTION callback:nil];
    [_peer on:SKW_PEER_EVENT_CALL callback:nil];
    [_peer on:SKW_PEER_EVENT_CLOSE callback:nil];
    [_peer on:SKW_PEER_EVENT_ERROR callback:nil];
}

//
// Unset callbacks for MEDIACONNECTION_EVENTs
//
- (void)unsetMediaCallbacks {
    if(nil == _mediaConnection) {
        return;
    }
    
    [_mediaConnection on:SKW_MEDIACONNECTION_EVENT_STREAM callback:nil];
    [_mediaConnection on:SKW_MEDIACONNECTION_EVENT_CLOSE callback:nil];
    [_mediaConnection on:SKW_MEDIACONNECTION_EVENT_ERROR callback:nil];
}

# 着信処理

相手から接続要求がきた場合に応答します。
相手から接続要求が来た場合はSKW_PEER_EVENT_CALLが発火します。 引数として相手との接続を管理するためのMediaConnectionオブジェクトが取得できるため、answerメソッドを実行し接続要求に応答します。
この時に、自分自身の_localStreamをセットすると、相手にカメラ映像・マイク音声を送信することができるようになります。
発信時の処理と同じくsetMediaCallbacksを実行し、イベントをセットします。中身については後ほど説明します。

Objective-C

- (void)viewDidLoad {
    [super viewDidLoad];
    
     :
     :
   
    // CALL (Incoming call)
    [_peer on:SKW_PEER_EVENT_CALL callback:^(NSObject* obj) {
        if (YES == [obj isKindOfClass:[SKWMediaConnection class]]) {
            _mediaConnection = (SKWMediaConnection *)obj;
            [self setMediaCallbacks];
            [_mediaConnection answer:_localStream];
        }
    }];

# MediaConnectionオブジェクトに必要なイベント

MediaConnectionオブジェクトに必要なイベントコールバックです。
SKW_MEDIACONNECTION_EVENT_STREAMは相手のカメラ映像・マイク音声を受信した際に発火します。
コールバック内では、UI上の接続ステータスのアップデート処理と、取得した相手のMediaStreamオブジェクトにaddVideoRendererメソッドを利用して、ビデオレンダラーを割り当てます。

Objective-C

//
// Set callbacks for MEDIACONNECTION_EVENTs
//
- (void)setMediaCallbacks {
    if (nil == _mediaConnection) {
        return;
    }
    
    [_mediaConnection on:SKW_MEDIACONNECTION_EVENT_STREAM callback:^(NSObject* obj) {
        if (YES == [obj isKindOfClass:[SKWMediaStream class]]) {
            if (YES == _bConnected) {
                return;
            }
            
            // Change connection state
            _bConnected = YES;
            [self updateActionButtonTitle];
            
            // Get a remote MediaStream & show it
            _remoteStream = (SKWMediaStream *)obj;
            dispatch_async(dispatch_get_main_queue(), ^{
                [_remoteStream addVideoRenderer:_remoteView track:0];
            });
            
        }
    }];
   
}

SKW_MEDIACONNECTION_EVENT_CLOSEは相手がメディアコネクションの切断処理を実行し、実際に切断されたら発火します。
コールバック内では、必要な切断処理を実行します。詳細は後述します。

Objective-C

//
// Set callbacks for MEDIACONNECTION_EVENTs
//
- (void)setMediaCallbacks {

     :
     :
    
    [_mediaConnection on:SKW_MEDIACONNECTION_EVENT_CLOSE callback:^(NSObject* obj) {
        if (NO == _bConnected) {
            return;
        }
        
        [self closeRemoteStream];
        [self unsetMediaCallbacks];
        _mediaConnection = nil;
        
        _bConnected = NO;
        [self updateActionButtonTitle];
        
    }];
    
}

SKW_MEDIACONNECTION_EVENT_ERRORは何らかのエラーが発生した際に発火します。エラーが発生したら、ログにその内容を表示できるようにします。

Objective-C

//
// Set callbacks for MEDIACONNECTION_EVENTs
//
- (void)setMediaCallbacks {

     :
     :
    
    [_mediaConnection on:SKW_MEDIACONNECTION_EVENT_ERROR callback:^(NSObject* obj) { }];
}

# UIのセットアップ

UI関連の必要な処理を追記してください。
actionButtonはトグルで利用するため、接続状態に応じてラベルを張り替えます。updateActionButtonTitleメソッドの中身を追記してください。

Objective-C

//
// UIViewcontroller lifecycle
//
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
    [self updateActionButtonTitle];
}

- (void)viewDidDisappear:(BOOL)animated {
    [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
    [super viewDidDisappear:animated];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

//
// Update actionButton title
//
- (void)updateActionButtonTitle {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString* title = (_bConnected) ? @"Hang up" : @"Make Call";
        [_actionButton setTitle:title forState:UIControlStateNormal];
    });
    
}

# カメラの切り替え

最後にカメラの切り替え処理を追記してください。
getCameraPositionメソッドで該当メディアストリームで利用しているカメラ位置情報を取得します。その取得結果を利用して、トグルで切り替えます。

Objective-C

//
// Action for switchCameraButton
//
- (IBAction)onSwitchCameraButtonClicked:(id)sender {
    if(nil == _localStream) {
        return;
    }
    
    SKWCameraPositionEnum pos = [_localStream getCameraPosition];
    if(SKW_CAMERA_POSITION_BACK == pos) {
        pos = SKW_CAMERA_POSITION_FRONT;
    }
    else if(SKW_CAMERA_POSITION_FRONT == pos) {
        pos = SKW_CAMERA_POSITION_BACK;
    }
    else {
        return;
    }
    
    [_localStream setCameraPosition:pos];
}

# ビルドする

  1. General > Identity から Bundle Identifierを適宜修正
  2. Signing & Capabilities > Signing(Debug) > Team から ビルドに利用するアカウントを選択
  3. 実機を接続しビルド実行

ビルドして左上にPeerID(ランダムな文字列)、右下にインカメラの映像が表示されていれば成功です。

実機上でアプリを実行した画面

# 動作確認

実機でビルドし動作を確認してください。listAllPeersで取得したPeerIDに対して発信し、相手とビデオ通話ができれば成功です。 実機が1台しかない場合は、JavaScript SDKで実装したWebアプリケーションとの相互接続で動作を確認することができます。

# サンプルコード

Objective-C、Swiftのサンプルコードを公開しています。

Objective-C
1対1、P2P ビデオ通話 テキストチャット
多人数、P2P ビデオ通話 テキストチャット
多人数、SFU ビデオ通話 テキストチャット
Swift
1対1、P2P ビデオ通話 テキストチャット