diff --git a/src/command_system/implementation/standard.py b/src/command_system/implementation/standard.py index 4cb19c466..8afa044e5 100644 --- a/src/command_system/implementation/standard.py +++ b/src/command_system/implementation/standard.py @@ -98,6 +98,22 @@ class StandardChatCommands(CommandContainer): raise CommandError(_('Command is not supported for zeroconf accounts')) gajim.connections[self.account].sendPing(self.contact) + @command('dtmf') + @documentation(_("Sends DTMF events through an open audio session")) + def dtmf(self, events): + if not self.audio_sid: + raise CommandError(_("There is no open audio session with this contact")) + # Valid values for DTMF tones are *, # or a number + events = [event for event in events + if event in ('*', '#') or event.isdigit()] + if events: + session = gajim.connections[self.account].get_jingle_session( + self.contact.get_full_jid(), self.audio_sid) + content = session.get_content('audio') + content.batch_dtmf(events) + else: + raise CommandError(_("No valid DTMF event specified")) + @command('audio') @documentation(_("Toggle audio session")) def audio(self): diff --git a/src/common/jingle.py b/src/common/jingle.py index f05886533..6549ee10c 100644 --- a/src/common/jingle.py +++ b/src/common/jingle.py @@ -47,6 +47,8 @@ # * handle different kinds of sink and src elements +import gobject + import gajim import xmpp import helpers @@ -831,6 +833,7 @@ class JingleRTPContent(JingleContent): def __init__(self, session, media, node=None): JingleContent.__init__(self, session, node) self.media = media + self._dtmf_running = False self.farsight_media = {'audio': farsight.MEDIA_TYPE_AUDIO, 'video': farsight.MEDIA_TYPE_VIDEO}[media] self.got_codecs = False @@ -873,6 +876,33 @@ class JingleRTPContent(JingleContent): self.p2pstream = self.p2psession.new_stream(participant, farsight.DIRECTION_RECV, 'nice', params) + def batch_dtmf(self, events): + if self._dtmf_running: + raise Exception #TODO: Proper exception + self._dtmf_running = True + self._start_dtmf(events.pop(0)) + gobject.timeout_add(500, self._next_dtmf, events) + + def _next_dtmf(self, events): + self._stop_dtmf() + if events: + self._start_dtmf(events.pop(0)) + gobject.timeout_add(500, self._next_dtmf, events) + else: + self._dtmf_running = False + + def _start_dtmf(self, event): + if event in ('*', '#'): + event = {'*': farsight.DTMF_EVENT_STAR, + '#': farsight.DTMF_EVENT_POUND}[event] + else: + event = int(event) + self.p2psession.start_telephony_event(event, 2, + farsight.DTMF_METHOD_RTP_RFC4733) + + def _stop_dtmf(self): + self.p2psession.stop_telephony_event(farsight.DTMF_METHOD_RTP_RFC4733) + def _fillContent(self, content): content.addChild(xmpp.NS_JINGLE_RTP + ' description', attrs={'media': self.media}, payload=self.iter_codecs())