Haskell处理流时管道破裂错误



我正在尝试使用流构建一个播放器。主要想法是让一个线程运行一个播放器,读取来自另一个线程同时下载youtube音频的字节。代码工作了一段时间,内容正确流式传输,但几秒钟后,我总是得到这个错误:Exception: fd:13: hPutBuf: resource vanished (Broken pipe).

我想我错过了一些东西,因为即使使用connect函数的结果是相同的。下面是代码(简化):

import Control.Concurrent
import System.IO.Streams 
import Data.ByteString
main = do
(sink,_,_,_) <- runInteractiveCommand "mplayer -novideo - cache 5096 -"
mainSink <- lockingOutputStream sink  -- main audio stream, goes straight to player
(_,source,_,_) <- runInteractiveCommand "yt-dlp "https://www.youtube.com/watch?v=uFtfDK39ZhI" -f bv+ba -o -"
loop mainSink source

loop :: OutputStream ByteString -> InputStream ByteString -> IO ()
loop sink src = do
sourceBytes <- peek src
case sourceBytes of
Nothing -> do loop sink src
Just _  -> do
audioBytes <- read src 
write audioBytes sink
loop sink src

问题似乎是mplayer在stdout和stderr上生成其通常的详细终端输出,而yt-dlp在stderr上类似地生成输出。由于您丢弃了这些句柄,并且从未吸干它们,因此最终管道缓冲区会被填满,进程就会卡住。我不能确切地说为什么一个或两个进程死亡而不是挂起,但这就是正在发生的事情。下面是一个简单的示例,将不需要的输出重定向到/dev/null,并且看起来有效:

import System.IO.Streams
main = do
(sink,_,_,_) <- runInteractiveCommand "mplayer -cache 5096 - 2>/dev/null >&2"
(_,source,_,_) <- runInteractiveCommand "yt-dlp "https://www.youtube.com/watch?v=uFtfDK39ZhI" -f bv+ba -o - 2>/dev/null"
connect source sink

最新更新