最近になって解決したネタについて書いてしまう。
私は自作コンポーネントで各トラック(ファイル)の最後に再生した日時を記録している。foobar2000を使う前はiTunesを使っていたので、iTunesの最後に再生した日時と同じタイミングで記録したいと思っていた。完全にファイルを再生完了したタイミングである。
しかし、foobar2000のSDKには標準でそのようなイベントはない。
標準で用意されているクラスとしては、play_statistics_collectorというのがあり、このクラスに、on_item_playedというイベントがあるが、このイベントは、再生開始から60秒後か、ファイルの1/3を再生完了した段階で発生するため、iTunes互換を希望する私の要望には合致しない。
コンポーネントを作り始めた時から、play_callback_impl_baseクラスの、onplayback_timeイベントでポーリングして、ファイルのduration(長さ)と比較して判定していた。しかし、元々このイベントは、毎秒イベントを起こして画面描画をするためのものであるため、別の操作をしているとイベントがキャンセルされたりするなど、不完全な実装であった。
そして、ほぼ完全にiTunes互換でトラックの再生完了イベントを処理する方法がわかり、テストもできたのでまとめておく。
使うのは、play_callback_impl_baseクラスの、on_playback_new_trackとon_playback_stopである。
on_playback_new_trackでは、パラメータに再生を始めたトラックの情報が渡されるので、これを保持しておく。初回の時には何もしない。再生を始めた時なので、完了したわけではないのだから、何もする必要がない。
2度目以降のon_playback_new_trackでは、新しく再生を始めたトラックの情報が新たに渡されるが、前回保持しておいたトラックが再生完了した、ということにもなるので、そのトラックについて再生完了の処理を行う。連続して再生を行っている場合はこれでまず間違いがない。
次は、on_playback_stopである。これのパラメータに、stop_reasonというものがある。その理由は、EOFに達した(詳細は後述)、ユーザが止めた、別のトラックの再生を始めた、シャットダウンしたという内容となる。最後まで再生した場合だけ処理をするのが目的なので、ここでは、EOFに達した、というstop_reason_eofというENUM値のときだけ再生完了の処理を特別に行うこととする。
これは少しわかりにくいのであるが、通常は次のトラックの再生が始まった時に、前のトラックを最後まで再生された、として処理するのであるが、EOFまで再生して止まった、という場合には次のトラックが始まらないので、on_playback_stopで処理をするのである。
逆に、それ以外のon_playback_stopでは、トラック(ファイル)を最後まで再生していないので、対象トラックのクリアを行う。
on_playback_stopにおける、EOFというのは、通常のファイル終端では発生しないイベントであることに注意が必要なのである。このイベントは、プレイリストの最後の曲の再生が終了したタイミングと、「Stop after current」をしておいて現在再生中のトラック再生終了後に自動停止フラグを立ててトラックの再生が完了したタイミングでしか発生しない。その意味でのEOFである。「End Of File」のEOFとは違うことが重要なのである。
テストしたところ、トラックの途中で別のトラックの再生を始めた場合、on_playback_stopで対象トラックをクリアしておけば、on_playback_new_trackでは対象トラックなし、として再生完了の処理は行われなかった。
順番として、on_playback_stop→on_playback_new_trackのようである。手元の環境(Windows Vista 32bit in VirtualBOX + foobar2000 1.1.17, Windows7 64bit + foobar2000 1.1.17)での確認なので、完全保証とも言えないのであるが。
英語のフォーラムで同じ質問をしている人がいて、この解決策が出ていて、実験したところ想定通りの動きをした。
ひとまず、まとめておく。
コメント