Python 当 运行 脚本在 RPi 3B+ 上进行多处理时出现 vlc 错误
Python vlc errors when running script with multiprocessing on RPi 3B+
我在 Raspberry Pi 3B+ 上有一个 python 脚本 (sound_play.py),它使用 vlc 播放 mp3 文件和网络广播流。
它可以单独 运行(用于测试目的),也可以作为进程中的模块由另一个脚本 (clock.py) 使用多处理启动。
当我单独 运行 sound_play.py 时,一切正常,但如果脚本作为子进程启动,当 file/the webradio 时,我会在下面收到错误消息应该玩。
我在 ALSA 和 PulseAudio 上都试过了,但行为是一样的,它自己可以工作,多处理就不行。
一些背景信息:我刚刚重新安装了 Raspbian(以解决一个不相关的问题),所以现在我有了 Bullseye。在那之前我有一些版本的 Buster,脚本运行良好,无论是在它自己还是在子进程中。我只在重新安装 Raspbian.
后才收到错误
这可能是什么原因造成的?我该如何解决?提前谢谢你。
使用 ALSA 时出错:
17:29:42 playing https://orf-live.ors-shoutcast.at/oe1-q2a
[6d691318] prefetch stream error: unimplemented query (264) in control
[025e28a8] alsa audio output error: cannot open ALSA device "default": Input/output error
[025e28a8] main audio output error: Audio output failed
[025e28a8] main audio output error: The audio device "default" could not be used:
Input/output error.
[025e28a8] main audio output error: module not functional
[71f45f68] main decoder error: failed to create audio output
使用 PulseAudio 时出错:
17:46:26 playing https://orf-live.ors-shoutcast.at/oe1-q2a
[4cd97a68] prefetch stream error: unimplemented query (264) in control
[02019030] vlcpulse audio output error: stream creation failure: Client forked
[02019030] main audio output error: module not functional
[71f4c390] main decoder error: failed to create audio output
sound_play.py
#!/usr/bin/env python3
"""
sound_play.py
play sounds at certain times
"""
#IMPORTS
import time
from datetime import datetime, timedelta
import vlc
#CONSTANTS
DEBUG = True
VOLUME = 80 #in percent
DUR_SUNRISE = 5 #min
DUR_AFTERGLOW = 5 #min
MUSIC_PATH = "./alarms/"
HOURBELL = "./hourbell.mp3"
RADIO_NAME = "Radio Österreich Eins"
RADIO_URL = "https://orf-live.ors-shoutcast.at/oe1-q2a"
#GLOBALS
config = None
temp = None
instance = vlc.Instance('--aout=alsa')
player = instance.media_player_new()
def start(source):
media = instance.media_new(source)
player.set_media(media)
player.play()
if DEBUG: print(time.strftime("%T"), "playing " + str(source))
def stop():
player.stop()
if DEBUG: print(time.strftime("%T"), "stopped playing")
def main(*args):
global DEBUG, config, temp
if args:
(debug, config, temp) = args
if debug == True:
DEBUG = True
global instance
radio_active = False
radio_start = 0.0
music_active = False
music_start = 0.0
hourbell_active = False
hourbell_start = 0.0
hourbell_last = ""
vlc.libvlc_audio_set_volume(player, VOLUME)
if not DEBUG: instance.log_unset()
while True:
if not config == None:
#radio
if temp["button_new"] and temp["read_button"] == "*":
temp["button_new"] = False
if (music_active and not radio_active) or radio_active:
radio_active = False
music_active = False
stop()
else:
start(RADIO_URL)
radio_active = True
music_active = False
radio_start = time.time()
if radio_active and time.time() >= radio_start + (60 * 60):
radio_active = False
stop()
#alarm
if config["alarm_music"] and time.strftime("%H%M") == config["alarm_time"] and time.time() >= music_start + 60:
if config["alarm_song"] != RADIO_NAME and not music_active:
if not radio_active: start(MUSIC_PATH + config["alarm_song"] + ".mp3")
music_active = True
elif config["alarm_song"] == RADIO_NAME:
if not radio_active: start(RADIO_URL)
radio_active = True
music_active = True
radio_start = time.time()
music_start = time.time()
elif music_active and not radio_active and time.time() >= music_start + 1.5:
if time.time() >= music_start + player.get_length() / 1000 + 1.5:
music_active = False
stop()
elif music_active and radio_active and time.time() >= music_start + (5 * 60):
music_active = False
#hourbell
if time.strftime("%M") == "00" and not time.strftime("%H") == hourbell_last:
hourbell_last = time.strftime("%H")
if config["alarm_hourbell"] and not hourbell_active and not music_active and not radio_active \
and (time.time() - temp["afterglow_start"] < DUR_AFTERGLOW * 60 or temp["light_on"]):
start(HOURBELL)
hourbell_active = True
hourbell_start = time.time()
elif hourbell_active and time.time() >= hourbell_start + 1.5:
if time.time() >= hourbell_start + player.get_length() / 1000 + 1.5:
hourbell_active = False
stop()
#sunrise
time_after_duration = time.strftime("%H%M", time.localtime((datetime.now() + timedelta(minutes=DUR_SUNRISE)).timestamp()))
if time_after_duration == config["alarm_time"] and config["alarm_sunrise"] and not temp["sunrise_active"]:
temp["sunrise_active"] = True
elif time.strftime("%H%M") >= config["alarm_time"] and temp["sunrise_active"] and not music_active:
temp["sunrise_active"] = False
time.sleep(0.01)
else:
source = input("source: ")
if source == "r": start(RADIO_URL)
else: start(MUSIC_PATH + source + ".mp3")
input("stop")
stop()
if __name__ == "__main__":
main()
clock.py
#!/usr/bin/env python3
"""
clock.py
main script, manage module threads
"""
#IMPORTS
import os
from multiprocessing import Process, Manager
import json
import time
import RPi.GPIO as GPIO
#import time_sync
import weather_fetch
import arduino_talk
import room_measure
import hands_move
import sound_play
import gui_show
#CONSTANTS
debug = False #debug for all modules
DEBUG = False #debug for this script
NICENESS = -5
CONFIG_FILE = "./config.json"
PIN_STEPPER = {
"hour": {
"A": 4,
"B": 17,
"C": 27,
"D": 22,
},
"minute": {
"A": 5,
"B": 6,
"C": 13,
"D": 19,
}
}
def main():
def store_clock(config):
while True:
with open(CONFIG_FILE, "w") as config_file:
json.dump(config.copy(), config_file)
if debug: print(time.strftime("%T"), "Configuration stored")
time.sleep(20)
global DEBUG
if debug:
DEBUG = True
config_reset = {
#hands_move
"calibration": {'first': {'hour': 1926, 'minute': 1920}, 'second': {'hour': 1915, 'minute': 1920}},
#gui_show
"alarm_time": "0000",
"alarm_sunrise": False,
"alarm_music": False,
"alarm_hourbell": False,
"alarm_song": "",
"weather_location": "Lessach",
}
temp_reset = {
#weather_fetch
"weather_current": "",
"weather_forecast": "",
#arduino_talk
"light_on": True,
"read_button": "",
"button_new": False,
#room_measure
"room_climate": "",
#gui_show
"sunrise_active": False,
"afterglow_start": 0.0,
}
os.system("sudo renice -n " + str(NICENESS) + " -p " + str(os.getpid()) + ">/dev/null")
print("MULTIFUNKTIONS-DESIGNUHR")
print("Michael Matthias Jesner")
print("WSH Gesellenstück 2020")
print("Zum Beenden Enter drücken\n")
if not os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, "w") as config_file:
json.dump(config_reset, config_file)
if debug: print(time.strftime("%T"), "Reset config.json")
with open(CONFIG_FILE, "r") as config_file:
config = Manager().dict(json.load(config_file))
temp = Manager().dict(temp_reset)
store_process = Process(target = store_clock, args = (config,))
process = [
#Process(target = time_sync.main, args = (debug, config, temp)),
Process(target = weather_fetch.main, args = (debug, config, temp)),
Process(target = arduino_talk.main, args = (debug, config, temp)),
Process(target = room_measure.main, args = (debug, config, temp)),
Process(target = hands_move.main, args = (debug, config, temp)),
Process(target = sound_play.main, args = (debug, config, temp)),
Process(target = gui_show.main, args = (debug, config, temp)),
]
for x in range(len(process)):
process[x].start()
store_process.start()
input("")
store_process.terminate()
with open(CONFIG_FILE, "w") as config_file:
json.dump(config.copy(), config_file)
for x in range(len(process)):
process[x].terminate()
GPIO.setmode(GPIO.BCM)
for x in PIN_STEPPER:
for y in PIN_STEPPER[x]:
GPIO.setup(PIN_STEPPER[x][y],GPIO.OUT)
GPIO.output(PIN_STEPPER[x][y], GPIO.LOW)
if __name__ == "__main__":
main()
最小可重现示例:
test1.py
from multiprocessing import Process, Manager
import test2
def main():
p = Process(target = test2.main)
p.start()
input()
p.terminate()
if __name__ == "__main__":
main()
test2.py
#!/usr/bin/env python3
import vlc
import time
VOLUME = 100
URL = "https://orf-live.ors-shoutcast.at/oe1-q2a"
instance = vlc.Instance('--aout=alsa')
player = instance.media_player_new()
vlc.libvlc_audio_set_volume(player, VOLUME)
def main():
media = instance.media_new(URL)
player.set_media(media)
while True:
player.play()
time.sleep(5)
player.pause()
time.sleep(5)
if __name__ == "__main__":
main()
我找到了错误的原因:在 python 中导入模块运行其中的代码。 instance
和 player
因此在导入时创建,因为这两行在 main()
之外。我将它们放在 main()
中,它起作用了。
我不知道为什么在我重新安装 os 之前这没有引起同样的问题,但这已经不重要了。
工作示例:
test1.py
from multiprocessing import Process, Manager
import test2
def main():
p = Process(target = test2.main)
p.start()
input()
p.terminate()
if __name__ == "__main__":
main()
test2.py
#!/usr/bin/env python3
import vlc
import time
VOLUME = 100
URL = "https://orf-live.ors-shoutcast.at/oe1-q2a"
def main():
instance = vlc.Instance('--aout=alsa')
player = instance.media_player_new()
vlc.libvlc_audio_set_volume(player, VOLUME)
media = instance.media_new(URL)
player.set_media(media)
while True:
player.play()
time.sleep(5)
player.pause()
time.sleep(5)
if __name__ == "__main__":
main()
我在 Raspberry Pi 3B+ 上有一个 python 脚本 (sound_play.py),它使用 vlc 播放 mp3 文件和网络广播流。 它可以单独 运行(用于测试目的),也可以作为进程中的模块由另一个脚本 (clock.py) 使用多处理启动。
当我单独 运行 sound_play.py 时,一切正常,但如果脚本作为子进程启动,当 file/the webradio 时,我会在下面收到错误消息应该玩。 我在 ALSA 和 PulseAudio 上都试过了,但行为是一样的,它自己可以工作,多处理就不行。
一些背景信息:我刚刚重新安装了 Raspbian(以解决一个不相关的问题),所以现在我有了 Bullseye。在那之前我有一些版本的 Buster,脚本运行良好,无论是在它自己还是在子进程中。我只在重新安装 Raspbian.
后才收到错误这可能是什么原因造成的?我该如何解决?提前谢谢你。
使用 ALSA 时出错:
17:29:42 playing https://orf-live.ors-shoutcast.at/oe1-q2a
[6d691318] prefetch stream error: unimplemented query (264) in control
[025e28a8] alsa audio output error: cannot open ALSA device "default": Input/output error
[025e28a8] main audio output error: Audio output failed
[025e28a8] main audio output error: The audio device "default" could not be used:
Input/output error.
[025e28a8] main audio output error: module not functional
[71f45f68] main decoder error: failed to create audio output
使用 PulseAudio 时出错:
17:46:26 playing https://orf-live.ors-shoutcast.at/oe1-q2a
[4cd97a68] prefetch stream error: unimplemented query (264) in control
[02019030] vlcpulse audio output error: stream creation failure: Client forked
[02019030] main audio output error: module not functional
[71f4c390] main decoder error: failed to create audio output
sound_play.py
#!/usr/bin/env python3
"""
sound_play.py
play sounds at certain times
"""
#IMPORTS
import time
from datetime import datetime, timedelta
import vlc
#CONSTANTS
DEBUG = True
VOLUME = 80 #in percent
DUR_SUNRISE = 5 #min
DUR_AFTERGLOW = 5 #min
MUSIC_PATH = "./alarms/"
HOURBELL = "./hourbell.mp3"
RADIO_NAME = "Radio Österreich Eins"
RADIO_URL = "https://orf-live.ors-shoutcast.at/oe1-q2a"
#GLOBALS
config = None
temp = None
instance = vlc.Instance('--aout=alsa')
player = instance.media_player_new()
def start(source):
media = instance.media_new(source)
player.set_media(media)
player.play()
if DEBUG: print(time.strftime("%T"), "playing " + str(source))
def stop():
player.stop()
if DEBUG: print(time.strftime("%T"), "stopped playing")
def main(*args):
global DEBUG, config, temp
if args:
(debug, config, temp) = args
if debug == True:
DEBUG = True
global instance
radio_active = False
radio_start = 0.0
music_active = False
music_start = 0.0
hourbell_active = False
hourbell_start = 0.0
hourbell_last = ""
vlc.libvlc_audio_set_volume(player, VOLUME)
if not DEBUG: instance.log_unset()
while True:
if not config == None:
#radio
if temp["button_new"] and temp["read_button"] == "*":
temp["button_new"] = False
if (music_active and not radio_active) or radio_active:
radio_active = False
music_active = False
stop()
else:
start(RADIO_URL)
radio_active = True
music_active = False
radio_start = time.time()
if radio_active and time.time() >= radio_start + (60 * 60):
radio_active = False
stop()
#alarm
if config["alarm_music"] and time.strftime("%H%M") == config["alarm_time"] and time.time() >= music_start + 60:
if config["alarm_song"] != RADIO_NAME and not music_active:
if not radio_active: start(MUSIC_PATH + config["alarm_song"] + ".mp3")
music_active = True
elif config["alarm_song"] == RADIO_NAME:
if not radio_active: start(RADIO_URL)
radio_active = True
music_active = True
radio_start = time.time()
music_start = time.time()
elif music_active and not radio_active and time.time() >= music_start + 1.5:
if time.time() >= music_start + player.get_length() / 1000 + 1.5:
music_active = False
stop()
elif music_active and radio_active and time.time() >= music_start + (5 * 60):
music_active = False
#hourbell
if time.strftime("%M") == "00" and not time.strftime("%H") == hourbell_last:
hourbell_last = time.strftime("%H")
if config["alarm_hourbell"] and not hourbell_active and not music_active and not radio_active \
and (time.time() - temp["afterglow_start"] < DUR_AFTERGLOW * 60 or temp["light_on"]):
start(HOURBELL)
hourbell_active = True
hourbell_start = time.time()
elif hourbell_active and time.time() >= hourbell_start + 1.5:
if time.time() >= hourbell_start + player.get_length() / 1000 + 1.5:
hourbell_active = False
stop()
#sunrise
time_after_duration = time.strftime("%H%M", time.localtime((datetime.now() + timedelta(minutes=DUR_SUNRISE)).timestamp()))
if time_after_duration == config["alarm_time"] and config["alarm_sunrise"] and not temp["sunrise_active"]:
temp["sunrise_active"] = True
elif time.strftime("%H%M") >= config["alarm_time"] and temp["sunrise_active"] and not music_active:
temp["sunrise_active"] = False
time.sleep(0.01)
else:
source = input("source: ")
if source == "r": start(RADIO_URL)
else: start(MUSIC_PATH + source + ".mp3")
input("stop")
stop()
if __name__ == "__main__":
main()
clock.py
#!/usr/bin/env python3
"""
clock.py
main script, manage module threads
"""
#IMPORTS
import os
from multiprocessing import Process, Manager
import json
import time
import RPi.GPIO as GPIO
#import time_sync
import weather_fetch
import arduino_talk
import room_measure
import hands_move
import sound_play
import gui_show
#CONSTANTS
debug = False #debug for all modules
DEBUG = False #debug for this script
NICENESS = -5
CONFIG_FILE = "./config.json"
PIN_STEPPER = {
"hour": {
"A": 4,
"B": 17,
"C": 27,
"D": 22,
},
"minute": {
"A": 5,
"B": 6,
"C": 13,
"D": 19,
}
}
def main():
def store_clock(config):
while True:
with open(CONFIG_FILE, "w") as config_file:
json.dump(config.copy(), config_file)
if debug: print(time.strftime("%T"), "Configuration stored")
time.sleep(20)
global DEBUG
if debug:
DEBUG = True
config_reset = {
#hands_move
"calibration": {'first': {'hour': 1926, 'minute': 1920}, 'second': {'hour': 1915, 'minute': 1920}},
#gui_show
"alarm_time": "0000",
"alarm_sunrise": False,
"alarm_music": False,
"alarm_hourbell": False,
"alarm_song": "",
"weather_location": "Lessach",
}
temp_reset = {
#weather_fetch
"weather_current": "",
"weather_forecast": "",
#arduino_talk
"light_on": True,
"read_button": "",
"button_new": False,
#room_measure
"room_climate": "",
#gui_show
"sunrise_active": False,
"afterglow_start": 0.0,
}
os.system("sudo renice -n " + str(NICENESS) + " -p " + str(os.getpid()) + ">/dev/null")
print("MULTIFUNKTIONS-DESIGNUHR")
print("Michael Matthias Jesner")
print("WSH Gesellenstück 2020")
print("Zum Beenden Enter drücken\n")
if not os.path.exists(CONFIG_FILE):
with open(CONFIG_FILE, "w") as config_file:
json.dump(config_reset, config_file)
if debug: print(time.strftime("%T"), "Reset config.json")
with open(CONFIG_FILE, "r") as config_file:
config = Manager().dict(json.load(config_file))
temp = Manager().dict(temp_reset)
store_process = Process(target = store_clock, args = (config,))
process = [
#Process(target = time_sync.main, args = (debug, config, temp)),
Process(target = weather_fetch.main, args = (debug, config, temp)),
Process(target = arduino_talk.main, args = (debug, config, temp)),
Process(target = room_measure.main, args = (debug, config, temp)),
Process(target = hands_move.main, args = (debug, config, temp)),
Process(target = sound_play.main, args = (debug, config, temp)),
Process(target = gui_show.main, args = (debug, config, temp)),
]
for x in range(len(process)):
process[x].start()
store_process.start()
input("")
store_process.terminate()
with open(CONFIG_FILE, "w") as config_file:
json.dump(config.copy(), config_file)
for x in range(len(process)):
process[x].terminate()
GPIO.setmode(GPIO.BCM)
for x in PIN_STEPPER:
for y in PIN_STEPPER[x]:
GPIO.setup(PIN_STEPPER[x][y],GPIO.OUT)
GPIO.output(PIN_STEPPER[x][y], GPIO.LOW)
if __name__ == "__main__":
main()
最小可重现示例:
test1.py
from multiprocessing import Process, Manager
import test2
def main():
p = Process(target = test2.main)
p.start()
input()
p.terminate()
if __name__ == "__main__":
main()
test2.py
#!/usr/bin/env python3
import vlc
import time
VOLUME = 100
URL = "https://orf-live.ors-shoutcast.at/oe1-q2a"
instance = vlc.Instance('--aout=alsa')
player = instance.media_player_new()
vlc.libvlc_audio_set_volume(player, VOLUME)
def main():
media = instance.media_new(URL)
player.set_media(media)
while True:
player.play()
time.sleep(5)
player.pause()
time.sleep(5)
if __name__ == "__main__":
main()
我找到了错误的原因:在 python 中导入模块运行其中的代码。 instance
和 player
因此在导入时创建,因为这两行在 main()
之外。我将它们放在 main()
中,它起作用了。
我不知道为什么在我重新安装 os 之前这没有引起同样的问题,但这已经不重要了。
工作示例:
test1.py
from multiprocessing import Process, Manager
import test2
def main():
p = Process(target = test2.main)
p.start()
input()
p.terminate()
if __name__ == "__main__":
main()
test2.py
#!/usr/bin/env python3
import vlc
import time
VOLUME = 100
URL = "https://orf-live.ors-shoutcast.at/oe1-q2a"
def main():
instance = vlc.Instance('--aout=alsa')
player = instance.media_player_new()
vlc.libvlc_audio_set_volume(player, VOLUME)
media = instance.media_new(URL)
player.set_media(media)
while True:
player.play()
time.sleep(5)
player.pause()
time.sleep(5)
if __name__ == "__main__":
main()