123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- #!/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()
|