From ee3fbeb03b503bedcc1f61791e678eb9998c4d3e Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sat, 28 Oct 2017 07:11:40 +0200 Subject: [PATCH] Split call control from built-in call console by using MNCC layer --- src/amps/amps.c | 26 +- src/amps/dsp.c | 2 +- src/amps/transaction.c | 2 +- src/anetz/anetz.c | 26 +- src/anetz/dsp.c | 2 +- src/bnetz/bnetz.c | 28 +- src/bnetz/dsp.c | 2 +- src/cnetz/cnetz.c | 44 +- src/cnetz/dsp.c | 2 +- src/cnetz/transaction.c | 2 +- src/common/Makefile.am | 1 + src/common/call.c | 950 +++++++++++--------------------------- src/common/call.h | 40 +- src/common/cause.h | 3 + src/common/debug.c | 4 +- src/common/main_mobile.c | 41 +- src/common/mncc_console.c | 473 +++++++++++++++++++ src/common/mncc_console.h | 10 + src/common/mncc_sock.c | 31 +- src/common/mncc_sock.h | 7 +- src/nmt/dsp.c | 2 +- src/nmt/nmt.c | 36 +- src/r2000/dsp.c | 2 +- src/r2000/r2000.c | 34 +- src/test/dummy.c | 10 +- 25 files changed, 926 insertions(+), 854 deletions(-) create mode 100644 src/common/mncc_console.c create mode 100644 src/common/mncc_console.h diff --git a/src/amps/amps.c b/src/amps/amps.c index 9fe0c4e..b9fa3ed 100644 --- a/src/amps/amps.c +++ b/src/amps/amps.c @@ -643,7 +643,7 @@ void amps_go_idle(amps_t *amps) if (amps->trans_list) { PDEBUG(DAMPS, DEBUG_ERROR, "Releasing but still having transaction, please fix!\n"); if (amps->trans_list->callref) - call_in_release(amps->trans_list->callref, CAUSE_NORMAL); + call_up_release(amps->trans_list->callref, CAUSE_NORMAL); destroy_transaction(amps->trans_list); } @@ -676,7 +676,7 @@ static void amps_release(transaction_t *trans, uint8_t cause) trans->order = 3; /* release towards call control */ if (trans->callref) { - call_in_release(trans->callref, cause); + call_up_release(trans->callref, cause); trans->callref = 0; } /* change DSP mode to transmit release */ @@ -709,14 +709,14 @@ void amps_rx_signaling_tone(amps_t *amps, int tone, double quality) break; timer_stop(&trans->timer); if (trans->callref) - call_in_release(trans->callref, CAUSE_NORMAL); + call_up_release(trans->callref, CAUSE_NORMAL); destroy_transaction(trans); amps_go_idle(amps); break; case TRANS_CALL_MT_ALERT: if (tone) { timer_stop(&trans->timer); - call_in_alerting(trans->callref); + call_up_alerting(trans->callref); amps_set_dsp_mode(amps, DSP_MODE_AUDIO_RX_AUDIO_TX, 0); trans_new_state(trans, TRANS_CALL_MT_ALERT_SEND); timer_start(&trans->timer, ALERT_TO); @@ -727,7 +727,7 @@ void amps_rx_signaling_tone(amps_t *amps, int tone, double quality) timer_stop(&trans->timer); if (!trans->sat_detected) timer_start(&trans->timer, SAT_TO1); - call_in_answer(trans->callref, amps_min2number(trans->min1, trans->min2)); + call_up_answer(trans->callref, amps_min2number(trans->min1, trans->min2)); trans_new_state(trans, TRANS_CALL); } break; @@ -887,7 +887,7 @@ reject: */ /* Call control starts call towards mobile station. */ -int call_out_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) +int call_down_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) { sender_t *sender; amps_t *amps; @@ -959,7 +959,7 @@ inval: return 0; } -void call_out_answer(int __attribute__((unused)) callref) +void call_down_answer(int __attribute__((unused)) callref) { } @@ -967,7 +967,7 @@ void call_out_answer(int __attribute__((unused)) callref) * An active call stays active, so tones and annoucements can be received * by mobile station. */ -void call_out_disconnect(int callref, int cause) +void call_down_disconnect(int callref, int cause) { sender_t *sender; amps_t *amps; @@ -984,7 +984,7 @@ void call_out_disconnect(int callref, int cause) } if (!sender) { PDEBUG(DAMPS, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n"); - call_in_release(callref, CAUSE_INVALCALLREF); + call_up_release(callref, CAUSE_INVALCALLREF); return; } @@ -1001,7 +1001,7 @@ void call_out_disconnect(int callref, int cause) return; default: PDEBUG_CHAN(DAMPS, DEBUG_INFO, "Call control disconnects on control channel, removing transaction.\n"); - call_in_release(callref, cause); + call_up_release(callref, cause); trans->callref = 0; destroy_transaction(trans); amps_go_idle(amps); @@ -1009,7 +1009,7 @@ void call_out_disconnect(int callref, int cause) } /* Call control releases call toward mobile station. */ -void call_out_release(int callref, int cause) +void call_down_release(int callref, int cause) { sender_t *sender; amps_t *amps; @@ -1046,7 +1046,7 @@ void call_out_release(int callref, int cause) } /* Receive audio from call instance. */ -void call_rx_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, sample_t *samples, int count) { sender_t *sender; amps_t *amps; @@ -1126,7 +1126,7 @@ static amps_t *assign_voice_channel(transaction_t *trans) if (!trans->callref) { /* setup call */ PDEBUG(DAMPS, DEBUG_INFO, "Setup call to network.\n"); - rc = call_in_setup(callref, callerid, trans->dialing); + rc = call_up_setup(callref, callerid, trans->dialing); if (rc < 0) { PDEBUG(DAMPS, DEBUG_NOTICE, "Call rejected (cause %d), releasing.\n", rc); amps_release(trans, 0); diff --git a/src/amps/dsp.c b/src/amps/dsp.c index f3eb35b..27575f7 100644 --- a/src/amps/dsp.c +++ b/src/amps/dsp.c @@ -841,7 +841,7 @@ static void sender_receive_audio(amps_t *amps, sample_t *samples, int length) if (pos == 160) { if (amps->dtx_state == 0) comfort_noise(spl, 160); - call_tx_audio(trans->callref, spl, 160); + call_up_audio(trans->callref, spl, 160); pos = 0; } } diff --git a/src/amps/transaction.c b/src/amps/transaction.c index d5e7976..6b6add5 100644 --- a/src/amps/transaction.c +++ b/src/amps/transaction.c @@ -127,7 +127,7 @@ transaction_t *create_transaction(amps_t *amps, enum amps_trans_state state, uin if (old_amps) /* should be... */ amps_go_idle(old_amps); if (old_callref) - call_in_release(old_callref, CAUSE_NORMAL); + call_up_release(old_callref, CAUSE_NORMAL); } trans = calloc(1, sizeof(*trans)); diff --git a/src/anetz/anetz.c b/src/anetz/anetz.c index 27eb1b0..e6b9d1e 100644 --- a/src/anetz/anetz.c +++ b/src/anetz/anetz.c @@ -287,7 +287,7 @@ void anetz_loss_indication(anetz_t *anetz, double loss_time) if (anetz->state == ANETZ_GESPRAECH) { PDEBUG_CHAN(DANETZ, DEBUG_NOTICE, "Detected loss of signal after %.1f seconds, releasing.\n", loss_time); anetz_release(anetz); - call_in_release(anetz->callref, CAUSE_TEMPFAIL); + call_up_release(anetz->callref, CAUSE_TEMPFAIL); anetz->callref = 0; } } @@ -328,7 +328,7 @@ void anetz_receive_tone(anetz_t *anetz, int tone) int rc; PDEBUG_CHAN(DANETZ, DEBUG_INFO, "1750 Hz signal from mobile station is gone, setup call.\n"); - rc = call_in_setup(callref, NULL, "010"); + rc = call_up_setup(callref, NULL, "010"); if (rc < 0) { PDEBUG_CHAN(DANETZ, DEBUG_NOTICE, "Call rejected (cause %d), sending release tone.\n", -rc); anetz_release(anetz); @@ -337,7 +337,7 @@ void anetz_receive_tone(anetz_t *anetz, int tone) anetz->callref = callref; } else { PDEBUG_CHAN(DANETZ, DEBUG_INFO, "1750 Hz signal from mobile station is gone, answer call.\n"); - call_in_answer(anetz->callref, anetz->station_id); + call_up_answer(anetz->callref, anetz->station_id); } anetz_set_dsp_mode(anetz, DSP_MODE_AUDIO, 0); } @@ -345,7 +345,7 @@ void anetz_receive_tone(anetz_t *anetz, int tone) if (tone == 1) { PDEBUG_CHAN(DANETZ, DEBUG_INFO, "Received 1750 Hz release signal from mobile station, sending release tone.\n"); anetz_release(anetz); - call_in_release(anetz->callref, CAUSE_NORMAL); + call_up_release(anetz->callref, CAUSE_NORMAL); anetz->callref = 0; break; } @@ -373,7 +373,7 @@ static void anetz_timeout(struct timer *timer) case ANETZ_ANRUF: PDEBUG_CHAN(DANETZ, DEBUG_NOTICE, "Timeout while waiting for answer, releasing.\n"); anetz_go_idle(anetz); - call_in_release(anetz->callref, CAUSE_NOANSWER); + call_up_release(anetz->callref, CAUSE_NOANSWER); anetz->callref = 0; break; case ANETZ_AUSLOESEN: @@ -385,7 +385,7 @@ static void anetz_timeout(struct timer *timer) } /* Call control starts call towards mobile station. */ -int call_out_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) +int call_down_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) { sender_t *sender; anetz_t *anetz; @@ -433,12 +433,12 @@ inval: anetz->callref = callref; anetz_page(anetz, dialing, freq); - call_in_alerting(callref); + call_up_alerting(callref); return 0; } -void call_out_answer(int __attribute__((unused)) callref) +void call_down_answer(int __attribute__((unused)) callref) { } @@ -446,7 +446,7 @@ void call_out_answer(int __attribute__((unused)) callref) * An active call stays active, so tones and annoucements can be received * by mobile station. */ -void call_out_disconnect(int callref, int cause) +void call_down_disconnect(int callref, int cause) { sender_t *sender; anetz_t *anetz; @@ -460,7 +460,7 @@ void call_out_disconnect(int callref, int cause) } if (!sender) { PDEBUG(DANETZ, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n"); - call_in_release(callref, CAUSE_INVALCALLREF); + call_up_release(callref, CAUSE_INVALCALLREF); return; } @@ -476,14 +476,14 @@ void call_out_disconnect(int callref, int cause) break; } - call_in_release(callref, cause); + call_up_release(callref, cause); anetz->callref = 0; } /* Call control releases call toward mobile station. */ -void call_out_release(int callref, __attribute__((unused)) int cause) +void call_down_release(int callref, __attribute__((unused)) int cause) { sender_t *sender; anetz_t *anetz; @@ -518,7 +518,7 @@ void call_out_release(int callref, __attribute__((unused)) int cause) } /* Receive audio from call instance. */ -void call_rx_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, sample_t *samples, int count) { sender_t *sender; anetz_t *anetz; diff --git a/src/anetz/dsp.c b/src/anetz/dsp.c index 4d60110..0cd8184 100644 --- a/src/anetz/dsp.c +++ b/src/anetz/dsp.c @@ -227,7 +227,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double rf_l for (i = 0; i < count; i++) { spl[pos++] = samples[i]; if (pos == 160) { - call_tx_audio(anetz->callref, spl, 160); + call_up_audio(anetz->callref, spl, 160); pos = 0; } } diff --git a/src/bnetz/bnetz.c b/src/bnetz/bnetz.c index 8aee197..f216d8c 100644 --- a/src/bnetz/bnetz.c +++ b/src/bnetz/bnetz.c @@ -391,7 +391,7 @@ void bnetz_loss_indication(bnetz_t *bnetz, double loss_time) || bnetz->state == BNETZ_RUFHALTUNG) { PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Detected loss of signal after %.1f seconds, releasing.\n", loss_time); bnetz_release(bnetz, TRENN_COUNT); - call_in_release(bnetz->callref, CAUSE_TEMPFAIL); + call_up_release(bnetz->callref, CAUSE_TEMPFAIL); bnetz->callref = 0; } } @@ -425,7 +425,7 @@ void bnetz_receive_tone(bnetz_t *bnetz, int bit) timer_stop(&bnetz->timer); bnetz_new_state(bnetz, BNETZ_RUFHALTUNG); bnetz_set_dsp_mode(bnetz, DSP_MODE_1); - call_in_alerting(bnetz->callref); + call_up_alerting(bnetz->callref); timer_start(&bnetz->timer, ALERTING_TO); break; } @@ -439,7 +439,7 @@ void bnetz_receive_tone(bnetz_t *bnetz, int bit) /* start metering pulses if forced */ if (bnetz->metering < 0) timer_start(&bnetz->timer, METERING_START); - call_in_answer(bnetz->callref, bnetz->station_id); + call_up_answer(bnetz->callref, bnetz->station_id); break; } default: @@ -615,7 +615,7 @@ void bnetz_receive_telegramm(bnetz_t *bnetz, uint16_t telegramm, double level_av /* setup call */ PDEBUG(DBNETZ, DEBUG_INFO, "Setup call to network.\n"); - rc = call_in_setup(callref, bnetz->station_id, dialing); + rc = call_up_setup(callref, bnetz->station_id, dialing); if (rc < 0) { PDEBUG(DBNETZ, DEBUG_NOTICE, "Call rejected (cause %d), releasing.\n", -rc); bnetz_release(bnetz, TRENN_COUNT); @@ -652,7 +652,7 @@ lets see, if noise will not generate a release signal.... if (digit == 't') { PDEBUG(DBNETZ, DEBUG_NOTICE, "Received 'Schlusssignal' from mobile station\n"); bnetz_release(bnetz, TRENN_COUNT); - call_in_release(bnetz->callref, CAUSE_NORMAL); + call_up_release(bnetz->callref, CAUSE_NORMAL); bnetz->callref = 0; break; } @@ -691,7 +691,7 @@ static void bnetz_timeout(struct timer *timer) if (bnetz->page_try == PAGE_TRIES) { PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Timeout while waiting for call acknowledge from mobile station, going idle.\n"); bnetz_release(bnetz, TRENN_COUNT); - call_in_release(bnetz->callref, CAUSE_OUTOFORDER); + call_up_release(bnetz->callref, CAUSE_OUTOFORDER); bnetz->callref = 0; break; } @@ -701,7 +701,7 @@ static void bnetz_timeout(struct timer *timer) case BNETZ_RUFHALTUNG: PDEBUG_CHAN(DBNETZ, DEBUG_NOTICE, "Timeout while waiting for answer of mobile station, releasing.\n"); bnetz_release(bnetz, TRENN_COUNT_NA); - call_in_release(bnetz->callref, CAUSE_NOANSWER); + call_up_release(bnetz->callref, CAUSE_NOANSWER); bnetz->callref = 0; break; case BNETZ_GESPRAECH: @@ -726,7 +726,7 @@ static void bnetz_timeout(struct timer *timer) } /* Call control starts call towards mobile station. */ -int call_out_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) +int call_down_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) { sender_t *sender; bnetz_t *bnetz; @@ -776,7 +776,7 @@ inval: return 0; } -void call_out_answer(int __attribute__((unused)) callref) +void call_down_answer(int __attribute__((unused)) callref) { } @@ -784,7 +784,7 @@ void call_out_answer(int __attribute__((unused)) callref) * An active call stays active, so tones and annoucements can be received * by mobile station. */ -void call_out_disconnect(int callref, int cause) +void call_down_disconnect(int callref, int cause) { sender_t *sender; bnetz_t *bnetz; @@ -798,7 +798,7 @@ void call_out_disconnect(int callref, int cause) } if (!sender) { PDEBUG(DBNETZ, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n"); - call_in_release(callref, CAUSE_INVALCALLREF); + call_up_release(callref, CAUSE_INVALCALLREF); return; } @@ -820,13 +820,13 @@ void call_out_disconnect(int callref, int cause) break; } - call_in_release(callref, cause); + call_up_release(callref, cause); bnetz->callref = 0; } /* Call control releases call toward mobile station. */ -void call_out_release(int callref, int __attribute__((unused)) cause) +void call_down_release(int callref, int __attribute__((unused)) cause) { sender_t *sender; bnetz_t *bnetz; @@ -867,7 +867,7 @@ void call_out_release(int callref, int __attribute__((unused)) cause) } /* Receive audio from call instance. */ -void call_rx_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, sample_t *samples, int count) { sender_t *sender; bnetz_t *bnetz; diff --git a/src/bnetz/dsp.c b/src/bnetz/dsp.c index 1c9bec3..f77680e 100644 --- a/src/bnetz/dsp.c +++ b/src/bnetz/dsp.c @@ -239,7 +239,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double rf_l for (i = 0; i < count; i++) { spl[pos++] = samples[i]; if (pos == 160) { - call_tx_audio(bnetz->callref, spl, 160); + call_up_audio(bnetz->callref, spl, 160); pos = 0; } } diff --git a/src/cnetz/cnetz.c b/src/cnetz/cnetz.c index 0ec5f09..8842a00 100644 --- a/src/cnetz/cnetz.c +++ b/src/cnetz/cnetz.c @@ -486,7 +486,7 @@ void cnetz_go_idle(cnetz_t *cnetz) if (cnetz->trans_list) { PDEBUG(DCNETZ, DEBUG_ERROR, "Releasing but still having transaction, please fix!\n"); if (cnetz->trans_list->callref) - call_in_release(cnetz->trans_list->callref, CAUSE_NORMAL); + call_up_release(cnetz->trans_list->callref, CAUSE_NORMAL); destroy_transaction(cnetz->trans_list); } @@ -524,7 +524,7 @@ static void cnetz_release(transaction_t *trans, uint8_t cause) } /* Receive audio from call instance. */ -void call_rx_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, sample_t *samples, int count) { sender_t *sender; cnetz_t *cnetz; @@ -543,7 +543,7 @@ void call_rx_audio(int callref, sample_t *samples, int count) } } -int call_out_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) +int call_down_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) { sender_t *sender; cnetz_t *cnetz, *spk; @@ -626,7 +626,7 @@ inval: return 0; } -void call_out_answer(int __attribute__((unused)) callref) +void call_down_answer(int __attribute__((unused)) callref) { } @@ -634,7 +634,7 @@ void call_out_answer(int __attribute__((unused)) callref) * An active call stays active, so tones and annoucements can be received * by mobile station. */ -void call_out_disconnect(int callref, int cause) +void call_down_disconnect(int callref, int cause) { sender_t *sender; cnetz_t *cnetz; @@ -651,7 +651,7 @@ void call_out_disconnect(int callref, int cause) } if (!sender) { PDEBUG(DCNETZ, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n"); - call_in_release(callref, CAUSE_INVALCALLREF); + call_up_release(callref, CAUSE_INVALCALLREF); return; } @@ -663,12 +663,12 @@ void call_out_disconnect(int callref, int cause) case DSP_MODE_SPK_K: PDEBUG(DCNETZ, DEBUG_INFO, "Call control disconnects on speech channel, releasing towards mobile station.\n"); cnetz_release(trans, cnetz_cause_isdn2cnetz(cause)); - call_in_release(callref, cause); + call_up_release(callref, cause); trans->callref = 0; break; default: PDEBUG(DCNETZ, DEBUG_INFO, "Call control disconnects on organisation channel, removing transaction.\n"); - call_in_release(callref, cause); + call_up_release(callref, cause); trans->callref = 0; if (trans->state == TRANS_MT_QUEUE || trans->state == TRANS_MT_DELAY) { cnetz_release(trans, cnetz_cause_isdn2cnetz(cause)); @@ -681,7 +681,7 @@ void call_out_disconnect(int callref, int cause) } /* Call control releases call toward mobile station. */ -void call_out_release(int callref, int cause) +void call_down_release(int callref, int cause) { sender_t *sender; cnetz_t *cnetz; @@ -815,7 +815,7 @@ void transaction_timeout(struct timer *timer) break; case TRANS_MT_QUEUE: PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Phone in queue, but still no channel available, releasing call!\n"); - call_in_release(trans->callref, CAUSE_NOCHANNEL); + call_up_release(trans->callref, CAUSE_NOCHANNEL); trans->callref = 0; cnetz_release(trans, CNETZ_CAUSE_GASSENBESETZT); break; @@ -840,26 +840,26 @@ void transaction_timeout(struct timer *timer) else PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "Lost signal from 'FuTln' (mobile station)\n"); if (trans->callref) { - call_in_release(trans->callref, CAUSE_TEMPFAIL); + call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; } cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; case TRANS_DS: PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after connect 'Durchschalten'\n"); - call_in_release(trans->callref, CAUSE_TEMPFAIL); + call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; case TRANS_RTA: PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after ringing order 'Rufton anschalten'\n"); - call_in_release(trans->callref, CAUSE_TEMPFAIL); + call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; case TRANS_AHQ: PDEBUG_CHAN(DCNETZ, DEBUG_NOTICE, "No response after answer 'Abhebequittung'\n"); - call_in_release(trans->callref, CAUSE_TEMPFAIL); + call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); break; @@ -1050,7 +1050,7 @@ vak: telegramm.opcode = OPCODE_WSK_R; trans_new_state(trans, TRANS_MT_QUEUE); timer_start(&trans->timer, T_VAK); /* Maximum time to hold queue */ - call_in_alerting(trans->callref); + call_up_alerting(trans->callref); default: ; /* LR */ } @@ -1283,7 +1283,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz) if (trans->mo_call) { int rc; trans->callref = ++new_callref; - rc = call_in_setup(trans->callref, transaction2rufnummer(trans), trans->dialing); + rc = call_up_setup(trans->callref, transaction2rufnummer(trans), trans->dialing); if (rc < 0) { PDEBUG(DCNETZ, DEBUG_NOTICE, "Call rejected (cause %d), releasing.\n", -rc); trans->callref = 0; @@ -1298,7 +1298,7 @@ const telegramm_t *cnetz_transmit_telegramm_spk_k(cnetz_t *cnetz) trans_new_state(trans, TRANS_RTA); timer_start(&trans->timer, 0.0375 * F_RTA); /* F_RTA frames */ trans->repeat = 0; - call_in_alerting(trans->callref); + call_up_alerting(trans->callref); } } break; @@ -1348,7 +1348,7 @@ call_failed: trans->page_failed = 1; cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); if (trans->callref) - call_in_release(trans->callref, CAUSE_TEMPFAIL); + call_up_release(trans->callref, CAUSE_TEMPFAIL); /* must destroy transaction after cnetz_release */ destroy_transaction(trans); cnetz_go_idle(cnetz); @@ -1364,7 +1364,7 @@ call_failed: PDEBUG(DCNETZ, DEBUG_NOTICE, "Cannot retry, because currently no OgK available (busy)\n"); cnetz_release(trans, CNETZ_CAUSE_FUNKTECHNISCH); if (trans->callref) - call_in_release(trans->callref, CAUSE_NOCHANNEL); + call_up_release(trans->callref, CAUSE_NOCHANNEL); /* must destroy transaction after cnetz_release */ destroy_transaction(trans); break; @@ -1473,7 +1473,7 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) trans_new_state(trans, TRANS_AHQ); trans->repeat = 0; timer_stop(&trans->timer); - call_in_answer(trans->callref, transaction2rufnummer(trans)); + call_up_answer(trans->callref, transaction2rufnummer(trans)); break; case OPCODE_AT_K: if (!match_fuz(cnetz, telegramm, cnetz->cell_nr)) { @@ -1491,7 +1491,7 @@ void cnetz_receive_telegramm_spk_k(cnetz_t *cnetz, telegramm_t *telegramm) trans->repeat = 0; timer_stop(&trans->timer); if (trans->callref) { - call_in_release(trans->callref, CAUSE_NORMAL); + call_up_release(trans->callref, CAUSE_NORMAL); trans->callref = 0; } break; @@ -1622,7 +1622,7 @@ void cnetz_receive_telegramm_spk_v(cnetz_t *cnetz, telegramm_t *telegramm) trans->repeat = 0; timer_stop(&trans->timer); if (trans->callref) { - call_in_release(trans->callref, CAUSE_NORMAL); + call_up_release(trans->callref, CAUSE_NORMAL); trans->callref = 0; } break; diff --git a/src/cnetz/dsp.c b/src/cnetz/dsp.c index af15a68..bcd63e0 100644 --- a/src/cnetz/dsp.c +++ b/src/cnetz/dsp.c @@ -837,7 +837,7 @@ void unshrink_speech(cnetz_t *cnetz, sample_t *speech_buffer, int count) for (i = 0; i < count; i++) { spl[pos++] = speech_buffer[i]; if (pos == 160) { - call_tx_audio(cnetz->trans_list->callref, spl, 160); + call_up_audio(cnetz->trans_list->callref, spl, 160); pos = 0; } } diff --git a/src/cnetz/transaction.c b/src/cnetz/transaction.c index 844b9bc..1945d0a 100644 --- a/src/cnetz/transaction.c +++ b/src/cnetz/transaction.c @@ -62,7 +62,7 @@ transaction_t *create_transaction(cnetz_t *cnetz, uint64_t state, uint8_t futln_ if (old_cnetz) /* should be... */ cnetz_go_idle(old_cnetz); if (old_callref) - call_in_release(old_callref, CAUSE_NORMAL); + call_up_release(old_callref, CAUSE_NORMAL); } trans = calloc(1, sizeof(*trans)); diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 0ae7f9c..3b3375e 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -27,6 +27,7 @@ libmobile_a_SOURCES = \ cause.c \ call.c \ testton.c \ + mncc_console.c \ mncc_sock.c \ hagelbarger.c \ display_status.c \ diff --git a/src/common/call.c b/src/common/call.c index 1bfc233..53c0886 100644 --- a/src/common/call.c +++ b/src/common/call.c @@ -1,4 +1,4 @@ -/* built-in call control +/* interface between mobile network/phone implementation and MNCC * * (C) 2016 by Andreas Eversberg * All Rights Reserved @@ -30,8 +30,7 @@ #include "cause.h" #include "call.h" #include "timer.h" -#include "mncc_sock.h" -#include "testton.h" +#include "mncc.h" #define DISC_TIMEOUT 30 @@ -52,53 +51,35 @@ static double level_of(double *samples, int count) } #endif +static int send_patterns; /* send patterns towards fixed network */ +static int release_on_disconnect; /* release towards mobile phone, if MNCC call disconnects, don't send disconnect tone */ + /* stream patterns/announcements */ -int16_t *test_spl = NULL; int16_t *ringback_spl = NULL; -int16_t *hangup_spl = NULL; -int16_t *busy_spl = NULL; -int16_t *noanswer_spl = NULL; -int16_t *outoforder_spl = NULL; -int16_t *invalidnumber_spl = NULL; -int16_t *congestion_spl = NULL; -int16_t *recall_spl = NULL; -int test_size = 0; int ringback_size = 0; -int hangup_size = 0; -int busy_size = 0; -int noanswer_size = 0; -int outoforder_size = 0; -int invalidnumber_size = 0; -int congestion_size = 0; -int recall_size = 0; -int test_max = 0; int ringback_max = 0; +int16_t *hangup_spl = NULL; +int hangup_size = 0; int hangup_max = 0; +int16_t *busy_spl = NULL; +int busy_size = 0; int busy_max = 0; +int16_t *noanswer_spl = NULL; +int noanswer_size = 0; int noanswer_max = 0; +int16_t *outoforder_spl = NULL; +int outoforder_size = 0; int outoforder_max = 0; +int16_t *invalidnumber_spl = NULL; +int invalidnumber_size = 0; int invalidnumber_max = 0; +int16_t *congestion_spl = NULL; +int congestion_size = 0; int congestion_max = 0; +int16_t *recall_spl = NULL; +int recall_size = 0; int recall_max = 0; -enum call_state { - CALL_IDLE = 0, - CALL_SETUP_MO, - CALL_SETUP_MT, - CALL_ALERTING, - CALL_CONNECT, - CALL_DISCONNECTED, -}; - -static const char *call_state_name[] = { - "IDLE", - "SETUP_MO", - "SETUP_MT", - "ALERTING", - "CONNECT", - "DISCONNECTED", -}; - enum audio_pattern { PATTERN_NONE = 0, PATTERN_TEST, @@ -112,18 +93,13 @@ enum audio_pattern { PATTERN_RECALL, }; -void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pattern) +static void get_pattern(const int16_t **spl, int *size, int *max, enum audio_pattern pattern) { *spl = NULL; *size = 0; *max = 0; switch (pattern) { - case PATTERN_TEST: - *spl = test_spl; - *size = test_size; - *max = test_max; - break; case PATTERN_RINGBACK: no_recall: *spl = ringback_spl; @@ -184,82 +160,6 @@ no_invalidnumber: } } -static int new_callref = 0; /* toward mobile */ - -/* built in call instance */ -typedef struct call { - int callref; - enum call_state state; - int disc_cause; /* cause that has been sent by transceiver instance for release */ - char station_id[16]; - char dialing[16]; - char audiodev[64]; /* headphone interface, if used */ - int samplerate; /* sample rate of headphone interface */ - void *sound; /* headphone interface */ - int latspl; /* sample latency at headphone interface */ - samplerate_t srstate; /* patterns/announcement upsampling */ - jitter_t dejitter; /* headphone audio dejittering */ - int audio_pos; /* position when playing patterns */ - int test_audio_pos; /* position for test tone toward mobile */ - int dial_digits; /* number of digits to be dialed */ - int loopback; /* loopback test for echo */ - int echo_test; /* send echo back to mobile phone */ - int use_mncc_sock; /* use MNCC socket instead of built-in call control */ - int send_patterns; /* send patterns towards fixed network */ - int release_on_disconnect; /* release towards mobile phone, if MNCC call disconnects, don't send disconnect tone */ - -} call_t; - -static call_t call; - -static void call_new_state(enum call_state state) -{ - PDEBUG(DCALL, DEBUG_DEBUG, "Call state '%s' -> '%s'\n", call_state_name[call.state], call_state_name[state]); - call.state = state; - call.audio_pos = 0; - call.test_audio_pos = 0; -} - -static void get_call_patterns(int16_t *samples, int length, enum audio_pattern pattern) -{ - const int16_t *spl; - int size, max, pos; - - get_pattern(&spl, &size, &max, pattern); - - /* stream sample */ - pos = call.audio_pos; - while(length--) { - if (pos >= size) - *samples++ = 0; - else - *samples++ = spl[pos] >> 1; - if (++pos == max) - pos = 0; - } - call.audio_pos = pos; -} - -static void get_test_patterns(int16_t *samples, int length) -{ - const int16_t *spl; - int size, max, pos; - - get_pattern(&spl, &size, &max, PATTERN_TEST); - - /* stream sample */ - pos = call.test_audio_pos; - while(length--) { - if (pos >= size) - *samples++ = 0; - else - *samples++ = spl[pos] >> 2; - if (++pos == max) - pos = 0; - } - call.test_audio_pos = pos; -} - static enum audio_pattern cause2pattern(int cause) { int pattern; @@ -290,11 +190,21 @@ static enum audio_pattern cause2pattern(int cause) return pattern; } +enum process_state { + PROCESS_IDLE = 0, /* IDLE */ + PROCESS_SETUP_RO, /* call from radio to MNCC */ + PROCESS_SETUP_RT, /* call from MNCC to radio */ + PROCESS_ALERTING_RO, /* call from radio to MNCC */ + PROCESS_ALERTING_RT, /* call from MNCC to radio */ + PROCESS_CONNECT, + PROCESS_DISCONNECT, +}; + /* MNCC call instance */ typedef struct process { struct process *next; int callref; - enum call_state state; + enum process_state state; int audio_disconnected; /* if not associated with transceiver anymore */ enum audio_pattern pattern; int audio_pos; @@ -306,7 +216,7 @@ static process_t *process_head = NULL; static void process_timeout(struct timer *timer); -static void create_process(int callref, int state) +static process_t *create_process(int callref, enum process_state state) { process_t *process; @@ -321,6 +231,8 @@ static void create_process(int callref, int state) process->callref = callref; process->state = state; + + return process; } static void destroy_process(int callref) @@ -341,108 +253,55 @@ static void destroy_process(int callref) PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); } -static int is_process(int callref) +static process_t *get_process(int callref) { process_t *process = process_head; while (process) { if (process->callref == callref) - return 1; + return process; process = process->next; } - return 0; + return NULL; } -static enum call_state is_process_state(int callref) +static void new_state_process(int callref, enum process_state state) { - process_t *process = process_head; + process_t *process = get_process(callref); - while (process) { - if (process->callref == callref) - return process->state; - process = process->next; + if (!process) { + PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); + return; } - return CALL_IDLE; -} - -static void set_state_process(int callref, enum call_state state) -{ - process_t *process = process_head; - - while (process) { - if (process->callref == callref) { - process->state = state; - return; - } - process = process->next; - } - PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); + process->state = state; } static void set_pattern_process(int callref, enum audio_pattern pattern) { - process_t *process = process_head; + process_t *process = get_process(callref); - while (process) { - if (process->callref == callref) { - process->pattern = pattern; - process->audio_pos = 0; - return; - } - process = process->next; + if (!process) { + PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); + return; } - PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); + process->pattern = pattern; + process->audio_pos = 0; } /* disconnect audio, now send audio directly from pattern/announcement, not from transceiver */ static void disconnect_process(int callref, int cause) { - process_t *process = process_head; + process_t *process = get_process(callref); - while (process) { - if (process->callref == callref) { - process->pattern = cause2pattern(cause); - process->audio_disconnected = 1; - process->audio_pos = 0; - process->cause = cause; - timer_start(&process->timer, DISC_TIMEOUT); - return; - } - process = process->next; + if (!process) { + PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); + return; } - PDEBUG(DCALL, DEBUG_ERROR, "Process with callref 0x%x not found!\n", callref); -} - -/* check if audio is disconnected */ -static int is_process_disconnected(int callref) -{ - process_t *process = process_head; - - while (process) { - if (process->callref == callref) { - return process->audio_disconnected; - } - process = process->next; - } - PDEBUG(DCALL, DEBUG_DEBUG, "Process with callref 0x%x not found, this is ok!\n", callref); - - return 0; -} - -/* check if pattern is set, so we send patterns and announcements */ -static int is_process_pattern(int callref) -{ - process_t *process = process_head; - - while (process) { - if (process->callref == callref) { - return (process->pattern != PATTERN_NONE); - } - process = process->next; - } - PDEBUG(DCALL, DEBUG_DEBUG, "Process with callref 0x%x not found, this is ok!\n", callref); - - return 0; + process->pattern = cause2pattern(cause); + process->audio_disconnected = 1; + process->audio_pos = 0; + process->cause = cause; + timer_start(&process->timer, DISC_TIMEOUT); } static void get_process_patterns(process_t *process, int16_t *samples, int length) @@ -478,301 +337,56 @@ static void process_timeout(struct timer *timer) mncc->msg_type = MNCC_REL_IND; mncc->callref = process->callref; mncc->fields |= MNCC_F_CAUSE; - mncc->cause.location = 1; /* private local */ + mncc->cause.location = LOCATION_PRIVATE_LOCAL; mncc->cause.value = process->cause; destroy_process(process->callref); - PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network (after timeout)\n"); - mncc_write(buf, sizeof(struct gsm_mncc)); + PDEBUG(DCALL, DEBUG_INFO, "Releasing MNCC call towards fixed network (after timeout)\n"); + mncc_up(buf, sizeof(struct gsm_mncc)); } } -int call_init(const char *station_id, const char *audiodev, int samplerate, int latency, int dial_digits, int loopback, int use_mncc_sock, int send_patterns, int release_on_disconnect, int echo_test) +int call_init(int _send_patterns, int _release_on_disconnect) { - int rc = 0; - - init_testton(); - - memset(&call, 0, sizeof(call)); - strncpy(call.station_id, station_id, sizeof(call.station_id) - 1); - call.latspl = latency * samplerate / 1000; - call.dial_digits = dial_digits; - call.loopback = loopback; - call.echo_test = echo_test; - call.use_mncc_sock = use_mncc_sock; - call.send_patterns = send_patterns; - call.release_on_disconnect = release_on_disconnect; - call.samplerate = samplerate; - strncpy(call.audiodev, audiodev, sizeof(call.audiodev) - 1); - - if (use_mncc_sock && audiodev[0]) { - PDEBUG(DSENDER, DEBUG_ERROR, "You selected MNCC interface, but it cannot be used with call device (headset).\n"); - rc = -EINVAL; - goto error; - } - if (use_mncc_sock && echo_test) { - PDEBUG(DSENDER, DEBUG_ERROR, "You selected MNCC interface, but it cannot be used with echo test.\n"); - rc = -EINVAL; - goto error; - } - if (audiodev[0] && echo_test) { - PDEBUG(DSENDER, DEBUG_ERROR, "You selected call device (headset), but it cannot be used with echo test.\n"); - rc = -EINVAL; - goto error; - } - - if (use_mncc_sock) - return 0; - - if (!audiodev[0]) - return 0; - - rc = init_samplerate(&call.srstate, 8000.0, (double)samplerate, 3300.0); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to init sample rate conversion!\n"); - goto error; - } - - rc = jitter_create(&call.dejitter, samplerate / 5); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init dejitter buffer!\n"); - goto error; - } + send_patterns = _send_patterns; + release_on_disconnect = _release_on_disconnect; return 0; - -error: - call_cleanup(); - return rc; -} - -int call_open_audio(int latspl) -{ - if (!call.audiodev[0]) - return 0; - - /* open sound device for call control */ - /* use factor 1.4 of speech level for complete range of sound card */ - call.sound = sound_open(call.audiodev, NULL, NULL, 1, 0.0, call.samplerate, latspl, 1.4, 4000.0); - if (!call.sound) { - PDEBUG(DSENDER, DEBUG_ERROR, "No sound device!\n"); - return -EIO; - } - - return 0; -} - -int call_start_audio(void) -{ - if (!call.audiodev[0]) - return 0; - - return sound_start(call.sound); -} - -void call_cleanup(void) -{ - if (call.use_mncc_sock) - return; - - /* close sound devoice */ - if (call.sound) - sound_close(call.sound); - - jitter_destroy(&call.dejitter); - - if (process_head) { - PDEBUG(DMNCC, DEBUG_ERROR, "Not all MNCC instances have been released!\n"); - } -} - -static char console_text[256]; -static char console_clear[256]; -static int console_len = 0; - -static void process_ui(int c) -{ - char text[256]; - int len; - - switch (call.state) { - case CALL_IDLE: - if (c > 0) { - if (c >= '0' && c <= '9' && (int)strlen(call.station_id) < call.dial_digits) { - call.station_id[strlen(call.station_id) + 1] = '\0'; - call.station_id[strlen(call.station_id)] = c; - } - if ((c == 8 || c == 127) && strlen(call.station_id)) - call.station_id[strlen(call.station_id) - 1] = '\0'; -dial_after_hangup: - if (c == 'd' && (int)strlen(call.station_id) == call.dial_digits) { - int rc; - int callref = ++new_callref; - - PDEBUG(DCALL, DEBUG_INFO, "Outgoing call to %s\n", call.station_id); - call.dialing[0] = '\0'; - call_new_state(CALL_SETUP_MT); - call.callref = callref; - rc = call_out_setup(callref, "", TYPE_NOTAVAIL, call.station_id); - if (rc < 0) { - PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc); - call_new_state(CALL_DISCONNECTED); - call.callref = 0; - call.disc_cause = -rc; - } - } - } - if (call.dial_digits != (int)strlen(call.station_id)) - sprintf(text, "on-hook: %s%s (enter digits 0..9)\r", call.station_id, "..............." + 15 - call.dial_digits + strlen(call.station_id)); - else - sprintf(text, "on-hook: %s (press d=dial)\r", call.station_id); - break; - case CALL_SETUP_MO: - case CALL_SETUP_MT: - case CALL_ALERTING: - case CALL_CONNECT: - case CALL_DISCONNECTED: - if (c > 0) { - if (c == 'h' || (c == 'd' && call.state == CALL_DISCONNECTED)) { - PDEBUG(DCALL, DEBUG_INFO, "Call hangup\n"); - call_new_state(CALL_IDLE); - if (call.callref) { - call_out_release(call.callref, CAUSE_NORMAL); - call.callref = 0; - } - if (c == 'd') - goto dial_after_hangup; - } - } - if (call.state == CALL_SETUP_MT) - sprintf(text, "call setup: %s (press h=hangup)\r", call.station_id); - if (call.state == CALL_ALERTING) - sprintf(text, "call ringing: %s (press h=hangup)\r", call.station_id); - if (call.state == CALL_CONNECT) { - if (call.dialing[0]) - sprintf(text, "call active: %s->%s (press h=hangup)\r", call.station_id, call.dialing); - else - sprintf(text, "call active: %s (press h=hangup)\r", call.station_id); - } - if (call.state == CALL_DISCONNECTED) - sprintf(text, "call disconnected: %s (press h=hangup d=redial)\r", cause_name(call.disc_cause)); - break; - } - /* skip if nothing has changed */ - len = strlen(text); - if (console_len == len && !memcmp(console_text, text, len)) - return; - clear_console_text(); - console_len = len; - memcpy(console_text, text, len); - memset(console_clear, ' ', len - 1); - console_clear[len - 1] = '\r'; - print_console_text(); - fflush(stdout); -} - -void clear_console_text(void) -{ - if (!console_len) - return; - - fwrite(console_clear, console_len, 1, stdout); - // note: fflused by user of this function - console_len = 0; -} - -void print_console_text(void) -{ - if (!console_len) - return; - - printf("\033[1;37m"); - fwrite(console_text, console_len, 1, stdout); - printf("\033[0;39m"); -} - -/* get keys from keyboad to control call via console - * returns 1 on exit (ctrl+c) */ -void process_call(int c) -{ - if (call.use_mncc_sock) { - mncc_handle(); - return; - } - - if (!call.loopback) - process_ui(c); - - if (!call.sound) - return; - - /* handle audio, if sound device is used */ - sample_t samples[call.latspl + 10], *samples_list[1]; - uint8_t *power_list[1]; - double rf_level_db[1]; - int count; - int rc; - - count = sound_get_tosend(call.sound, call.latspl); - if (count < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); - if (count == -EPIPE) - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); - return; - } - if (count > 0) { - int16_t spl[count + 10]; /* more than enough, count will be reduced by scaling with factor */ - switch(call.state) { - case CALL_ALERTING: - /* the count will be an approximation that will be upsampled */ - count = (int)((double)count / call.srstate.factor + 0.5); - get_call_patterns(spl, count, PATTERN_RINGBACK); - int16_to_samples(samples, spl, count); - count = samplerate_upsample(&call.srstate, samples, count, samples); - /* prevent click after hangup */ - jitter_clear(&call.dejitter); - break; - case CALL_DISCONNECTED: - /* the count will be an approximation that will be upsampled */ - count = (int)((double)count / call.srstate.factor + 0.5); - get_call_patterns(spl, count, cause2pattern(call.disc_cause)); - int16_to_samples(samples, spl, count); - count = samplerate_upsample(&call.srstate, samples, count, samples); - /* prevent click after hangup */ - jitter_clear(&call.dejitter); - break; - default: - jitter_load(&call.dejitter, samples, count); - } - samples_list[0] = samples; - power_list[0] = NULL; - rc = sound_write(call.sound, samples_list, power_list, count, NULL, NULL, 1); - if (rc < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc); - if (rc == -EPIPE) - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); - return; - } - } - samples_list[0] = samples; - count = sound_read(call.sound, samples_list, call.latspl, 1, rf_level_db); - if (count < 0) { - PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from sound device (rc = %d)!\n", count); - if (count == -EPIPE) - PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); - return; - } - if (count) { - if (call.loopback == 3) - jitter_save(&call.dejitter, samples, count); - count = samplerate_downsample(&call.srstate, samples, count); - call_rx_audio(call.callref, samples, count); - } } /* Setup is received from transceiver. */ -int call_in_setup(int callref, const char *callerid, const char *dialing) +static int _indicate_setup(int callref, const char *callerid, const char *dialing) { + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + int rc; + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = MNCC_SETUP_IND; + mncc->callref = callref; + mncc->fields |= MNCC_F_CALLING; + if (callerid) { + strncpy(mncc->calling.number, callerid, sizeof(mncc->calling.number) - 1); + mncc->calling.type = 4; /* caller ID is of type 'subscriber' */ + } // otherwise unknown and no number + mncc->fields |= MNCC_F_CALLED; + strncpy(mncc->called.number, dialing, sizeof(mncc->called.number) - 1); + mncc->called.type = 0; /* dialing is of type 'unknown' */ + mncc->lchan_type = GSM_LCHAN_TCH_F; + mncc->fields |= MNCC_F_BEARER_CAP; + mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ; + mncc->bearer_cap.speech_ver[1] = -1; + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC setup towards fixed network\n"); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); + return rc; +} +int call_up_setup(int callref, const char *callerid, const char *dialing) +{ + int rc; + if (!callref) { PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring setup, because callref not set. (not for us)\n"); return -CAUSE_INVALCALLREF; @@ -787,63 +401,31 @@ int call_in_setup(int callref, const char *callerid, const char *dialing) if (!strcmp(dialing, "010")) PDEBUG(DCALL, DEBUG_INFO, " -> Call to Operator '%s'\n", dialing); - if (call.use_mncc_sock) { - uint8_t buf[sizeof(struct gsm_mncc)]; - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - int rc; - memset(buf, 0, sizeof(buf)); - mncc->msg_type = MNCC_SETUP_IND; - mncc->callref = callref; - mncc->fields |= MNCC_F_CALLING; - if (callerid) { - strncpy(mncc->calling.number, callerid, sizeof(mncc->calling.number) - 1); - mncc->calling.type = 4; /* caller ID is of type 'subscriber' */ - } // otherwise unknown and no number - mncc->fields |= MNCC_F_CALLED; - strncpy(mncc->called.number, dialing, sizeof(mncc->called.number) - 1); - mncc->called.type = 0; /* dialing is of type 'unknown' */ - mncc->lchan_type = GSM_LCHAN_TCH_F; - mncc->fields |= MNCC_F_BEARER_CAP; - mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ; - mncc->bearer_cap.speech_ver[1] = -1; + create_process(callref, PROCESS_SETUP_RO); - PDEBUG(DMNCC, DEBUG_INFO, "Sending MNCC call towards Network\n"); + rc = _indicate_setup(callref, callerid, dialing); - create_process(callref, CALL_SETUP_MO); - - rc = mncc_write(buf, sizeof(struct gsm_mncc)); - if (rc < 0) { - PDEBUG(DCALL, DEBUG_NOTICE, "We have no MNCC connection, rejecting.\n"); - destroy_process(callref); - return -CAUSE_TEMPFAIL; - } - return 0; - } - - /* setup is also allowed on disconnected call */ - if (call.state == CALL_DISCONNECTED) - call_new_state(CALL_IDLE); - if (call.state != CALL_IDLE) { - PDEBUG(DCALL, DEBUG_NOTICE, "We are busy, rejecting.\n"); - return -CAUSE_BUSY; - } - call.callref = callref; - if (callerid) { - strncpy(call.station_id, callerid, call.dial_digits); - call.station_id[call.dial_digits] = '\0'; - } - strncpy(call.dialing, dialing, sizeof(call.dialing) - 1); - call.dialing[sizeof(call.dialing) - 1] = '\0'; - call_new_state(CALL_CONNECT); - PDEBUG(DCALL, DEBUG_INFO, "Call automatically answered\n"); - call_out_answer(callref); - - return 0; + return rc; } /* Transceiver indicates alerting. */ -void call_in_alerting(int callref) +static void _indicate_alerting(int callref) +{ + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + int rc; + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = MNCC_ALERT_IND; + mncc->callref = callref; + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC alerting towards fixed network\n"); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); +} +void call_up_alerting(int callref) { if (!callref) { PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring alerting, because callref not set. (not for us)\n"); @@ -852,27 +434,10 @@ void call_in_alerting(int callref) PDEBUG(DCALL, DEBUG_INFO, "Call is alerting\n"); - if (call.use_mncc_sock) { - uint8_t buf[sizeof(struct gsm_mncc)]; - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - - if (!call.send_patterns) { - memset(buf, 0, sizeof(buf)); - mncc->msg_type = MNCC_ALERT_IND; - mncc->callref = callref; - PDEBUG(DMNCC, DEBUG_INFO, "Indicate MNCC alerting towards Network\n"); - mncc_write(buf, sizeof(struct gsm_mncc)); - } else - set_pattern_process(callref, PATTERN_RINGBACK); - return; - } - - if (call.callref != callref) { - PDEBUG(DCALL, DEBUG_ERROR, "invalid call ref.\n"); - call_out_release(callref, CAUSE_INVALCALLREF); - return; - } - call_new_state(CALL_ALERTING); + if (!send_patterns) + _indicate_alerting(callref); + set_pattern_process(callref, PATTERN_RINGBACK); + new_state_process(callref, PROCESS_ALERTING_RT); } /* Transceiver indicates answer. */ @@ -880,6 +445,7 @@ static void _indicate_answer(int callref, const char *connect_id) { uint8_t buf[sizeof(struct gsm_mncc)]; struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + int rc; memset(buf, 0, sizeof(buf)); mncc->msg_type = MNCC_SETUP_CNF; @@ -892,11 +458,12 @@ static void _indicate_answer(int callref, const char *connect_id) mncc->connected.present = 0; mncc->connected.screen = 3; - - PDEBUG(DMNCC, DEBUG_INFO, "Indicate MNCC answer towards Network\n"); - mncc_write(buf, sizeof(struct gsm_mncc)); + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC answer towards fixed network\n"); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); } -void call_in_answer(int callref, const char *connect_id) +void call_up_answer(int callref, const char *connect_id) { if (!callref) { PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring answer, because callref not set. (not for us)\n"); @@ -905,26 +472,35 @@ void call_in_answer(int callref, const char *connect_id) PDEBUG(DCALL, DEBUG_INFO, "Call has been answered by '%s'\n", connect_id); - if (call.use_mncc_sock) { + if (!send_patterns) _indicate_answer(callref, connect_id); - set_pattern_process(callref, PATTERN_NONE); - set_state_process(callref, CALL_CONNECT); - return; - } - - if (call.callref != callref) { - PDEBUG(DCALL, DEBUG_ERROR, "invalid call ref.\n"); - call_out_release(callref, CAUSE_INVALCALLREF); - return; - } - call_new_state(CALL_CONNECT); - strncpy(call.station_id, connect_id, call.dial_digits); - call.station_id[call.dial_digits] = '\0'; + set_pattern_process(callref, PATTERN_NONE); + new_state_process(callref, PROCESS_CONNECT); } /* Transceiver indicates release. */ -void call_in_release(int callref, int cause) +static void _indicate_disconnect_release(int callref, int cause, int disc) { + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + int rc; + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = (disc) ? MNCC_DISC_IND : MNCC_REL_IND; + mncc->callref = callref; + mncc->fields |= MNCC_F_CAUSE; + mncc->cause.location = LOCATION_PRIVATE_LOCAL; + mncc->cause.value = cause; + + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC %s towards fixed network\n", (disc) ? "disconnect" : "release"); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); +} +void call_up_release(int callref, int cause) +{ + process_t *process; + if (!callref) { PDEBUG(DCALL, DEBUG_DEBUG, "Ignoring release, because callref not set. (not for us)\n"); return; @@ -932,99 +508,69 @@ void call_in_release(int callref, int cause) PDEBUG(DCALL, DEBUG_INFO, "Call has been released with cause=%d\n", cause); - if (call.use_mncc_sock) { - uint8_t buf[sizeof(struct gsm_mncc)]; - struct gsm_mncc *mncc = (struct gsm_mncc *)buf; - - memset(buf, 0, sizeof(buf)); - mncc->msg_type = MNCC_REL_IND; - mncc->callref = callref; - mncc->fields |= MNCC_F_CAUSE; - mncc->cause.location = 1; /* private local */ - mncc->cause.value = cause; - - if (is_process(callref)) { - if (!call.send_patterns - || is_process_state(callref) == CALL_DISCONNECTED - || is_process_state(callref) == CALL_SETUP_MO) { - PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network\n"); - destroy_process(callref); - mncc_write(buf, sizeof(struct gsm_mncc)); - } else { - disconnect_process(callref, cause); - } + process = get_process(callref); + if (process) { + /* just keep MNCC connection it tones shall be sent. + * no tones while setting up / alerting the call. */ + if (send_patterns && !process->state == PROCESS_SETUP_RO && !process->state == PROCESS_ALERTING_RO) + disconnect_process(callref, cause); + else + if (process->state == PROCESS_DISCONNECT + || process->state == PROCESS_SETUP_RO + || process->state == PROCESS_ALERTING_RO) { + destroy_process(callref); + _indicate_disconnect_release(callref, cause, 0); } else { - PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network\n"); - mncc_write(buf, sizeof(struct gsm_mncc)); + disconnect_process(callref, cause); + _indicate_disconnect_release(callref, cause, 1); } - return; + } else { + /* we don't know about the process, just send release to upper layer anyway */ + _indicate_disconnect_release(callref, cause, 0); } - - if (call.callref != callref) { - PDEBUG(DCALL, DEBUG_ERROR, "invalid call ref.\n"); - /* don't send release, because caller already released */ - return; - } - call_new_state(CALL_DISCONNECTED); - call.callref = 0; - call.disc_cause = cause; } /* turn recall tone on or off */ void call_tone_recall(int callref, int on) { - /* can do that only with MNCC socket */ - if (call.use_mncc_sock) - set_pattern_process(callref, (on) ? PATTERN_RECALL : PATTERN_NONE); + set_pattern_process(callref, (on) ? PATTERN_RECALL : PATTERN_NONE); } /* forward audio to MNCC or call instance */ -void call_tx_audio(int callref, sample_t *samples, int count) +void call_up_audio(int callref, sample_t *samples, int count) { + if (count != 160) { + fprintf(stderr, "Samples must be 160, please fix!\n"); + abort(); + } + /* is MNCC us used, forward audio */ + uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)]; + struct gsm_data_frame *data = (struct gsm_data_frame *)buf; + process_t *process; + if (!callref) return; - /* is MNCC us used, forward audio */ - if (call.use_mncc_sock) { - uint8_t buf[sizeof(struct gsm_data_frame) + count * sizeof(int16_t)]; - struct gsm_data_frame *data = (struct gsm_data_frame *)buf; + /* if we are disconnected, ignore audio */ + process = get_process(callref); + if (!process || process->pattern != PATTERN_NONE) + return; - /* if we are disconnected, ignore audio */ - if (is_process_pattern(callref)) - return; - - /* forward audio */ - data->msg_type = ANALOG_8000HZ; - data->callref = callref; + /* forward audio */ + data->msg_type = ANALOG_8000HZ; + data->callref = callref; #ifdef DEBUG_LEVEL - double lev = level_of(samples, count); - printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev))); + double lev = level_of(samples, count); + printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev))); #endif - samples_to_int16((int16_t *)data->data, samples, count); + samples_to_int16((int16_t *)data->data, samples, count); - mncc_write(buf, sizeof(buf)); - } else - /* else, save audio from transceiver to jitter buffer */ - if (call.sound) { - sample_t up[(int)((double)count * call.srstate.factor + 0.5) + 10]; - count = samplerate_upsample(&call.srstate, samples, count, up); - jitter_save(&call.dejitter, up, count); - } else - /* else, if echo test is used, send echo back to mobile */ - if (call.echo_test) { - call_rx_audio(callref, samples, count); - } else - /* else, if no sound is used, send test tone to mobile */ - if (call.state == CALL_CONNECT) { - int16_t spl[count]; - get_test_patterns(spl, count); - int16_to_samples(samples, spl, count); - call_rx_audio(callref, samples, count); - } + mncc_up(buf, sizeof(buf)); + /* don't destroy process here in case of an error */ } /* clock that is used to transmit patterns */ -void call_mncc_clock(void) +void call_clock(void) { process_t *process = process_head; uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)]; @@ -1043,14 +589,15 @@ void call_mncc_clock(void) printf(" mobil-level: %s%.4f\n", debug_db(lev), (20 * log10(lev))); samples_to_int16((int16_t *)data->data, samples, 160); #endif - mncc_write(buf, sizeof(buf)); + mncc_up(buf, sizeof(buf)); + /* don't destroy process here in case of an error */ } process = process->next; } } -/* mncc messages received from network */ -void call_mncc_recv(uint8_t *buf, int length) +/* mncc messages received from fixed network */ +void mncc_down(uint8_t *buf, int length) { struct gsm_mncc *mncc = (struct gsm_mncc *)buf; char number[sizeof(mncc->called.number)]; @@ -1058,41 +605,53 @@ void call_mncc_recv(uint8_t *buf, int length) enum number_type caller_type; int callref; int rc; + process_t *process; + + callref = mncc->callref; + process = get_process(callref); + if (!process) { + if (mncc->msg_type == MNCC_SETUP_REQ) + process = create_process(callref, PROCESS_SETUP_RT); + else { + if (mncc->msg_type != MNCC_REL_REQ) + PDEBUG(DCALL, DEBUG_ERROR, "No process!\n"); + return; + } + } if (mncc->msg_type == ANALOG_8000HZ) { struct gsm_data_frame *data = (struct gsm_data_frame *)buf; - int count = (length - sizeof(struct gsm_data_frame)) / 2; - sample_t samples[count]; + sample_t samples[160]; /* if we are disconnected, ignore audio */ - if (is_process_pattern(data->callref)) + if (process->pattern != PATTERN_NONE) return; - int16_to_samples(samples, (int16_t *)data->data, count); + int16_to_samples(samples, (int16_t *)data->data, 160); #ifdef DEBUG_LEVEL - double lev = level_of(samples, count); + double lev = level_of(samples, 160); printf("festnetz-level: %s %.4f\n", debug_db(lev), (20 * log10(lev))); #endif - call_rx_audio(data->callref, samples, count); + call_down_audio(callref, samples, 160); return; } - callref = mncc->callref; - - if (is_process_disconnected(callref)) { + if (process->audio_disconnected) { switch(mncc->msg_type) { case MNCC_DISC_REQ: - PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC disconnect from Network with cause %d\n", mncc->cause.value); + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value); PDEBUG(DCALL, DEBUG_INFO, "Call disconnected, releasing!\n"); destroy_process(callref); - PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network\n"); + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n"); mncc->msg_type = MNCC_REL_IND; - mncc_write(buf, sizeof(struct gsm_mncc)); + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); break; case MNCC_REL_REQ: - PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC release from Network with cause %d\n", mncc->cause.value); + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value); PDEBUG(DCALL, DEBUG_INFO, "Call released\n"); @@ -1127,14 +686,14 @@ void call_mncc_recv(uint8_t *buf, int length) if (mncc->calling.present == 1) caller_type = TYPE_ANONYMOUS; - PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC call from Network to '%s'\n", caller_id); + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC call from fixed network '%s' to mobile '%s'\n", caller_id, number); if (mncc->callref >= 0x4000000) { - fprintf(stderr, "Invalid callref from network, please fix!\n"); + fprintf(stderr, "Invalid callref from fixed network, please fix!\n"); abort(); } - PDEBUG(DMNCC, DEBUG_INFO, "Confirming MNCC call to Network\n"); + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC call confirm towards fixed network\n"); memset(buf, 0, length); mncc->msg_type = MNCC_CALL_CONF_IND; mncc->callref = callref; @@ -1143,77 +702,82 @@ void call_mncc_recv(uint8_t *buf, int length) mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ; mncc->bearer_cap.speech_ver[1] = -1; - mncc_write(buf, sizeof(struct gsm_mncc)); + mncc_up(buf, sizeof(struct gsm_mncc)); PDEBUG(DCALL, DEBUG_INFO, "Outgoing call from '%s' to '%s'\n", caller_id, number); - create_process(callref, CALL_SETUP_MT); - - rc = call_out_setup(callref, caller_id, caller_type, number); + rc = call_down_setup(callref, caller_id, caller_type, number); if (rc < 0) { PDEBUG(DCALL, DEBUG_NOTICE, "Call rejected, cause %d\n", -rc); - if (call.send_patterns) { + if (send_patterns) { PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n"); _indicate_answer(callref, number); - disconnect_process(callref, -rc); - break; + } else { + PDEBUG(DCALL, DEBUG_INFO, "Disconnecting MNCC call towards fixed network (cause=%d)\n", -rc); + _indicate_disconnect_release(callref, -rc, 1); } - PDEBUG(DMNCC, DEBUG_INFO, "Rejecting MNCC call towards Network (cause=%d)\n", -rc); - memset(buf, 0, length); - mncc->msg_type = MNCC_REL_IND; - mncc->callref = callref; - mncc->fields |= MNCC_F_CAUSE; - mncc->cause.location = 1; /* private local */ - mncc->cause.value = -rc; - mncc_write(buf, sizeof(struct gsm_mncc)); - destroy_process(callref); + disconnect_process(callref, -rc); break; } - if (call.send_patterns) { + if (send_patterns) { PDEBUG(DCALL, DEBUG_DEBUG, "Early connecting after setup\n"); _indicate_answer(callref, number); break; } break; + case MNCC_ALERT_REQ: + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC alerting from fixed network\n"); + new_state_process(callref, PROCESS_ALERTING_RO); + break; case MNCC_SETUP_RSP: - PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC answer from Network\n"); - set_state_process(callref, CALL_CONNECT); + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC answer from fixed network\n"); + new_state_process(callref, PROCESS_CONNECT); PDEBUG(DCALL, DEBUG_INFO, "Call answered\n"); - call_out_answer(callref); + call_down_answer(callref); + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC setup complete towards fixed network\n"); + memset(buf, 0, length); + mncc->msg_type = MNCC_SETUP_COMPL_IND; + mncc->callref = callref; + rc = mncc_up(buf, sizeof(struct gsm_mncc)); + if (rc < 0) + destroy_process(callref); break; case MNCC_DISC_REQ: - PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC disconnect from Network with cause %d\n", mncc->cause.value); + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC disconnect from fixed network with cause %d\n", mncc->cause.value); - if (is_process_state(callref) == CALL_CONNECT && call.release_on_disconnect) { + process = get_process(callref); + if (process && process->state == PROCESS_CONNECT && release_on_disconnect) { PDEBUG(DCALL, DEBUG_INFO, "Releasing, because we don't send disconnect tones to mobile phone\n"); - PDEBUG(DMNCC, DEBUG_INFO, "Releasing MNCC call towards Network\n"); + PDEBUG(DCALL, DEBUG_INFO, "Indicate MNCC release towards fixed network\n"); mncc->msg_type = MNCC_REL_IND; - mncc_write(buf, sizeof(struct gsm_mncc)); + mncc_up(buf, sizeof(struct gsm_mncc)); goto release; } - set_state_process(callref, CALL_DISCONNECTED); + new_state_process(callref, PROCESS_DISCONNECT); PDEBUG(DCALL, DEBUG_INFO, "Call disconnected\n"); - call_out_disconnect(callref, mncc->cause.value); + call_down_disconnect(callref, mncc->cause.value); break; case MNCC_REL_REQ: - PDEBUG(DMNCC, DEBUG_INFO, "Received MNCC release from Network with cause %d\n", mncc->cause.value); + PDEBUG(DCALL, DEBUG_INFO, "Received MNCC release from fixed network with cause %d\n", mncc->cause.value); release: destroy_process(callref); PDEBUG(DCALL, DEBUG_INFO, "Call released\n"); - call_out_release(callref, mncc->cause.value); + call_down_release(callref, mncc->cause.value); break; } } +int (*mncc_up)(uint8_t *buf, int length) = NULL; + /* break down of MNCC socket */ -void call_mncc_flush(void) +void mncc_flush(void) { while(process_head) { - PDEBUG(DMNCC, DEBUG_NOTICE, "MNCC socket closed, releasing call\n"); - call_out_release(process_head->callref, CAUSE_TEMPFAIL); + PDEBUG(DCALL, DEBUG_NOTICE, "MNCC socket closed, releasing call\n"); + call_down_release(process_head->callref, CAUSE_TEMPFAIL); destroy_process(process_head->callref); /* note: callref is released by sender's instance */ } diff --git a/src/common/call.h b/src/common/call.h index e9462d6..7273a1e 100644 --- a/src/common/call.h +++ b/src/common/call.h @@ -9,34 +9,32 @@ enum number_type { TYPE_INTERNATIONAL, }; -int call_init(const char *station_id, const char *audiodev, int samplerate, int latency, int dial_digits, int loopback, int use_mncc_sock, int send_patterns, int release_on_disconnect, int echo_test); -void call_cleanup(void); -int call_open_audio(int latspl); -int call_start_audio(void); -void process_call(int c); -void clear_console_text(void); -void print_console_text(void); +int call_init(int _send_patterns, int _release_on_disconnect); + +/* function pointer to delive MNCC messages to upper layer */ +extern int (*mncc_up)(uint8_t *buf, int length); +/* MNCC messages from upper layer */ +void mncc_down(uint8_t *buf, int length); +/* flush all calls in case of MNCC socket failure */ +void mncc_flush(void); /* received messages */ -int call_in_setup(int callref, const char *callerid, const char *dialing); -void call_in_alerting(int callref); -void call_in_answer(int callref, const char *connect_id); -void call_in_release(int callref, int cause); +int call_up_setup(int callref, const char *callerid, const char *dialing); +void call_up_alerting(int callref); +void call_up_answer(int callref, const char *connect_id); +void call_up_release(int callref, int cause); void call_tone_recall(int callref, int on); /* send messages */ -int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing); -void call_out_answer(int callref); -void call_out_disconnect(int callref, int cause); -void call_out_release(int callref, int cause); +int call_down_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing); +void call_down_answer(int callref); +void call_down_disconnect(int callref, int cause); +void call_down_release(int callref, int cause); /* send and receive audio */ -void call_rx_audio(int callref, sample_t *samples, int count); -void call_tx_audio(int callref, sample_t *samples, int count); +void call_up_audio(int callref, sample_t *samples, int count); +void call_down_audio(int callref, sample_t *samples, int count); -/* receive from mncc */ -void call_mncc_recv(uint8_t *buf, int length); -void call_mncc_flush(void); /* clock to transmit to */ -void call_mncc_clock(void); +void call_clock(void); diff --git a/src/common/cause.h b/src/common/cause.h index a6333c6..d7781a1 100644 --- a/src/common/cause.h +++ b/src/common/cause.h @@ -7,6 +7,9 @@ #define CAUSE_TEMPFAIL 41 #define CAUSE_INVALCALLREF 81 +#define LOCATION_USER 0 +#define LOCATION_PRIVATE_LOCAL 1 + const char *cause_name(int cause); diff --git a/src/common/debug.c b/src/common/debug.c index d2eedb8..2bf48d1 100644 --- a/src/common/debug.c +++ b/src/common/debug.c @@ -27,7 +27,7 @@ #include "sample.h" #include "debug.h" #include "display.h" -#include "call.h" +#include "mncc_console.h" const char *debug_level[] = { "debug ", @@ -51,7 +51,7 @@ struct debug_cat { { "amps", "\033[1;34m" }, { "r2000", "\033[1;34m" }, { "frame", "\033[0;36m" }, - { "call", "\033[1;37m" }, + { "call", "\033[0;37m" }, { "mncc", "\033[1;32m" }, { "database", "\033[0;33m" }, { "transaction", "\033[0;32m" }, diff --git a/src/common/main_mobile.c b/src/common/main_mobile.c index f906d6d..bab9579 100644 --- a/src/common/main_mobile.c +++ b/src/common/main_mobile.c @@ -35,6 +35,7 @@ #include "sender.h" #include "timer.h" #include "call.h" +#include "mncc_console.h" #include "mncc_sock.h" #ifdef HAVE_SDR #include "sdr.h" @@ -425,6 +426,20 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), /* latency of send buffer in samples */ latspl = samplerate * latency / 1000; + /* check MNCC support */ + if (use_mncc_sock && call_audiodev[0]) { + fprintf(stderr, "You selected MNCC interface, but it cannot be used with call device (headset).\n"); + return; + } + if (use_mncc_sock && echo_test) { + fprintf(stderr, "You selected MNCC interface, but it cannot be used with echo test.\n"); + return; + } + if (echo_test && call_audiodev[0]) { + fprintf(stderr, "You selected call device (headset), but it cannot be used with echo test.\n"); + return; + } + /* init mncc */ if (use_mncc_sock) { char mncc_sock_name[64]; @@ -433,15 +448,17 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), mncc_sock_name[sizeof(mncc_sock_name) - 1] = '\0'; } else strcpy(mncc_sock_name, "/tmp/bsc_mncc"); - rc = mncc_init(mncc_sock_name); + rc = mncc_sock_init(mncc_sock_name); if (rc < 0) { fprintf(stderr, "Failed to setup MNCC socket. Quitting!\n"); return; } + } else { + console_init(station_id, call_audiodev, call_samplerate, latency, station_id_digits, loopback, echo_test); } - /* init call device */ - rc = call_init(station_id, call_audiodev, call_samplerate, latency, station_id_digits, loopback, use_mncc_sock, send_patterns, release_on_disconnect, echo_test); + /* init call control instance */ + rc = call_init((use_mncc_sock) ? send_patterns : 0, release_on_disconnect); if (rc < 0) { fprintf(stderr, "Failed to create call control instance. Quitting!\n"); return; @@ -456,7 +473,7 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), /* open audio */ if (sender_open_audio(latspl)) return; - if (call_open_audio(latspl)) + if (console_open_audio(latspl)) return; /* real time priority */ @@ -488,7 +505,7 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), /* start streaming */ if (sender_start_audio()) *quit = 1; - if (call_start_audio()) + if (console_start_audio()) *quit = 1; while(!(*quit)) { @@ -512,7 +529,7 @@ void main_mobile(int *quit, int latency, int interval, void (*myhandler)(void), if (now - last_time_call >= 0.020) { last_time_call += 0.020; /* call clock every 20ms */ - call_mncc_clock(); + call_clock(); } next_char: @@ -578,8 +595,11 @@ next_char: goto next_char; } - /* process audio of built-in call control */ - process_call(c); + /* process call control */ + if (use_mncc_sock) + mncc_sock_handle(); + else + process_console(c); if (myhandler) myhandler(); @@ -619,10 +639,11 @@ next_char: } /* cleanup call control */ - call_cleanup(); + if (!use_mncc_sock) + console_cleanup(); /* close mncc socket */ if (use_mncc_sock) - mncc_exit(); + mncc_sock_exit(); } diff --git a/src/common/mncc_console.c b/src/common/mncc_console.c new file mode 100644 index 0000000..1e65d04 --- /dev/null +++ b/src/common/mncc_console.c @@ -0,0 +1,473 @@ +/* built-in console to talk to a phone + * + * (C) 2017 by Andreas Eversberg + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + G* along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sample.h" +#include "samplerate.h" +#include "jitter.h" +#include "debug.h" +#include "testton.h" +#include "mncc.h" +#include "call.h" +#include "cause.h" +#include "mncc_console.h" +#include "sound.h" + +static int new_callref = 0; /* toward mobile */ + +enum console_state { + CONSOLE_IDLE = 0, /* IDLE */ + CONSOLE_SETUP_RO, /* call from radio to console */ + CONSOLE_SETUP_RT, /* call from console to radio */ + CONSOLE_ALERTING_RO, /* call from radio to console */ + CONSOLE_ALERTING_RT, /* call from console to radio */ + CONSOLE_CONNECT, + CONSOLE_DISCONNECT, +}; + +static const char *console_state_name[] = { + "IDLE", + "SETUP_RO", + "SETUP_RT", + "ALERTING_RO", + "ALERTING_RT", + "CONNECT", + "DISCONNECT", +}; + +/* console call instance */ +typedef struct console { + uint32_t callref; + enum console_state state; + int disc_cause; /* cause that has been sent by transceiver instance for release */ + char station_id[16]; + char dialing[16]; + char audiodev[64]; /* headphone interface, if used */ + int samplerate; /* sample rate of headphone interface */ + void *sound; /* headphone interface */ + int latspl; /* sample latency at headphone interface */ + samplerate_t srstate; /* patterns/announcement upsampling */ + jitter_t dejitter; /* headphone audio dejittering */ + int test_audio_pos; /* position for test tone toward mobile */ + sample_t tx_buffer[160];/* transmit audio buffer */ + int tx_buffer_pos; /* current position in transmit audio buffer */ + int dial_digits; /* number of digits to be dialed */ + int loopback; /* loopback test for echo */ + int echo_test; /* send echo back to mobile phone */ +} console_t; + +static console_t console; + +/* stream test music */ +int16_t *test_spl = NULL; +int test_size = 0; +int test_max = 0; + +static void get_test_patterns(int16_t *samples, int length) +{ + const int16_t *spl; + int size, max, pos; + + spl = test_spl; + size = test_size; + max = test_max; + + /* stream sample */ + pos = console.test_audio_pos; + while(length--) { + if (pos >= size) + *samples++ = 0; + else + *samples++ = spl[pos] >> 2; + if (++pos == max) + pos = 0; + } + console.test_audio_pos = pos; +} + +static void console_new_state(enum console_state state) +{ + PDEBUG(DMNCC, DEBUG_DEBUG, "Call state '%s' -> '%s'\n", console_state_name[console.state], console_state_name[state]); + console.state = state; + console.test_audio_pos = 0; +} + +static int console_mncc_up(uint8_t *buf, int length) +{ + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + + if (mncc->msg_type == ANALOG_8000HZ) { + struct gsm_data_frame *data = (struct gsm_data_frame *)buf; + int count = 160; + sample_t samples[count]; + + /* save audio from transceiver to jitter buffer */ + if (console.sound) { + sample_t up[(int)((double)count * console.srstate.factor + 0.5) + 10]; + int16_to_samples(samples, (int16_t *)data->data, count); + count = samplerate_upsample(&console.srstate, samples, count, up); + jitter_save(&console.dejitter, up, count); + return 0; + } + /* if echo test is used, send echo back to mobile */ + if (console.echo_test) { + /* send down reused MNCC */ + mncc_down(buf, length); + return 0; + } + /* if no sound is used, send test tone to mobile */ + if (console.state == CONSOLE_CONNECT) { + /* send down reused MNCC */ + get_test_patterns((int16_t *)data->data, count); + mncc_down(buf, length); + return 0; + } + return 0; + } + + if (mncc->msg_type != MNCC_SETUP_IND && console.callref != mncc->callref) { + PDEBUG(DMNCC, DEBUG_ERROR, "invalid call ref.\n"); + /* send down reused MNCC */ + mncc->msg_type = MNCC_REL_REQ; + mncc->fields |= MNCC_F_CAUSE; + mncc->cause.location = LOCATION_USER; + mncc->cause.value = CAUSE_INVALCALLREF; + mncc_down(buf, length); + return 0; + } + + switch(mncc->msg_type) { + case MNCC_SETUP_IND: + PDEBUG(DMNCC, DEBUG_INFO, "Incoming call from '%s'\n", mncc->calling.number); + /* setup is also allowed on disconnected call */ + if (console.state == CONSOLE_DISCONNECT) + console_new_state(CONSOLE_IDLE); + if (console.state != CONSOLE_IDLE) { + PDEBUG(DMNCC, DEBUG_NOTICE, "We are busy, rejecting.\n"); + return -CAUSE_BUSY; + } + console.callref = mncc->callref; + if (mncc->calling.number[0]) { + strncpy(console.station_id, mncc->calling.number, console.dial_digits); + console.station_id[console.dial_digits] = '\0'; + } + strncpy(console.dialing, mncc->called.number, sizeof(console.dialing) - 1); + console.dialing[sizeof(console.dialing) - 1] = '\0'; + console_new_state(CONSOLE_CONNECT); + PDEBUG(DMNCC, DEBUG_INFO, "Call automatically answered\n"); + /* send down reused MNCC */ + mncc->msg_type = MNCC_SETUP_RSP; + mncc_down(buf, length); + break; + case MNCC_ALERT_IND: + PDEBUG(DMNCC, DEBUG_INFO, "Call alerting\n"); + console_new_state(CONSOLE_ALERTING_RT); + break; + case MNCC_SETUP_CNF: + PDEBUG(DMNCC, DEBUG_INFO, "Call connected to '%s'\n", mncc->connected.number); + console_new_state(CONSOLE_CONNECT); + strncpy(console.station_id, mncc->connected.number, console.dial_digits); + console.station_id[console.dial_digits] = '\0'; + /* send down reused MNCC */ + mncc->msg_type = MNCC_SETUP_COMPL_REQ; + mncc_down(buf, length); + break; + case MNCC_DISC_IND: + PDEBUG(DMNCC, DEBUG_INFO, "Call disconnected (%s)\n", cause_name(mncc->cause.value)); + console_new_state(CONSOLE_DISCONNECT); + console.disc_cause = mncc->cause.value; + break; + case MNCC_REL_IND: + PDEBUG(DMNCC, DEBUG_INFO, "Call released (%s)\n", cause_name(mncc->cause.value)); + console_new_state(CONSOLE_IDLE); + console.callref = 0; + break; + } + return 0; +} + +int console_init(const char *station_id, const char *audiodev, int samplerate, int latency, int dial_digits, int loopback, int echo_test) +{ + int rc = 0; + + init_testton(); + + memset(&console, 0, sizeof(console)); + strncpy(console.station_id, station_id, sizeof(console.station_id) - 1); + strncpy(console.audiodev, audiodev, sizeof(console.audiodev) - 1); + console.samplerate = samplerate; + console.latspl = latency * samplerate / 1000; + console.dial_digits = dial_digits; + console.loopback = loopback; + console.echo_test = echo_test; + + mncc_up = console_mncc_up; + + if (!audiodev[0]) + return 0; + + rc = init_samplerate(&console.srstate, 8000.0, (double)samplerate, 3300.0); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to init sample rate conversion!\n"); + goto error; + } + + rc = jitter_create(&console.dejitter, samplerate / 5); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to create and init dejitter buffer!\n"); + goto error; + } + + return 0; + +error: + console_cleanup(); + return rc; +} + +int console_open_audio(int latspl) +{ + if (!console.audiodev[0]) + return 0; + + /* open sound device for call control */ + /* use factor 1.4 of speech level for complete range of sound card */ + console.sound = sound_open(console.audiodev, NULL, NULL, 1, 0.0, console.samplerate, latspl, 1.4, 4000.0); + if (!console.sound) { + PDEBUG(DSENDER, DEBUG_ERROR, "No sound device!\n"); + return -EIO; + } + + return 0; +} + +int console_start_audio(void) +{ + if (!console.audiodev[0]) + return 0; + + return sound_start(console.sound); +} + +void console_cleanup(void) +{ + /* close sound devoice */ + if (console.sound) + sound_close(console.sound); + + jitter_destroy(&console.dejitter); +} + +static char console_text[256]; +static char console_clear[256]; +static int console_len = 0; + +static void process_ui(int c) +{ + char text[256]; + int len; + + switch (console.state) { + case CONSOLE_IDLE: + if (c > 0) { + if (c >= '0' && c <= '9' && (int)strlen(console.station_id) < console.dial_digits) { + console.station_id[strlen(console.station_id) + 1] = '\0'; + console.station_id[strlen(console.station_id)] = c; + } + if ((c == 8 || c == 127) && strlen(console.station_id)) + console.station_id[strlen(console.station_id) - 1] = '\0'; +dial_after_hangup: + if (c == 'd' && (int)strlen(console.station_id) == console.dial_digits) { + int callref = ++new_callref; + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + + PDEBUG(DMNCC, DEBUG_INFO, "Outgoing call to '%s'\n", console.station_id); + console.dialing[0] = '\0'; + console_new_state(CONSOLE_SETUP_RT); + console.callref = callref; + memset(buf, 0, sizeof(buf)); + mncc->msg_type = MNCC_SETUP_REQ; + mncc->callref = callref; + mncc->fields |= MNCC_F_CALLED; + strncpy(mncc->called.number, console.station_id, sizeof(mncc->called.number) - 1); + mncc->called.type = 0; /* dialing is of type 'unknown' */ + mncc->lchan_type = GSM_LCHAN_TCH_F; + mncc->fields |= MNCC_F_BEARER_CAP; + mncc->bearer_cap.speech_ver[0] = BCAP_ANALOG_8000HZ; + mncc->bearer_cap.speech_ver[1] = -1; + mncc_down(buf, sizeof(struct gsm_mncc)); + } + } + if (console.dial_digits != (int)strlen(console.station_id)) + sprintf(text, "on-hook: %s%s (enter digits 0..9)\r", console.station_id, "..............." + 15 - console.dial_digits + strlen(console.station_id)); + else + sprintf(text, "on-hook: %s (press d=dial)\r", console.station_id); + break; + case CONSOLE_SETUP_RO: + case CONSOLE_SETUP_RT: + case CONSOLE_ALERTING_RO: + case CONSOLE_ALERTING_RT: + case CONSOLE_CONNECT: + case CONSOLE_DISCONNECT: + if (c > 0) { + if (c == 'h' || (c == 'd' && console.state == CONSOLE_DISCONNECT)) { + PDEBUG(DMNCC, DEBUG_INFO, "Call hangup\n"); + console_new_state(CONSOLE_IDLE); + if (console.callref) { + uint8_t buf[sizeof(struct gsm_mncc)]; + struct gsm_mncc *mncc = (struct gsm_mncc *)buf; + + memset(buf, 0, sizeof(buf)); + mncc->msg_type = MNCC_REL_REQ; + mncc->callref = console.callref; + mncc->fields |= MNCC_F_CAUSE; + mncc->cause.location = LOCATION_USER; + mncc->cause.value = CAUSE_NORMAL; + mncc_down(buf, sizeof(struct gsm_mncc)); + console.callref = 0; + } + if (c == 'd') + goto dial_after_hangup; + } + } + if (console.state == CONSOLE_SETUP_RT) + sprintf(text, "call setup: %s (press h=hangup)\r", console.station_id); + if (console.state == CONSOLE_ALERTING_RT) + sprintf(text, "call ringing: %s (press h=hangup)\r", console.station_id); + if (console.state == CONSOLE_CONNECT) { + if (console.dialing[0]) + sprintf(text, "call active: %s->%s (press h=hangup)\r", console.station_id, console.dialing); + else + sprintf(text, "call active: %s (press h=hangup)\r", console.station_id); + } + if (console.state == CONSOLE_DISCONNECT) + sprintf(text, "call disconnected: %s (press h=hangup d=redial)\r", cause_name(console.disc_cause)); + break; + } + /* skip if nothing has changed */ + len = strlen(text); + if (console_len == len && !memcmp(console_text, text, len)) + return; + clear_console_text(); + console_len = len; + memcpy(console_text, text, len); + memset(console_clear, ' ', len - 1); + console_clear[len - 1] = '\r'; + print_console_text(); + fflush(stdout); +} + +void clear_console_text(void) +{ + if (!console_len) + return; + + fwrite(console_clear, console_len, 1, stdout); + // note: fflused by user of this function + console_len = 0; +} + +void print_console_text(void) +{ + if (!console_len) + return; + + printf("\033[1;37m"); + fwrite(console_text, console_len, 1, stdout); + printf("\033[0;39m"); +} + +/* get keys from keyboad to control call via console + * returns 1 on exit (ctrl+c) */ +void process_console(int c) +{ + if (!console.loopback) + process_ui(c); + + if (!console.sound) + return; + + /* handle audio, if sound device is used */ + sample_t samples[console.latspl + 10], *samples_list[1]; + uint8_t *power_list[1]; + double rf_level_db[1]; + int count; + int rc; + + count = sound_get_tosend(console.sound, console.latspl); + if (count < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to get samples in buffer (rc = %d)!\n", count); + if (count == -EPIPE) + PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); + return; + } + if (count > 0) { + jitter_load(&console.dejitter, samples, count); + samples_list[0] = samples; + power_list[0] = NULL; + rc = sound_write(console.sound, samples_list, power_list, count, NULL, NULL, 1); + if (rc < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to write TX data to sound device (rc = %d)\n", rc); + if (rc == -EPIPE) + PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); + return; + } + } + samples_list[0] = samples; + count = sound_read(console.sound, samples_list, console.latspl, 1, rf_level_db); + if (count < 0) { + PDEBUG(DSENDER, DEBUG_ERROR, "Failed to read from sound device (rc = %d)!\n", count); + if (count == -EPIPE) + PDEBUG(DSENDER, DEBUG_ERROR, "Trying to recover.\n"); + return; + } + if (count) { + int i; + + if (console.loopback == 3) + jitter_save(&console.dejitter, samples, count); + count = samplerate_downsample(&console.srstate, samples, count); + /* put samples into ring buffer */ + for (i = 0; i < count; i++) { + console.tx_buffer[console.tx_buffer_pos] = samples[i]; + /* if ring buffer wrapps, deliver data down to call process */ + if (++console.tx_buffer_pos == 160) { + console.tx_buffer_pos = 0; + /* only if we have a call */ + if (console.callref) { + uint8_t buf[sizeof(struct gsm_data_frame) + 160 * sizeof(int16_t)]; + struct gsm_data_frame *data = (struct gsm_data_frame *)buf; + + data->msg_type = ANALOG_8000HZ; + data->callref = console.callref; + samples_to_int16((int16_t *)data->data, console.tx_buffer, 160); + mncc_down(buf, sizeof(struct gsm_mncc)); + } + } + } + } +} + diff --git a/src/common/mncc_console.h b/src/common/mncc_console.h new file mode 100644 index 0000000..f61c8a4 --- /dev/null +++ b/src/common/mncc_console.h @@ -0,0 +1,10 @@ + +int console_init(const char *station_id, const char *audiodev, int samplerate, int latency, int dial_digits, int loopback, int echo_test); +void console_cleanup(void); +int console_open_audio(int latspl); +int console_start_audio(void); +void console_process(int c); +void clear_console_text(void); +void print_console_text(void); +void process_console(int c); + diff --git a/src/common/mncc_sock.c b/src/common/mncc_sock.c index 437dec1..4e97c52 100644 --- a/src/common/mncc_sock.c +++ b/src/common/mncc_sock.c @@ -29,33 +29,34 @@ #include "sample.h" #include "debug.h" #include "call.h" +#include "cause.h" #include "mncc_sock.h" static int listen_sock = -1; static int mncc_sock = -1; /* write to mncc socket, return error or -EIO if no socket connection */ -int mncc_write(uint8_t *buf, int length) +static int mncc_write(uint8_t *buf, int length) { int rc; if (mncc_sock <= 0) { - PDEBUG(DMNCC, DEBUG_NOTICE, "MNCC not connected.\n"); - return -EIO; + PDEBUG(DMNCC, DEBUG_NOTICE, "We have no MNCC connection, rejecting.\n"); + return -CAUSE_TEMPFAIL; } rc = send(mncc_sock, buf, length, 0); if (rc < 0) { PDEBUG(DMNCC, DEBUG_ERROR, "MNCC connection failed (errno = %d).\n", errno); mncc_sock_close(); - return 0; + return -CAUSE_TEMPFAIL; } if (rc != length) { PDEBUG(DMNCC, DEBUG_NOTICE, "MNCC write failed.\n"); mncc_sock_close(); - return 0; + return -CAUSE_TEMPFAIL; } - return rc; + return 0; } @@ -80,7 +81,7 @@ static int mncc_read(void) return -errno; } - call_mncc_recv(buf, rc); + mncc_down(buf, rc); return rc; } @@ -141,7 +142,7 @@ static int mncc_accept(void) return 1; } -void mncc_handle(void) +void mncc_sock_handle(void) { mncc_accept(); @@ -159,11 +160,11 @@ void mncc_sock_close(void) close(mncc_sock); mncc_sock = -1; /* clear all call instances */ - call_mncc_flush(); + mncc_flush(); } } -int mncc_init(const char *sock_name) +int mncc_sock_init(const char *sock_name) { struct sockaddr_un local; unsigned int namelen; @@ -197,14 +198,14 @@ int mncc_init(const char *sock_name) if (rc < 0) { PDEBUG(DMNCC, DEBUG_ERROR, "Failed to bind the unix domain " "socket. '%s'\n", local.sun_path); - mncc_exit(); + mncc_sock_exit(); return rc; } rc = listen(listen_sock, 0); if (rc < 0) { PDEBUG(DMNCC, DEBUG_ERROR, "Failed to listen.\n"); - mncc_exit(); + mncc_sock_exit(); return rc; } @@ -213,16 +214,18 @@ int mncc_init(const char *sock_name) rc = fcntl(listen_sock, F_SETFL, flags | O_NONBLOCK); if (rc < 0) { PDEBUG(DMNCC, DEBUG_ERROR, "Failed to set socket into non-blocking IO mode.\n"); - mncc_exit(); + mncc_sock_exit(); return rc; } + mncc_up = mncc_write; + PDEBUG(DMNCC, DEBUG_DEBUG, "MNCC socket at '%s' initialized, waiting for connection.\n", sock_name); return 0; } -void mncc_exit(void) +void mncc_sock_exit(void) { mncc_sock_close(); diff --git a/src/common/mncc_sock.h b/src/common/mncc_sock.h index 3f2ac4b..7406dbe 100644 --- a/src/common/mncc_sock.h +++ b/src/common/mncc_sock.h @@ -1,8 +1,7 @@ #include "mncc.h" -int mncc_write(uint8_t *buf, int length); -void mncc_handle(void); +void mncc_sock_handle(void); void mncc_sock_close(void); -int mncc_init(const char *sock_name); -void mncc_exit(void); +int mncc_sock_init(const char *sock_name); +void mncc_sock_exit(void); diff --git a/src/nmt/dsp.c b/src/nmt/dsp.c index 9ff6d67..9ce6ba8 100644 --- a/src/nmt/dsp.c +++ b/src/nmt/dsp.c @@ -349,7 +349,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at for (i = 0; i < count; i++) { spl[pos++] = samples[i]; if (pos == 160) { - call_tx_audio(nmt->trans->callref, spl, 160); + call_up_audio(nmt->trans->callref, spl, 160); pos = 0; } } diff --git a/src/nmt/nmt.c b/src/nmt/nmt.c index 73dcdc7..b0bc0c9 100644 --- a/src/nmt/nmt.c +++ b/src/nmt/nmt.c @@ -881,7 +881,7 @@ static void rx_mo_dialing(nmt_t *nmt, frame_t *frame) int callref = ++new_callref; int rc; PDEBUG(DNMT, DEBUG_INFO, "Setup call to network.\n"); - rc = call_in_setup(callref, &trans->subscriber.country, nmt->dialing); + rc = call_up_setup(callref, &trans->subscriber.country, nmt->dialing); if (rc < 0) { PDEBUG(DNMT, DEBUG_NOTICE, "Call rejected (cause %d), releasing.\n", rc); nmt_release(nmt); @@ -971,7 +971,7 @@ void timeout_mt_paging(transaction_t *trans) PDEBUG(DNMT, DEBUG_NOTICE, "No answer from mobile phone (try %d).\n", trans->page_try); if (trans->page_try == PAGE_TRIES) { PDEBUG(DNMT, DEBUG_INFO, "Release call towards network.\n"); - call_in_release(trans->callref, CAUSE_OUTOFORDER); + call_up_release(trans->callref, CAUSE_OUTOFORDER); destroy_transaction(trans); return; } @@ -1036,7 +1036,7 @@ static void tx_mt_ident(nmt_t *nmt, frame_t *frame) if (nmt->tx_frame_count == 8) { PDEBUG_CHAN(DNMT, DEBUG_NOTICE, "Timeout waiting for identity reply\n"); PDEBUG_CHAN(DNMT, DEBUG_INFO, "Release call towards network.\n"); - call_in_release(trans->callref, CAUSE_TEMPFAIL); + call_up_release(trans->callref, CAUSE_TEMPFAIL); destroy_transaction(trans); } } @@ -1066,7 +1066,7 @@ static void rx_mt_ident(nmt_t *nmt, frame_t *frame) nmt->tx_callerid_count = 0; } timer_start(&nmt->timer, RINGING_TO); - call_in_alerting(trans->callref); + call_up_alerting(trans->callref); } break; default: @@ -1092,7 +1092,7 @@ static void tx_mt_autoanswer(nmt_t *nmt, frame_t *frame) nmt->tx_frame_count = 0; nmt->tx_callerid_count = 0; timer_start(&nmt->timer, RINGING_TO); - call_in_alerting(trans->callref); + call_up_alerting(trans->callref); } } @@ -1121,7 +1121,7 @@ static void rx_mt_autoanswer(nmt_t *nmt, frame_t *frame) PDEBUG_CHAN(DNMT, DEBUG_INFO, "Received acknowledge to autoanswer.\n"); nmt_new_state(nmt, STATE_MT_COMPLETE); nmt->tx_frame_count = 0; - call_in_answer(trans->callref, &trans->subscriber.country); + call_up_answer(trans->callref, &trans->subscriber.country); break; default: PDEBUG_CHAN(DNMT, DEBUG_DEBUG, "Dropping message %s in state %s\n", nmt_frame_name(frame->mt), nmt_state_name(nmt->state)); @@ -1180,7 +1180,7 @@ static void rx_mt_ringing(nmt_t *nmt, frame_t *frame) nmt_new_state(nmt, STATE_MT_COMPLETE); nmt->tx_frame_count = 0; timer_stop(&nmt->timer); - call_in_answer(trans->callref, &trans->subscriber.country); + call_up_answer(trans->callref, &trans->subscriber.country); break; default: PDEBUG_CHAN(DNMT, DEBUG_DEBUG, "Dropping message %s in state %s\n", nmt_frame_name(frame->mt), nmt_state_name(nmt->state)); @@ -1220,7 +1220,7 @@ static void timeout_mt_ringing(nmt_t *nmt) PDEBUG_CHAN(DNMT, DEBUG_NOTICE, "Timeout while waiting for answer of the phone.\n"); PDEBUG(DNMT, DEBUG_INFO, "Release call towards network.\n"); - call_in_release(trans->callref, CAUSE_NOANSWER); + call_up_release(trans->callref, CAUSE_NOANSWER); trans->callref = 0; nmt_release(nmt); } @@ -1320,7 +1320,7 @@ static void timeout_active(nmt_t *nmt, double duration) else PDEBUG_CHAN(DNMT, DEBUG_NOTICE, "Timeout after %.0f seconds loosing supervisory signal.\n", duration); PDEBUG_CHAN(DNMT, DEBUG_INFO, "Release call towards network.\n"); - call_in_release(trans->callref, CAUSE_TEMPFAIL); + call_up_release(trans->callref, CAUSE_TEMPFAIL); trans->callref = 0; nmt_release(nmt); } @@ -1497,7 +1497,7 @@ void nmt_receive_frame(nmt_t *nmt, const char *bits, double quality, double leve nmt_set_dsp_mode(nmt, DSP_MODE_FRAME); if (nmt->trans->callref) { PDEBUG(DNMT, DEBUG_INFO, "Release call towards network.\n"); - call_in_release(nmt->trans->callref, CAUSE_NORMAL); + call_up_release(nmt->trans->callref, CAUSE_NORMAL); nmt->trans->callref = 0; } return; @@ -1719,7 +1719,7 @@ inval: return 0; } -int call_out_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing) +int call_down_setup(int callref, const char *caller_id, enum number_type caller_type, const char *dialing) { return _out_setup(callref, caller_id, caller_type, dialing, NULL); } @@ -1728,7 +1728,7 @@ int sms_out_setup(char *dialing, const char *caller_id, enum number_type caller_ return _out_setup(0, caller_id, caller_type, dialing, sms); } -void call_out_answer(int __attribute__((unused)) callref) +void call_down_answer(int __attribute__((unused)) callref) { } @@ -1736,7 +1736,7 @@ void call_out_answer(int __attribute__((unused)) callref) * An active call stays active, so tones and annoucements can be received * by mobile station. */ -void call_out_disconnect(int callref, int cause) +void call_down_disconnect(int callref, int cause) { transaction_t *trans; nmt_t *nmt; @@ -1746,13 +1746,13 @@ void call_out_disconnect(int callref, int cause) trans = get_transaction_by_callref(callref); if (!trans) { PDEBUG(DNMT, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n"); - call_in_release(callref, CAUSE_INVALCALLREF); + call_up_release(callref, CAUSE_INVALCALLREF); return; } nmt = trans->nmt; if (!nmt) { - call_in_release(callref, cause); + call_up_release(callref, cause); trans->callref = 0; destroy_transaction(trans); return; @@ -1774,11 +1774,11 @@ void call_out_disconnect(int callref, int cause) break; } - call_in_release(callref, cause); + call_up_release(callref, cause); } /* Call control releases call toward mobile station. */ -void call_out_release(int callref, int __attribute__((unused)) cause) +void call_down_release(int callref, int __attribute__((unused)) cause) { transaction_t *trans; nmt_t *nmt; @@ -1817,7 +1817,7 @@ void call_out_release(int callref, int __attribute__((unused)) cause) } /* Receive audio from call instance. */ -void call_rx_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, sample_t *samples, int count) { transaction_t *trans; nmt_t *nmt; diff --git a/src/r2000/dsp.c b/src/r2000/dsp.c index d689971..f34889e 100644 --- a/src/r2000/dsp.c +++ b/src/r2000/dsp.c @@ -282,7 +282,7 @@ void sender_receive(sender_t *sender, sample_t *samples, int length, double __at for (i = 0; i < count; i++) { spl[pos++] = samples[i]; if (pos == 160) { - call_tx_audio(r2000->callref, spl, 160); + call_up_audio(r2000->callref, spl, 160); pos = 0; } } diff --git a/src/r2000/r2000.c b/src/r2000/r2000.c index 7eda9f7..1271292 100644 --- a/src/r2000/r2000.c +++ b/src/r2000/r2000.c @@ -557,7 +557,7 @@ void r2000_go_idle(r2000_t *r2000) if (r2000->callref) { PDEBUG(DR2000, DEBUG_ERROR, "Going idle, but still having callref, please fix!\n"); - call_in_release(r2000->callref, CAUSE_NORMAL); + call_up_release(r2000->callref, CAUSE_NORMAL); r2000->callref = 0; } @@ -635,7 +635,7 @@ static r2000_t *move_call_to_chan(r2000_t *old_r2000, enum r2000_chan_type chan_ PDEBUG(DR2000, DEBUG_NOTICE, "Cannot move us to %s, because there is no free channel!\n", chan_type_long_name(chan_type)); if (old_r2000->callref) { PDEBUG(DR2000, DEBUG_NOTICE, "Failed to assign channel, releasing towards network\n"); - call_in_release(old_r2000->callref, CAUSE_NOCHANNEL); + call_up_release(old_r2000->callref, CAUSE_NOCHANNEL); old_r2000->callref = 0; } r2000_release(old_r2000); @@ -835,7 +835,7 @@ static void rx_ident(r2000_t *r2000, frame_t *frame) /* alert the phone */ r2000_new_state(r2000, STATE_IN_ALERT); timer_start(&r2000->timer, ALERT_TIME); - call_in_alerting(r2000->callref); + call_up_alerting(r2000->callref); break; case STATE_RECALL_IDENT: /* alert the phone */ @@ -884,7 +884,7 @@ static void timeout_in_ident(r2000_t *r2000) /* ... or release */ PDEBUG_CHAN(DR2000, DEBUG_NOTICE, "Phone does not response, releasing towards network\n"); - call_in_release(r2000->callref, CAUSE_OUTOFORDER); + call_up_release(r2000->callref, CAUSE_OUTOFORDER); r2000->callref = 0; r2000_release(r2000); } @@ -920,7 +920,7 @@ static int setup_call(r2000_t *r2000) /* make call toward network */ PDEBUG(DR2000, DEBUG_INFO, "Setup call to network.\n"); - rc = call_in_setup(callref, subscriber2string(&r2000->subscriber), r2000->subscriber.dialing); + rc = call_up_setup(callref, subscriber2string(&r2000->subscriber), r2000->subscriber.dialing); if (rc < 0) { PDEBUG(DR2000, DEBUG_NOTICE, "Call rejected (cause %d), releasing.\n", -rc); r2000_release(r2000); @@ -952,7 +952,7 @@ static void rx_alert(r2000_t *r2000, frame_t *frame) case STATE_IN_ALERT: /* answer incomming call */ PDEBUG(DR2000, DEBUG_INFO, "Answer call to network.\n"); - call_in_answer(r2000->callref, subscriber2string(&r2000->subscriber)); + call_up_answer(r2000->callref, subscriber2string(&r2000->subscriber)); break; case STATE_OUT_ALERT: /* setup call, possible r2000_release() is called there! */ @@ -983,7 +983,7 @@ static void timeout_alert(r2000_t *r2000) PDEBUG_CHAN(DR2000, DEBUG_NOTICE, "Phone does not response, releasing towards network\n"); if (r2000->callref) { - call_in_release(r2000->callref, CAUSE_NOANSWER); + call_up_release(r2000->callref, CAUSE_NOANSWER); r2000->callref = 0; } r2000_release(r2000); @@ -1150,7 +1150,7 @@ static void timeout_active(r2000_t *r2000) { PDEBUG_CHAN(DR2000, DEBUG_INFO, "Timeout after loosing supervisory signal, releasing call\n"); - call_in_release(r2000->callref, CAUSE_TEMPFAIL); + call_up_release(r2000->callref, CAUSE_TEMPFAIL); r2000->callref = 0; r2000_release(r2000); } @@ -1309,7 +1309,7 @@ void r2000_receive_frame(r2000_t *r2000, const char *bits, double quality, doubl PDEBUG_CHAN(DR2000, DEBUG_INFO, "Received release from station mobile\n"); if (r2000->callref) { - call_in_release(r2000->callref, CAUSE_NORMAL); + call_up_release(r2000->callref, CAUSE_NORMAL); r2000->callref = 0; } r2000_go_idle(r2000); @@ -1425,7 +1425,7 @@ static void r2000_timeout(struct timer *timer) */ /* Call control starts call towards station mobile. */ -int call_out_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) +int call_down_setup(int callref, const char __attribute__((unused)) *caller_id, enum number_type __attribute__((unused)) caller_type, const char *dialing) { sender_t *sender; r2000_t *r2000, *tc; @@ -1475,7 +1475,7 @@ int call_out_setup(int callref, const char __attribute__((unused)) *caller_id, e } /* Call control answers call toward station mobile. */ -void call_out_answer(int callref) +void call_down_answer(int callref) { sender_t *sender; r2000_t *r2000; @@ -1487,7 +1487,7 @@ void call_out_answer(int callref) } if (!sender) { PDEBUG(DR2000, DEBUG_NOTICE, "Outgoing answer, but no callref!\n"); - call_in_release(callref, CAUSE_INVALCALLREF); + call_up_release(callref, CAUSE_INVALCALLREF); return; } @@ -1506,7 +1506,7 @@ void call_out_answer(int callref) * An active call stays active, so tones and annoucements can be received * by station mobile. */ -void call_out_disconnect(int callref, int __attribute__((unused)) cause) +void call_down_disconnect(int callref, int __attribute__((unused)) cause) { sender_t *sender; r2000_t *r2000; @@ -1520,7 +1520,7 @@ void call_out_disconnect(int callref, int __attribute__((unused)) cause) } if (!sender) { PDEBUG(DR2000, DEBUG_NOTICE, "Outgoing disconnect, but no callref!\n"); - call_in_release(callref, CAUSE_INVALCALLREF); + call_up_release(callref, CAUSE_INVALCALLREF); return; } @@ -1535,11 +1535,11 @@ void call_out_disconnect(int callref, int __attribute__((unused)) cause) break; } - call_in_release(callref, cause); + call_up_release(callref, cause); } /* Call control releases call toward station mobile. */ -void call_out_release(int callref, int __attribute__((unused)) cause) +void call_down_release(int callref, int __attribute__((unused)) cause) { sender_t *sender; r2000_t *r2000; @@ -1572,7 +1572,7 @@ void call_out_release(int callref, int __attribute__((unused)) cause) } /* Receive audio from call instance. */ -void call_rx_audio(int callref, sample_t *samples, int count) +void call_down_audio(int callref, sample_t *samples, int count) { sender_t *sender; r2000_t *r2000; diff --git a/src/test/dummy.c b/src/test/dummy.c index 3cd55b5..5d08d6b 100644 --- a/src/test/dummy.c +++ b/src/test/dummy.c @@ -1,8 +1,8 @@ -void call_rx_audio() { } -void call_out_setup() { } -void call_out_release() { } -void call_out_disconnect() { } -void call_out_answer() { } +void call_down_audio() { } +void call_down_setup() { } +void call_down_release() { } +void call_down_disconnect() { } +void call_down_answer() { } void print_help() { } void sender_send() { } void sender_receive() { }