Outgoing DTMF / dialpad support

David Woodhouse dwmw2 at infradead.org
Mon Oct 14 08:43:01 EDT 2013


There are two open requests about DTMF support.

 - https://developer.pidgin.im/ticket/12617
   (Patch to add out-of-band DTMF support)

This adds a generic way for protocols to send DTMF out-of-band, and
falls back to sending in-band in the media stream. And a second patch
adds the required protocol-specific support for Jabber. The patches
didn't even seem to build out-of-the-box, due to typos and mismatched
function declarations, and the ticket has been open and mostly unloved
for three years.

 - https://developer.pidgin.im/ticket/15575
   (dialpad support)

This is more recent, and actually adds a UI for users to dial DTMF tones
whilst in an audio call. The patch here operates directly on a gstreamer
pipeline to send dtmf-events, and looking at the code I'm not entirely
sure the pipeline it selects will have *anything* to do with the media
stream it was actually *asked* to send DTMF on.

So I've generated a patch which combines the two — fixing up the generic
part of the media_dtmf patch in ticket 12617, and combining it with the
UI support added in ticket 15575. I am inclined to suggest we should
leave ticket 12617 open for the Jabber support which I haven't updated
and can't easily test, and handle the UI along with the generic part
(i.e. my patch) in the new ticket 15575.

I have some outstanding issues with my patch which I would appreciate
some more clueful input on...

Firstly, to make the generic DTMF support build cleanly I had to go
through all the protocol plugins and add an explicit extra NULL to each 
PurplePluginProtocolInfo structure. Do we *really* still have to do it
this way and use structure declarations from last century, or should I
submit a separate patch which updates the code to use C99 structure
initialisation? It's been 14 years now...

Secondly, and more importantly, see the FIXME and the leak of the
session-id string in the gtkmedia.c patch. I didn't bother to fix that
because I'm assuming the session-id is going to be stored *somewhere* we
can access it anyway, but I wasn't sure. Or perhaps we can even continue
to use the one we were given, and its lifetime will exceed that of the
UI? Suggestions welcome...

Third: why wasn't pidgin_media_ready_cb() passing the sid to
pidgin_media_add_audio_widget()? If you look carefully at the final hunk
below, you'll see I 'fix' that too...

This is just the patch of the patch which affects gtkmedia.c:

diff --git a/pidgin/gtkmedia.c b/pidgin/gtkmedia.c
index d91a951..9d5f4d8 100644
--- a/pidgin/gtkmedia.c
+++ b/pidgin/gtkmedia.c
@@ -759,6 +759,150 @@ pidgin_media_add_audio_widget(PidginMedia *gtkmedia,
 }
 
 static void
+phone_dtmf_pressed_cb(GtkButton *button, gpointer user_data)
+{
+	PidginMedia *gtkmedia = user_data;
+	gint num;
+	gchar *sid;
+
+	num = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "dtmf-digit"));
+	sid = g_object_get_data(G_OBJECT(button), "session-id");
+
+	purple_media_send_dtmf(gtkmedia->priv->media, sid, num, 25, 50);
+}
+
+static inline GtkWidget *
+phone_create_button(const gchar *text_hi, const gchar *text_lo)
+{
+	GtkWidget *button;
+	GtkWidget *label_hi;
+	GtkWidget *label_lo;
+	GtkWidget *grid;
+
+	grid = gtk_vbox_new(TRUE, 0);
+
+	button = gtk_button_new();
+	label_hi = gtk_label_new(text_hi);
+	gtk_misc_set_alignment(GTK_MISC(label_hi), 0.5, 0.5);
+	gtk_box_pack_end(GTK_BOX(grid), label_hi, FALSE, TRUE, 0);
+	label_lo = gtk_label_new(text_lo);
+	gtk_misc_set_alignment(GTK_MISC(label_lo), 0.5, 0.5);
+	gtk_label_set_use_markup(GTK_LABEL(label_lo), TRUE);
+	gtk_box_pack_end(GTK_BOX(grid), label_lo, FALSE, TRUE, 0);
+	gtk_container_add(GTK_CONTAINER(button), grid);
+
+	return button;
+}
+
+static GtkWidget *
+pidgin_media_add_dtmf_widget(PidginMedia *gtkmedia,
+		PurpleMediaSessionType type, const gchar *_sid)
+{
+	GtkWidget *grid = gtk_table_new(4, 3, TRUE);
+	GtkWidget *button1;
+	GtkWidget *button2;
+	GtkWidget *button3;
+	GtkWidget *button4;
+	GtkWidget *button5;
+	GtkWidget *button6;
+	GtkWidget *button7;
+	GtkWidget *button8;
+	GtkWidget *button9;
+	GtkWidget *button_asterisk;
+	GtkWidget *button0;
+	GtkWidget *button_pound;
+	gchar *sid = g_strdup(_sid); /* FIXME: This leaks. */
+
+	/* Button 1 */
+	button1 = phone_create_button("o_o", "<b>1</b>");
+	g_signal_connect(button1, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button1), "dtmf-digit", GINT_TO_POINTER('1'));
+	g_object_set_data(G_OBJECT(button1), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button1, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 2 */
+	button2 = phone_create_button("ABC", "<b>2</b>");
+	g_signal_connect(button2, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button2), "dtmf-digit", GINT_TO_POINTER('2'));
+	g_object_set_data(G_OBJECT(button2), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button2, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 3 */
+	button3 = phone_create_button("DEF", "<b>3</b>");
+	g_signal_connect(button3, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button3), "dtmf-digit", GINT_TO_POINTER('3'));
+	g_object_set_data(G_OBJECT(button3), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button3, 2, 3, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 4 */
+	button4 = phone_create_button("GHI", "<b>4</b>");
+	g_signal_connect(button4, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button4), "dtmf-digit", GINT_TO_POINTER('4'));
+	g_object_set_data(G_OBJECT(button4), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button4, 0, 1, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 5 */
+	button5 = phone_create_button("JKL", "<b>5</b>");
+	g_signal_connect(button5, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button5), "dtmf-digit", GINT_TO_POINTER('5'));
+	g_object_set_data(G_OBJECT(button5), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button5, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 6 */
+	button6 = phone_create_button("MNO", "<b>6</b>");
+	g_signal_connect(button6, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button6), "dtmf-digit", GINT_TO_POINTER('6'));
+	g_object_set_data(G_OBJECT(button6), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button6, 2, 3, 1, 2, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 7 */
+	button7 = phone_create_button("PQRS", "<b>7</b>");
+	g_signal_connect(button7, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button7), "dtmf-digit", GINT_TO_POINTER('7'));
+	g_object_set_data(G_OBJECT(button7), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button7, 0, 1, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 8 */
+	button8 = phone_create_button("TUV", "<b>8</b>");
+	g_signal_connect(button8, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button8), "dtmf-digit", GINT_TO_POINTER('8'));
+	g_object_set_data(G_OBJECT(button8), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button8, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 9 */
+	button9 = phone_create_button("WXYZ", "<b>9</b>");
+	g_signal_connect(button9, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button9), "dtmf-digit", GINT_TO_POINTER('9'));
+	g_object_set_data(G_OBJECT(button9), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button9, 2, 3, 2, 3, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button Asterisk */
+	button_asterisk = phone_create_button(_("DEL"), "<b>*</b>");
+	g_signal_connect(button_asterisk, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button_asterisk), "dtmf-digit", GINT_TO_POINTER('*'));
+	g_object_set_data(G_OBJECT(button_asterisk), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button_asterisk, 0, 1, 3, 4, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button 0 */
+	button0 = phone_create_button("", "<b>0</b>");
+	g_signal_connect(button0, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button0), "dtmf-digit", GINT_TO_POINTER('0'));
+	g_object_set_data(G_OBJECT(button0), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button0, 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	/* Button Pound */
+	button_pound = phone_create_button(_("RETURN"), "<b>#</b>");
+	g_signal_connect(button_pound, "pressed", G_CALLBACK(phone_dtmf_pressed_cb), gtkmedia);
+	g_object_set_data(G_OBJECT(button_pound), "dtmf-digit", GINT_TO_POINTER('#'));
+	g_object_set_data(G_OBJECT(button_pound), "session-id", sid);
+	gtk_table_attach(GTK_TABLE(grid), button_pound, 2, 3, 3, 4, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2, 2);
+
+	gtk_widget_show_all(grid);
+
+	return grid;
+}
+
+static void
 pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia, const gchar *sid)
 {
 	GtkWidget *send_widget = NULL, *recv_widget = NULL, *button_widget = NULL;
@@ -888,7 +1032,11 @@ pidgin_media_ready_cb(PurpleMedia *media, PidginMedia *gtkmedia, const gchar *si
 
 		gtk_box_pack_end(GTK_BOX(recv_widget),
 				pidgin_media_add_audio_widget(gtkmedia,
-				PURPLE_MEDIA_SEND_AUDIO, NULL), FALSE, FALSE, 0);
+				PURPLE_MEDIA_SEND_AUDIO, sid), FALSE, FALSE, 0);
+
+		gtk_box_pack_end(GTK_BOX(recv_widget),
+				pidgin_media_add_dtmf_widget(gtkmedia,
+				PURPLE_MEDIA_SEND_AUDIO, sid), FALSE, FALSE, 0);
 	}
 
 	if (type & PURPLE_MEDIA_AUDIO &&



-- 
David Woodhouse                            Open Source Technology Centre
David.Woodhouse at intel.com                              Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/x-pkcs7-signature
Size: 5745 bytes
Desc: not available
URL: <http://pidgin.im/pipermail/devel/attachments/20131014/53664b8b/attachment.bin>


More information about the Devel mailing list