我正在编写一个iOS应用程序,以通过MQTT控制在Raspberry pi上运行的Python 3.6程序。 Python程序通过OMX Player播放视频。定义了一个名为VideoDisplay的类,该类使用OMXPlayer(object)类。触发接近传感器后,就会选择并播放视频。
我的iOS控制器应用程序具有一个暂停按钮,按下该按钮可停止视频播放并显示“ PAUSED”图像。这很好。将此称为案例1
iOS控制器具有一个视图,该视图在播放从tableView中选择的视频时显示。此视图具有一个视频停止按钮,该按钮调用的代码与案例1中使用的代码相同,但是视频不会停止。将此称为案例2 。
从到目前为止的调试尝试来看,情况1中的播放视频立即被发送到MQTT处理程序的消息中断,而情况2中,播放的视频并未中断并且iOS发送的消息被中断在视频播放完毕之前,将忽略通过MQTT的控制器应用程序。我知道这是因为在视频播放结束后,MQTT处理程序中的打印语句仍然无法执行。
我不明白为什么在案例1中而不是在案例2中发生了immeidate中断。我敢肯定我缺少一些基本的东西,尤其是Python。流程管理。有人可以向我解释为什么在一种情况下而不是在其他情况下会忽略来自控制器应用程序的消息吗?
所有MQTT消息似乎都按应有的方式发送和接收。注意代码中的其他注释,这些注释确定了我认为应该发生的地方。大多数打印语句是从我的调试中获得的。
以下是视频显示和OMX Player声明:
#SETTUP OMX PLAYER -----------------------------------------------------------------------
class OMXPlayer(object):
def __init__(self):
"""Create an instance of a video player that runs omxplayer in the
background.
"""
self._process = None
self._playbackType = "auto"
def play(self, movie, loop=False, vol=0):
print("PLAY")
self.stop(1) # Up to 3 second delay to let the old player stop.
# Assemble list of arguments.
args = ['omxplayer', "-b"]
#args.extend(['-o', self._sound_vol]) # Add sound arguments.
#args.extend(self._extra_args) # Add extra arguments from config.
if vol is not 0:
args.extend(['--vol', str(vol)])
if loop:
args.append('--loop') # Add loop parameter if necessary.
args.append(movie) # Add movie file path.
# Run omxplayer process and direct standard output to /dev/null.
self._process = subprocess.Popen(args,
stdout=open(os.devnull, 'wb'),
close_fds=True)
while True:
if self._process.poll() is not None:
break
print(self._playbackType)
if self._playbackType == "auto playing":
mqttClient.publish("movie", "done")
elif self._playbackType == "list":
mqttClient.publish("list-play-cntl", "list-play-done")
self._playbackType = "auto"
def is_playing(self):
"""Return true if the video player is running, false otherwise."""
if self._process is None:
return False
self._process.poll()
return self._process.returncode is None
def stop(self, block_timeout_sec=None):
print("STOP Called")
"""Stop the video player. block_timeout_sec is how many seconds to
block waiting for the player to stop before moving on.
"""
# Stop the player if it's running.
if self._process is not None and self._process.returncode is None:
# There are a couple processes used by omxplayer, so kill both
# with a pkill command.
subprocess.call(['pkill', '-9', 'omxplayer'])
# If a blocking timeout was specified, wait up to that amount of time
# for the process to stop.
start = time.time()
while self._process is not None and self._process.returncode is None:
if (time.time() - start) >= block_timeout_sec:
break
time.sleep(0)
# Let the process be garbage collected.
self._process = None
"""If the stop was made when playing from the list, we have to signal done """
if self._playbackType == "list":
mqttClient.publish("list-play-cntl", "list-play-done")
self._playbackType = "auto playing"
#END OF OMXPLAYER
# SETUP VIDEO DISPLAY OBJECT -------------------------------------------------------------
class VideoDisplay:
def __init__(self):
pygame.init()
pygame.display.init()
pygame.mouse.set_visible(False)
self._running = True
size = (pygame.display.Info().current_w,pygame.display.Info().current_h)
self._screen = pygame.display.set_mode(size, pygame.FULLSCREEN)
# set the background image
self._bgkImage = pygame.image.load('/home/pi/PythonProjects/videoheadimg/BigBlack.png')
self._set_image()
# setup the omxplayer
self._player = OMXPlayer()
self._sound_vol = 0
pygame.font.init()
self._small_font = pygame.font.SysFont('monospace',25)
#self._fgcolor = (1,1,1)
#self._bgcolor = (0,0,0)
#self._render_text("PYGAME INIT",100,100)
self.videoLastPlayed = ""
def _render_text(self, message, x, y):
self._set_image()
font = self._small_font
thetext = self._small_font.render(message, True, (255,255,255))
self._screen.blit(thetext,(x,y))
pygame.display.update()
sleep(1)
def _blank_screen(self):
self._screen.fill((0,0,0))
pygame.display.update()
pygame.event.pump()
def _set_image(self):
self._screen.blit(self._bgkImage, [0,0])
pygame.display.update()
def _load_player(self):
create_player()
# We dont't want to play the same video twice in a row,
# so make sure the movie chosen is not the last one played
def _select_movie(self):
movie = video_path + movies[random.randint(0,number_of_movies-1)]
print(movie)
if movie == self.videoLastPlayed:
self._select_movie()
else:
self.videoLastPlayed = movie
return movie
def _play_welcome_msg(self):
movie = welcome_msg
mqttClient.publish("movie", movie)
self._player.play(movie, loop=False, vol = self._sound_vol)
这是在触发接近传感器时调用视频的主循环:
# MAIN LOOP -----------------------------------------------------------------------------
def run(self):
mqttClient.loop_start()
GPIO.output(RUNNING_LED,True)
setColor("blue")
print(videohead_running)
while True:
if self._running == True:
# provide a way to quit the program from the keyboard
pressed = pygame.key.get_pressed()
if pressed[pygame.K_q]:
pygame.quit()
GPIO.output(RUNNING_LED,False)
GPIO.cleanup()
sys.exit()
pygame.event.pump()
# if the radar sensor detects a presence
if GPIO.input(RADAR_IN):
setColor("brown")
# if no video is currently playing, try to play a movie
if not self._player.is_playing():
# 1) Get a movie title from the arry of titles
movie = self._select_movie()
setColor("red")
# 2) Play the movie
if movie is not None:
now = datetime.datetime.now()
mqttClient.publish("movie", movie)
###### This is where the Case 1 video is played
self._player.play(movie, loop=False, vol=self._sound_vol)
videoLastPlayedAt = now
# Give the CPU some time to do other tasks.
time.sleep(0.002)
elif self._running == False:
setColor("red")
time.sleep(2)
setColor("blue")
time.sleep(2)
# Shutdown properly
def signal_quit(self, signal, frame):
print("Shutdown")
self._running = False
if self._player is not None:
self._player.stop()
GPIO.cleanup()
pygame.quit()
def _play_list_video(self, video):
self._player.play(video, loop=False, vol = self._sound_vol)
这是MQTT处理程序:
def messageDecoder(client, userdata, msg):
if videodisplay._player.is_playing():
print("player is playing")
topic = msg.topic
message = msg.payload.decode(encoding='UTF-8')
print("topic: " + msg.topic)
print("msg: " + message)
print("----------------------------------------------")
if topic == "control":
if message == "disable":
mqttClient.publish("control","disable")
time.sleep(0.005)
videodisplay._player.stop(1)
os.system('sudo supervisorctl stop Videohead')
GPIO.cleanup()
pygame.quit()
exit()
if message == "stop":
mqttClient.publish("control","stopped")
time.sleep(0.005)
videodisplay._player.stop(1)
GPIO.cleanup()
pygame.quit()
exit()
###### This is the Case 1 code that stops video playback as it should
if message == "pause":
videodisplay._running = False
videodisplay._bgkImage = pygame.image.load('/home/pi/PythonProjects/videoheadimg/paused.png')
videodisplay._set_image()
mqttClient.publish("control","paused")
videodisplay._player.stop(1)
if message == "resume":
videodisplay._running = True
videodisplay._bgkImage = pygame.image.load('/home/pi/PythonProjects/videoheadimg/BigBlack.png')
videodisplay._set_image()
mqttClient.publish("control","resumed")
if message == "restart":
pygame.quit()
GPIO.cleanup()
os.system( 'sudo python3.6 /home/pi/PythonProjects/omxcall_radar.py')
print("restart")
if message == "reboot":
pygame.quit()
GPIO.cleanup()
os.system ('sudo reboot')
if message == "shutdown":
os.system('sudo shutdown now')
if topic == "video-list-request":
if message == "sendMovieList":
makeCSListofVideoNamesAndSend()
# STEP (1) OF PLAY FROM LIST
# Takes the filename and calls getVideoInfo to get the info
if topic == "get-video-description":
videodisplay._player.stop(1)
setColor("green")
getVideoInfo(message)
# PLAY MOVIE FROM LIST
##### This is the Case 2 code that's not called until after the video started below finishes playing
if topic == "video-cntl":
if message == "stop-video":
print("stop-video") ##### Not seen until video finishes
videodisplay._player.stop(1)
if message == "play-video":
print("PV: " + pendingVideo)
videodisplay._player._playbackType = "list"
videodisplay._play_list_video(pendingVideo)