モーグルとカバとパウダーの日記

モーグルやカバ(EXカービング)山スキー(BC)などがメインの日記でした。今は仕事のコンピュータ系のネタが主になっています。以前はスパム対策関連が多かったのですが最近はディープラーニング関連が多めです。

Ustreamでチャンネルをリアルタイム切り替え出来る「Ucastation」

この週末、長野県大町市の美麻地区で全日本大学対抗選手権ロードレースが開催されました。


その時、Ustreamを使ってマルチチャンネル(複数カメラ)での配信を行いました。
山間でワイヤレスの回線状況は非常に弱いため、6地点に固定のカメラを置いて、地区内に導入されているケーブルインターネット網を経由して、動画を上げました。
ロードレースのような場合だと、だいたい集団は固まっていますので、次見てもらいたいチャンネルというのはほぼ決まってきます。
そこで、去年は6チャンネルマルチ画面で見てもらったのですが、今年は配信側が今見て欲しいチャンネルを選択出来るシステムを作って提供しました。
つまり、よくテレビのスポーツ中継でマルチカメラを切り替えながら放送しているような、それに近い事が出来るわけです。


このシステムには「Ucastation」という名前を付けました。


下記URLから、見に来た人が見ていたページと、管理用のデモページを利用できます。
管理側画面からは、左上のラジオボタンでチャンネルの切り替えと、レース状況などの告知用掲示板が使えます。
実際に動きを試すことが出来ますので、ウインドウを2つ開いて管理用ページの操作で動画が切り替わるのを試してみてください。


Ucastation view page
http://miasa.info:2011/


Ucastation admin page
http://miasa.info:2011/admin.html


これ、Ustream本家で出来ても良いような機能だと思うのですが、実際には出来ません。
ではどうやって実現しているかというと、node.jsとsocket.ioを利用して、view pageを見ている人に今見て欲しいチャンネル名を送ってやり、ブラウザ側でそのチャンネルの動画を表示し直す、としているのです。


コアとなる部分のソースはこんな感じです。実際のソースからチャンネル変更の機能がらみだけを抜粋してます。

【ucastation.js】

var conf = {
  port : 20011,
  admin_password : '***password***'
};

var express = require( 'express' );
var app = express.createServer();
var io = require( 'socket.io' ).listen( app );

app.configure( function() {
  app.use( express.static( __dirname + '/public' ) );
});
app.listen( conf.port );

var channel;

// viewとの通信
var view = io.of( '/view' ).on( 'connection', function( client ) {
  // 接続時、クライアントに現在のチャンネルを送信
  if ( channel ) {
    client.emit( 'channel', channel );
  }

  // 切断処理
  client.on( 'disconnect', function() {
    console.log( "disconnect" );
  });
});

// adminとの通信
var admin = io.of( '/admin' ).on( 'connection', function( client ) {
  var login = false;

  // 管理者のログインリクエスト
  client.on( 'admin login', function( password, fn ) {
    if ( password == conf.admin_password ) {
      console.log( "admin login success." );
      login = true;
      fn( "OK admin login" );
    }
    else {
      console.log( "warning! admin password failer." );
      login = false;
    }
  });

  // チャンネル変更
  client.on( 'admin channel', function( ch, fn ) {
    if ( login == true ) {
      console.log( "admin channel" );
      channel = ch;
      view.emit( 'channel', channel );
      fn( "OK admin channel" );
    }
    else {
      console.log( "warning! not login." );
    }
  });

  // 切断処理
  client.on( 'disconnect', function() {
    console.log( "disconnect" );
  });
});

console.log( "Server started." );

【admin.js】

var port = 20011;
var password = '***password***';

var socket = io.connect( "/admin", { port: port } );

socket.emit( 'admin login', password, function( reply ) {
  if ( reply == "OK admin login" ) {
    $("#condition").html( "<div class='alert-message success'>管理者認証成功</div>" );
  }
});

socket.on( 'connect', function() {
  $("#condition").html( "<div class='alert-message success'>接続成功</div>" );
});

socket.on( 'disconnect', function() {
  $("#condition").html( "<div class='alert-message error'>切断</div>" );
});

function sendChannel( channel ) {
  $("#condition").html( "<div class='alert-message info'>チャンネル送信中...</div>" );
  socket.emit( 'admin channel', channel, function( reply ) {
    if ( reply == "OK admin channel" ) {
      $("#condition").html( "<div class='alert-message success'>チャンネル送信成功</div>" );
    }
  });
}

【view.js】

// WebSocketでの通信部分
var port = 20011;

var socket = io.connect( "/view", { port: port } );

socket.on( 'connect', function() {
});

socket.on( 'channel', function( channel ) {
  Player.play( channel, 'ust_main' );
});


いろいろ端折ってあるし、Ustの動画を表示するjavascriptとかも必要ですが、こんなに短いコードでこんなことが書けちゃいます。
Coffeeスクリプトの書式で書いたらさらに短く、2/3くらいで済むのではないでしょうか。node&websocketすげえ!


ちなみにgithubはここ。小汚いソースですが、なにか参考になれば。

https://github.com/stealthinu/ucastation


Ucastationは、まだまだα版という感じで上手く動かない状況もあるようだったりしますが、今後もいろいろ機能アップを考えているところです。