#!/usr/bin/env python3 """ Questo script tiene d'occhio una specifica ConfBridge. SE c'e' almeno un partecipante, allora cerca di far entrare lo speaker (ovvero quello che noi chiamiamo "mixer", e che รจ semplicemente un'estensione PJSIP) dentro la confbridge Nella configurazione di asterisk si deve porre attenzione ad un dettaglio: lo speaker si deve trovare in un contesto diverso da tutti gli altri telefoni, e in particolare da quello in cui si trovano gli utenti remoti che entrano nella confbridge in questione. In questo modo si puo' facilmente distinguere lo speaker. """ import logging from argparse import ArgumentParser from panoramisk.actions import Action import asterisk_misc_common CONFERENCE = "400" APP = None log = logging.getLogger("transferback") async def on_tutto(manager, msg): for prefix in ["Var", "RTC"]: if msg.event.startswith(prefix): return log.info("... Event %s", msg.event) async def refresh(manager, *args): ret = await manager.send_action( Action({"Action": "ConfbridgeList", "Conference": CONFERENCE}), as_list=False ) if ret.response == "Error": await APP.on_users(None, ret) class ConfbridgeInviter: def __init__(self, manager): self.manager = manager self.users = [] self.tmp_users = [] self.log = logging.getLogger(self.__class__.__name__) self.manager.register_event("EndpointDetail", self.on_speaker_endpoint_info) self.on_speaker_endpoint_info_active = False def get_context(self): return "from-mixer" def get_extension(self): return "9400" def get_speaker_channel(self): return "PJSIP/400" def get_conference(self): return CONFERENCE def is_speaker(self, msg): """ questo metodo capisce se un utente e' lo speaker. Si sarebbe potuto fare anche in altri modi, ad esempio guardando il channel, o la Exten, o utilizzando admin/marked in maniera opportuna. """ return msg.context == self.get_context() async def run(self): self.log.info("runno") self.manager.register_event("ConfbridgeList", self.on_user) self.manager.register_event("ConfbridgeListComplete", self.on_users) async def on_user(self, _, msg): if msg.conference != self.get_conference(): return self.tmp_users.append(msg) async def on_users(self, _, _msg): self.users = self.tmp_users self.tmp_users = [] someone_inside = len(self.users) > 0 speaker_inside = any(True for u in self.users if self.is_speaker(u)) for u in self.users: self.log.debug(" - %s %s", u.context, u.channel) self.log.debug( "%d users - speaker_inside=%s", len(self.users), str(speaker_inside) ) if not speaker_inside: if someone_inside: await self.maybe_invite_speaker() self.users = [] async def maybe_invite_speaker(self): self.log.debug("Maybe?") self.on_speaker_endpoint_info_active = True ret = await self.manager.send_action( Action( { "Action": "PJSIPShowEndpoint", "Endpoint": self.get_speaker_channel().split("/")[-1], } ), as_list=False, ) self.on_speaker_endpoint_info_active = ret.actionid async def on_speaker_endpoint_info(self, _, msg): self.log.debug("Vediamo") active = self.on_speaker_endpoint_info_active if active is False or (type(active) is str and active != msg.actionid): return self.on_speaker_endpoint_info_active = False self.log.debug(" Speaker dev = %s", msg.devicestate) if msg.devicestate == "Not in use": self.invite_speaker() def invite_speaker(self): cmd = "channel originate {chan} extension {ext}@{ctx}".format( chan=self.get_speaker_channel(), ext=self.get_extension(), ctx=self.get_context(), ) self.log.debug("CMD = %s", cmd) self.manager.send_command(cmd) async def kick_speaker(self): return cmd = "confbridge kick {conf} all".format( conf=self.get_conference(), ) self.log.debug("CMD = %s", cmd) ret = await self.manager.send_command(cmd) return ret async def run_app(Cls, manager): global APP APP = Cls(manager) await APP.run() async def init(manager): manager.register_event("*", on_tutto) for event in [ "FullyBooted", "ConfbridgeStart", "ConfbridgeJoin", "ConfbridgeLeave", "ConfbridgeEnd", "TestEvent", "Hangup", "Newstate", # XXX: solo se lo stato che cambia e' quello dello speaker ]: manager.register_event(event, refresh) pass await run_app(ConfbridgeInviter, manager) async def on_shutdown(m): pass def main(): p = ArgumentParser() asterisk_misc_common.add_arguments(p) args = p.parse_args() asterisk_misc_common.do_common_options(args) manager = asterisk_misc_common.get_manager(args) asterisk_misc_common.run_manager( manager, args, on_startup=init, on_shutdown=on_shutdown ) if __name__ == "__main__": main()