From a8d304fd8f5fb6224cffabfadf61fbef6ea0577e Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Thu, 28 Nov 2013 11:59:35 +0100 Subject: [PATCH] * implement reporting of dtmf received via SIP info * dtmf can be typed on keyboard with gtk app. --- coreapi/bellesip_sal/sal_impl.c | 2 ++ coreapi/bellesip_sal/sal_op_call.c | 14 +++++--- coreapi/callbacks.c | 2 ++ coreapi/sal.c | 55 ++++++++++++++++++++++++++++++ gtk/keypad.ui | 3 ++ gtk/main.c | 40 ++++++++++++++++++++++ include/sal/sal.h | 4 +++ mediastreamer2 | 2 +- 8 files changed, 116 insertions(+), 6 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index e69359e9c..2bfe23795 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -895,3 +895,5 @@ unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size){ return belle_sip_random_bytes(ret,size); } + + diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index dc8618020..b434a1c38 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -362,7 +362,6 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } dialog_state=belle_sip_dialog_get_state(op->dialog); switch(dialog_state) { - case BELLE_SIP_DIALOG_NULL: { if (strcmp("INVITE",belle_sip_request_get_method(req))==0) { if (!op->replaces && (op->replaces=belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_replaces_t))) { @@ -461,7 +460,13 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t }else{ SalBody salbody; if (sal_op_get_body(op,(belle_sip_message_t*)req,&salbody)) { - op->base.root->callbacks.info_received(op,&salbody); + if (sal_body_has_type(&salbody,"application","dtmf-relay")){ + char tmp[10]; + if (sal_lines_get_value(salbody.data, "Signal",tmp, sizeof(tmp))){ + op->base.root->callbacks.dtmf_received(op,tmp[0]); + } + }else + op->base.root->callbacks.info_received(op,&salbody); } else { op->base.root->callbacks.info_received(op,NULL); } @@ -485,10 +490,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t unsupported_method(server_transaction,req); } break; - default: { + default: ms_error("unexpected dialog state [%s]",belle_sip_dialog_state_to_string(dialog_state)); - } - /* no break */ + break; } if (server_transaction) belle_sip_object_unref(server_transaction); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 183371130..4c931cc33 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -67,6 +67,8 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); rtp_session_set_remote_addr_full(call->videostream->ms.session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); } +#else + (void)new_videodesc; #endif } diff --git a/coreapi/sal.c b/coreapi/sal.c index 7d471a7c8..25fa8dcd8 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -26,6 +26,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "config.h" #endif #include "sal/sal.h" + +#include + const char* sal_transport_to_string(SalTransport transport) { switch (transport) { case SalTransportUDP:return "udp"; @@ -572,3 +575,55 @@ const char* sal_privacy_to_string(SalPrivacy privacy) { default: return NULL; } } + +static void remove_trailing_spaces(char *line){ + int i; + for(i=strlen(line)-1;i>=0;--i){ + if (isspace(line[i])) line[i]='\0'; + else break; + } +} + +static int line_get_value(const char *input, const char *key, char *value, size_t value_size, int *read){ + const char *end=strchr(input,'\n'); + char line[256]={0}; + char key_candidate[256]; + char *equal; + size_t len; + if (!end) len=strlen(input); + else len=end +1 -input; + *read=len; + strncpy(line,input,MIN(len,sizeof(line))); + equal=strchr(line,'='); + if (!equal) return FALSE; + *equal='\0'; + if (sscanf(line,"%s",key_candidate)!=1) return FALSE; + if (strcasecmp(key,key_candidate)==0){ + equal++; + remove_trailing_spaces(equal); + strncpy(value,equal,value_size-1); + value[value_size-1]='\0'; + return TRUE; + } + return FALSE; +} + +int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size){ + int read=0; + + do{ + if (line_get_value(data,key,value,value_size,&read)) + return TRUE; + data+=read; + }while(read!=0); + return FALSE; +} + +int sal_body_has_type(const SalBody *body, const char *type, const char *subtype){ + return body->type && body->subtype + && strcmp(body->type,type)==0 + && strcmp(body->subtype,subtype)==0; +} + + + diff --git a/gtk/keypad.ui b/gtk/keypad.ui index 6b5376762..5dfcfc487 100644 --- a/gtk/keypad.ui +++ b/gtk/keypad.ui @@ -8,8 +8,11 @@ True False + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK 0.5 none + + True diff --git a/gtk/main.c b/gtk/main.c index 87c278ddd..d8a8a2ede 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -64,6 +64,7 @@ static void linphone_gtk_call_log_updated(LinphoneCore *lc, LinphoneCallLog *cl) static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cs, const char *msg); static void linphone_gtk_call_encryption_changed(LinphoneCore *lc, LinphoneCall *call, bool_t enabled, const char *token); static void linphone_gtk_transfer_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState cstate); +static void linphone_gtk_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf); void linphone_gtk_save_main_window_position(GtkWindow* mw, GdkEvent *event, gpointer data); static gboolean linphone_gtk_auto_answer(LinphoneCall *call); void linphone_gtk_status_icon_set_blinking(gboolean val); @@ -251,6 +252,7 @@ static void linphone_gtk_init_liblinphone(const char *config_file, vtable.buddy_info_updated=linphone_gtk_buddy_info_updated; vtable.call_encryption_changed=linphone_gtk_call_encryption_changed; vtable.transfer_state_changed=linphone_gtk_transfer_state_changed; + vtable.dtmf_received=linphone_gtk_dtmf_received; the_core=linphone_core_new(&vtable,config_file,factory_config_file,NULL); //lp_config_set_int(linphone_core_get_config(the_core), "sip", "store_auth_info", 0); @@ -1049,6 +1051,10 @@ static void linphone_gtk_auth_info_requested(LinphoneCore *lc, const char *realm auth_timeout_new(w); } +static void linphone_gtk_dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf){ + ms_message("Dtmf %c received.",dtmf); +} + static void linphone_gtk_display_status(LinphoneCore *lc, const char *status){ GtkWidget *w=linphone_gtk_get_main_window(); GtkWidget *status_bar=linphone_gtk_get_widget(w,"status_bar"); @@ -1715,6 +1721,40 @@ void linphone_gtk_init_dtmf_table(GtkWidget *mw){ g_object_set_data(G_OBJECT(linphone_gtk_get_widget(mw,"dtmf_*")),"label","*"); } +static gboolean key_allowed(guint32 code){ + static const char *allowed="1234567890#*ABCD"; + return code!=0 && strchr(allowed,(char)code)!=NULL; +} + +static GtkButton *get_button_from_key(GtkWidget *w, GdkEvent *event){ + guint keyval=event->key.keyval; + guint32 code=gdk_keyval_to_unicode(keyval); + code=g_unichar_toupper(code); + if (key_allowed(code)){ + char widgetname[16]; + w=gtk_widget_get_toplevel(w); + snprintf(widgetname,sizeof(widgetname),"dtmf_%c",code); + return GTK_BUTTON(linphone_gtk_get_widget(w,widgetname)); + } + return NULL; +} + +void linphone_gtk_keypad_key_pressed(GtkWidget *w, GdkEvent *event, gpointer userdata){ + GtkButton *button=get_button_from_key(w,event); + if (button) { + linphone_gtk_dtmf_pressed(button); + /*g_signal_emit_by_name(button, "button-press-event");*/ + } +} + +void linphone_gtk_keypad_key_released(GtkWidget *w, GdkEvent *event, gpointer userdata){ + GtkButton *button=get_button_from_key(w,event); + if (button) { + linphone_gtk_dtmf_released(button); + /*g_signal_emit_by_name(button, "button-release-event");*/ + } +} + void linphone_gtk_create_keypad(GtkWidget *button){ GtkWidget *mw=linphone_gtk_get_main_window(); GtkWidget *k=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"keypad"); diff --git a/include/sal/sal.h b/include/sal/sal.h index 046f2928f..99b04fba8 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -691,4 +691,8 @@ LINPHONE_PUBLIC void sal_set_dns_user_hosts_file(Sal *sal, const char *hosts_fil LINPHONE_PUBLIC const char *sal_get_dns_user_hosts_file(const Sal *sal); unsigned char * sal_get_random_bytes(unsigned char *ret, size_t size); +int sal_body_has_type(const SalBody *body, const char *type, const char *subtype); +/*this function parses a document with key=value pairs separated by new lines, and extracts the value for a given key*/ +int sal_lines_get_value(const char *data, const char *key, char *value, size_t value_size); + #endif diff --git a/mediastreamer2 b/mediastreamer2 index f8cba9686..25d5fc4a3 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit f8cba968622ce3400d2c67bfb8a248ef48363627 +Subproject commit 25d5fc4a3383c3eeb79193bb31f1d2f123246dfd