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:
James 2012-03-08 17:42:38 -05:00
parent d4a387e113
commit f193047a1c
19 changed files with 383 additions and 38 deletions

View file

@ -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%%'

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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."

View file

@ -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):

View file

@ -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':