Detecting when phone calls terminate

This commit is contained in:
Pierre Pronchery 2010-05-09 17:58:23 +00:00
parent 2666b2fa59
commit 7568bb814e
6 changed files with 157 additions and 24 deletions

View File

@ -87,6 +87,15 @@ void on_phone_call_answer(gpointer data)
}
/* on_phone_call_close */
void on_phone_call_close(gpointer data)
{
Phone * phone = data;
phone_show_call(phone, FALSE);
}
/* on_phone_call_hangup */
void on_phone_call_hangup(gpointer data)
{

View File

@ -28,6 +28,7 @@ GdkFilterReturn on_phone_filter(GdkXEvent * xevent, GdkEvent * event,
/* calls */
void on_phone_call_answer(gpointer data);
void on_phone_call_close(gpointer data);
void on_phone_call_hangup(gpointer data);
void on_phone_call_reject(gpointer data);

108
src/gsm.c
View File

@ -79,9 +79,6 @@ struct _GSM
/* variables */
/* ANSWERS */
static char const * _gsm_errors[] = { "ERROR", "NO CARRIER", NULL };
/* CME ERROR */
static struct
{
@ -162,6 +159,8 @@ static void _gsm_queue_pop(GSM * gsm);
static int _gsm_queue_push(GSM * gsm);
/* triggers */
static int _gsm_trigger_busy(GSM * gsm, char const * result,
gboolean * answered);
static int _gsm_trigger_cfun(GSM * gsm, char const * result);
static int _gsm_trigger_cgmm(GSM * gsm, char const * result);
static int _gsm_trigger_cme_error(GSM * gsm, char const * result,
@ -169,12 +168,20 @@ static int _gsm_trigger_cme_error(GSM * gsm, char const * result,
static int _gsm_trigger_cms_error(GSM * gsm, char const * result);
static int _gsm_trigger_cmgl(GSM * gsm, char const * result);
static int _gsm_trigger_cmgs(GSM * gsm, char const * result);
static int _gsm_trigger_connect(GSM * gsm, char const * result,
gboolean * answered);
static int _gsm_trigger_cops(GSM * gsm, char const * result);
static int _gsm_trigger_cpbr(GSM * gsm, char const * result);
static int _gsm_trigger_cpin(GSM * gsm, char const * result);
static int _gsm_trigger_creg(GSM * gsm, char const * result);
static int _gsm_trigger_cring(GSM * gsm, char const * result);
static int _gsm_trigger_csq(GSM * gsm, char const * result);
static int _gsm_trigger_no_answer(GSM * gsm, char const * result,
gboolean * answered);
static int _gsm_trigger_no_carrier(GSM * gsm, char const * result,
gboolean * answered);
static int _gsm_trigger_no_dialtone(GSM * gsm, char const * result,
gboolean * answered);
/* triggers */
static GSMTrigger _gsm_triggers[] =
@ -182,18 +189,23 @@ static GSMTrigger _gsm_triggers[] =
#define GSM_TRIGGER(trigger, callback) \
{ trigger, sizeof(trigger) - 1, \
(GSMTriggerCallback)_gsm_trigger_ ## callback }
GSM_TRIGGER("BUSY", busy),
GSM_TRIGGER("+CFUN: ", cfun),
GSM_TRIGGER("+CGMM: ", cgmm),
GSM_TRIGGER("+CME ERROR: ", cme_error),
GSM_TRIGGER("+CMS ERROR: ", cms_error),
GSM_TRIGGER("+CMGL: ", cmgl),
GSM_TRIGGER("+CMGS: ", cmgs),
GSM_TRIGGER("CONNECT", connect),
GSM_TRIGGER("+COPS: ", cops),
GSM_TRIGGER("+CPBR: ", cpbr),
GSM_TRIGGER("+CPIN: ", cpin),
GSM_TRIGGER("+CREG: ", creg),
GSM_TRIGGER("+CRING: ", cring),
GSM_TRIGGER("+CSQ: ", csq),
GSM_TRIGGER("NO ANSWER", no_answer),
GSM_TRIGGER("NO CARRIER", no_carrier),
GSM_TRIGGER("NO DIALTONE", no_dialtone),
{ NULL, 0, NULL }
};
@ -845,23 +857,21 @@ static int _gsm_parse_line(GSM * gsm, char const * line, gboolean * answered)
callback(gsm);
return 0;
}
for(i = 0; _gsm_errors[i] != NULL; i++)
{
if(strcmp(_gsm_errors[i], line) != 0)
continue;
if(answered != NULL)
*answered = TRUE;
if(gsmc != NULL)
error = gsm_command_get_error(gsmc);
gsm_event(gsm, GSM_EVENT_TYPE_ERROR, error, line);
return 0;
}
for(i = 0; _gsm_triggers[i].trigger != NULL; i++)
if(strncmp(line, _gsm_triggers[i].trigger,
_gsm_triggers[i].trigger_cnt) == 0)
return _gsm_triggers[i].callback(gsm,
&line[_gsm_triggers[i].trigger_cnt],
answered);
if(strcmp(line, "ERROR") == 0)
{
if(answered != NULL)
*answered = TRUE;
if(gsmc != NULL)
error = gsm_command_get_error(gsmc);
gsm_event(gsm, GSM_EVENT_TYPE_ERROR, error, _("Unknown error"));
return 0;
}
/* XXX look for a potential trigger */
if(gsmc != NULL && (cmd = gsm_command_get_command(gsmc)) != NULL
&& strncmp(cmd, "AT+", 3) == 0 && isupper((c = cmd[3])))
@ -966,6 +976,19 @@ static int _gsm_queue_push(GSM * gsm)
/* triggers */
/* gsm_trigger_busy */
static int _gsm_trigger_busy(GSM * gsm, char const * result,
gboolean * answered)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
#endif
if(answered != NULL)
*answered = TRUE;
return gsm_event(gsm, GSM_EVENT_TYPE_ERROR, GSM_ERROR_BUSY, "BUSY");
}
/* gsm_trigger_cfun */
static int _gsm_trigger_cfun(GSM * gsm, char const * result)
{
@ -1081,6 +1104,21 @@ static int _gsm_trigger_cmgs(GSM * gsm, char const * result)
}
/* gsm_trigger_connect */
static int _gsm_trigger_connect(GSM * gsm, char const * result,
gboolean * answered)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
#endif
if(answered != NULL)
*answered = TRUE;
/* FIXME implement pass-through */
/* FIXME reset is probably not enough (send "+++"?) */
return gsm_reset(gsm, gsm->retry);
}
/* gsm_trigger_cops */
static int _gsm_trigger_cops(GSM * gsm, char const * result)
{
@ -1234,6 +1272,48 @@ static int _gsm_trigger_csq(GSM * gsm, char const * result)
}
/* gsm_trigger_no_answer */
static int _gsm_trigger_no_answer(GSM * gsm, char const * result,
gboolean * answered)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
#endif
if(answered != NULL)
*answered = TRUE;
return gsm_event(gsm, GSM_EVENT_TYPE_ERROR, GSM_ERROR_NO_ANSWER,
"NO ANSWER");
}
/* gsm_trigger_no_carrier */
static int _gsm_trigger_no_carrier(GSM * gsm, char const * result,
gboolean * answered)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
#endif
if(answered != NULL)
*answered = TRUE;
return gsm_event(gsm, GSM_EVENT_TYPE_ERROR, GSM_ERROR_NO_CARRIER,
"NO CARRIER");
}
/* gsm_trigger_no_dialtone */
static int _gsm_trigger_no_dialtone(GSM * gsm, char const * result,
gboolean * answered)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
#endif
if(answered != NULL)
*answered = TRUE;
return gsm_event(gsm, GSM_EVENT_TYPE_ERROR, GSM_ERROR_NO_DIALTONE,
"NO DIALTONE");
}
/* callbacks */
/* on_reset */
static int _reset_do(GSM * gsm, int fd);

View File

@ -55,6 +55,7 @@ typedef enum _GSMError
{
GSM_ERROR_UNKNOWN = 0,
GSM_ERROR_ANSWER_FAILED,
GSM_ERROR_BUSY,
GSM_ERROR_CALL_FAILED,
GSM_ERROR_CONTACT_FETCH_FAILED,
GSM_ERROR_CONTACT_LIST_FAILED,
@ -63,6 +64,9 @@ typedef enum _GSMError
GSM_ERROR_MESSAGE_FETCH_FAILED,
GSM_ERROR_MESSAGE_LIST_FAILED,
GSM_ERROR_MESSAGE_SEND_FAILED,
GSM_ERROR_NO_ANSWER,
GSM_ERROR_NO_CARRIER,
GSM_ERROR_NO_DIALTONE,
GSM_ERROR_OPERATOR_MODE_FAILED,
GSM_ERROR_SIGNAL_LEVEL_FAILED,
GSM_ERROR_RESET_FAILED,

View File

@ -77,8 +77,10 @@ struct _Phone
GtkWidget * ca_hangup;
GtkWidget * ca_image;
GtkWidget * ca_reject;
GtkWidget * ca_close;
GtkWidget * ca_volume;
GtkWidget * ca_speaker;
GtkWidget * ca_mute;
/* code */
PhoneCode en_code;
@ -505,25 +507,35 @@ void phone_show_call(Phone * phone, gboolean show, ...)
vbox = gtk_vbox_new(FALSE, 4);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
/* buttons */
/* answer */
phone->ca_answer = _phone_create_button("call-start",
_("Answer"));
g_signal_connect_swapped(G_OBJECT(phone->ca_answer), "clicked",
G_CALLBACK(on_phone_call_answer), phone);
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_answer, FALSE, TRUE,
0);
/* hangup */
phone->ca_hangup = _phone_create_button("call-stop",
_("Hangup"));
g_signal_connect_swapped(G_OBJECT(phone->ca_hangup), "clicked",
G_CALLBACK(on_phone_call_hangup), phone);
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_hangup, FALSE, TRUE,
0);
/* reject */
phone->ca_reject = _phone_create_button("call-stop",
_("Reject"));
g_signal_connect_swapped(G_OBJECT(phone->ca_reject), "clicked",
G_CALLBACK(on_phone_call_reject), phone);
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_reject, FALSE, TRUE,
0);
/* close */
phone->ca_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
g_signal_connect_swapped(G_OBJECT(phone->ca_close), "clicked",
G_CALLBACK(on_phone_call_close), phone);
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_close, FALSE, TRUE,
0);
hbox = gtk_hbox_new(FALSE, 0);
/* volume bar */
phone->ca_image = gtk_image_new_from_icon_name(
"audio-volume-muted", GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start(GTK_BOX(hbox), phone->ca_image, FALSE, TRUE,
@ -532,18 +544,26 @@ void phone_show_call(Phone * phone, gboolean show, ...)
gtk_box_pack_start(GTK_BOX(hbox), phone->ca_volume, TRUE, TRUE,
0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
/* speaker mode */
phone->ca_speaker = gtk_toggle_button_new_with_label(
_("Loudspeaker"));
gtk_button_set_image(GTK_BUTTON(phone->ca_speaker),
gtk_image_new_from_icon_name("stock_volume",
gtk_image_new_from_icon_name("stock_volume-max",
GTK_ICON_SIZE_BUTTON));
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_speaker, FALSE,
TRUE, 0);
/* mute microphone */
phone->ca_mute = gtk_toggle_button_new_with_label(
_("Mute microphone"));
gtk_button_set_image(GTK_BUTTON(phone->ca_mute),
gtk_image_new_from_icon_name(
"audio-input-microphone",
GTK_ICON_SIZE_BUTTON));
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_mute, FALSE,
TRUE, 0);
gtk_container_add(GTK_CONTAINER(phone->ca_window), vbox);
}
phone_show_dialer(phone, FALSE);
gtk_window_set_transient_for(GTK_WINDOW(phone->ca_window), GTK_WINDOW(
phone->di_window));
gtk_widget_show_all(phone->ca_window);
switch(call)
{
@ -552,17 +572,27 @@ void phone_show_call(Phone * phone, gboolean show, ...)
_("In conversation"));
gtk_widget_hide(phone->ca_answer);
gtk_widget_hide(phone->ca_reject);
gtk_widget_hide(phone->ca_close);
break;
case PHONE_CALL_INCOMING:
gtk_window_set_title(GTK_WINDOW(phone->ca_window),
_("Incoming call"));
gtk_widget_hide(phone->ca_hangup);
gtk_widget_hide(phone->ca_close);
break;
case PHONE_CALL_OUTGOING:
gtk_window_set_title(GTK_WINDOW(phone->ca_window),
_("Outgoing call"));
gtk_widget_hide(phone->ca_answer);
gtk_widget_hide(phone->ca_reject);
gtk_widget_hide(phone->ca_close);
break;
case PHONE_CALL_TERMINATED:
gtk_window_set_title(GTK_WINDOW(phone->ca_window),
_("Call finished"));
gtk_widget_hide(phone->ca_answer);
gtk_widget_hide(phone->ca_hangup);
gtk_widget_hide(phone->ca_reject);
break;
}
gtk_window_present(GTK_WINDOW(phone->ca_window));
@ -1413,13 +1443,13 @@ static int _gsm_event_error(Phone * phone, GSMEvent * event)
{
switch(event->error.error)
{
case GSM_ERROR_SIM_PIN_REQUIRED:
phone_code_clear(phone);
phone_show_code(phone, TRUE, PHONE_CODE_SIM_PIN);
case GSM_ERROR_BUSY:
case GSM_ERROR_NO_ANSWER:
case GSM_ERROR_NO_DIALTONE:
_phone_error(phone->ca_window, event->error.message);
break;
case GSM_ERROR_SIM_PIN_WRONG:
phone_code_clear(phone);
_phone_error(phone->en_window, _("Wrong SIM PIN code"));
case GSM_ERROR_NO_CARRIER:
phone_show_call(phone, TRUE, PHONE_CALL_TERMINATED);
break;
case GSM_ERROR_CONTACT_FETCH_FAILED:
case GSM_ERROR_MESSAGE_FETCH_FAILED:
@ -1440,6 +1470,14 @@ static int _gsm_event_error(Phone * phone, GSMEvent * event)
_phone_error(phone->wr_window,
_("Could not send message"));
break;
case GSM_ERROR_SIM_PIN_REQUIRED:
phone_code_clear(phone);
phone_show_code(phone, TRUE, PHONE_CODE_SIM_PIN);
break;
case GSM_ERROR_SIM_PIN_WRONG:
phone_code_clear(phone);
_phone_error(phone->en_window, _("Wrong SIM PIN code"));
break;
default:
phone_error(phone, event->error.message, 0);
break;

View File

@ -29,7 +29,8 @@ typedef enum _PhoneCall
{
PHONE_CALL_ESTABLISHED = 0,
PHONE_CALL_INCOMING,
PHONE_CALL_OUTGOING
PHONE_CALL_OUTGOING,
PHONE_CALL_TERMINATED
} PhoneCall;
typedef enum _PhoneCode