記憶回路断線中。。

SE→情シス→SE→また情シス(笑) IT系の困った事を徒然なるままに。。。

iOSからchromecastへRemote Display #3

Chromecast-2015

 

(前回記事) 

yo-tan.hatenablog.com

 

 

swiftプロジェクトの準備

Develop iOS Sender App with Cast v2  |  Cast  |  Google Developers

引き続き、このサイトに書いてある通りに進める。

真ん中くらいにある"iOS Development"から。

First, follow the guide, iOS Sender App Development to get started with building your app for remote display. Follow the procedures in that document up to, but not including, Launch application before following the procedures in this guide.

 まずは、iOS Sender App Developmentのリンク先の手順をやりなさいと。Launch applicationの前の手順まで。

 

cocoapodsを使用するのが推奨、と書いてあるが、正しいPodfileの記述の例が見当たらなかったので、sampleに倣って進めてみる。

sampleタブから以下のリンクに行くことで、"CastRemoteDisplay-iOS"のソースを取得。

Develop iOS Sender App with Cast v2  |  Cast  |  Google Developers

 

ダウンロードしたプロジェクトに対し、以下の設定を変更。

1. pod install
2. Build SettingsのSigningを正しく設定
3. Bundle Identifierを適当に変更

 

・・・その他、いろいろ足掻いてみるが、なかなかビルドエラーが取れない。

xcconfigの設定とか複雑で、知識不足のたなやんにはよくわからない・・・

 

 

というわけで、マニュアルに書いてある、手動設定の方の手順で行きます^^;

ただし、使用する外部モジュールは、cocoapodでdownloadしたものにする。

※バージョンは以下。

Installing google-cast-remote-display-sdk (2.10.4)
Installing google-cast-sdk (2.10.4.1)

 

 
(必要なモジュールのインストールと各種初期設定)

    1. create a new xcode project から新規プロジェクト作成(single view app, swift)

    2. Build SettingsのSigningを正しく設定

    3. Bundle IDを、Google Cast SDK Developer Console で設定したApplication IDに対応するものに設定(google cast sdkは、Bundle IDを見ておらず、applicationIDのみで判断しているように見えるが念のため)

    4.  Other Linker Flagsに追加
      In your Xcode project, set the Other Linker Flags to -ObjC
      f:id:yo--tan:20180706083724p:plain
       
    5. 必要なframeworkの追加

      f:id:yo--tan:20180708164008p:plain

      とりあえず、GoogleCast.framework以外のものを一通り指定。
      その後、以下の通りにGoogleCast.frameworkを追加。

      5-1. このxcodeプロジェクトのルートディレクトリに、GoogleCast.frameworkをコピー(コンソールなどから)

      5-2. GoogleCast.frameworkの中にある"GoogleCastResources.bundle"を、framework直下のディレクトリから、その親ディレクトリ(framework外)に移動。framework内にそのファイルがあると、以下のリンク先のエラーが発生する。
      stackoverflow.com
      5-3. このframeworkをD&Dでxcode上に設置。コピーはせずreferenceで。

      5-4. 5-3までで、Target > GeneralのLinked Frameworks and Librariesの中にGoogleCast.frameworkが入っていると思うが、なければ追加(Embedded Binariesには入れない)

 

swiftコード記述(google cast sender API部分。remote display APIは次で^^;)

やっと、コードを書きます。本来のゴールはremote displayなのだが、ベースとしてgoogle cast sdk自体をわかっておかないと辛そうなので、まずはそこから。

 

事前準備として、scanするのをボタントリガーとするためボタンを追加。

f:id:yo--tan:20180709075344p:plain

  

そして、そのボタンを押すとscan() メソッドが呼ばれるように設定し、以下のコードを記述。

import UIKit
import GoogleCast

class ViewController: UIViewController, GCKDeviceScannerListener, GCKDeviceManagerDelegate, GCKMediaControlChannelDelegate {

	let APP_ID = kGCKMediaDefaultReceiverApplicationID;
	
	var deviceScanner: GCKDeviceScanner?;
	var deviceManager: GCKDeviceManager?;
	var mediaControlChannel: GCKMediaControlChannel?;
	var mediaInformation: GCKMediaInformation?;
	
	// MARK:- UIViewController

	override func viewDidLoad() {
		super.viewDidLoad()
	}

	override func didReceiveMemoryWarning() {
		super.didReceiveMemoryWarning()
	}
	
	// MARK:- GCKDeviceScannerListener

	func deviceDidComeOnline(_ device: GCKDevice!) {
		print("Device found: \(device.friendlyName)");

		//connect
		deviceManager = GCKDeviceManager(device: device, clientPackageName: Bundle.main.bundleIdentifier)
		deviceManager!.delegate = self
		deviceManager!.connect()
	}
	
	func deviceDidGoOffline(_ device: GCKDevice!) {
		print("Device went away: \(device.friendlyName)");
	}
	
	func deviceDidChange(_ device: GCKDevice!) {
		print("Device did Change: \(device.friendlyName)");
	}

	// MARK:- GCKDeviceManagerDelegate

	func deviceManagerDidConnect(_ deviceManager: GCKDeviceManager!) {
		print("didConnect")
		let options = GCKLaunchOptions(relaunchIfRunning: true)
		deviceManager.launchApplication(APP_ID, with: options)
	}
	
	func deviceManager(_ deviceManager: GCKDeviceManager!, didConnectToCastApplication applicationMetadata: GCKApplicationMetadata!, sessionID: String!, launchedApplication: Bool) {
		print("Application has launched.")
		mediaControlChannel = GCKMediaControlChannel()
		mediaControlChannel!.delegate = self
		deviceManager.add(mediaControlChannel)
		mediaControlChannel!.requestStatus()
		
		let metadata = GCKMediaMetadata()
		metadata?.setString("Big Buck Bunny (2008)", forKey: kGCKMetadataKeyTitle)
		metadata?.setString("Big Buck Bunny tells the story of a giant rabbit with a heart bigger " +
			"than himself. When one sunny day three rodents rudely harass him, something " +
			"snaps... and the rabbit ain't no bunny anymore! In the typical cartoon " +
			"tradition he prepares the nasty rodents a comical revenge.",
						   forKey:kGCKMetadataKeySubtitle)
		
		let url = NSURL(string:"https://commondatastorage.googleapis.com/gtv-videos-bucket/" +
			"sample/images/BigBuckBunny.jpg")
		metadata?.addImage(GCKImage(url: url! as URL, width: 480, height: 360));

		mediaInformation = GCKMediaInformation(
			contentID:
			"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
			streamType: GCKMediaStreamType.none,
			contentType: "video/mp4",
			metadata: metadata,
			streamDuration: 0,
			mediaTracks: [],
			textTrackStyle: nil,
			customData: nil
		)
		
		// Cast the media
		mediaControlChannel!.loadMedia(mediaInformation, autoplay: true)
	}
	
	// MARK:- for this app
	
	@IBAction func scan() {
		// Establish filter criteria.
		let filterCriteria = GCKFilterCriteria(forAvailableApplicationWithID: APP_ID);
		
		// Initialize device scanner.
		deviceScanner = GCKDeviceScanner(filterCriteria: filterCriteria)
		if let deviceScanner = deviceScanner {
			deviceScanner.add(self)
			deviceScanner.startScan()
			deviceScanner.passiveScan = true
		}
	}
}

  

おお!できた!

googleさんが用意しているサンプル動画が、テレビに流れましたー。

複数のchromecast端末から対象を選択するところとかはとりあえず省いちゃったけど、これくらいの方が入り口としてはわかりやすいよね^^;

 

処理の流れとしては、以下のイメージ。

  1. deviceScanner.startScan() で、存在する端末を取得。
    (ただし、存在することがわかっているのであれば、省略も可能。)

  2. chromecastとonlineになった後に呼ばれるGCKDeviceScannerListener#deviceDidComeOnline() で、onlineになった(connectとはまた別なので用語に注意)端末とconnect

  3. 接続後に呼ばれるGCKDeviceManagerDelegate#deviceManagerDidConnect() で、アプリ起動

  4. アプリ起動後に呼ばれるGCKDeviceManagerDelegate#deviceManager(didConnectToCastApplication:) で、アプリからchromecastに渡すデータを処理して、渡す

 

では、次はついにremote displayの実装行きます!

 

 

yo-tan.hatenablog.com