Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serious drops with BonDriver_Mirakurun #4

Closed
tkmsst opened this issue Jan 3, 2020 · 75 comments
Closed

Serious drops with BonDriver_Mirakurun #4

tkmsst opened this issue Jan 3, 2020 · 75 comments
Assignees
Labels
bug Something isn't working

Comments

@tkmsst
Copy link

tkmsst commented Jan 3, 2020

mirakc + BonDriver_Mirakurun + TVTestを下記の環境で使用しておりますが、
大量のドロップが発生して、まともに視聴できない状況です。

Server:
CPU: Ryzen
Memory: 16GB
OS: OpenmediaVault4 (Debian Stretch)
Tuner: PT2 (chardev) + recpt1

Client: Core i7
CPU: Intel
Memory: 8GB
OS: Windows 10

本家のBonDriver_Mirakurunを少しシンプルに改造してみましたがそれでも同じ状況でした。

https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp
でのTS読み込み処理は非常に簡単で、576行目でsocketにconnectし、596行目でGETでrequestして、607行目から始まるThreadの619行目のrecvで読み込んでいるだけです。
Mirakurunを使用した場合には特に問題はありません。

mpc-beやvlcでのhttp接続の視聴に問題はないため、actix-webの仕様をよくわかっていないのが原因と思われますが、なにかアドバイスいただけましたら幸いです。

@masnagam
Copy link
Member

masnagam commented Jan 4, 2020

報告ありがとうございます.

同様の報告をTwitter上でも確認しており,動作確認用のWindows環境を構築して解析する予定です.

mirakcでの不具合解析方法はまだ確立していませんが,いくつか使える機能があります.

RUST_LOG

環境変数RUST_LOGでmirakcのログレベルを変更できます.

# mirakcのログレベルのみをdebugに
export RUST_LOG=info,mirakc=debug

# actix-webを含む全てのcrateのログレベルをdebugに
export RUST_LOG=debug

docker-composeを使っている場合は,環境変数をenvironmentに設定してください.

MIRAKC_ARIB_LOG

環境変数MIRAKC_ARIG_LOGでmirakc-aribのログレベルを変更できます.

debugレベルにすると大量のログが出力されます.今回の目的だとinfoレベルで十分だと思われます.

ログはstderrに出力されますが,そのままではmirakcはこれを/dev/nullに捨てます.環境変数MIRAKC_DEBUG_CHILD_PROCESSを定義することで(値は何でも良い)mirakc-aribからのログが出力されるようになります.

export MIRAKC_DEBUG_CHILD_PROCESS=1
export MIRAKC_ARIG_LOG=info

actix-webとスレッド

actix-webは非同期I/Oをサポートしていますが,mirakcでは実装が不十分です.そのため,TSストリームごとに1つのスレッドが必要な状態です.これはチューナー出力をブロッキングI/Oで処理するためです. https://github.com/masnagam/mirakc#configurationserver.workersのコメントを見てください.

もしチューナーがN個あるなら,server.workersをN+1にしてください.これをNにしてしまうと,すべてのチューナーを使用している状態ではREST APIが機能しなくなります(スレッドを使い果たしてしまっているため).

/api/channels/<type>/<channel>/streamを試してみる

BonDriver_Mirakurun + TVTestで可能かどうか分かりませんが,/api/channels///stream APIで試してみる方法が考えられます.

これを使うと,チューナーからの出力をそのままストリーミングするので(NULLもそのまま),mirakc-aribコマンドとの問題の切り分けができます.

decode/preprocess/postprocessを無効にしてみる

出力結果はpreprocessおよびpostprocess適用前のTSパケットとなりますが,この状態でパケットのドロップが発生していないのであれば,原因はpreprocess/postprocess使用時となり,切り分けができます.

@masnagam
Copy link
Member

masnagam commented Jan 4, 2020

ドロップ問題なので関係ないとは思いますが,mirakcには未実装のREST APIが多数あります.
https://github.com/masnagam/mirakc#rest-api-endpoints-compatible-with-mirakurun

/api/programs/{id}は最近実装したので,DockerHubのイメージには含まれていません(そろそろバージョン番号をつけないといけない時期かもしれませんね..).

@masnagam masnagam self-assigned this Jan 4, 2020
@masnagam masnagam added the bug Something isn't working label Jan 4, 2020
@tkmsst
Copy link
Author

tkmsst commented Jan 4, 2020

解説ありがとうございます。
以下mirakc e2e11be9cf02e2c10ebcd3b44e6bae4147b121e1で試しています。

1./api/channels/(type)/(channel)/streamを試してみる
BonDriver_Mirakurun.iniでSERVICE_SPLIT=0に設定すると可能ですが、変化ありませんでした。

2.decode/preprocess/postprocessを無効にしてみる
decodeはrecpt1 --b25によっており、いずれもconfig.ymlに記載しておりません。

上にも記載いたしましたが、同じ環境でもmpc、vlc等で直接http://:40772/api/channels/(type)/(channel)/streamにアクセスすると問題なく視聴が可能です。

@tkmsst
Copy link
Author

tkmsst commented Jan 4, 2020

TVTestでの視聴によるログを取得しましたので貼り付けておきます。

2020-01-05T00:13:57.336 DEBUG tokio_reactor > adding I/O source: 8388608
2020-01-05T00:13:57.337 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:13:57.337 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:13:57.337 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:13:57.337 INFO actix_web::middleware::logger > 192.168.x.xxx:xxxxx "GET /api/channels HTTP/1.1" 200 29130 "-" "-" 0.000618
2020-01-05T00:13:57.343 DEBUG tokio_reactor > dropping I/O source: 0
2020-01-05T00:13:57.396 DEBUG tokio_reactor > adding I/O source: 8388608
2020-01-05T00:13:57.396 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:13:57.396 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:13:57.397 DEBUG mirakc::tuner > tuner#3: Process#10811 has been spawned by recpt1 --b25 --strip --device /dev/pt1video3 25 - -
2020-01-05T00:13:57.397 INFO mirakc::tuner > tuner#3: Started streaming to 192.168.x.xxx:xxxxx#1578150837396 (priority=0)
2020-01-05T00:13:57.397 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:13:57.397 DEBUG mirakc::tuner > stream#3:3: Converted into futures::Stream
using B25...
enable B25 strip
using device: /dev/pt1video3
pid = 10811
device = /dev/pt1video3
C/N = 33.053378dB
Recording...
2020-01-05T00:13:58.425 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-05T00:13:58.431 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:13:58.431 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-05T00:13:58.452 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:13:58.452 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-05T00:13:58.464 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-05T00:14:03.606 INFO actix_web::middleware::logger > 192.168.x.xxx:xxxxx "GET /api/channels/GR/25/stream?decode=0 HTTP/1.1" 200 11444224 "-" "-" 6.209641
2020-01-05T00:14:03.606 DEBUG mirakc::tuner > stream#3:3: Dropping...
2020-01-05T00:14:03.606 DEBUG tokio_reactor > dropping I/O source: 0
2020-01-05T00:14:03.607 DEBUG mirakc::tuner > tuner#3: Process#10811 has terminated
2020-01-05T00:14:03.607 INFO mirakc::tuner > tuner#3: Stopped streaming to 192.168.x.xxx:xxxxx#1578150837396 (priority=0)

@masnagam
Copy link
Member

masnagam commented Jan 4, 2020

確認ありがとうございます.ストリーミング中に別のAPIが呼び出されていないので,プールされているスレッドが枯渇しているわけでもなさそうです.

これまでの結果をまとめると...

  • mirakcから直接ストリーミングを受ける場合はドロップは発生しない
  • BonDriver_Mirakurunを経由しTVTestで受けるとドロップが発生する

受信電波には問題はないと仮定した場合にドロップが発生する可能性がある箇所は...

  • デバイスドライバー
  • チューナープログラム
  • mirakc
  • BonDriver_Mirakurun
  • TVTest

のどれかということになります.

直接受信時にはドロップが発生しないということなので,以下の可能性が考えられます.

  • BonDriver_Mirakurun+TVTestが追加されたことで,パケット受信速度が何らかの理由で遅くなり,デバイスドライバー,チューナープログラム,またはmirakcでバッファーがあふれてしまった
  • BonDriver_MirakurunもしくはTVTestで,何らかの理由でパケットがドロップされた

後者の可能性もありますが,恐らく前者の可能性のほうが高いと思います.

mirakcのバッファーサイズが関係しているのかもしれません.

mirakcが利用しているtokio_core::io::Framedは8KBのバッファーを使って標準入力経由で上流から送られてくるTSストリームを処理します,下流(BonDriver_Mirakurun,TVTest)での受信が滞ると

  • 標準入力のバッファーがいっぱいになる
  • 上流(デバイスドライバー,チューナープログラム)で標準出力に書き込もうとするが,いっぱいなので書き込めない
  • 上流のバッファーがあふれる,もしくは上流の処理に不具合があり書き込めなかったデータが誤って捨てられる

ということがありそうです.

もし,利用しているデバイスドライバー,チューナープログラムにバッファーがあふれたときにログを出力する機能があるなら,あふれているかどうか確認できると思います.

@masnagam
Copy link
Member

masnagam commented Jan 4, 2020

BonDriver_Mirakurunのコードを見てみたのですが,結構複雑ですね.

単にコードを見ただけなので間違った指摘かもしれませんが,

m_CriticalSectionが何を保護しているのかが気になります.

例えば,m_sockを保護しているのだとすると,

がロックの外で行われています.

もし,m_pSrcを保護しているのだとすると

はロックの外で行われています.

あとは,RecvThreadm_pGrabTsDataに書き込んでいる最中にGetTsStreamされることがあると思いますが,GrabTsDataはatomic処理のみで書かれています.これだと単一変数に対する競合は防ぐことができますが,ロジックによっては変数間の整合性を保証できない可能性があります.

上記のような箇所が原因でBonDriver_Mirakurunでドロップが発生している可能性があるかもしれません.

@tkmsst
Copy link
Author

tkmsst commented Jan 5, 2020

ソースをご覧いただきありがとうございます。

ご指摘のm_CriticalSectionについてですが、m_sock(厳密にはm_sockを通じたアクセス)を保護しています。

まず、m_pSrcについては
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L645
でライトし、
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L649
でリードしているのみで、いずれもRecvThread内でのアクセスであるためそもそも排他制御(CriticalSection)は必要ないと考えています。

肝心のm_sockについてですが、これは
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L645
においてm_sockを通じたrecvが行われる瞬間までに、少なくとも
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L595
で、m_sockへのconnectが完了していないと未定義動作を起こす可能性を危惧して排他制御を行っています。

逆に、connectさえ完了してしまえば、
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L614
でのmirakcへのリクエストが未完了であっても、単にmirakcからsocketにデータが送信されず、
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L645
のところで待機(もしくはデータ未受信)になるだけで特に問題はないと考えました。

しかしながら、mirakcへのリクエストが完了する前にrecvを開始する意味もないため(あとclosesocketがバッティングする可能性もありますね)、LeaveCriticalSectionの位置を変更いたしました。

@tkmsst
Copy link
Author

tkmsst commented Jan 5, 2020

次に、ご指摘のm_pGrabTsDataですが、これはデータの送受信に関する処理のため、可能な限りロックフリーを目指してatomicを駆使して処理を行っています。

ざっくり言うと、
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/GrabTsData.h#L28
においてTSデータを格納するRing Bufferを確保し、このバッファの書き込みアドレスと読み込みアドレスを示すマーカー(m_nPush、m_nPull)をうまく操作して、同じアドレスへのライトとリードが同時に発生しないようにした上で、このマーカーをatomic制御することで、結果として全体が排他制御になるようにしています。

ご指摘の通り、際どい処理であることには変わらず、コンパイラの最適化等で期待した処理にならない可能性もあるため、自分の理解のためにも後でもう少し処理の詳細を記載しようと思います。

なお、ドロップと排他制御(atomic)の関連という意味では、get_TsStream
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L322
とput_TsStream
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L649
をCriticalSectionに入れても状況は変わらないため、とりあえず排他制御の問題ではないようです。

@masnagam
Copy link
Member

masnagam commented Jan 5, 2020

説明ありがとうございます.

m_pGrabTsData

putとgetで書き換える変数が異なるので,データが上書きされたりすることがないこを確認しました.

やはり上流のどこかでバッファーがあふれているのではないかと推測します.

@tkmsst
Copy link
Author

tkmsst commented Jan 5, 2020

m_pGrabTsDataにRing BufferのOverflowチェックを入れて検証してみました。
視聴を開始するとすぐドロップするのですが、そのまま放っておくとTVTestの読み出しが間に合わなくなりOverflowになりました。

Overflowの前にもドロップしているためあまり意味がなさそうですが、読み出しのバッファを10倍にしてみたところOverflowはなくなりましたが、ドロップの状況に変化はないです。

recvで受け取ったデータに余計なデータが含まれていてTVTestでうまく処理できない感じがします。

@masnagam
Copy link
Member

masnagam commented Jan 5, 2020

調査ありがとうございます.

mirakcとMirakurunのフィルタリングの違いを調べてみます.

mirakcで通過させているパケットの種類はmirakc-arib -hで表示される以下になります.

* PAT (PID=0x0000)
* CAT (PID=0x0001)
* NIT (PID=0x0010)
* SDT (PID=0x0011)
* EIT (PID=0x0012)
* RST (PID=0x0013)
* TDT/TOT (PID=0x0014)
* BIT (PID=0x0024)
* CDT (PID=0x0029)
* PMT (PID specified in PAT)
* EMM (PID specified in CAT)
* PCR (PID specified in PMT)
* ECM (PID specified in PMT)
* PES for video/audio/subtitles (PID specified in PMT)

@tkmsst
Copy link
Author

tkmsst commented Jan 5, 2020

ありがとうございます。こちらでも不要と思われるパケットを削除して試してみます。

@tkmsst
Copy link
Author

tkmsst commented Jan 7, 2020

recvの後
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L643
にpThis->m_pSrcを直接ファイルに書き出して見てみましたが、この時点でドロップしてました
。やはりmirakcからのrecvがうまくいっていないようです。

@masnagam
Copy link
Member

masnagam commented Jan 7, 2020

こちらの調査が進んでおらず申し訳ないです..

ドロップチェックに利用しているプログラム名を教えていただけますか?こちらでもチェックしてみます.

PATとPMTはチューナーが出力したものを書き換えているので,CCやCRCがおかしくなったりしているのかもしれません.

@tkmsst
Copy link
Author

tkmsst commented Jan 7, 2020

TVTestで視聴しているとドロップカウントが増加していきます。映像自体も乱れてまともに見れない状況です。上記の直接ファイルに書き出したTSをMPCで再生しても同じような映像です。
念の為エラーチェックも行いましたがエラーとドロップを検出しています。プログラム名はMulti2Decです。

なおmirakc-aribの影響を除くために
/api/channels/(type)/(channel)/stream
でTSを取得しています。

@masnagam
Copy link
Member

masnagam commented Jan 8, 2020

Windows環境を構築して確認してみました.

まず,SERVICE_SPLIT=1は現状では機能しません.なぜなら,mirakcは/api/channels/{type}/{channel}/services/{sid}/streamを実装していないからです.

SERVICE_SPLIT=0にすると,/api/channels/{type}/{channel}/streamを使用するようになります.mirakcはこのAPIでは一切TSパケットを書き換えません.Mirakurunは特定種類のTSパケットのみ送信しています.

SERVICE_SPLIT=0でドロップを確認しました.確認にはTVTestの「ストリーム情報の表示」を使いました.見た感じでは,特定の種類のみがドロップしているようでした.もし,どこかでバッファーがあふれた結果ドロップが起きているのだとすると,すべての種類でドロップが発生してもいいはずなのですが,そうではない点が気になります.

未実装の/api/channels/{type}/{channel}/services/{sid}/streamを実装してSERVICE_SPLIT=1にしてみましたが,状況は変わりませんでした.

「ストリーム情報の表示」を見て分かったことは,存在しないはずのPIDがtvtestに受信されていることです.つまり,どこかでデータが壊れていることを意味しています.mirakcよりも下流だと考えるのは早計です.上流で壊れた可能性も否定できません.

調査を継続します.

@masnagam
Copy link
Member

masnagam commented Jan 8, 2020

/api/channels/{type}/{channel}/services/{sid}/streamをファイルに記録し,これをtvtest+bondriver_mirakurunに返すようにしてみたところ,ドロップが発生しました.

もし,そちらでも再現するようでしたら,恐らくbondriver_mirakurunもしくはtvtestのどこかに不具合があるのだと思います.

テスト環境

手順

  1. SERVICE_SPLIT=0に設定
  2. データをファイルに保存
# GR/27を30秒記録(durationクエリーパラメーターはmirakcでしか動きません)
curl -fsSL 'http://localhost:40772/api/channels/GR/27/stream?duration=30' >stream
  1. 保存したデータにドロップがないことを確認
  2. tvtestを起動し,チャンネルスキャンを実行後,適当なチャンネルを開く
  3. 「ストリーム情報の表示」を開いておく
  4. mirakc停止
  5. 以下のpython(version 2)スクリプトを実行
# http.py
import SimpleHTTPServer
import SocketServer

ADDRESS = '0.0.0.0'
PORT = 40772

class CustomHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def __init__(self, req, client_addr, server):
        SimpleHTTPServer.SimpleHTTPRequestHandler.__init__(self, req, client_addr, server)

    def do_GET(self):
        self.path = '/stream'
        SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)

class MyTCPServer(SocketServer.ThreadingTCPServer):
    allow_reuse_address = True

if __name__ == '__main__':
    httpd = MyTCPServer((ADDRESS, PORT), CustomHandler)
    httpd.allow_reuse_address = True
    print "Serving at port", PORT
    httpd.serve_forever()
  1. http://mirakc:40772/api/channep/GR/27/streamをcurlなどで取得し,http.pyが期待通り動作していることを確認
  2. tvtestでチャンネル(どれでも良い)を変更し,ドロップが発生することを確認
PID      Input    Output   Dropped     Error Description
0000       272       272         6         0 PAT
0001         3         3         0         0 CAT
0010        27        27         2         0 NIT
0011        14        14         4         0 SDT
0012      1244      1244         6         0 H-EIT
0014         5         5         0         0 TOT
0024        27        27         2         0 BIT
0027       127       127         4         0 L-EIT
0029         5         5         0         0 CDT
0100    244144    244144         6         0 [0400] MPEG-2 Video [0401] MPEG-2 Video
0110      2534      2534         6         0 [0400] AAC [0401] AAC
0130        27        27         2         0 [0400] 字幕 [0401] 字幕
0138        27        27         2         0 [0400] 字幕 [0401] 字幕
0140      3291      3291         6         0 [0400] データ [0401] データ
0160     17464     17464         4         0 [0400] データ [0401] データ
0161       968       968         6         0 [0400] データ [0401] データ
0162      1411      1411         6         0 [0400] データ [0401] データ
0170      3497      3497         6         0 [0400] データ [0401] データ
0171      1432      1432         4         0 [0400] データ [0401] データ
0172        51        51         2         0 [0400] データ [0401] データ
01f0       540       540         5         0 [0400] PMT
01ff       457       457         0         0 [0400] PCR [0401] PCR
0238        27        27         2         0 
03f0       540       540         5         0 [0401] PMT
0580       965       965         6         0 [0580] データ
0581      3624      3624         4         0 [0580] H.264
0583      1051      1051         5         0 [0580] AAC
0587         4         4         1         0 [0580] 字幕
0589        28        28         4         0 [0580] データ
058b       451       451         6         0 [0580] データ
05ff       117       117         0         0 [0580] PCR
07d5         1         1         0         0 
0900       659       659         5         0 
0901       271       271         6         0 [0400] ECM [0401] ECM
0902       271       271         6         0 
1c61       178       178         5         0 [fff0] データ
1c76      3401      3401         6         0 [fff0] データ
1cf0        27        27         3         0 [fff0] PMT
1fc8        54        54         2         0 [0580] PMT

発生するドロップはランダムに見えます.ドロップが全く発生しない場合もありました.また,PIDごとの入力数も変化しました.入力数+ドロップが常に同じ数というわけでもありませんでした.

@tkmsst
Copy link
Author

tkmsst commented Jan 8, 2020

検証ありがとうございます。BonDriver_MirakurunはWinsock2を使っていますが、これだとデータをうまく受信できないのかもしれませんね。。。

@masnagam
Copy link
Member

masnagam commented Jan 9, 2020

時間ができたときで構いませんので,同じ手順で問題が発生するかどうか確認してください.

現時点では,私の環境でのみ確認した現象です.まだ1サンプルにすぎませんし,原因特定には至っていないため,上流を原因箇所から除外するのは早計だと考えています.

注意喚起のため,このissueはbugのままOpen状態を維持しておきます.上記手順で問題が再現した場合や,下流の原因箇所が特定できた場合は,コメントを追記していただけるとありがたいです.

@tkmsst
Copy link
Author

tkmsst commented Jan 10, 2020

お世話になっております。
sockでの実装をあきらめ、WinHTTPでの実装に変更して無事動作いたしました。
もう少しテストを重ねてからコミットしようと思います。
これでMirakurunの完全代替に近づきました。

あとは、可能でしたら、複数のクライアントからチューナーを共有できるようにしていただけたら大変うれしいです。

@masnagam
Copy link
Member

報告ありがとうございます.
本チケットの状態はこのままにしておくので,コミットした後に本チケットをクローズしてください.

複数のクライアントからチューナーを共有できるように

非同期化作業が終わったら検討してみます.ただ,対応のためには相当修正が必要だろうとは思っています.

@tkmsst
Copy link
Author

tkmsst commented Jan 11, 2020

ご検討のほどよろしくお願いいたします。

さて、とりあえず視聴できるようになったためコミットいたしました。
しかしPT2とTVTestと今回のBonDriver_Mirakurunの環境において下記の手順で不具合がでてしまいます。

  1. TVTestを起動し、視聴を開始する。(TVTest-A)
  2. もう1つTVTestを起動し、別のチャンネルを視聴する。(TVTest-B)
  3. 後から起動したTVTest(TVTest-B)で複数回チャンネルを変更する。

2つのチャンネルを同時に視聴しているため、mirakcのサーバーのシェルで「ps aux」を叩いてみると、当然recpt1(mirakc-aribも)が2つ起動されているのが見えますが、
上記の「3.」を繰り返しているとrecpt1が1つしか起動されず、後から起動したTVTest(TVTest-B)が固まる状況になってしまいます。
具体的には
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L575
でのmirakcへのGETリクエストが完了しません。

これはもしかしたら、チャンネル変更時の
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L565
においてmirakcとの接続がクローズされず、処理が衝突してしまうのかもしれません。

一難去ってまた一難です。。。

@tkmsst
Copy link
Author

tkmsst commented Jan 11, 2020

固まったところのログを貼っておきます。(テレ朝 ch.24 -> TBS Ch.22)
ちなみにTVTestを1つだけ起動してチャンネルを変えていく場合は問題ありません。

2020-01-12T02:43:22.775 INFO actix_web::middleware::logger > 192.xxx.xxx.xxx:51919 "GET /api/channels/GR/26/stream?decode=1 HTTP/1.1" 200 19898368 "-" "BonDriver_Mirakurun/1.0" 10.451457
2020-01-12T02:43:22.775 DEBUG mirakc::tuner > stream#2:65: Dropping...
2020-01-12T02:43:22.775 DEBUG tokio_reactor > dropping I/O source: 0
2020-01-12T02:43:22.875 DEBUG tokio_reactor > adding I/O source: 54525952
2020-01-12T02:43:22.875 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:22.875 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:22.876 DEBUG mirakc::tuner > tuner#2: Process#28481 has terminated
2020-01-12T02:43:22.876 INFO mirakc::tuner > tuner#2: Stopped streaming to 192.xxx.xxx.xxx:51919#1578764592324 (priority=0)
2020-01-12T02:43:22.877 DEBUG mirakc::tuner > tuner#2: Process#2735 has been spawned by recpt1 --b25 --strip --device /dev/pt1video2 25 - -
2020-01-12T02:43:22.877 INFO mirakc::tuner > tuner#2: Started streaming to 192.xxx.xxx.xxx:51921#1578764602875 (priority=0)
2020-01-12T02:43:22.877 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:22.877 DEBUG mirakc::tuner > stream#2:66: Converted into futures::Stream
2020-01-12T02:43:23.839 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-12T02:43:23.845 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:23.845 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-12T02:43:23.850 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:23.850 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-12T02:43:23.859 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:23.859 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-12T02:43:23.868 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:31.475 INFO actix_web::middleware::logger > 192.xxx.xxx.xxx:51921 "GET /api/channels/GR/25/stream?decode=1 HTTP/1.1" 200 16719872 "-" "BonDriver_Mirakurun/1.0" 8.600236
2020-01-12T02:43:31.475 DEBUG mirakc::tuner > stream#2:66: Dropping...
2020-01-12T02:43:31.475 DEBUG tokio_reactor > dropping I/O source: 0
2020-01-12T02:43:31.476 DEBUG mirakc::tuner > tuner#2: Process#2735 has terminated
2020-01-12T02:43:31.476 INFO mirakc::tuner > tuner#2: Stopped streaming to 192.xxx.xxx.xxx:51921#1578764602875 (priority=0)
2020-01-12T02:43:31.477 DEBUG tokio_reactor > adding I/O source: 54525952
2020-01-12T02:43:31.477 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:31.477 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:31.478 DEBUG mirakc::tuner > tuner#2: Process#28989 has been spawned by recpt1 --b25 --strip --device /dev/pt1video2 24 - -
2020-01-12T02:43:31.479 INFO mirakc::tuner > tuner#2: Started streaming to 192.xxx.xxx.xxx:51922#1578764611477 (priority=0)
2020-01-12T02:43:31.479 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:31.479 DEBUG mirakc::tuner > stream#2:67: Converted into futures::Stream
2020-01-12T02:43:32.315 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-12T02:43:32.321 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-12T02:43:40.435 INFO actix_web::middleware::logger > 192.xxx.xxx.xxx:51922 "GET /api/channels/GR/24/stream?decode=1 HTTP/1.1" 200 16465920 "-" "BonDriver_Mirakurun/1.0" 8.957983
2020-01-12T02:43:40.435 DEBUG mirakc::tuner > stream#2:67: Dropping...
2020-01-12T02:43:40.435 DEBUG tokio_reactor > dropping I/O source: 0
2020-01-12T02:43:40.436 DEBUG mirakc::tuner > tuner#2: Process#28989 has terminated
2020-01-12T02:43:40.436 INFO mirakc::tuner > tuner#2: Stopped streaming to 192.xxx.xxx.xxx:51922#1578764611477 (priority=0)

@masnagam
Copy link
Member

masnagam commented Jan 12, 2020

そのような現象の原因として,2つの可能性が考えられます.

背景

チューナーの開放はactix-webのHTTPトランザクション終了後に行われます.

HTTPトランザクション終了のリソース開放時に,チューナー開放のためのメッセージが送出されます.

このメッセージはキューに入りますから,これ以降に新しいチューナーの要求があった場合は,正しく割り当てられます.なぜなら,キューに入った順でメッセージが処理されるからです.

/api/xxx/streamでの,actix-webのトランザクション終了のタイミングはTCP切断時です.もちろん,actix-webから切断する場合はこの限りではありませんが,今回はクライアント側から切断するケースなので,actix-webから切断するケースについては原因の可能性から排除します.

可能性1:tuner開放処理が完了する前に次のリクエストがきており,その結果,チューナーを割り当てられない

この場合,以下のようなログが出力されます.

# メールで送られてきていた,再編集前のログからの抜粋
DEBUG actix_web::middleware::logger > Error in response: Unavailable

解決案

再接続のタイミングをもっと遅らせるか,TCP切断時のコールバックが呼び出された後で再接続する必要があるのではないかと思われます.

可能性2:HTTP keep-aliveが有効になっており,TCPの接続が継続されている

winhttpは初期値でkeep-aliveが有効になっているようです.

解決案

上記でkeep-alive自体を無効にしてしまうか,個別に"Connection: close"ヘッダーをつければ,TCP接続が切れます.

@masnagam
Copy link
Member

ちなみに,tvtest1つだけの場合に問題が発生しない理由として,チューナーが2つ以上存在することが挙げられます.

この場合,対象チューナーの開放が完了していなくても,別のチューナーを割り当てることができるので,問題は発生しません.

おすすめはしませんが,同時に使用するtvtestの数よりも多いチューナー(GRなどの種別ごとにこの条件を適用する必要があります)を用意すれば問題は発生しません.

@tkmsst
Copy link
Author

tkmsst commented Jan 13, 2020

詳細なご説明ありがとうございます。アドバイスをもとにkeep-aliveを無効にした上で試行錯誤の結果、やっと実用に耐える程度にもっていけました。

再接続のタイミングをもっと遅らせるか,TCP切断時のコールバックが呼び出された後で再接続する必要があるのではないかと思われます.

コールバック関数で処理しようと試みましたが、WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSEDが発行されることはなく、WINHTTP_CALLBACK_STATUS_HANDLE_CLOSINGはWinHttpCloseHandle()の直後(実際の切断の前)に発行されてしまうため、切断のタイミングを取得することはできませんでした。よって500msのウエイト(iniで指定可能)をおくことで対応しました。
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L567

ただし、これだとチューナーの切断に間に合わないことがあり、その場合はStatus codeとして401が返ってくることがわかりましたのでリトライを行う(リトライループから抜けない)ようにしました。
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L612

この状況で、上記と同じTVTestを2つ起動し、片方(TVTest-B)のチャンネルを変更していくことを繰り返した結果、前回の時と同様5~6回目で、WinHttpSendRequest()
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L599
の部分で停止(mirakcからレスポンスが返って来ない)してしまいました。

そこで、力技ではありますが、TIME_OUTを100msに設定し、
https://github.com/epgdatacapbon/BonDriver_Mirakurun/blob/develop/BonDriver_Mirakurun.cpp#L590
WinHttpSendRequest()が100ms停止した場合には、再度WinHttpSendRequest()を呼ぶこととしました。

config.ymlで「workers: 6」にしていることから、mirakcですべてのスレッドが埋まってしまったためにレスポンスを返せない(停止)しているのではないかという感じもするのですが、再度すぐにWinHttpSendRequest()でリクエストすると動き出すのでよくわかりませんでした。
ここさえなんとかできれば完成だと思います。

@tkmsst
Copy link
Author

tkmsst commented Jan 13, 2020

停止した時、および、再度WinHttpSendRequest()でリクエストして動き出したときのログを貼っておきます。(日テレ -> テレ朝)

2020-01-13T16:32:36.843 INFO actix_web::middleware::logger > 192.xxx.xxx.xxx:61710 "GET /api/services/3274001056/stream?decode=1 HTTP/1.1" 200 8645368 "-" "BonDriver_Mirakurun/1.0" 5.716843
2020-01-13T16:32:36.843 DEBUG mirakc::tuner > stream#3:49: Dropping...
2020-01-13T16:32:36.843 DEBUG mirakc::tuner > stream#3:49: Process#10837 has terminated
2020-01-13T16:32:36.843 DEBUG tokio_reactor > dropping I/O source: 0
2020-01-13T16:32:36.844 DEBUG mirakc::tuner > tuner#3: Process#10836 has terminated
2020-01-13T16:32:36.844 INFO mirakc::tuner > tuner#3: Stopped streaming to 192.xxx.xxx.xxx:61710#1578900751126 (priority=0)
2020-01-13T16:32:37.347 DEBUG tokio_reactor > adding I/O source: 58720256
2020-01-13T16:32:37.347 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:37.347 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:37.348 DEBUG mirakc::tuner > tuner#3: Process#10841 has been spawned by recpt1 --b25 --strip --device /dev/pt1video3 25 - -
2020-01-13T16:32:37.348 INFO mirakc::tuner > tuner#3: Started streaming to 192.xxx.xxx.xxx:61713#1578900757347 (priority=0)
2020-01-13T16:32:37.348 DEBUG mirakc::tuner > stream#3:50: Process#10842 has been spawned by mirakc-arib filter-service --sid=1040
2020-01-13T16:32:37.348 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:37.348 DEBUG mirakc::tuner > stream#3:50: Converted into futures::Stream
using B25...
enable B25 strip
using device: /dev/pt1video3
pid = 10841
device = /dev/pt1video3
C/N = 33.033802dB
Recording...
2020-01-13T16:32:38.309 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-13T16:32:38.311 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:38.312 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-13T16:32:38.319 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:38.419 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-13T16:32:38.422 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:43.707 INFO actix_web::middleware::logger > 192.xxx.xxx.xxx:61713 "GET /api/services/3273801040/stream?decode=1 HTTP/1.1" 200 6977808 "-" "BonDriver_Mirakurun/1.0" 6.359383
2020-01-13T16:32:43.707 DEBUG mirakc::tuner > stream#3:50: Dropping...
2020-01-13T16:32:43.707 DEBUG mirakc::tuner > stream#3:50: Process#10842 has terminated
2020-01-13T16:32:43.707 DEBUG tokio_reactor > dropping I/O source: 0
2020-01-13T16:32:43.707 DEBUG mirakc::tuner > tuner#3: Process#10841 has terminated
2020-01-13T16:32:43.707 INFO mirakc::tuner > tuner#3: Stopped streaming to 192.xxx.xxx.xxx:61713#1578900757347 (priority=0)

ここでWinHttpSendRequestが停止

2020-01-13T16:32:56.162 DEBUG tokio_reactor > adding I/O source: 58720256
2020-01-13T16:32:56.162 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:56.162 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:56.162 DEBUG mirakc::tuner > tuner#3: Process#10851 has been spawned by recpt1 --b25 --strip --device /dev/pt1video3 24 - -
2020-01-13T16:32:56.162 INFO mirakc::tuner > tuner#3: Started streaming to 192.xxx.xxx.xxx:61719#1578900776162 (priority=0)
2020-01-13T16:32:56.163 DEBUG mirakc::tuner > stream#3:51: Process#10852 has been spawned by mirakc-arib filter-service --sid=1064
2020-01-13T16:32:56.163 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:56.163 DEBUG mirakc::tuner > stream#3:51: Converted into futures::Stream
using B25...
enable B25 strip
using device: /dev/pt1video3
pid = 10851
device = /dev/pt1video3
C/N = 32.578067dB
Recording...
2020-01-13T16:32:57.035 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-13T16:32:57.044 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:57.044 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-13T16:32:57.049 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:57.049 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-13T16:32:57.054 DEBUG tokio_reactor::registration > scheduling Read for: 0
2020-01-13T16:32:57.468 DEBUG tokio_reactor::registration > scheduling Write for: 0
2020-01-13T16:32:57.469 DEBUG tokio_reactor::registration > scheduling Read for: 0

「SERVICE_SPLIT=0」でも同じ状況です。

@masnagam
Copy link
Member

masnagam commented Jan 13, 2020

指摘の通り,プールされているスレッドを使い切っているものと思われます.

Fiddlerやtcpdump/wiresharkでHTTP/TCP通信を解析すれば原因が特定できるかもしれません.

  • チャンネル切り替え時(HTTPトランザクション終了時)に,クライアントからTCP FIN(またはRST)が送られていない
    • winhttpの使い方に間違いがあり,TCPが接続されたままになっている
  • チャンネル切り替え時に,クライアントからTCP FIN(またはRST)を送っているにも関わらず,問題が発生している場合
    • mirakcの実装に問題があり,スレッドが即座に開放されない
    • もしくは,actix-webでのHTTP/TCP処理に何らかの問題があり,スレッドが即座に開放されない

過去に以下のような問題が報告されているので,actix-webの不具合である可能性も十分あります.

@masnagam
Copy link
Member

masnagam commented Feb 9, 2020

SERVICE_SPLIT=0の場合でフィルターコマンドが全く使われていない場合,

  • 2020-02-07T16:43:17.393Z(フィルターコマンドがkillされる)

のタイミングで「チューナー開放メッセージを送信」となるため,スリープなしでも問題が発生していないのだと推測されます.

フィルターなし

 <thread-1>                         | <thread-2>
 [tuner command]  -- (async task) --|-- (async task) --> [web]
                      broadcaster        mpeg_ts_stream

フィルターあり

 <thread-1>                         | <thread-2>
 [tuner command]  -- (async task) --|-- (async task) --> [filter command] -- (async task) --> [web]
                      broadcaster        mpeg_ts_stream

ここでasync taskは,各スレッドで実行される非同期タスクで,アップストリームからダウンストリームへのデータコピーを行います.async task間はバッファーを直接やり取りするので,コピーは発生しません.

filter commandがkillされると,mpeg_ts_streamでbroken pipeが検出され,チューナー開放メッセージが送信されるという手順になっています.

@masnagam
Copy link
Member

masnagam commented Feb 9, 2020

原理的にはwebの直前のasync taskからチューナー開放メッセージを送信すれば,開放までの遅延を短くできそうです.少し検討してみます.

@tkmsst
Copy link
Author

tkmsst commented Feb 9, 2020

詳細なご回答ありがとうございます。

とりあえずの対応としてSTATUS CODE 200が返ってくるまでSleep(200)でGETを繰り返すことといたしました。
tkmsst/BonDriver_mirakc@5edca49

@masnagam
Copy link
Member

masnagam commented Feb 9, 2020

f80e24a で遅延が短くなったと思います.確認してみてください.

@tkmsst
Copy link
Author

tkmsst commented Feb 11, 2020

ほぼ遅延がなくなりました。
たまに404が返ってくることがあるので、HTTP closeからGETの間にSleep(100)を置けばどのような環境でも問題ないのではないかと感じています。

@tkmsst
Copy link
Author

tkmsst commented Feb 11, 2020

ところで、TOKYO MX1(3239123608)とMX2(3239123610)の間でチャンネル切り替えを数回繰り返してみたのですが、「Reuse tuner already activated with GR 16」になるときと、通常のチャンネル切り替えと同様にTuner close -> openになるときがありました。本来的には常に「Reuse tuner already activated with GR 16」となるのではと思った次第です。

using B25...
enable B25 strip
using device: /dev/dvb/adapter3pid = 6237
device = /dev/dvb/adapter3/frontend0
Using DVB device "Toshiba TC90522 ISDB-T module"
tuning to 491.143 MHz
...ok(0x1F)
SNR0: 0
Recording...
2020-02-11T09:46:17.772Z INFO actix_web::middleware::logger > 192.168.xxx.xxx:59691 "GET /api/services/3239123608/stream?decode=1 HTTP/1.1" 200 7169756 "-" "BonDriver_Mirakurun/1.0" 6.298466
2020-02-11T09:46:17.772Z DEBUG mirakc::mpeg_ts_stream > tuner#3.6237.1: Closing...
2020-02-11T09:46:17.772Z DEBUG mirakc::tuner > Handle StopStreamingMessage
2020-02-11T09:46:17.772Z INFO mirakc::tuner > tuner#3.6237.1: Stop streaming
2020-02-11T09:46:17.772Z INFO mirakc::tuner > tuner#3.6237.1: Unsubscribed: Web(remote="192.168.xxx.xxx:59691" agent="BonDriver_Mirakurun/1.0") (priority=0)
2020-02-11T09:46:17.773Z DEBUG mirakc::command_util > tuner#3.6237.1: Killed 6238: mirakc-arib filter-service --sid=23608
2020-02-11T09:46:17.773Z DEBUG mirakc::tuner > tuner#3.6237: Killed 6237: recdvb --b25 --strip --dev 3 16 - -
2020-02-11T09:46:17.773Z INFO mirakc::tuner > tuner#3.6237: Deactivated
2020-02-11T09:46:17.773Z DEBUG mirakc::mpeg_ts_stream > tuner#3.6237.1: EOF reached
2020-02-11T09:46:17.773Z DEBUG mirakc::broadcaster > tuner#3.6237: EOS reached, stop
2020-02-11T09:46:17.773Z DEBUG mirakc::broadcaster > tuner#3.6237: Stopped
2020-02-11T09:46:17.776Z DEBUG mirakc::epg > QueryService By (NID#7E87, SID#5C3A)
2020-02-11T09:46:17.776Z WARN mirakc::web > Post-filter is required, but not defined
2020-02-11T09:46:17.776Z DEBUG mirakc::tuner > Handle StartStreamingMessage
2020-02-11T09:46:17.776Z INFO mirakc::tuner > tuner#3: Activate with GR 16
2020-02-11T09:46:17.777Z DEBUG mirakc::tuner > tuner#3.6400: Spawned 6400: recdvb --b25 --strip --dev 3 16 - -
2020-02-11T09:46:17.777Z INFO mirakc::tuner > tuner#3.6400: Activated with GR 16
2020-02-11T09:46:17.777Z INFO mirakc::tuner > tuner#3.6400.1: Subscribed: Web(remote="192.168.xxx.xxx:59695" agent="BonDriver_Mirakurun/1.0") (priority=0)
2020-02-11T09:46:17.777Z DEBUG mirakc::broadcaster > tuner#3.6400: Started
2020-02-11T09:46:17.777Z INFO mirakc::tuner > tuner#3.6400.1: Started streaming
2020-02-11T09:46:17.777Z DEBUG mirakc::command_util > tuner#3.6400.1: Spawned 6401: mirakc-arib filter-service --sid=23610
using B25...
enable B25 strip
using device: /dev/dvb/adapter3pid = 6400
device = /dev/dvb/adapter3/frontend0
Using DVB device "Toshiba TC90522 ISDB-T module"
tuning to 491.143 MHz
...ok(0x1F)
SNR0: 0
Recording...
2020-02-11T09:46:22.116Z DEBUG mirakc::epg > QueryService By (NID#7E87, SID#5C38)
2020-02-11T09:46:22.116Z WARN mirakc::web > Post-filter is required, but not defined
2020-02-11T09:46:22.117Z DEBUG mirakc::tuner > Handle StartStreamingMessage
2020-02-11T09:46:22.117Z INFO mirakc::tuner > tuner#3: Reuse tuner already activated with GR 16
2020-02-11T09:46:22.117Z INFO mirakc::tuner > tuner#3.6400.2: Subscribed: Web(remote="192.168.xxx.xxx:59698" agent="BonDriver_Mirakurun/1.0") (priority=0)
2020-02-11T09:46:22.117Z INFO mirakc::tuner > tuner#3.6400.2: Started streaming
2020-02-11T09:46:22.117Z DEBUG mirakc::command_util > tuner#3.6400.2: Spawned 6648: mirakc-arib filter-service --sid=23608
2020-02-11T09:46:22.133Z INFO actix_web::middleware::logger > 192.168.xxx.xxx:59695 "GET /api/services/3239123610/stream?decode=1 HTTP/1.1" 200 2182868 "-" "BonDriver_Mirakurun/1.0" 4.357291
2020-02-11T09:46:22.133Z DEBUG mirakc::mpeg_ts_stream > tuner#3.6400.1: Closing...
2020-02-11T09:46:22.134Z DEBUG mirakc::tuner > Handle StopStreamingMessage
2020-02-11T09:46:22.134Z INFO mirakc::tuner > tuner#3.6400.1: Stop streaming
2020-02-11T09:46:22.134Z INFO mirakc::tuner > tuner#3.6400.1: Unsubscribed: Web(remote="192.168.xxx.xxx:59695" agent="BonDriver_Mirakurun/1.0") (priority=0)
2020-02-11T09:46:22.134Z DEBUG mirakc::command_util > tuner#3.6400.1: Killed 6401: mirakc-arib filter-service --sid=23610
2020-02-11T09:46:22.134Z DEBUG mirakc::mpeg_ts_stream > tuner#3.6400.1: EOF reached

@masnagam
Copy link
Member

masnagam commented Feb 11, 2020

タイミングの問題ですね.

どちらも同じチャンネルなので,チューナーが閉じられる前に次のリクエストが処理されると,reuseになります.

どちらも期待動作です.

仮に(ほぼ無理ですが),遅延を0にできたなら,reuseすることはなくなります.

@tkmsst
Copy link
Author

tkmsst commented Feb 11, 2020

承知しました。早速のご回答ありがとうございます。

ごくたまになのですが、チャンネル切り替え後に映像が出てこない場合があるようなので、もう少し検証してみます。

@tkmsst
Copy link
Author

tkmsst commented Feb 14, 2020

テストを重ねていたところ、1点不便なことがありました。

例えば、デフォルトの設定では毎時7分に「update-schedules」が開始され、この後20分弱「Handle UpdateSchedulesMessage」の処理が実行されます。この間にTVTestを起動するとmirakcがepg処理(もしくは強制的なチャンネル変更)を行っているためか映像が表示されません。
なお、Priorityを高くしてみましたが特に変化はありませんでした。

GETリクエストの際にepg処理を中断するようなオプションを入れていただくことは可能でしょうか。

@tkmsst
Copy link
Author

tkmsst commented Feb 14, 2020

念の為、epg処理中にTVTestで視聴(テレ朝)を試みた際のログを貼っておきます。

2020-02-14T10:07:00.001Z INFO mirakc::job > update-schedules: Scheduled for 2020-02-14 20:07:00 +09:00
2020-02-14T10:07:00.001Z DEBUG mirakc::job > update-schedules: acquiring semaphore...
2020-02-14T10:07:00.001Z INFO mirakc::job > update-schedules: performing...
2020-02-14T10:07:00.001Z DEBUG mirakc::eit_feeder > Handle UpdateSchedulesMessage
2020-02-14T10:07:00.001Z DEBUG mirakc::epg > Handle QueryServicesMessage
2020-02-14T10:07:00.002Z INFO mirakc::eit_feeder > Collecting EIT sections...
2020-02-14T10:07:00.002Z DEBUG mirakc::eit_feeder > Collecting EIT sections in CTC...
2020-02-14T10:07:00.002Z DEBUG mirakc::tuner > Handle StartStreamingMessage
2020-02-14T10:07:00.002Z INFO mirakc::tuner > tuner#0: Activate with GR 30
2020-02-14T10:07:00.002Z DEBUG mirakc::tuner > tuner#0.7779: Spawned 7779: recfsusb2n --b25 30 - -
2020-02-14T10:07:00.002Z INFO mirakc::tuner > tuner#0.7779: Activated with GR 30
2020-02-14T10:07:00.002Z INFO mirakc::tuner > tuner#0.7779.1: Subscribed: Job(eit-collector) (priority=-1)
2020-02-14T10:07:00.002Z DEBUG mirakc::broadcaster > tuner#0.7779: Started
2020-02-14T10:07:00.002Z INFO mirakc::tuner > tuner#0.7779.1: Started streaming
2020-02-14T10:07:00.002Z DEBUG mirakc::command_util > tuner#0.7779.1: Spawned 7780: mirakc-arib collect-eits
recfsusb2n 0.1.13 beta 20170122_0026, (GPL) 2016 trinity19683
ISDB-T/S TV Tuner FSUSB2N: '/dev/bus/usb/001/003', freq= 575143 kHz, duration= 0 sec.
TMCC: TXmode=3 GuardInterval=1/8 OneSeg=Y
A: QPSK 1seg FEC=2/3 IL=4
B: 64QAM 12seg FEC=3/4 IL=2
StdB25 interface : done.
Start!
2020-02-14T10:07:07.449Z DEBUG mirakc::epg > Handle UpdateSchedulesMessage
2020-02-14T10:07:09.654Z DEBUG mirakc::epg > Handle QueryServicesMessage
2020-02-14T10:07:09.654Z INFO actix_web::middleware::logger > 192.168.xxx.xxx:57748 "GET /api/services HTTP/1.1" 200 16780 "-" "BonDriver_mirakc/1.0" 0.000456
2020-02-14T10:07:09.815Z DEBUG mirakc::epg > QueryService By (NID#7FE5, SID#0428)
2020-02-14T10:07:09.815Z WARN mirakc::web > Post-filter is required, but not defined
2020-02-14T10:07:09.815Z DEBUG mirakc::tuner > Handle StartStreamingMessage
2020-02-14T10:07:09.815Z INFO mirakc::tuner > tuner#0: Grab tuner, rectivate with GR 24
2020-02-14T10:07:09.822Z DEBUG mirakc::tuner > tuner#0.7779: Killed 7779: recfsusb2n --b25 30 - -
2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7779: Deactivated
2020-02-14T10:07:09.822Z DEBUG mirakc::tuner > tuner#0.7785: Spawned 7785: recfsusb2n --b25 24 - -
2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7785: Activated with GR 24
2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7785.1: Subscribed: Web(remote="192.168.xxx.xxx:57749" agent="BonDriver_mirakc/1.0") (priority=0)
2020-02-14T10:07:09.822Z DEBUG mirakc::broadcaster > tuner#0.7785: Started
2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7785.1: Started streaming
2020-02-14T10:07:09.822Z DEBUG mirakc::broadcaster > tuner#0.7779: EOS reached, stop
2020-02-14T10:07:09.822Z DEBUG mirakc::broadcaster > tuner#0.7779: Stopped
2020-02-14T10:07:09.822Z DEBUG mirakc::mpeg_ts_stream > tuner#0.7779.1: EOF reached
2020-02-14T10:07:09.822Z DEBUG mirakc::mpeg_ts_stream > tuner#0.7779.1: Closing...
2020-02-14T10:07:09.822Z DEBUG mirakc::tuner > Handle StopStreamingMessage
2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7779.1: Stop streaming
2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7779.1: Unsubscribed: Web(remote="192.168.xxx.xxx:57749" agent="BonDriver_mirakc/1.0") (priority=0)
2020-02-14T10:07:09.823Z DEBUG mirakc::command_util > tuner#0.7785.1: Spawned 7787: mirakc-arib filter-service --sid=1064
2020-02-14T10:07:09.823Z DEBUG mirakc::tuner > tuner#0.7785: Killed 7785: recfsusb2n --b25 24 - -
2020-02-14T10:07:09.823Z INFO mirakc::tuner > tuner#0.7785: Deactivated
2020-02-14T10:07:09.823Z DEBUG mirakc::broadcaster > tuner#0.7785: EOS reached, stop
2020-02-14T10:07:09.823Z DEBUG mirakc::broadcaster > tuner#0.7785: Stopped
2020-02-14T10:07:09.823Z DEBUG mirakc::mpeg_ts_stream > tuner#0.7785.1: EOF reached
2020-02-14T10:07:09.823Z DEBUG mirakc::command_util > tuner#0.7779.1: Killed 7780: mirakc-arib collect-eits
2020-02-14T10:07:09.823Z DEBUG mirakc::eit_feeder > Collected 45 EIT sections in CTC
2020-02-14T10:07:09.823Z DEBUG mirakc::epg > Handle UpdateSchedulesMessage
2020-02-14T10:07:09.823Z DEBUG mirakc::eit_feeder > Collecting EIT sections in NHK E...
2020-02-14T10:07:09.823Z DEBUG mirakc::tuner > Handle StartStreamingMessage
2020-02-14T10:07:09.823Z INFO mirakc::tuner > tuner#0: Activate with GR 26
2020-02-14T10:07:09.824Z DEBUG mirakc::tuner > tuner#0.7788: Spawned 7788: recfsusb2n --b25 26 - -
2020-02-14T10:07:09.824Z INFO mirakc::tuner > tuner#0.7788: Activated with GR 26
2020-02-14T10:07:09.824Z INFO mirakc::tuner > tuner#0.7788.1: Subscribed: Job(eit-collector) (priority=-1)
2020-02-14T10:07:09.824Z DEBUG mirakc::broadcaster > tuner#0.7788: Started
2020-02-14T10:07:09.824Z INFO mirakc::tuner > tuner#0.7788.1: Started streaming
2020-02-14T10:07:09.824Z DEBUG mirakc::command_util > tuner#0.7788.1: Spawned 7789: mirakc-arib collect-eits
recfsusb2n 0.1.13 beta 20170122_0026, (GPL) 2016 trinity19683
ISDB-T/S TV Tuner FSUSB2N: '/dev/bus/usb/001/003', freq= 551143 kHz, duration= 0 sec.
2020-02-14T10:07:09.829Z INFO actix_web::middleware::logger > 192.168.xxx.xxx:57749 "GET /api/services/3274101064/stream?decode=1 HTTP/1.1" 200 0 "-" "BonDriver_mirakc/1.0" 0.013533
2020-02-14T10:07:09.829Z DEBUG mirakc::mpeg_ts_stream > tuner#0.7785.1: Closing...
2020-02-14T10:07:09.829Z DEBUG mirakc::tuner > Handle StopStreamingMessage
2020-02-14T10:07:09.829Z INFO mirakc::tuner > tuner#0.7785.1: Stop streaming
2020-02-14T10:07:09.829Z DEBUG mirakc::command_util > tuner#0.7785.1: Killed 7787: mirakc-arib filter-service --sid=1064
2020-02-14T10:07:09.829Z INFO mirakc::tuner > tuner#0.7785.1: Unsubscribed: Job(eit-collector) (priority=-1)
2020-02-14T10:07:09.832Z DEBUG mirakc::tuner > tuner#0.7788: Killed 7788: recfsusb2n --b25 26 - -
2020-02-14T10:07:09.832Z INFO mirakc::tuner > tuner#0.7788: Deactivated
2020-02-14T10:07:09.832Z DEBUG mirakc::broadcaster > tuner#0.7788: EOS reached, stop
2020-02-14T10:07:09.832Z DEBUG mirakc::broadcaster > tuner#0.7788: Stopped
2020-02-14T10:07:09.832Z DEBUG mirakc::mpeg_ts_stream > tuner#0.7788.1: EOF reached
2020-02-14T10:07:09.832Z DEBUG mirakc::mpeg_ts_stream > tuner#0.7788.1: Closing...
2020-02-14T10:07:09.832Z DEBUG mirakc::tuner > Handle StopStreamingMessage
2020-02-14T10:07:09.832Z INFO mirakc::tuner > tuner#0.7788.1: Stop streaming
2020-02-14T10:07:09.833Z DEBUG mirakc::command_util > tuner#0.7788.1: Killed 7789: mirakc-arib collect-eits
2020-02-14T10:07:09.833Z DEBUG mirakc::eit_feeder > Collected 0 EIT sections in NHK E
2020-02-14T10:07:09.833Z DEBUG mirakc::eit_feeder > Collecting EIT sections in TX...
2020-02-14T10:07:09.833Z DEBUG mirakc::tuner > Handle StartStreamingMessage
2020-02-14T10:07:09.833Z INFO mirakc::tuner > tuner#0: Activate with GR 23
2020-02-14T10:07:09.833Z DEBUG mirakc::tuner > tuner#0.7790: Spawned 7790: recfsusb2n --b25 23 - -
2020-02-14T10:07:09.833Z INFO mirakc::tuner > tuner#0.7790: Activated with GR 23
2020-02-14T10:07:09.833Z INFO mirakc::tuner > tuner#0.7790.1: Subscribed: Job(eit-collector) (priority=-1)
2020-02-14T10:07:09.833Z DEBUG mirakc::broadcaster > tuner#0.7790: Started
2020-02-14T10:07:09.833Z INFO mirakc::tuner > tuner#0.7790.1: Started streaming
2020-02-14T10:07:09.833Z DEBUG mirakc::command_util > tuner#0.7790.1: Spawned 7791: mirakc-arib collect-eits
recfsusb2n 0.1.13 beta 20170122_0026, (GPL) 2016 trinity19683
ISDB-T/S TV Tuner FSUSB2N: '/dev/bus/usb/001/003', freq= 533143 kHz, duration= 0 sec.
TMCC: TXmode=3 GuardInterval=1/8 OneSeg=Y
A: QPSK 1seg FEC=2/3 IL=4
B: 64QAM 12seg FEC=3/4 IL=2
StdB25 interface : done.
Start!
2020-02-14T10:07:15.035Z DEBUG mirakc::epg > Handle UpdateSchedulesMessage
2020-02-14T10:07:18.833Z DEBUG mirakc::epg > Handle UpdateSchedulesMessage
2020-02-14T10:07:22.128Z DEBUG mirakc::epg > Handle UpdateSchedulesMessage
2020-02-14T10:07:29.477Z DEBUG mirakc::epg > Handle UpdateSchedulesMessage
...

@masnagam
Copy link
Member

何らかの不具合が起きているようです.

2020-02-14T10:07:00.002Z INFO mirakc::tuner > tuner#0.7779.1: Subscribed: Job(eit-collector) (priority=-1)
...
2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7779.1: Unsubscribed: Web(remote="192.168.xxx.xxx:57749" agent="BonDriver_mirakc/1.0") (priority=0)

subscribeとunsubscribeのユーザーが一致していません.

これを修正すれば,機能追加などは必要なく期待動作するもとも思われます.

@tkmsst
Copy link
Author

tkmsst commented Feb 14, 2020

よくわからないです。。。

状況としては、mirakcにアクセスしているのはBonDriver_mirakcとEPGStationのみです。

10:07に録画サーバーでmirakcによる自動の番組情報の取得が開始され、その直後に別のPCでTVTestを起動してBonDriver_mirakcでmirakcにアクセスしています。

「2020-02-14T10:07:00.002Z INFO mirakc::tuner > tuner#0.7779.1: Subscribed: Job(eit-collector) (priority=-1)」はpriority=-1なのでmirakc自身によるtunerアクセス、「2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7779.1: Unsubscribed: Web(remote="192.168.xxx.xxx:57749" agent="BonDriver_mirakc/1.0") (priority=0)」はBonDriver_mirakcによるアクセスだというのはわかるのですが。。。

いったんEPGStationを停止して検証してみます。

ちなみに同様の現象はmirakcの起動直後「Always update schedules at startup」の直後でも再現可能で、この場合はブラウザによる「api/services/ID/stream」でも確認できます(ダウンロードが一瞬で停止する)。

@masnagam
Copy link
Member

たぶん誤解されたのだと思いますが,不具合はmirakc側で発生しています.mirakcのバグです.

各mpeg tsストリームには一意のidが割り振られていて,これを使って開放処理を行っています.

2020-02-14T10:07:00.002Z INFO mirakc::tuner > tuner#0.7779.1: Subscribed: Job(eit-collector) (priority=-1)

上記ログのtuner#0.7779.1です.上記は確保時のログですが,対応する開放ログが

2020-02-14T10:07:09.822Z INFO mirakc::tuner > tuner#0.7779.1: Unsubscribed: Web(remote="192.168.xxx.xxx:57749" agent="BonDriver_mirakc/1.0") (priority=0)

ですが,確保時のユーザー(Job(eit-collector))とは異なっており,これは想定外です.

こちらで修正しますので,少々お待ち下さい.

@tkmsst
Copy link
Author

tkmsst commented Feb 14, 2020

いつもありがとうございます。報告ばかりで協力できず申し訳ありません。

実はあと1つ他の不具合の可能性を発見しております。
デフォルトでは毎時7分と37分にepg取得処理を行うようになっていると思いますが、mirakcを起動してある程度(?)時間が経ったころに、BonDriverでアクセスすると、アクセス直後(7分、37分以外)にepg取得処理を開始するときがあります(その場合、上記のバグのためか映像がでてこない)。
これについては発生頻度が低く、条件が特定できていないので、わかり次第報告させて頂きたく存じます。

@masnagam
Copy link
Member

masnagam commented Feb 14, 2020

報告をいただけるだけで十分助かっています.本当はユニットテストなどで見つけるべき不具合なのですが,actorのテストが結構厄介でうまくテストできていない状況です.仕方ないので,実際に動かしてテストしていますが,効率が良くないです..

BonDriverでアクセスすると、アクセス直後(7分、37分以外)にepg取得処理を開始するときがあります

可能性としては,利用しているtokioのタスク管理に問題があり,スリープしてしまっているのかもしれません.HTTPリクエストが来たのでタスクスケジューラーが起きて,溜まっていたタイマー処理を実行したというシナリオが,一番ありそうな気がします.

epgstaionを使っていると,10分間隔くらいでいくつかのREST APIを呼び出すので,問題が見つかっていないだけなのかもしれません.

@tkmsst
Copy link
Author

tkmsst commented Feb 14, 2020

感覚的には「HTTPリクエストが来たのでタスクスケジューラーが起きて,溜まっていたタイマー処理を実行した」のように感じます。
EPGStation等の、mirakcへのアクセスをすべて止めてから、数時間後にBonDriverでアクセスして検証してみます。

@masnagam
Copy link
Member

ありがとうございます.こちらでも,開放処理の誤りの修正後に動作を確認してみます.

@masnagam
Copy link
Member

3d7127d で開放処理の不具合を修正しました.DockerHubのmasterタグも更新されています.

@tkmsst
Copy link
Author

tkmsst commented Feb 23, 2020

お世話になっております。
だいぶテストを重ねまして、エラーなく動いております。
CSについてもかなりテストしましたが問題はないようです。
このあたりでcloseしようと思います。
ありがとうございました。

最後に、 2807172 によってsocketが使えるようになったようですが、mirakcのconfig.ymlで
- unix: /var/run/mirakc.sock
とした上で、EPGStationのconfig.jsonで
"mirakurunPath": "http+unix://%2Fvar%2Frun%2Fmirakc.sock/"
としても、EPGStationからアクセスできないようです。

あと余談ですが、BonDriver_Mirakurunでは相変わらずドロップで使用できないため、BonDriver_mirakcを使用する必要があります。

@masnagam
Copy link
Member

masnagam commented Feb 23, 2020

こちらこそありがとうございました.おかげでmirakcの不具合も減りました.

EPGStationからアクセスできないようです

少なくとも,curlでは問題は起きていません.macOSとLinuxで確認しています.なので,UDSの機能自体は動作していると思われます.

念の為,dockerを使って動作確認してみましたが,epgstationとmirakcはunix domain socketを使って通信できているように見えます.
https://qiita.com/techneconn/items/1dbd904a158844714f4e

mirakc-testbed-mirakc |  2020-02-23T03:36:04.045Z INFO  actix_server::builder > Starting "actix-web-service-"/socket/mirakc.sock"" service on "/socket/mirakc.sock" (pathname)
...
mirakc-testbed-mirakc |  2020-02-23T03:36:05.116Z INFO  actix_web::middleware::logger > - "GET /api/status HTTP/1.1" 200 2 "-" "EPGStation/1.6.3 MirakurunClient/2.13.0 Node/v12.15.0 (linux)" 0.000118
mirakc-testbed-mirakc |  2020-02-23T03:36:05.601Z INFO  actix_web::middleware::logger > - "GET /api/services HTTP/1.1" 200 583 "-" "EPGStation/1.6.3 MirakurunClient/2.13.0 Node/v12.15.0 (linux)" 0.000188
mirakc-testbed-mirakc |  2020-02-23T03:36:05.650Z INFO  actix_web::middleware::logger > - "GET /api/programs HTTP/1.1" 200 549769 "-" "EPGStation/1.6.3 MirakurunClient/2.13.0 Node/v12.15.0 (linux)" 0.006822
mirakc-testbed-mirakc |  2020-02-23T03:36:05.864Z INFO  actix_web::middleware::logger > - "GET /api/tuners HTTP/1.1" 200 254 "-" "EPGStation/1.6.3 MirakurunClient/2.13.0 Node/v12.15.0 (linux)" 0.000366

macOS上でmirakcを起動し,docker run -v /host/mirakc.sock:/var/run/mirakc.sockなどとしてepgstationを起動した場合,ホストとコンテナーでOSが違っているためunix domain socketでの通信ができないようです.恐らく,これに類する状況なのではないかと想像しますが,どのような状況で発生しているのか詳しく教えてください.

あと余談ですが、BonDriver_Mirakurunでは相変わらずドロップで使用できないため、BonDriver_mirakcを使用する必要があります。

ドキュメントではBonDriver_Mirakurunで使えるみたいに書いてあるので,書き換えておきます.

想像ですが,BonDriver_Mirakurunまたはmirakcに何らかのタイミングに依存した問題があるのだろうと思います.ひとまずBonDriver_mirakcで動かせるようにしていただいたので,時間があるときにBonDriver_Mirakurunの動作を見てみることにします.

@tkmsst
Copy link
Author

tkmsst commented Feb 23, 2020

ご返答ありがとうございます。
環境はなるべくシンプルに、Debian Busterでdockerを使わずに直接 pm2によるEPGStationの起動と、シェルでmirakcの起動を行っています。
configの記述の仕方
- unix: /var/run/mirakc.sock (mirakc)
"mirakurunPath": "http+unix://%2Fvar%2Frun%2Fmirakc.sock/" (EPGStatinon)
が悪いのかと思ったのですが、そういうわけでもないのでしょうか。
(/var/runのディレクトリにmirakc.sockが作成されていることは確認しています)

なお当然ながら、Mirakurunでは問題ありませんし、mirakcでも
"mirakurunPath": "http://127.0.0.1:40772"
の記述では問題ありません。

@masnagam
Copy link
Member

masnagam commented Feb 23, 2020

ファイルのアクセス権とかでしょうか?
dockerだと何もしなければどちらもrootなので特に気にしていませんでしたが.

configの記述の仕方
が悪いのかと思ったのですが、そういうわけでもないのでしょうか。

設定の問題ではないと思います.パスは異なりますが,同じような設定でmirakc/EPGStation間でUDSが動作することを確認済みです.先のコメントのログを見てください.

@masnagam
Copy link
Member

masnagam commented Feb 23, 2020

多分アクセス権ですね.
https://github.com/Chinachu/Mirakurun/blob/master/src/Mirakurun/Server.ts#L166

mirakcをEPGStationと同じユーザーで実行するか,mirakc実行後にソケットファイルのパーミッションを変更すれば(chmod 0777とか),つながるようになるかもしれません.

@tkmsst
Copy link
Author

tkmsst commented Feb 23, 2020

パーミッション(chmod 0777)、ユーザー変更、どちらでもできました。ありがとうございます。
もし可能であれば、この辺の設定をconfig.ymlで可能にできたらありがたいです!

@masnagam
Copy link
Member

この辺の設定をconfig.ymlで可能にできたらありがたいです

申し訳ありませんが,そのような設定を追加する考えはありません.

個人的意見ですが,安全上の理由などがない限りは,利用者側で対応可能なことまでアプリケーションで対応する必要はないと考えています.

今回の場合ですと,mirakc起動後にchmodしたり,SUID/SGIDを使うなどで回避可能なので,類似機能をアプリケーションに実装する必要はないと考えています.

@tkmsst
Copy link
Author

tkmsst commented Feb 24, 2020

承知いたしました。
mirakc起動からmirakc.sockファイル作成にタイムラグがあるため、forとsleepをからめたシェスクリプトを作って対処することといたしました。

ありがとうございました。

@tkmsst tkmsst closed this as completed Feb 24, 2020
@tkmsst
Copy link
Author

tkmsst commented Feb 24, 2020

README.mdの記述

It's strongly recommended to enable SERVICE_SPLIT in BonDriver_Mirakurun.ini

BonDriver_mirakc.iniですね。

@masnagam
Copy link
Member

そうですね.書き換えておきます.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants