compassが遅い件 vol.3
「compassが遅い件 vol.2」の続きです。今回はcssの生成を並列化したいと思います。
ディレクトリ構成等々は、vol.1・vol.2と同様です。
またもやconfig.rbに処理を書き込むカタチになります。
※ vol.1に記載した↓とは別件です。
> 最終的には、このグループでのコンパイルをforkさせ、複数のグループを並列にコンパイルさせるとこまでやりました。
> 今回は、それをするための前準備になります。
必要なものをインストールする
今回は並列実行ということで、Parallelというgemを使いたいと思います。
(スレッド数の管理もしてくれるし、とても楽に導入できたので。)
・Parallelをインストール(筆者はMacです…)
$ sudo gem install parallel
・Compassのバージョン
$ compass -v
Compass 0.12.2 (Alnilam)
Copyright (c) 2008-2014 Chris Eppstein
Released under the MIT License.
Compass is charityware.
Please make a tax deductable donation for a worthy cause: http://umdf.org/compass
並列化が実感できる環境をつくる
「vol.2」で作成したsass/test.scssはコンパイルに10秒以上かかっていたので、test2.scssとtest3.scssをつくり、css生成がブロックされる状態にしておく。
$ cp -ip sass/print.scss sass/test2.scss
$ cp -ip sass/print.scss sass/test3.scss
準備オッケー。
通常のコンパイルをしてみる。
$ compass compile --time --force
identical stylesheets/ie.css (0.0s)
identical stylesheets/print.css (0.0s)
identical stylesheets/screen.css (0.03s)
identical stylesheets/test.css (18.165s)
identical stylesheets/test2.css (0.001s)
identical stylesheets/test3.css (0.0s)
Compilation took 18.201s
test.css生成に時間がかかり、test2.cssとtest3.cssの生成がブロックされているのが分かります。
ソースの修正
修正箇所は、sass_filesのループで回してるところをparallelを使って並列化させるだけ。
ここの処理を_config.rbで上書きし、並列化させる。
すると、上限2スレッドでcss生成が開始される。
(test.cssでブロック中にtest2.css、test3.cssが生成されてるのがわかる。
(test.cssでブロック中にtest2.css、test3.cssが生成されてるのがわかる。
$ compass compile --time --force
identical stylesheets/ie.css (0.001s)
identical stylesheets/print.css (0.001s)
identical stylesheets/screen.css (0.016s)
identical stylesheets/test2.css (0.001s)
identical stylesheets/test3.css (0.001s)
identical stylesheets/test.css (16.213s)
Compilation took 16.216s
オプションで指定できるようにする
例のごとく、環境変数でパラメータを受け取れるようにします。今回は、全ソース乗っけます。(いろいろ細かく書いていってたので、まとめの意味で。
下記のようなコマンドで実行できます。
$ ./bin/zoocompass compile --time --force --compile-threads 2
終わりに
だいぶ複雑になってきましたね。。
苦肉の策でもあるので、ほんとにどうしようもないときに。。とか使いどきを選んでいただきたい所存。
以上!
苦肉の策でもあるので、ほんとにどうしようもないときに。。とか使いどきを選んでいただきたい所存。
以上!
Knockout.jsで大規模開発してみた件について。
筆者の担当していた案件では、Knockout.jsを使って開発していました。今回はどんな感じで使ってたのか?というのを記事にしたいと思います。
Knockout.jsとは?
MVVM(Model-View-ViewModel)パターンをサポートするフレームワークです。
双方向バインディング云々…書こうとしましたが、こちらを参照したほうが良いでしょう。
わかりやすいです。
[Knockout]MVVMパターンでアプリケーションを構築する
どんな案件?
- 内容
webviewを使ったスマートフォン向けのアプリ開発。
- サポート端末
Android4.0以上
iOS6.0以上
- 案件規模
フロントエンジニアは5名程度。
- コード量
愚直に↓をしてみると、数十万行
$ find . -name "*.js" | xargs wc -l
いいとこわるいとこ
いいとこ
- 学習コストが低い
機能がシンプル(このくらい)というのもあるが、チュートリアルがしっかりしているので、これだけやればすぐ案件に入れるレベルになる。
チュートリアル:http://learn.knockoutjs.com/
- 機能はシンプルだが、拡張しやすい
data-bind内で指定する、バインディングを独自に拡張することができます。
例えば、
スマホの場合、clickイベントとtouchイベントを両方使うと問題が起きやすいので、
筆者の案件ではclickバインディングではtouchstartイベントを使うようにカスタムバインディングで上書きしている。
作り方は、こんなに簡単です↓
- ko.utilsというユーティリティがついてくる
地味に便利です。
ko.utils.unwrapObservableなどはカスタムバインディングを作る際によく使います。
- 分業できる
開発チーム内で、下記のように分業することができる。
フロントチームのコーディング担当
HTML+CSSを使ってViewのみを作成。作成後、JavaScript担当へパス。
独自タグもないので、とっつきやすい。
フロントチームのJavaScript担当
サーバーチームとAPIの設計について相談し、ViewModelを作成。
そして、コーディング担当から受け取ったViewにdata-bind属性を追加し動きをつける。
サーバーチーム
JavaScript担当と相談しAPIを作成する。
わるいとこ
- テストしづらい
Karma(mocha+sinon-chai)を使ってテストをするようにしましたが、Viewと紐付いているViewModelの実装はテストしづらかったです。
View側のテストもできないし、何かいい手はないかなーという感じでした。
(案件内ではテスト必須にはならず)
- だめというか、開発者が気をつけてなきゃいけないとこ
View側に複雑なロジックを入れないようにすること。
<!-- if hogehoge().length < 10 || nantokahuragu -->
このぐらいだとまだ良いが、ネストが深くなったり条件が複雑になると、可読性がものすごく下がる。
withの多様も要注意。
どんな感じで使ってたか
基本は、このような感じ。
(実際はファイル結合してminファイルを出力したり、styleはcssにちゃんと書いてたり、いろいろやってます。あと、ディレクトリ構成も適当です。)
javascriptでClass風の実装ができるようなライブラリを使い、継承して使用する。
※ 案件で使ってるコード・ライブラリではないです。
(バンバン継承しよう!というのは推奨せずでしたが。)
まあ、CoffeeScriptなりTypeScript使っとけよって感じかも知れませんが。
まあ、CoffeeScriptなりTypeScript使っとけよって感じかも知れませんが。
ある程度コードに規則性もできたので、保守しやすくなりました。
また、機能がシンプルというのもあり、
Knockout.jsのカスタムバインディングなどを使って、下記のような様々な仕組みも実装しました。
・1ページ内にViewModelが複数の場合の制御
・SEの制御
・ダイアログの制御
などなど
おわりに
フレームワーク選定の際に重視するのは、学習コストだったり運用のしやすさだと思うので、Knockout.jsは結構使いやすいんじゃないかなーと思いました。
また、使ってみてですが、筆者はKnockout.jsの不具合には遭遇しませんでした。
要素が多くなりすぎるとパフォーマンスに影響がでるということはありました。
(ko.applyBindings実行時に負荷がかかるが、Knockoutで処理させる箇所が数百箇所とかにならなければそんなに問題にならなかったです。)
小規模向け・プロトタイプで使うと良い。と書かれてる記事もよく見ますが、
小規模でも使いやすく、大規模でも使いやすいやつでした。
以上!
また、使ってみてですが、筆者はKnockout.jsの不具合には遭遇しませんでした。
要素が多くなりすぎるとパフォーマンスに影響がでるということはありました。
(ko.applyBindings実行時に負荷がかかるが、Knockoutで処理させる箇所が数百箇所とかにならなければそんなに問題にならなかったです。)
小規模向け・プロトタイプで使うと良い。と書かれてる記事もよく見ますが、
小規模でも使いやすく、大規模でも使いやすいやつでした。
以上!
WebRTCのRTCDataChannel APIを使って、複数人にデータを送信してみる
WebRTCで複数人接続してみるの続きです。今回は「RTCDataChannel API」を使って、データの送受信を試してみたいと思います。
複数人接続の記事の後なので、複数人に対してデータの送受信までを試してみます。
RTCDataChannel APIとは?
Peerの接続を利用して、データを送受信できる仕組み。・送受信できるデータ形式
Blob、ArrayBuffer、ArrayBufferViewのようなデータ形式をサポート。
・通信プロトコル
UDP、TCP、SCTPをサポート。
RTCDataChannel APIを使うには?
こんな感じで生成することができます。DataChannelの接続リクエストをハンドリングする。
これで送信する準備はオッケーです。
下記をconsoleから実行すると端末B側の「dataChannel.onmessage」が動作します。
remoteDataChannel.send("test test");
注意点ですが、Peerでの接続確立後に「peer.createDataChannel」をしても相手側の「peer.ondatachannel」は動作しませんでした。
オファー前に「peer.createDataChannel」をしとくと良いようです。
参考:http://blog.wnotes.net/blog/article/beginning-webrtc-datachannel
前回のソース(WebRTCで複数人接続してみる)を修正してみる
webrtc.jsを修正する・initの処理を変更(this.dataChannelsとthis.remoteDataChannelsを初期化させる処理追加
・connectの処理を変更(this.option.dataChannelsのif文を追加
・createDataChannelを新規追加
index.htmlを修正する
・createWebrtcInstanceの処理を変更(new するところに、dataChannelsを追加しただけ
追加してるコードは50行ぐらいです。
データ送受信の実行手順
1. WebRTCで複数人接続してみるの「作ってみた」の手順通り実施し、複数人接続をさせておく2. 全てのブラウザでDeveloper Toolsを開く
3. どれか1つでconsoleから下記を実行する
for (var i in webrtcTest.webRtcInstances) {4. 実行したタブ以外で、下記のようなメッセージがconsole上に流れていることを確認できる
if (i !== webrtcTest.localInstanceKey) {
webrtcTest.webRtcInstances[i].remoteDataChannels['test channel'].send("test dayo");
}
}
data channel message:test dayoできた!!
(個別に送信したい場合は、下記を実行する
webrtcTest.webRtcInstances[id].remoteDataChannels['test channel'].send("test dayo");※ idは送信したい端末のid
終わりに
ここまでやったらWebRTCはお腹いっぱい気味。つぎは、ファイルの送受信をできるようにするかなあ。。
(チャンクさせるようにするなんて面倒だ。。
まあ、そこまでやるならサービスレベルのものを作るときかなー。
あとは、peer.jsとかライブラリを使ってみるとか。
気が向いたらやります。
参考
・WebRTC data channelshttp://www.html5rocks.com/ja/tutorials/webrtc/datachannels/
・WebRTC-DataChannel使ってみたよ
http://blog.wnotes.net/blog/article/beginning-webrtc-datachannel
以上!
WebRTCで複数人接続してみる
WebRTCをさわってみる&手動シグナリングしてみるの続きです。今回は、WebRTCを使って複数人接続してみたいと思います。
1対1で接続するときとの違いは?
前回のおさらいですが、1対1で接続するとこんな感じになる。
図1. 1on1の接続 |
No | 端末A | 端末B |
1 | video要素を作っておく | video要素を作っておく |
2 | Peerを生成 | Peerを生成 |
3 | メディアに接続(カメラの起動を許可すること) ・Peerにストリームを接続し、自身の端末の状態をvideo要素で閲覧できる状態になる | メディアに接続(カメラの起動を許可すること) ・Peerにストリームを接続し、自身の端末の状態をvideo要素で閲覧できる状態になる |
4 | 端末Bへ送信するOfferを生成 | |
5 | 端末Aで生成したOfferを受信 | |
6 | 端末Aへ送信するAnswerを生成 | |
7 | 端末Bで生成したAnswerを受信 | |
8 | 端末Bへ送信する経路情報を出力 | |
9 | 端末Aで生成した経路情報を受信 | |
10 | 端末Aへ送信する経路情報を出力 | |
11 | 端末Bで生成した経路情報を受信 |
じゃあ、複数人接続の場合はどうなるのか?
3端末のときの接続を例として記述します。
上記のように接続するには、
端末Aと端末Bと端末Cがそれぞれ、下記のようなPeerを生成しなければなりません。
・端末Aと端末BをつなぐPeerの生成、端末Aと端末CをつなぐPeerの生成
・端末Bと端末AをつなぐPeerの生成、端末Bと端末CをつなぐPeerの生成
・端末Cと端末AをつなぐPeerの生成、端末Cと端末BをつなぐPeerの生成
そして、4台目が追加になる場合は更に1つずつPeerを生成することになり、
それを動的に通知して接続処理をするようにしなければなりません。
結構複雑っす。
どういう流れで複数接続させるか?
3端末での接続手順を記載します。(灰色のセルは端末未接続時・25〜38、25`〜38`は並行で処理されます)
No | 端末A | 端末B | 端末C |
1 | 特定URLにアクセス | ||
2 | socket.ioでコネクションをはる | ||
3 | コネクションをはってるユーザー全員にコールする | ||
4 | いなかったので終わり。 | ||
5 | 特定URLにアクセス | ||
6 | socket.ioでコネクションをはる | ||
7 | コネクションをはってるユーザー全員にコールする | ||
8 | 端末Bからコールされた | ||
9 | 端末Aのsocketのidを端末Bに返却する | ||
10 | 端末Aのsocketのidを返却される | ||
11 | Peerを生成 | ||
12 | socketのidを元に、端末AへSDPを送信(オファー) | ||
13 | Peerを生成 | ||
14 | 端末BのSDPを受信(オファーをレシーブ) | ||
15 | socketのidを元に、端末BへSDPを送信(アンサー) | ||
16 | 端末AのSDPを受信(アンサーをレシーブ) | ||
17 | 端末Aへ端末Bまでの経路情報を送信 | ||
18 | 端末Bから経路情報を受信 | ||
19 | 端末Bへ端末Aまでの経路情報を送信 | ||
20 | 端末Aから経路情報を受信 | ||
21 | Peer to Peer! | Peer to Peer! | |
22 | 特定URLにアクセス | ||
23 | socket.ioでコネクションをはる | ||
24 | コネクションをはってるユーザー全員にコールする | ||
下記のAとC / BとCのやりとりは並行して行われる | |||
25 | 端末Cからコールされた | ||
26 | 端末Aのsocketのidを端末Cに返却する | ||
27 | 端末Aのsocketのidを返却される | ||
28 | Peerを生成 | ||
29 | socketのidを元に、端末AへSDPを送信(オファー) | ||
30 | Peerを生成 | ||
31 | 端末CのSDPを受信(オファーをレシーブ) | ||
32 | socketのidを元に、端末CへSDPを送信(アンサー) | ||
33 | 端末AのSDPを受信(アンサーをレシーブ) | ||
34 | 端末Aへ端末Cまでの経路情報を送信 | ||
35 | 端末Cから経路情報を受信 | ||
36 | 端末Cへ端末Aまでの経路情報を送信 | ||
37 | 端末Aから経路情報を受信 | ||
38 | Peer to Peer! | Peer to Peer! | |
25` | 端末Cからコールされた | ||
26` | 端末Bのsocketのidを端末Cに返却する | ||
27` | 端末Bのsocketのidを返却される | ||
28` | Peerを生成 | ||
29` | socketのidを元に、端末BへSDPを送信(オファー) | ||
30` | Peerを生成 | ||
31` | 端末CのSDPを受信(オファーをレシーブ) | ||
32` | socketのidを元に、端末CへSDPを送信(アンサー) | ||
33` | 端末CのSDPを受信(アンサーをレシーブ) | ||
34` | 端末Bへ端末Cまでの経路情報を送信 | ||
35` | 端末Cから経路情報を受信 | ||
36` | 端末Cへ端末Bまでの経路情報を送信 | ||
37` | 端末Bから経路情報を受信 | ||
38` | Peer to Peer! | Peer to Peer! |
基本的な流れは1対1の時と一緒ですが、
Peerの生成タイミングや、Peer生成後にローカルのストリームとの接続手順などが変わってきます。
(「コネクションはっているユーザー全員にコールする」のレスポンスでオファー送ることもできた。そうすると、通信回数としては最小になりそう。)
作ってみた
このソースを使うと、↓↓のような画面がでるので、手順にそって作業してみてください。・シグナリングサーバー(Node.js)
これをして、node_modulesを取得してください。
$ npm installそして、これで起動する。
$ node app.js
・Webサーバー(Class風実装は特に見ないでいいです。。
(長いっすね。。
上記のソースをDocumentRoot以下に配置し、ブラウザからアクセスして、動作確認をしてみる。
1. 特定のURLへアクセス(筆者はここhttp://localhost/index.html
図3. カメラ・マイクへのアクセス確認 |
2. カメラの表示確認
図4. カメラ動画表示 |
そして、「ここを押したら繋がるけどカメラを先に許可しといてね」ボタンを押すことで、シグナリングサーバーへアクセスします。
(自分がページを開いてるよ。ってことを通知してるだけで、ここの手順では何も起こりません。)
※上記手順の1〜4です。
3. リモートのカメラ画像を表示する
図5. リモートのカメラ動画表示 |
終わりに。
タブを複数開いて通知確認しながらテストしてたのですが、頭がこんがらがるし、結構たいへんでした。シグナリングサーバーを応用! 「WebRTCを使って複数人で話してみよう」を参考にさせて頂きました!
つぎこそはDataChannelやるぞー!
以上!
Web ComponentsとPolymerをさわってみる。
いまさらですが、Web Componentsってナニ?
ってことをサラッと書きたいと思います。
下記のW3C 提案をまとめてWeb Components というらしい。
Custom Elements
⇒ ウェブ開発者が HTML に独自のタグを追加できる仕組み。
HTML Imports
⇒ HTML Imports は別ファイルに定義した Custom Elements をページ内に読み込む仕組み。
(プログラミング言語の require や import みたいなもの)
HTML Templates
⇒ ページ本体のDOMと切り離されたHTMLを生成することができる仕組み。
(HTML Templates に定義された <template> タグでテンプレート用の HTML を囲んでおくと、 ページ本体の DOM とは切り離され、<img> や <video> を書いてもロードはおこらないし、<style> は適用されず <script> は実行されない)
Shadow DOM
⇒ DOM要素のレンダリング結果を、その要素が持つDOM のサブツリーとは独立に与える仕組み。
(DOMツリーをカプセル化し、ページの他の部分からDOMツリーを分離することができる)
Web Animations
⇒ CSS Animations と CSS Transitions と SVG Animations を 統合する仕組み。
Pointer Events
⇒ マウス、タッチ、ペンのイベントを統一する仕組み。
そこで、Polymerの提供しているplatform.jsを使えば該当APIをJavaScriptで再実装し、ブラウザにまだない機能を補ってくれる。
Web ComponentsのPolyfillライブラリがplatform.jsで、その上で動作するUIフレームワークがpolymer.js。
Polymerにはdesigner toolもあり、コードを書かなくてもUIを生成することができます。
(使ったことないけど、いい感じなのかな?)
更に、Polymerにはレイアウトの例だったり、アイコン群のサンプルがあります。
PolymerとWeb Componentsの関連は、下記を見ると分かりやすいです。
(各APIの土台の上に、platform.jsがあり、polymer.jsがある)
*画像をお借りしました!
(/test/webcomponents/index.htmlにおく
ブラウザで下記URLにアクセスすると、こんな表示になるとはず。(線と右上のは気にしないでください…
http://localhost/test/webcomponents/index.html
ちなみに、polymer使用時のネットワークタブはこんな感じになります。
ソース見てて思ったんですが、結構直列で取得しにいってますね。
この順番で取得しにいってます。
1. test/webcomponents/index.html
2. bower_components/core-toolbar/core-toolbar.html
3a. bower_components/core-toolbar/core-toolbar.css
3b. bower_components/polymer/polymer.html
4a. bower_components/polymer/layout.html
4b. bower_components/polymer/polymer.js
この仕組み、結構遅いんじゃないの…
ということで、インラインにしてくれる仕組みなどが既にあるようです。
まあ、これだけじゃよく分からないと思うので、次回以降に詳細を書ければいいなーと思います。
Polymerウンヌンから入るより、Web Componentsの各APIの詳細を掘り下げていったほうが分かりやすい気がする。
ってことをサラッと書きたいと思います。
Web Componentsとは
Web Componentsは新しく提案されたウェブブラウザ向け API 一式の総称。下記のW3C 提案をまとめてWeb Components というらしい。
Custom Elements
⇒ ウェブ開発者が HTML に独自のタグを追加できる仕組み。
HTML Imports
⇒ HTML Imports は別ファイルに定義した Custom Elements をページ内に読み込む仕組み。
(プログラミング言語の require や import みたいなもの)
HTML Templates
⇒ ページ本体のDOMと切り離されたHTMLを生成することができる仕組み。
(HTML Templates に定義された <template> タグでテンプレート用の HTML を囲んでおくと、 ページ本体の DOM とは切り離され、<img> や <video> を書いてもロードはおこらないし、<style> は適用されず <script> は実行されない)
Shadow DOM
⇒ DOM要素のレンダリング結果を、その要素が持つDOM のサブツリーとは独立に与える仕組み。
(DOMツリーをカプセル化し、ページの他の部分からDOMツリーを分離することができる)
Web Animations
⇒ CSS Animations と CSS Transitions と SVG Animations を 統合する仕組み。
Pointer Events
⇒ マウス、タッチ、ペンのイベントを統一する仕組み。
Polymerとは?
新しいAPI に依存してしまい、一体どのブラウザなら動くのかということになる。そこで、Polymerの提供しているplatform.jsを使えば該当APIをJavaScriptで再実装し、ブラウザにまだない機能を補ってくれる。
Web ComponentsのPolyfillライブラリがplatform.jsで、その上で動作するUIフレームワークがpolymer.js。
Polymerにはdesigner toolもあり、コードを書かなくてもUIを生成することができます。
(使ったことないけど、いい感じなのかな?)
更に、Polymerにはレイアウトの例だったり、アイコン群のサンプルがあります。
PolymerとWeb Componentsの関連は、下記を見ると分かりやすいです。
(各APIの土台の上に、platform.jsがあり、polymer.jsがある)
図. PolymerとWeb Components |
Polymerを試してみる
・インストールする
(筆者はDocumentRoot以下の、/test/webcomponentsで実行
(筆者はDocumentRoot以下の、/test/webcomponentsで実行
# Bower のインストール・実行用のソースを用意する
$ sudo npm install bower -g
# 初期化処理
$ bower init
# Polymer のインストール
$ bower install --save Polymer/polymer
# コンポーネントのインストール
$ bower install --save Polymer/core-elements
$ bower install --save Polymer/paper-elements
(/test/webcomponents/index.htmlにおく
<!DOCTYPE HTML>・アクセスする
<html lang="ja">
<head>
<meta charset="UTF-8">
<title></title>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="bower_components/core-toolbar/core-toolbar.html">
</head>
<body>
<core-toolbar>TEST</core-toolbar>
</body>
</html>
ブラウザで下記URLにアクセスすると、こんな表示になるとはず。(線と右上のは気にしないでください…
http://localhost/test/webcomponents/index.html
図. core-toolbarをつかう |
ちなみに、polymer使用時のネットワークタブはこんな感じになります。
図. polymer使用時のネットワークタブ |
この順番で取得しにいってます。
1. test/webcomponents/index.html
2. bower_components/core-toolbar/core-toolbar.html
3a. bower_components/core-toolbar/core-toolbar.css
3b. bower_components/polymer/polymer.html
4a. bower_components/polymer/layout.html
4b. bower_components/polymer/polymer.js
この仕組み、結構遅いんじゃないの…
ということで、インラインにしてくれる仕組みなどが既にあるようです。
まあ、これだけじゃよく分からないと思うので、次回以降に詳細を書ければいいなーと思います。
Polymerウンヌンから入るより、Web Componentsの各APIの詳細を掘り下げていったほうが分かりやすい気がする。
終わりに
この技術が標準化されてきたら、Web業界の職種も変わってきそうですね。
web componentsストアみたいなのできないかなー
参考にさせて頂きました!
Web Component概要
web componentsストアみたいなのできないかなー
参考にさせて頂きました!
Web Component概要
Polymer と Web Components
以上!
WebRTCをさわってみる&手動シグナリングしてみる
今回は、WebRTCについて書きたいと思います。WebRTCって何ぞ?
WebRTCって何ぞ?ってとこから書きたいなと思ったのですが、他の方の記事見てるとよく書けてるな。。
改めて書く必要ないんじゃないかな。。
図ないと分かりづらいよな。。面倒だなこれ。。
って感じになりました。
ということで、WebRTCって何ぞ?とかは下記の記事を参考にしてください!
・WebRTCを仕組みから実装までやってみる
http://blog.wnotes.net/blog/article/webrtc-beginning
・WebRTCで変わるWebの未来
http://www.qcontokyo.com/data_2013/ToruYoshikawa_QConTokyo2013.pdf
んで、今回書くのは
P2Pで通信を開始するまでのシーケンスを1手順ずつ、自分でわかるように、自分のために書きます。
今回やろうとすること
端末A・端末BをPeer to Peerし、Macに内蔵しているカメラで撮影している内容をリアルタイムに共有するところまでやる。
必要っぽいもの
シグナリングサーバーICEサーバー(STUN / TURN)
と思ったけど、シグナリングは手動でできそうだし、ICEサーバーだけでいいんじゃないか感。
ということで、今回は↓でやります。
・シグナリングは手動
・Googleが提供しているSTUNサーバー
接続手順
事前準備(共通)No | 端末A | 端末B |
1 | video要素を作っておく | video要素を作っておく |
2 | Peerを生成 | Peerを生成 |
3 | メディアに接続(カメラの起動を許可すること) ・Peerにストリームを接続し、自身の端末の状態をvideo要素で閲覧できる状態になる | メディアに接続(カメラの起動を許可すること) ・Peerにストリームを接続し、自身の端末の状態をvideo要素で閲覧できる状態になる |
この作業は接続する端末共通です。
ここまで実施することで、ブラウザで自身の姿が見れるようになるはずです。
接続対象へSDPを送受信してセッションを確立
Simple Traversal of UDP through NATs (STUN): NAT越えの方法としてRFC3489で定められた標準的な仕組み。
外部のSTUNサーバに対してクライアントが一度接続し、グローバルIPとマッピングされたポート番号を記憶しておくことで、そのデータを使ってPeerは相手のマシンを特定することができる。
No | 端末A | 端末B |
4 | 端末Bへ送信するOfferを生成 | |
5 | 端末Aで生成したOfferを受信 | |
6 | 端末Bへ送信するAnswerを生成 | |
7 | 端末Bで生成したAnswerを受信 |
リモート側のストリームを共有する
接続経由を共有することで、端末Aと端末BをPeer to Peer接続する。
No | 端末A | 端末B |
8 | 端末Bへ送信する経路情報を出力 | |
9 | 端末Aで生成した経路情報を受信 | |
10 | 端末Aへ送信する経路情報を出力 | |
11 | 端末Bで生成した経路情報を受信 |
ここまでくると、接続した端末のカメラの動画が表示されるようになっているはずです。
まとめて書くと、こんな手順です。
No | 端末A | 端末B |
1 | video要素を作っておく | video要素を作っておく |
2 | Peerを生成 | Peerを生成 |
3 | メディアに接続(カメラの起動を許可すること) ・Peerにストリームを接続し、自身の端末の状態をvideo要素で閲覧できる状態になる | メディアに接続(カメラの起動を許可すること) ・Peerにストリームを接続し、自身の端末の状態をvideo要素で閲覧できる状態になる |
4 | 端末Bへ送信するOfferを生成 | |
5 | 端末Aで生成したOfferを受信 | |
6 | 端末Aへ送信するAnswerを生成 | |
7 | 端末Bで生成したAnswerを受信 | |
8 | 端末Bへ送信する経路情報を出力 | |
9 | 端末Aで生成した経路情報を受信 | |
10 | 端末Aへ送信する経路情報を出力 | |
11 | 端末Bで生成した経路情報を受信 |
手動でやると面倒ですね。これ。
接続してみよう!
コードはこんな感じ(1〜11の上記手順通り番号をつけています。このコードをブラウザで表示すると、こうなります。
図. webrtcテストサンプル |
(カメラを許可すると、左上に端末A(自分の顔)が表示されます。
では、ブラウザを2つ立ち上げ(別のPCでも可)、端末Aと端末Bとして作業してみましょう。
4〜11は下記のような作業が必要なので実行してみてください。
図. 手順説明用 |
No | 端末A | 端末B |
4 | 端末Bへ送信するOfferを生成 ・Developer ToolsのConsoleで下記を実行し、表示される文字列をコピーする(文字列に変換して表示されてるやつ webrtc.createOffer() | |
5 | 端末Aで生成したOfferを受信 ・4でコピーした文字列をブラウザに表示されてるテキストエリア左側(図の①)に貼り付け、Consoleから下記を実行する webrtc.receiveSdp() | |
6 | 端末Aへ送信するAnswerを生成 ・Consoleで下記を実行し、表示される文字列をコピーする(文字列に変換して表示されてるやつ webrtc.createAnswer() | |
7 | 端末Bで生成したAnswerを受信 ・6でコピーした文字列をブラウザに表示されてるテキストエリア左側(図の①)に貼り付け、Consoleから下記を実行する webrtc.receiveSdp() | |
8 | 端末Bへ送信する経路情報を出力 ・Consoleで下記を実行し、表示される文字列をコピーする(文字列に変換して表示されてるやつ webrtc.displayCandidates() | |
9 | 端末Aで生成した経路情報を受信 ・8でコピーした文字列をブラウザに表示されてるテキストエリア右側(図の②)に貼り付け、Consoleから下記を実行する webrtc.receiveCandidates() | |
10 | 端末Aへ送信する経路情報を出力 ・Consoleで下記を実行し、表示される文字列をコピーする(文字列に変換して表示されてるやつ webrtc.displayCandidates() | |
11 | 端末Bで生成した経路情報を受信 ・10でコピーした文字列をブラウザに表示されてるテキストエリア右側(図の②)に貼り付け、Consoleから下記を実行する webrtc.receiveCandidates() |
11を実行することで、右上に端末B(相手の顔)が表示されます。
おわりに
手動でやるとことで、流れがだいぶ理解できました。
今度は自動でシグナリングするようにして、DataChannelでもいじってみたいと思います。
以上!
Android4.4 WebviewでGoogle NotoSansを使ってハマったポイント
筆者がAndroid4.4のWebviewでNoto Sansを使った際にハマった点を忘れないように書いておきます。Noto Sansってなに?
Noto SansとはGoogleとAdobeが共同で開発したフリーフォントです。
AdobeからはSource HanSansという名称でリリースされています。
Noto Sans Japanese |
Noto Sansは無償で使えるうえ、改編・再配布も可能です。
日本語にも対応しており漢字も多く扱っています。
ウェイトも7種類用意されておりクオリティーも高い。
つまり、とても素敵なフォントだと言うことです。
Noto Sans Japanese
ハマりポイント
で、何にハマったかと言うと、、
Android4.4だけ文字が上にズレてしまうんです(泣)
Android4.4以外 |
Android4.4 |
調べてみるとこんなことが、
`Android Chromeでline-heightがかわる?`
どうやら、Android4.4ではベースラインが少し上に上がっているようです。
リンク先のブログさんと同じく、
User agentがAndroid4.4であればline-heightを調整するよう対応しました。
通常のNoto Sansでは発生しなかったので、日本語が入っているとベースラインが狂うのかもしれないです。このへん詳しくはわかっていません。
CSS3アニメーションでハマったこと。
筆者が以前担当していたWebviewを使ったスマホアプリの案件で、CSS3でFlashバリのアニメーションを作る。ということをやったので、その時にハマったことを書いていきたいと思います。
既存のFlashアニメーションをスマホでも表現したいと言われたのが背景です。
ツールとかは使わず、独自に書いていくスタイルでした。(1人でやってた。
どんな案件?
下記をサポートしたWebviewアプリ。Android2.3系
Android4.x系
iosのいくつか忘れた
ハマったポイント
再現機種 | 現象 | 原因 / 対策 |
Gylaxy S XperiaAcroHD (Android2.3系) | border-radiusを指定しても、角丸が再現できない。 | 特定のAndroid端末では、border-radiusで%(パーセント)指定ができない。 bordera-radiusをpx指定にする。 |
Android2.3系 | animation-fill-modeプロパティを指定していても、アニメーション後の表示を維持することができない。(forwards) | サポートしていないプロパティだった。 筆者は、予めアニメーション終了後のプロパティを指定しておくことで回避した。 |
Android2.3系 | -webkit-filterを指定しても、画像にエフェクトがかからない。 | サポートしていないプロパティだった。 エフェクトのかかった画像にするなどして、使わないようにする。 |
Gylaxy S3 一部Android? | アニメーション中、画像がちらつく。 | -webkit-backface-visibility:hiddenを指定すると収まる。 要素全体を囲むと別の要因を引き起こすこともあるので、使うときは要注意。 |
Gylaxy S XperiaAcroHD (Android2.3系) | -webkit-transform:scale で要素が拡大できない。 | -webkit-backface-visibility:hiddenを指定していることが原因だった。 拡大したい要素には指定しないようにする。 |
Android2.3系 | 一気に複数のアニメーションをスタートさせるとカクつく・アニメーションが変な動きをする | そもそも、一気に複数のアニメーションをスタートさせないように作る。 どうしてもっていう場合は、keyframeの0%〜50%を動作させない・0.5秒後からアニメーション実行させるなど遅延実行にすると大丈夫だった。 |
iOS6? | z-indexが効かない。 | 親要素でもz-indexを指定してあげることで効くようになった。 |
Android2.3系 | overflow:scrollが効かない。 | CSSでスクロールできないのでJSを使ってスクロールさせる必要がある。 |
Android2.3系 | モーダル時、下部の要素のイベントが発火してしまう。 | 上の要素のタップイベントを通り越して下の要素のタップイベントが発火する。 jsで、e.preventDefault()でイベントをキャンセルさせる。 |
Android4.0x系 | jsでクラスを置き換えても、表示が切り替わらないことがある。 | 再レンダリングが走らない? 原因分からず。 |
Android2.3系 | アニメーションを0%、100% のみで指定すると、アニメーション中に他要素のtransformが効かなくなることがある。 | keyframesを指定を0%と100%のみにすると、他の要素のtransformプロパティが効かなくなる。 対策としては、0%と50%と100%を指定する。(間に1つ挟むと大丈夫だった。 |
この他にも色々ありましたが、曖昧なものも混ざってるため記述しません。
また、他のサイトでも色々報告があがっていたので参考になりました。
・AndroidやiPhoneのHTML,CSS,JavaScriptのバグまとめ
http://blog.webcreativepark.net/2012/03/13-093853.html
・[css, css3, html] スマートフォン(iPhone, Android)ブラウザのバグまとめ
http://tenderfeel.xsrv.jp/css/1177/
http://blog.webcreativepark.net/2012/03/13-093853.html
・[css, css3, html] スマートフォン(iPhone, Android)ブラウザのバグまとめ
http://tenderfeel.xsrv.jp/css/1177/
終わりに
完全に、工数に見合わない作業でした。
Android2.3系だとAdobe EdgeとかSenchaAnimatorとかでもキレイに動かないし。。
実装時は、Android2.3系から確認して書いていくのが正。
いや、Android2.3系はサポート対象外にするのが正。
そうすると、みんな幸せに。。
Android2.3系だとAdobe EdgeとかSenchaAnimatorとかでもキレイに動かないし。。
実装時は、Android2.3系から確認して書いていくのが正。
いや、Android2.3系はサポート対象外にするのが正。
そうすると、みんな幸せに。。
以上!
登録:
投稿
(
Atom
)
0 件のコメント :
コメントを投稿