テレビのインターネット接続機能
「テレビ視聴データに関する民放5社共同の技術検証および運用実証実験」ってニュースが流れてたけど、そもそも「テレビ視聴データって何?」「どうやって取ってるの?」「Dボタンを押さなくても勝手に通信するの?」と疑問が浮かび調べてみた。
この記事で扱っているデータは、5社共同実験の期間終了後なので、他社と視聴ログを共有しない「テレビ朝日 - 視聴データの取扱いについて」の挙動と考えます。
この記事では扱っておりませんが、他局( フジテレビ / TBS / テレビ東京 / 日本テレビ / NHK )からも同様の告知が出ていることから、他局も同様の機能を持っていると考えられます。
作業環境
- スイッチは「NETGEAR GS108Ev2」
 テレビを接続したポートからパケットキャプチャを接続したポートへのミラーポートを設定。
- パケットキャプチャは「Wireshark」
 「テレビのMACアドレスを含むパケットのみ取得」する設定でキャプチャ
 Windows10のノートPCで起動
- テレビは「SHARP LC-22L5」
 ごく普通の2011年製22型
- PC用のテレビチューナーは「アースソフト PT3」
 「TS抜き」で使えるBonDriver対応チューナー
視聴データ送信条件確認
とりあえずNHKに合わせて数分待ってみたけど通信なし。
チャンネルをテレビ朝日に合わせると何かのパケット取れた。
平文で送られてたので、内容も読めた。
下記のパケットを15秒間隔で送っていた。
URL
 http://d-log.tv-asahi.co.jp/from-to
PostData
 Form item: "Denbun" = "luid=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ&event_id=2837&network_id=7FE5&service_id=0428&zip_code=999-9999&status_code=0&optin=0&maker_id=11&maker_ver=001&minor_ver=021&time_from=20200211235658&time_to=20200211235732"
- 
luid=ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZは、端末識別IDっぽい物が入っていたのでマスク。[A-Za-z0-9-]な感じのランダム文字列。
- 
event_id=2837は、調査時に見ていた番組のID。
- 
network_id=7FE5&service_id=0428はテレビ朝日のチャンネルIDと思われる。
- 
zip_code=999-9999は、テレビの初期設定で入力したと思われる自宅の郵便番号が入っていたのでマスク。
- 
テレビのDボタンを押して、「視聴データについて」の画面を表示した時に何か通信してる 
- 
「視聴データについて」の画面で「協力する」「協力しない」を切り替えると何か通信してる 
- 
テレビ朝日以外は数分見ただけでは視聴データっぽいパケットは取れなかった 
 間隔が長いのか、通信処理が入ってないのか判らないけど、容易に取れたテレビ朝日をサンプルにした。
 他の局もdボタンを押して「視聴データ」画面を表示すると何か通信してる。
端末識別IDはどこから湧いて来るの?
- 動いてるスクリプトを読みたいけど、テレビ内の動きを読むのは難しい。
- PCでデータ放送対応したアプリ持ってないから、取り出す方法を探してみた。
データ放送の仕組みとか
- 
Broadcast Markup Language (BML)(Wikipedia) 
- 
データ放送は「BMLブラウザ」で表示する様だけど、それらしいアプリを知らなかった。 
- 
スクリプトはECMA Script 
- 
テレビのデータはMPEG2-TS形式で配信されており、データ放送のリソースはMPEG2-TSのDSM-CCデータカルーセルで配信されてる。 
 「カルーセル」は回転木馬的な意味で、途中から視聴始めた人もデータを受信できるよう、同じデータを繰り返し配信する方式。
- 
録画アプリはデフォルトで「映像、音声、字幕」を記録して、データカルーセルは捨てられる? 
 データ放送も記録したい場合は、データカルーセルも入る設定でTSファイルに保存する必要がある。
 同じファイルが繰り返し送られて来るので、ファイルサイズが肥大化しそう。通常運用で録画ファイルに加えるなら、ファイルが更新された場合のみ記録するような設定が欲しい。既にそうなってるかも?
MPEG2-TSの解析
- 日本のテレビ放送規格はISDB(Wikipedia)
- 規格文章はARIB(電波産業会)の「標準規格」と「技術資料」で、データ放送は「STD-B24」辺り。
- MPEG2-TSから PAT → PMT → DII(DownloadInfoIndication) → DDB(DownloadInfoIndication) と解析していけば良いっぽいけど、無料公開されてる規格書は英語のみで、日本語版は有料販売しかなかった。
- WiresharkでTSファイルを開くと、DSM-CCまで対応してるっぽいのでいくつか眺めてみたけど、圧縮されてる様でテキストっぽい文字列は見つからなかった。(MIMEヘッダっぽいのがあったかも)
- ググっていると「TSDataExtractor」なるものを見つけたので方針転換。
TSDataExtractorの入手
- 2ちゃんねるのDTV板発祥(たぶん)。公開当時のアップローダは何らかの原因で消えたっぽい。
- ググって「up0136.zip データ放送用プログラム詰め合わせ その2」を拾ってきた。
- バイナリも入ってたけど、怪しい所から拾ったファイルは怖いのでソースを斜め読みして、ヨシッ!と言ってビルドする。
- 「zlib」のソ-スが必要と書いてたので、ソースを入れてみたけど、VisualStudio2019がファイルが足りないと怒るので、プロジェクトから「*.cpp」と「*.h」を抜いて、フォルダに入ってるファイルを登録し直したら通った。ReadMe読み返すと version 1.2.3 と書いてたので、最初からそれを入れれば良かったのでは?(今回は1.2.11を使った)
- ビルドで出力された「TSDataExtractor.tvtp」は、TVTestのプラグインファイル。
- ついでに「BTBViewer.exe」「clt2png.exe」もビルドした。
- 「BTBViewer.exe」はアプリを開き直すと、画面外にウィンドウが現れた。(マルチモニタに対応してないっぽい?)
- 「BMLAnalyzer.exe」も気になるけど、ソース付いて無いので見なかったことにした。
TVTestの入手
- 何らかの圧力でバイナリは公開できないっぽい。
- ググってビルドする。
- BonDriver関係は、EDCBで使ってるPT3のをそのままコピーしたので、録画予約時間に起動するとダメかも。
データ放送のファイル書き出し
- TVTestの「Plugins」フォルダに「TSDataExtractor.tvtp」プラグインを入れる。
- 右クリックでコンテキストメニューを出して、「プラグイン」→「TSDataExtractor」にチェックを入れプラグインを有効にすると、「TSDataExtractor」ウィンドウが開く
- データを取得したい番組を表示する
- 「TSDataExtractor」ウィンドウに何か出るので、データが貯まって安定するまで待つ。(15秒くらい?)
- 「TSDataExtractor」ウィンドウの「ファイル」→「現在のサービスを保存」で、ファイルを書き出す。
出てきたファイル
- *.bml
- XMLベースのhtmlっぽいファイル
- *.css
- 多分名前の通り
- *.ecm
- スクリプトファイル
- *.btb
- バイナリーテーブル(DBとかCSVみたいな)
 スクリプトからファイル名とテーブル定義を指定して扱えるっぽい
 例)BinaryTable(this.getPath("log-conf.btb"),"2,S:1V,S:1B,S:2V")
- *.jpg
- 画像ファイル
- *.png
- データ放送規格の画像ファイル。「clt2png」でパレット情報を追加すると一般的なPNGファイルになるっぽい
- *.clt
- PNGから分離されたパレット情報?
スクリプトを読む
- パケットに入ってた文字列で検索すると「EXT_function.ecm」がヒット
- それらしい処理を抜粋して、改行とコメント追加。
 抜粋前のファイルサイズは28KBくらい
//視聴データ送信処理
function LOG_Obj_sendBeacon(){
	if( !this.beaconIsPause ){
		if( this.linkId=="" || this.optoutFlg==1 ){
			return false;		//端末識別IDが未設定 か OptOut設定 なら処理中止
		}
		var b=new Date();
		var c="";
		var e=browser.Ureg[this.UREG_IDX].split("_");
		var d=this.deleteDateStringMark(new Date().toString());
		var a="-";
		if( e.length==3 && e[1]!="" ){
			a=this.deleteDateStringMark(e[1]);
		}
		c+="luid="+this.linkId;					//★端末識別ID
		c+="&event_id="+COMMON.getEventId();	//番組ID
		c+="&network_id="+COMMON.network_id;
		c+="&service_id="+COMMON.service_id;
		c+="&zip_code="+COMMON.zip;				//郵便番号
		c+="&status_code="+this.beaconStatusCode;
		c+="&optin="+this.optinFlg;
		if( this.canSendCrossLog==1 && CROSSLOG.validCrossId() ){
			c+="&cross_id="+CROSSLOG.crossId;
		}
		c+="&maker_id="+COMMON.maker_id;
		c+="&maker_ver="+COMMON.major_ver;
		c+="&minor_ver="+COMMON.minor_ver;
		c+="&time_from="+a;
		c+="&time_to="+d;
		if( this.fromPreDate!="-" && this.fromPreDate!="" ){
			c+="&time_from_pre="+this.deleteDateStringMark(this.fromPreDate);
		}
		if( this.toPreDate!="-"&&this.toPreDate!="" ){
			c+="&time_to_pre="+this.deleteDateStringMark(this.toPreDate);
		}
		this.transmission(this.logConf.API_URL_FROMTO,c);	//ビーコン送信
		var f=new Date();
		if( browser.subDate(f,b,1)>this.logConf.BEACON_TIMEOUT ){
			this.beaconStatusCode=1;
		}
	}
	this.beaconLastTransmitDate=new Date();
	return true;
}
//端末識別ID生成処理
function LOG_Obj_setNewLinkId(){
	if(!COMMON.isIP){
		return"";
	}
	var a=this.transmission(this.logConf.API_URL_LUID,"");
	this.linkId=this.formatLinkIdParam(a.receiveTextData);
	if(this.linkId!=""){
		this.writeOptoutNVRAM();
	}
}
function LOG_Obj_formatLinkIdParam(b){
	var a="";
	if( b!=null && b.length==32 && b.lengthByte()==32 ){
		a=b;
	}
	return a;
}
- ソースの上の方にthis.formatLinkIdParam=LOG_Obj_formatLinkIdParam;の記述がある
- 端末識別IDは http://d-log●tv-asahi●co●jp/luid から貰った値をそのまま使うっぽい。
 テレビの製造番号やB-CASカード番号から生成してるのかと思ったけど、Cookie的な物だった。
- linkId(端末識別ID) は、テレビのNVRAMに保存されるっぽい
参考テーブルファイル
- 「BTBViewer.exe」で開き「2,S:1V,S:1B,S:2V」で閲覧
- 「log-conf.btb」が視聴データ収集用の設定ファイルっぽい。
- 「crosslog-conf.btb」の用途は調べてないけど、コレを参照してるコードもあった。
API_URL_LUID	S	http://d-log.tv-asahi.co.jp/luid
API_URL_BEACON	S	http://d-log.tv-asahi.co.jp/logging
API_URL_FROMTO	S	http://d-log.tv-asahi.co.jp/from-to
API_URL_OPTOUT	S	http://d-log.tv-asahi.co.jp/optout
API_URL_OPTOUT_PV	S	http://d-log.tv-asahi.co.jp/optout-pv
BEACON_INTERVAL	N	15
BEACON_TIMEOUT	N	15
BEACON_TIMEOUT_WAIT	N	600
HC_ENABLE		B	0
LINKID_BUNSAN	N	30
D_AIT_ID		S	d-ait
FIRST_BEACON_INTERVAL	N	15
PANA_SMTBOX		B	0
API_URL_CREATE	S	http://mic-tvid.yourtv.jp/spot/dtv/7fe5/create
API_URL_RELAY	S	http://mic-beat.yourtv.jp/spot/dtv/7fe5/relay
API_URL_OPTOUT	S	http://mic-tvid.yourtv.jp/spot/dtv/7fe5/optout
API_URL_ADDRESS	S	http://mic-tvid.yourtv.jp/spot/dtv/7fe5/address
ID				S	Logtrial0002
PASS_KEYCODE	S	21-22-23-22-21
その他
- Webブラウザの「クッキーを削除」に相当する機能は無いの?
 データ放送画面では「同意する/しない」の選択肢しか見つからなかった。
 テレビの設定画面に「個人情報初期化」があったので、設定やり直す手間を惜しまなければ消せそう。
- テレビを買った時の初期設定で入力する郵便番号が、外部に送信される物だと思わなかった。プライバシーを重視する人は要注意。
- 平文で良いの?暗号化しよ?
 マンションや寮のインターネットみたいに脆弱な回線だとプライバシー的にダメかも?
 新しいテレビならSSL/TLS通信使うとか出来ないのかしら?スクリプト書くの面倒だからやってないだけかも。
- EUのGDPRにより「Cookieの利用を許可しますか?」と執拗に確認されるWebと、端末を一意に識別するIDをNVRAMに保存し、それをこっそり送信する挙動が許されるテレビのギャップ。
- テレビをネットに接続すると裏で勝手に通信するのって、視聴者は知ってるのかしら?
 所有者の意図しない動作させたらCoinhiveみたいに逮捕されない?
- Qiitaを使ってみたかったので使ってみた。はじめてのMarkdown。なるほど便利。