FlvPlayBack Component エラー + AS3
2009年08月17日 21:41
最近のプロジェクトを通して納期の都合上 FlvPlayBack を本格的に使ってみたのだけど、「存在しない Flv の URL を source に指定するとエラーが取得出来ない。」という挙動に悩まされた。色々なパターンで様々な挙動をするので気づいた点を忘れない様にメモ。
FlvPlayBack の source プロパティに存在しない URL を設定した場合に Error が Throw されるんですが、これは try/catch で処理すればと思って色々トライしてみたんですが、全然 catch してくれませんでした。source を指定して FlvPlayBack を play する流れで、おそらく処理的なタイムラグなのか play がコールされた後に source 側で Error を Throw するのでどうしてもプログラム上でエラーを catch 出来ないのではないのかなとか考えてます。
例えば、http://www.test.com/no.flv という存在しない URL を FlvPlayBack の source に設定すると下記の様なエラーが起こってしまい、完全にプロセスが止まってしまいます。
compPlayer.source = "http://www.test.com/no.flv";
try
{
compPlayer.play();
}
catch(e:Error)
{
trace("@@@ ERROR @@@ " + e);
}
Error opening URL 'http://www.test.com/no.flv'
VideoError: 1000: Unable to make connection to server or to find FLV on server
at fl.video::VideoPlayer/stop()
at fl.video::FLVPlayback/http://www.adobe.com/2007/flash/flvplayback/internal::showFirstStream()
at fl.video::FLVPlayback/http://www.adobe.com/2007/flash/flvplayback/internal::handleVideoEvent()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at fl.video::VideoPlayer/http://www.adobe.com/2007/flash/flvplayback/internal::setState()
at fl.video::VideoPlayer/http://www.adobe.com/2007/flash/flvplayback/internal::httpNetStatus()
この様な静的な URL の設定の場合は書き間違えさえしなければ問題ないのですが、動的に処理する時には問題なので、ここの方が setTimeOut で解決しているみたいなので自分も同様に Timer を使って処理を加えて対応してみました。しかし、機能を切り出しモック的に対応すると動作が正常に動いても、本番環境では安定した挙動をしませんでした。一応色々な状況の挙動を試してみたので、下記に記述しておこう。
(1) 何の問題もない静的で正しい URL にアクセス
いずれかも正しく挙動。
compPlayer.source = "http://www.convexstyle.com/existing.flv";
もしくは
compPlayer.play("http://www.convexstyle.com/existing.flv");
(2) 存在しない相対パスの flv にアクセス
Error はキャッチされない。
compPlayer.source = "no.flv";
try
{
compPlayer.play();
}
catch(e:Error)
{
trace("@@@ ERROR @@@ " + e);
}
(3) 存在しない相対パスの flv に Timer を使ってアクセス
Error がキャッチされた。
var timer:Timer = new Timer(0, 0);
timer.addEventListener(TimerEvent.TIMER, onPlayHandler, false, 0, true);
compPlayer.source = "no.flv";
timer.start();
function onPlayHandler(evt:TimerEvent):void
{
timer.stop();
try
{
compPlayer.play();
}
catch(e:Error)
{
trace("@@@ ERROR @@@ " + e);
}
}
(4) 存在しない絶対パスの flv に Timer でアクセスするテスト
Error がキャッチされない。
var timer:Timer = new Timer(0, 0);
timer.addEventListener(TimerEvent.TIMER, onPlayHandler, false, 0, true);
compPlayer.source = "http://www.convexstyle.com/no.flv";
timer.start();
function onPlayHandler(evt:TimerEvent):void
{
timer.stop();
try
{
compPlayer.play();
}
catch(e:Error)
{
trace("@@@ ERROR @@@ " + e);
}
}
(5) 存在しない flv に timer の delay を 1000 でアクセス
Error がキャッチされた。
var timer:Timer = new Timer(1000, 0);
timer.addEventListener(TimerEvent.TIMER, onPlayHandler, false, 0, true);
compPlayer.source = "http://www.convexstyle.com/no.flv";
timer.start();
function onPlayHandler(evt:TimerEvent):void
{
timer.stop();
try
{
compPlayer.play();
}
catch(e:Error)
{
trace("@@@ ERROR @@@ " + e);
}
}
・・・・・
何かエラー時のイベントハンドラとか無いのかなと探してみたんですが、VideoEvent.STATE_CHANGE というイベントが実装されていて、このイベントハンドラの event.state が VideoState の connectionError と同等の時エラーと認識出来るようです。ただしこれにも何故か最初の1回目に存在しない URL を指定してやると connectionError を取得出来ませんでした。下記の図の様に、最初の source の指定が正しく 2 回目の source 指定が正しくない時には connectionError は取得できました。

(6) 存在しない flv に最初からアクセス
conttectionError を取得されないで Error が Throw されプロセス停止。
compPlayer.source = "http://www.test.com/no.flv";
compPlayer.addEventListener(VideoEvent.STATE_CHANGE, onStateChangeHandler, false, 0, true);
compPlayer.play();
function onStateChangeHandler(evt:VideoEvent):void
{
switch(evt.state)
{
case "connectionError":
{
trace('@@@ connectionError @@@');
break;
}
default:
{
break;
}
}
}
(7) 存在する flv にアクセスしてから、クリックイベントで存在しない flv にアクセス。
MouseEvent.Click 時に ConnectionError を取得する。
compPlayer.source = "http://www.test.com/existing.flv";
compPlayer.addEventListener(VideoEvent.STATE_CHANGE, onStageChangeHandler, false, 0, true);
compPlayer.play();
mcButton.buttonMode = true;
mcButton.addEventListener(MouseEvent.CLICK, onClickHandler, false, 0, true);
function onStageChangeHandler(evt:VideoEvent):void
{
switch(evt.state)
{
case "connectionError":
{
trace('@@@ connectionError @@@');
break;
}
default:
{
break;
}
}
}
function onClickHandler(evt:MouseEvent):void
{
compPlayer.source = "http://www.convexstyle.com/no.flv";
compPlayer.play();
}
(8) 存在しない flv に timer の delay を 1000 にしてアクセス。
Error をキャッチし、なおかつ connectionError も取得する。
var timer:Timer = new Timer(1000, 0);
timer.addEventListener(TimerEvent.TIMER, onPlayVideoHandler, false, 0, true);
compPlayer.source = "http://www.convexstyle.com/no.flv";
compPlayer.addEventListener(VideoEvent.STATE_CHANGE, onStageChangeHandler, false, 0, true);
timer.start();
function onPlayVideoHandler(evt:TimerEvent):void
{
timer.stop();
try
{
compPlayer.play();
}
catch(e:Error)
{
trace("@@@ ERROR @@@ " + e);
}
}
function onStageChangeHandler(evt:VideoEvent):void
{
switch(evt.state)
{
case "connectionError":
{
trace('@@@ connectionError @@@');
break;
}
default:
{
break;
}
}
}
・・・・・
(8) 番目が一番近いのかな!?
今回のプロジェクトでは一定規則の feed が提供されるので存在しない URL の場合は正規表現で回避しましたが、FlvPlayBack 側で存在しない URL に万が一接続した場合に回避する正しい方法はどの様にするんでしょうか?分かっている方がいらっしゃったら是非情報をお待ちしてます。
FlvPlayBack は基本的には YouTube の様な使い方がメインだろうから、色々の機能を実装する場合はやはり自作の Video 系コンポーネントを開発しておいた方が後々良い気がするので、時間を見つけて制作しようと思います。本格的に AS をやっている方はおそらく自作のプレイヤーを持っていて FlvPlayBack は単純な使用目的以外はさほど使っていないと思うので、自分もせっかくの機会だし近いうちにボタン類(Play/Stop/PlayStop/FullScreen/Mute)やバー類(Seek/Buffer)やその他(PlayHead Text) 系を VideoController で統括する形で自作して、出来るだけあらゆる用途に対応できる形で自分のフレームワークに組み込んでおこうと思います。
・・・・・
『参考サイト』
VideoState について
VideoEvent について
【AS3.0】FLVPlayback で VideoError がキャッチできない

compPlayer.source = "no.flv";
var _ns:NetStream = _player.getVideoPlayer(0).netStream;
function _handler (event : NetStatusEvent) {
if(event.info.code == "NetStream.Play.StreamNotFound")
throw new Error("StreamNotFound");
if(event.info.code == "NetStream.Play.Start")
_player.play();
}
_ns.addEventListener(NetStatusEvent.NET_STATUS ,_handler);
このようなのはいかがでしょうか?
間違った解釈でしたらすみません
Posted by 通りすがり | 2009年08月18日 17:10
Posted on 2009年08月18日 17:10
すみません、一部間違えました
お目汚し失礼しました
_player = compPlayer です。
Posted by 通りすがり | 2009年08月18日 17:19
Posted on 2009年08月18日 17:19
通りすがりの方!コメントありがとうございます!
getVideoPlayer という関数が VideoPlayer(Video の子クラス)を返すんですね!この関数を何となく見ていて素通りしていました。これで netStatusEvent からエラーを取れそうです。きっちり確認しましたらまたエントリーを書きます。
ありがとうございました。
Posted by convexstyle | 2009年08月20日 01:51
Posted on 2009年08月20日 01:51