fix: use native python function to create non-blocking pipe.
Thanks @azlux for this solution. Close #116. Also created an option 'redirect_ffmpeg_log' to enable/disable reading the log of ffmpeg.
This commit is contained in:
@ -105,6 +105,7 @@ password =
|
|||||||
[debug]
|
[debug]
|
||||||
# Set ffmpeg to True if you want to display DEBUG level log of ffmpeg.
|
# Set ffmpeg to True if you want to display DEBUG level log of ffmpeg.
|
||||||
ffmpeg = False
|
ffmpeg = False
|
||||||
|
redirect_ffmpeg_log = True
|
||||||
mumbleConnection = False
|
mumbleConnection = False
|
||||||
|
|
||||||
# This is a list of default radio stations.
|
# This is a list of default radio stations.
|
||||||
|
33
mumbleBot.py
33
mumbleBot.py
@ -162,6 +162,8 @@ class MumbleBot:
|
|||||||
self._display_rms = False
|
self._display_rms = False
|
||||||
self._max_rms = 0
|
self._max_rms = 0
|
||||||
|
|
||||||
|
self.redirect_ffmpeg_log = var.config.getboolean('debug', 'redirect_ffmpeg_log', fallback=True)
|
||||||
|
|
||||||
# Set the CTRL+C shortcut
|
# Set the CTRL+C shortcut
|
||||||
def ctrl_caught(self, signal, frame):
|
def ctrl_caught(self, signal, frame):
|
||||||
|
|
||||||
@ -375,9 +377,12 @@ class MumbleBot:
|
|||||||
|
|
||||||
# The ffmpeg process is a thread
|
# The ffmpeg process is a thread
|
||||||
# prepare pipe for catching stderr of ffmpeg
|
# prepare pipe for catching stderr of ffmpeg
|
||||||
pipe_rd, pipe_wd = os.pipe()
|
if self.redirect_ffmpeg_log:
|
||||||
util.pipe_no_wait(pipe_rd) # Let the pipe work in non-blocking mode
|
pipe_rd, pipe_wd = util.pipe_no_wait() # Let the pipe work in non-blocking mode
|
||||||
self.thread_stderr = os.fdopen(pipe_rd)
|
self.thread_stderr = os.fdopen(pipe_rd)
|
||||||
|
else:
|
||||||
|
pipe_rd, pipe_wd = None, None
|
||||||
|
|
||||||
self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480)
|
self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480)
|
||||||
self.is_pause = False
|
self.is_pause = False
|
||||||
self.read_pcm_size = 0
|
self.read_pcm_size = 0
|
||||||
@ -449,12 +454,13 @@ class MumbleBot:
|
|||||||
raw_music = self.thread.stdout.read(480)
|
raw_music = self.thread.stdout.read(480)
|
||||||
self.read_pcm_size += 480
|
self.read_pcm_size += 480
|
||||||
|
|
||||||
try:
|
if self.redirect_ffmpeg_log:
|
||||||
self.last_ffmpeg_err = self.thread_stderr.readline()
|
try:
|
||||||
if self.last_ffmpeg_err:
|
self.last_ffmpeg_err = self.thread_stderr.readline()
|
||||||
self.log.debug("ffmpeg: " + self.last_ffmpeg_err.strip("\n"))
|
if self.last_ffmpeg_err:
|
||||||
except:
|
self.log.debug("ffmpeg: " + self.last_ffmpeg_err.strip("\n"))
|
||||||
pass
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
if raw_music:
|
if raw_music:
|
||||||
# Adjust the volume and send it to mumble
|
# Adjust the volume and send it to mumble
|
||||||
@ -623,9 +629,12 @@ class MumbleBot:
|
|||||||
self.log.info("bot: execute ffmpeg command: " + " ".join(command))
|
self.log.info("bot: execute ffmpeg command: " + " ".join(command))
|
||||||
# The ffmpeg process is a thread
|
# The ffmpeg process is a thread
|
||||||
# prepare pipe for catching stderr of ffmpeg
|
# prepare pipe for catching stderr of ffmpeg
|
||||||
pipe_rd, pipe_wd = os.pipe()
|
if self.redirect_ffmpeg_log:
|
||||||
util.pipe_no_wait(pipe_rd) # Let the pipe work in non-blocking mode
|
pipe_rd, pipe_wd = util.pipe_no_wait() # Let the pipe work in non-blocking mode
|
||||||
self.thread_stderr = os.fdopen(pipe_rd)
|
self.thread_stderr = os.fdopen(pipe_rd)
|
||||||
|
else:
|
||||||
|
pipe_rd, pipe_wd = None, None
|
||||||
|
|
||||||
self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480)
|
self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480)
|
||||||
self.last_volume_cycle_time = time.time()
|
self.last_volume_cycle_time = time.time()
|
||||||
self.pause_at_id = ""
|
self.pause_at_id = ""
|
||||||
|
36
util.py
36
util.py
@ -163,19 +163,29 @@ def url_unban(url):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def pipe_no_wait(pipefd):
|
def pipe_no_wait():
|
||||||
""" Used to fetch the STDERR of ffmpeg. pipefd is the file descriptor returned from os.pipe()"""
|
""" Generate a non-block pipe used to fetch the STDERR of ffmpeg.
|
||||||
|
"""
|
||||||
|
|
||||||
if platform == "linux" or platform == "linux2" or platform == "darwin":
|
if platform == "linux" or platform == "linux2" or platform == "darwin":
|
||||||
import fcntl
|
import fcntl
|
||||||
import os
|
import os
|
||||||
try:
|
|
||||||
fl = fcntl.fcntl(pipefd, fcntl.F_GETFL)
|
pipe_rd = 0
|
||||||
fcntl.fcntl(pipefd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
|
pipe_wd = 0
|
||||||
except:
|
|
||||||
print(sys.exc_info()[1])
|
if hasattr(os, "pipe2"):
|
||||||
return False
|
pipe_rd, pipe_wd = os.pipe2(os.O_NONBLOCK)
|
||||||
else:
|
else:
|
||||||
return True
|
pipe_rd, pipe_wd = os.pipe()
|
||||||
|
|
||||||
|
try:
|
||||||
|
fl = fcntl.fcntl(pipe_rd, fcntl.F_GETFL)
|
||||||
|
fcntl.fcntl(pipe_rd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
|
||||||
|
except:
|
||||||
|
print(sys.exc_info()[1])
|
||||||
|
return None, None
|
||||||
|
return pipe_rd, pipe_wd
|
||||||
|
|
||||||
elif platform == "win32":
|
elif platform == "win32":
|
||||||
# https://stackoverflow.com/questions/34504970/non-blocking-read-on-os-pipe-on-windows
|
# https://stackoverflow.com/questions/34504970/non-blocking-read-on-os-pipe-on-windows
|
||||||
@ -185,6 +195,8 @@ def pipe_no_wait(pipefd):
|
|||||||
from ctypes import windll, byref, wintypes, WinError, POINTER
|
from ctypes import windll, byref, wintypes, WinError, POINTER
|
||||||
from ctypes.wintypes import HANDLE, DWORD, BOOL
|
from ctypes.wintypes import HANDLE, DWORD, BOOL
|
||||||
|
|
||||||
|
pipe_rd, pipe_wd = os.pipe()
|
||||||
|
|
||||||
LPDWORD = POINTER(DWORD)
|
LPDWORD = POINTER(DWORD)
|
||||||
PIPE_NOWAIT = wintypes.DWORD(0x00000001)
|
PIPE_NOWAIT = wintypes.DWORD(0x00000001)
|
||||||
ERROR_NO_DATA = 232
|
ERROR_NO_DATA = 232
|
||||||
@ -193,13 +205,13 @@ def pipe_no_wait(pipefd):
|
|||||||
SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
|
SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD]
|
||||||
SetNamedPipeHandleState.restype = BOOL
|
SetNamedPipeHandleState.restype = BOOL
|
||||||
|
|
||||||
h = msvcrt.get_osfhandle(pipefd)
|
h = msvcrt.get_osfhandle(pipe_rd)
|
||||||
|
|
||||||
res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
|
res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None)
|
||||||
if res == 0:
|
if res == 0:
|
||||||
print(WinError())
|
print(WinError())
|
||||||
return False
|
return None, None
|
||||||
return True
|
return pipe_rd, pipe_wd
|
||||||
|
|
||||||
|
|
||||||
class Dir(object):
|
class Dir(object):
|
||||||
|
Reference in New Issue
Block a user