smooth stream switch

Fixed using pty and select to pipe streamNum to a running nrsc5 without disrupting process operation.
This commit is contained in:
markjfine 2021-03-28 14:52:44 -04:00 committed by GitHub
parent 1f1aaaa556
commit 157419e838
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -21,7 +21,7 @@
# Updated and enhanced by markjfine ~ 2021 # Updated and enhanced by markjfine ~ 2021
#import os, sys, shutil, re, gtk, gobject, json, datetime, numpy, glob, time, platform #import os, sys, shutil, re, gtk, gobject, json, datetime, numpy, glob, time, platform
import os, sys, shutil, re, json, datetime, numpy, glob, time, platform import os, pty, select, sys, shutil, re, json, datetime, numpy, glob, time, platform
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from threading import Timer, Thread from threading import Timer, Thread
from dateutil import tz from dateutil import tz
@ -72,6 +72,8 @@ class NRSC5_DUI(object):
self.mapFile = os.path.join(resDir, "map.png") self.mapFile = os.path.join(resDir, "map.png")
self.defaultSize = [490,250] # default width,height of main app self.defaultSize = [490,250] # default width,height of main app
self.nrsc5 = None # nrsc5 process self.nrsc5 = None # nrsc5 process
self.nrsc5master = None
self.nrsc5slave = None
self.playerThread = None # player thread self.playerThread = None # player thread
self.playing = False # currently playing self.playing = False # currently playing
self.statusTimer = None # status update timer self.statusTimer = None # status update timer
@ -85,6 +87,7 @@ class NRSC5_DUI(object):
self.lastXHDR = "" # the last XHDR data received self.lastXHDR = "" # the last XHDR data received
self.stationStr = "" # current station frequency (string) self.stationStr = "" # current station frequency (string)
self.streamNum = 0 # current station stream number self.streamNum = 0 # current station stream number
self.nrsc5msg = "" # send key command to nrsc5 (streamNum)
self.update_btns = True self.update_btns = True
self.set_program_btns() self.set_program_btns()
self.bookmarks = [] # station bookmarks self.bookmarks = [] # station bookmarks
@ -136,12 +139,12 @@ class NRSC5_DUI(object):
262 : "Private Data Network", 262 : "Private Data Network",
263 : "Service Maintenance", 263 : "Service Maintenance",
264 : "HD Radio System Services", 264 : "HD Radio System Services",
265 : "Audio Related Data", 265 : "Audio-Related Objects",
511 : "Test_Str_E" 511 : "Test_Str_E"
} }
self.ProgramType = { self.ProgramType = {
0 : "Undefined", 0 : "None",
1 : "News", 1 : "News",
2 : "Information", 2 : "Information",
3 : "Sports", 3 : "Sports",
@ -157,8 +160,8 @@ class NRSC5_DUI(object):
13 : "Nostalgia", 13 : "Nostalgia",
14 : "Jazz", 14 : "Jazz",
15 : "Classical", 15 : "Classical",
16 : "Rhythm And Blues", 16 : "Rhythm and Blues",
17 : "Soft Rhythm And Blues", 17 : "Soft Rhythm and Blues",
18 : "Foreign Language", 18 : "Foreign Language",
19 : "Religious Music", 19 : "Religious Music",
20 : "Religious Talk", 20 : "Religious Talk",
@ -167,7 +170,7 @@ class NRSC5_DUI(object):
23 : "College", 23 : "College",
24 : "Spanish Talk", 24 : "Spanish Talk",
25 : "Spanish Music", 25 : "Spanish Music",
26 : "Hip Hop", 26 : "Hip-Hop",
29 : "Weather", 29 : "Weather",
30 : "Emergency Test", 30 : "Emergency Test",
31 : "Emergency", 31 : "Emergency",
@ -281,6 +284,9 @@ class NRSC5_DUI(object):
self.loadSettings() self.loadSettings()
self.proccessWeatherMaps() self.proccessWeatherMaps()
#self..connect('check-resize',self.on_window_resized) # TODO: fix on resize infinite loop #self..connect('check-resize',self.on_window_resized) # TODO: fix on resize infinite loop
# set up pty
self.nrsc5master,self.nrsc5slave = pty.openpty()
def img_to_pixbuf(self,img): def img_to_pixbuf(self,img):
"""convert PIL.Image to GdkPixbuf.Pixbuf""" """convert PIL.Image to GdkPixbuf.Pixbuf"""
@ -580,13 +586,14 @@ class NRSC5_DUI(object):
self.streamInfo["Logo"] = "" self.streamInfo["Logo"] = ""
self.streamInfo["Bitrate"] = 0 self.streamInfo["Bitrate"] = 0
self.set_program_btns() self.set_program_btns()
#if self.playing: if self.playing:
# self.display_logo() self.nrsc5msg = str(self.streamNum)
self.displayLogo()
#TODO: fix so stream change is smoother - should be able to pipe new stream number to running application and update display_logo() #TODO: fix so stream change is smoother - should be able to pipe new stream number to running application and update display_logo()
# For now, just restart # For now, just restart
if (self.playing): #if (self.playing):
self.on_btnStop_clicked(None) # self.on_btnStop_clicked(None)
self.on_btnPlay_clicked(None) # self.on_btnPlay_clicked(None)
def set_program_btns(self): def set_program_btns(self):
self.btnAudioPrgs0.set_active(self.update_btns and self.streamNum == 0) self.btnAudioPrgs0.set_active(self.update_btns and self.streamNum == 0)
@ -689,9 +696,16 @@ class NRSC5_DUI(object):
FTMP = open('tmp.log','w') FTMP = open('tmp.log','w')
# run nrsc5 and output stdout & stderr to pipes # run nrsc5 and output stdout & stderr to pipes
self.nrsc5 = Popen(self.nrsc5Args, stderr=PIPE, stdout=PIPE, universal_newlines=True) #self.nrsc5 = Popen(self.nrsc5Args, stdout=PIPE, stderr=PIPE, universal_newlines=True)
self.nrsc5 = Popen(self.nrsc5Args, shell=False, stdin=self.nrsc5slave, stdout=PIPE, stderr=PIPE, universal_newlines=True)
while True: while True:
# send input to nrsc5 if needed
if (self.nrsc5msg != ""):
select.select([],[self.nrsc5master],[])
os.write(self.nrsc5master,str.encode(self.nrsc5msg))
#print(self.nrsc5msg)
self.nrsc5msg = ""
# read output from nrsc5 # read output from nrsc5
output = self.nrsc5.stderr.readline() output = self.nrsc5.stderr.readline()
# parse the output # parse the output
@ -712,7 +726,7 @@ class NRSC5_DUI(object):
# restart nrsc5 if it crashes # restart nrsc5 if it crashes
self.debugLog("Restarting NRSC5") self.debugLog("Restarting NRSC5")
time.sleep(1) time.sleep(1)
self.nrsc5 = Popen(self.nrsc5Args, stderr=PIPE, stdout=PIPE, universal_newlines=True) self.nrsc5 = Popen(self.nrsc5Args, stdin=PIPE, stderr=PIPE, stdout=PIPE, universal_newlines=True)
def set_synchronization(self, state): def set_synchronization(self, state):
self.imgNoSynch.set_visible(state == 0) self.imgNoSynch.set_visible(state == 0)