CC-3367: Display in Now Playing whether Live DJ stream and Live Master stream
are connected and give user the ability to block those streams - added stream source switch interface - backend code
This commit is contained in:
parent
d4a387e113
commit
f193047a1c
19 changed files with 383 additions and 38 deletions
|
@ -104,3 +104,6 @@ update_liquidsoap_status = 'update-liquidsoap-status/format/json/api_key/%%api_k
|
|||
#URL to check live stream auth
|
||||
check_live_stream_auth = 'check-live-stream-auth/format/json/api_key/%%api_key%%/username/%%username%%/password/%%password%%/djtype/%%djtype%%'
|
||||
|
||||
#URL to update source status
|
||||
update_source_status = 'update-source-status/format/json/api_key/%%api_key%%/sourcename/%%sourcename%%/status/%%status%%'
|
||||
|
||||
|
|
|
@ -583,6 +583,20 @@ class AirTimeApiClient(ApiClientInterface):
|
|||
response = urllib2.urlopen(req).read()
|
||||
except Exception, e:
|
||||
logger.error("Exception: %s", e)
|
||||
|
||||
def notify_source_status(self, sourcename, status):
|
||||
logger = self.logger
|
||||
try:
|
||||
url = "http://%s:%s/%s/%s" % (self.config["base_url"], str(self.config["base_port"]), self.config["api_base"], self.config["update_source_status"])
|
||||
|
||||
url = url.replace("%%api_key%%", self.config["api_key"])
|
||||
url = url.replace("%%sourcename%%", sourcename)
|
||||
url = url.replace("%%status%%", status)
|
||||
|
||||
req = urllib2.Request(url)
|
||||
response = urllib2.urlopen(req).read()
|
||||
except Exception, e:
|
||||
logger.error("Exception: %s", e)
|
||||
|
||||
"""
|
||||
This function updates status of mounted file system information on airtime
|
||||
|
|
|
@ -15,6 +15,31 @@ def append_title(m) =
|
|||
end
|
||||
end
|
||||
|
||||
default_dj_fade_in = ref 5.
|
||||
default_dj_fade_out = ref 5.
|
||||
|
||||
def transition(a,b) =
|
||||
log("transition called...")
|
||||
add(normalize=false,
|
||||
[ sequence([ blank(duration=2.),
|
||||
fade.initial(duration=!default_dj_fade_in, b) ]),
|
||||
fade.final(duration=!default_dj_fade_out, a) ])
|
||||
end
|
||||
|
||||
def transition_to_live(a,b) =
|
||||
log("transition called...")
|
||||
#add(normalize=false,
|
||||
# [fade.initial(duration=5.,type="log", b),fade.final(duration=5.,type="log",a)])
|
||||
smooth_add(delay=10., normal=a, special=b)
|
||||
end
|
||||
|
||||
def transition_from_live(a,b) =
|
||||
log("transition called...")
|
||||
#add(normalize=false,
|
||||
# [fade.initial(duration=5.,type="log", b),fade.final(duration=5.,type="log",a)])
|
||||
smooth_add(delay=10., normal=b, special=a)
|
||||
end
|
||||
|
||||
def crossfade(s)
|
||||
#duration is automatically overwritten by metadata fields passed in
|
||||
#with audio
|
||||
|
|
|
@ -8,7 +8,7 @@ set("server.telnet.port", 1234)
|
|||
|
||||
time = ref string_of(gettimeofday())
|
||||
|
||||
queue = audio_to_stereo(request.queue(id="queue", length=0.5))
|
||||
queue = audio_to_stereo(id="queue_src", request.queue(id="queue", length=0.5))
|
||||
queue = cue_cut(queue)
|
||||
|
||||
pypo_data = ref '0'
|
||||
|
@ -26,6 +26,10 @@ s3_namespace = ref ''
|
|||
|
||||
%include "ls_lib.liq"
|
||||
|
||||
queue = on_metadata(notify, queue)
|
||||
queue = map_metadata(append_title, queue)
|
||||
ignore(output.dummy(queue, fallible=true))
|
||||
|
||||
server.register(namespace="vars", "pypo_data", fun (s) -> begin pypo_data := s "Done" end)
|
||||
server.register(namespace="vars", "web_stream_enabled", fun (s) -> begin web_stream_enabled := (s == "true") string_of(!web_stream_enabled) end)
|
||||
server.register(namespace="vars", "stream_metadata_type", fun (s) -> begin stream_metadata_type := int_of_string(s) s end)
|
||||
|
@ -35,8 +39,9 @@ server.register(namespace="vars", "bootup_time", fun (s) -> begin time := s s en
|
|||
server.register(namespace="streams", "connection_status", fun (s) -> begin "1:#{!s1_connected},2:#{!s2_connected},3:#{!s3_connected}" end)
|
||||
|
||||
|
||||
default = amplify(0.00001, noise())
|
||||
default = amplify(id="silence_src", 0.00001, noise())
|
||||
default = rewrite_metadata([("artist","Airtime"), ("title", "offline")],default)
|
||||
ignore(output.dummy(default, fallible=true))
|
||||
|
||||
master_dj_enabled = ref false;
|
||||
live_dj_enabled = ref false;
|
||||
|
@ -87,33 +92,53 @@ def check_dj_client(user,password) =
|
|||
end
|
||||
end
|
||||
|
||||
def append_master_dj_input(master_harbor_input_port, master_harbor_input_mount_point, s) =
|
||||
if master_harbor_input_port != 0 and master_harbor_input_mount_point != "" then
|
||||
master_dj = input.harbor(master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client, buffer=0.5,max=15.)
|
||||
def update_source_status(sourcename, status) =
|
||||
system("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --source-name=#{sourcename} --source-status=#{status}")
|
||||
log("/usr/lib/airtime/pypo/bin/liquidsoap_scripts/notify.sh --source-name=#{sourcename} --source-status=#{status}")
|
||||
end
|
||||
|
||||
def live_dj_connect(header) =
|
||||
update_source_status("live_dj", true)
|
||||
end
|
||||
|
||||
def live_dj_disconnect() =
|
||||
update_source_status("live_dj", false)
|
||||
end
|
||||
|
||||
def master_dj_connect(header) =
|
||||
update_source_status("master_dj", true)
|
||||
end
|
||||
|
||||
def master_dj_disconnect() =
|
||||
update_source_status("master_dj", false)
|
||||
end
|
||||
|
||||
def append_dj_inputs(master_harbor_input_port, master_harbor_input_mount_point, dj_harbor_input_port, dj_harbor_input_mount_point, s) =
|
||||
if master_harbor_input_port != 0 and master_harbor_input_mount_point != "" and dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then
|
||||
master_dj = input.harbor(id="master_harbor", master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client,
|
||||
max=40., on_connect=master_dj_connect, on_disconnect=master_dj_disconnect)
|
||||
dj_live = input.harbor(id="live_dj_harbor", dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client,
|
||||
max=40., on_connect=live_dj_connect, on_disconnect=live_dj_disconnect)
|
||||
ignore(output.dummy(master_dj, fallible=true))
|
||||
stopable_master_dj = switch(track_sensitive=false, [({!master_dj_enabled},master_dj)])
|
||||
fallback(track_sensitive=false, [stopable_master_dj, s])
|
||||
else
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
def append_dj_input(dj_harbor_input_port, dj_harbor_input_mount_point, s) =
|
||||
if dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then
|
||||
dj_live = input.harbor(dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client, buffer=0.5,max=15.)
|
||||
ignore(output.dummy(dj_live, fallible=true))
|
||||
stopable_live_dj = switch(track_sensitive=false, [({!live_dj_enabled},dj_live)])
|
||||
fallback(track_sensitive=false, [stopable_live_dj, s])
|
||||
switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition, transition], [({!master_dj_enabled},master_dj), ({!live_dj_enabled},dj_live), ({true}, s)])
|
||||
elsif master_harbor_input_port != 0 and master_harbor_input_mount_point != "" then
|
||||
master_dj = input.harbor(id="master_harbor", master_harbor_input_mount_point, port=master_harbor_input_port, auth=check_master_dj_client,
|
||||
max=40., on_connect=master_dj_connect, on_disconnect=master_dj_disconnect)
|
||||
ignore(output.dummy(master_dj, fallible=true))
|
||||
switch(id="master_dj_switch", track_sensitive=false, transitions=[transition, transition], [({!master_dj_enabled},master_dj), ({true}, s)])
|
||||
elsif dj_harbor_input_port != 0 and dj_harbor_input_mount_point != "" then
|
||||
dj_live = input.harbor(id="live_dj_harbor", dj_harbor_input_mount_point, port=dj_harbor_input_port, auth=check_dj_client,
|
||||
max=40., on_connect=live_dj_connect, on_disconnect=live_dj_disconnect)
|
||||
ignore(output.dummy(dj_live, fallible=true))
|
||||
switch(id="live_dj_switch", track_sensitive=false, transitions=[transition, transition], [({!live_dj_enabled},dj_live), ({true}, s)])
|
||||
else
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
s = fallback(track_sensitive=false, [queue, default])
|
||||
s = on_metadata(notify, s)
|
||||
s = map_metadata(append_title, s)
|
||||
s = append_dj_input(dj_live_stream_port, dj_live_stream_mp, s)
|
||||
s = append_master_dj_input(master_live_stream_port, master_live_stream_mp, s)
|
||||
s = fallback(id="default_fallback", track_sensitive=false, [queue, default])
|
||||
s = append_dj_inputs(master_live_stream_port, master_live_stream_mp, dj_live_stream_port, dj_live_stream_mp, s)
|
||||
|
||||
|
||||
s = crossfade(s)
|
||||
|
|
|
@ -51,6 +51,8 @@ parser.add_option("-e", "--error", action="store", dest="error", type="string",
|
|||
parser.add_option("-s", "--stream-id", help="ID stream", metavar="stream_id")
|
||||
parser.add_option("-c", "--connect", help="liquidsoap connected", action="store_true", metavar="connect")
|
||||
parser.add_option("-t", "--time", help="liquidsoap boot up time", action="store", dest="time", metavar="time", type="string")
|
||||
parser.add_option("-x", "--source-name", help="source connection name", metavar="source_name")
|
||||
parser.add_option("-y", "--source-status", help="source connection stauts", metavar="source_status")
|
||||
|
||||
# parse options
|
||||
(options, args) = parser.parse_args()
|
||||
|
@ -91,6 +93,16 @@ class Notify:
|
|||
logger.debug('msg = '+ str(msg))
|
||||
response = self.api_client.notify_liquidsoap_status(msg, stream_id, time)
|
||||
logger.debug("Response: "+json.dumps(response))
|
||||
|
||||
def notify_source_status(self, source_name, status):
|
||||
logger = logging.getLogger()
|
||||
|
||||
logger.debug('#################################################')
|
||||
logger.debug('# Calling server to update source status #')
|
||||
logger.debug('#################################################')
|
||||
logger.debug('msg = '+ str(source_name) + ' : ' + str(status))
|
||||
response = self.api_client.notify_source_status(source_name, status)
|
||||
logger.debug("Response: "+json.dumps(response))
|
||||
|
||||
if __name__ == '__main__':
|
||||
print
|
||||
|
@ -101,7 +113,6 @@ if __name__ == '__main__':
|
|||
|
||||
# initialize
|
||||
logger = logging.getLogger("notify")
|
||||
|
||||
if options.error and options.stream_id:
|
||||
try:
|
||||
n = Notify()
|
||||
|
@ -114,6 +125,12 @@ if __name__ == '__main__':
|
|||
n.notify_liquidsoap_status("OK", options.stream_id, options.time)
|
||||
except Exception, e:
|
||||
print e
|
||||
elif options.source_name and options.source_status:
|
||||
try:
|
||||
n = Notify()
|
||||
n.notify_source_status(options.source_name, options.source_status)
|
||||
except Exception, e:
|
||||
print e
|
||||
else:
|
||||
if not options.data:
|
||||
print "NOTICE: 'data' command-line argument not given."
|
||||
|
|
|
@ -92,6 +92,9 @@ class PypoFetch(Thread):
|
|||
elif command == 'cancel_current_show':
|
||||
self.logger.info("Cancel current show command received...")
|
||||
self.stop_current_show()
|
||||
elif command == 'switch_source':
|
||||
self.logger.info("switch_on_source show command received...")
|
||||
self.switch_source(m['sourcename'], m['status'])
|
||||
except Exception, e:
|
||||
import traceback
|
||||
top = traceback.format_exc()
|
||||
|
@ -99,6 +102,27 @@ class PypoFetch(Thread):
|
|||
self.logger.error("traceback: %s", top)
|
||||
self.logger.error("Exception in handling Message Handler message: %s", e)
|
||||
|
||||
def switch_source(self, sourcename, status):
|
||||
self.logger.debug('Switching source: %s to "%s" status', sourcename, status)
|
||||
command = "streams."
|
||||
if(sourcename == "master_dj"):
|
||||
command += "master_dj_"
|
||||
else:
|
||||
command += "live_dj_"
|
||||
|
||||
if(status == "on"):
|
||||
command += "start\n"
|
||||
else:
|
||||
command += "stop\n"
|
||||
|
||||
try:
|
||||
tn = telnetlib.Telnet(LS_HOST, LS_PORT)
|
||||
tn.write(command)
|
||||
tn.write('exit\n')
|
||||
tn.read_all()
|
||||
except Exception, e:
|
||||
self.logger.debug(e)
|
||||
self.logger.debug('Could not connect to liquidsoap')
|
||||
|
||||
def stop_current_show(self):
|
||||
self.logger.debug('Notifying Liquidsoap to stop playback.')
|
||||
|
@ -353,15 +377,22 @@ class PypoFetch(Thread):
|
|||
|
||||
|
||||
def create_liquidsoap_annotation(self, media):
|
||||
entry = \
|
||||
"""entry = \
|
||||
'annotate:media_id="%s",liq_start_next="%s",liq_fade_in="%s",liq_fade_out="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s":%s' \
|
||||
% (media['id'], 0, \
|
||||
float(media['fade_in']) / 1000, \
|
||||
float(media['fade_out']) / 1000, \
|
||||
float(media['cue_in']), \
|
||||
float(media['cue_out']), \
|
||||
media['row_id'], media['dst'])"""
|
||||
|
||||
entry = \
|
||||
'annotate:media_id="%s",liq_start_next="%s",liq_cue_in="%s",liq_cue_out="%s",schedule_table_id="%s":%s' \
|
||||
% (media['id'], 0, \
|
||||
float(media['cue_in']), \
|
||||
float(media['cue_out']), \
|
||||
media['row_id'], media['dst'])
|
||||
|
||||
|
||||
return entry
|
||||
|
||||
def check_for_previous_crash(self, media_item):
|
||||
|
|
|
@ -74,6 +74,9 @@ class PypoMessageHandler(Thread):
|
|||
elif command == 'cancel_current_show':
|
||||
self.logger.info("Cancel current show command received...")
|
||||
self.pypo_queue.put(message)
|
||||
elif command == 'switch_source':
|
||||
self.logger.info("switch_source command received...")
|
||||
self.pypo_queue.put(message)
|
||||
elif command == 'update_recorder_schedule':
|
||||
self.recorder_queue.put(message)
|
||||
elif command == 'cancel_recording':
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue