Split call control from built-in call console by using MNCC layer

pull/1/head
Andreas Eversberg 5 years ago
parent 7cbebaeb75
commit ee3fbeb03b
  1. 26
      src/amps/amps.c
  2. 2
      src/amps/dsp.c
  3. 2
      src/amps/transaction.c
  4. 26
      src/anetz/anetz.c
  5. 2
      src/anetz/dsp.c
  6. 28
      src/bnetz/bnetz.c
  7. 2
      src/bnetz/dsp.c
  8. 44
      src/cnetz/cnetz.c
  9. 2
      src/cnetz/dsp.c
  10. 2
      src/cnetz/transaction.c
  11. 1
      src/common/Makefile.am
  12. 942
      src/common/call.c
  13. 40
      src/common/call.h
  14. 3
      src/common/cause.h
  15. 4
      src/common/debug.c
  16. 41
      src/common/main_mobile.c
  17. 473
      src/common/mncc_console.c
  18. 10
      src/common/mncc_console.h
  19. 31
      src/common/mncc_sock.c
  20. 7
      src/common/mncc_sock.h
  21. 2
      src/nmt/dsp.c
  22. 36
      src/nmt/nmt.c
  23. 2
      src/r2000/dsp.c
  24. 34
      src/r2000/r2000.c
  25. 10
      src/test/dummy.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);

@ -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;
}
}

@ -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));

@ -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;

@ -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;
}
}

@ -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;

@ -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;
}
}

@ -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;

@ -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;
}
}

@ -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));

@ -27,6 +27,7 @@ libmobile_a_SOURCES = \
cause.c \
call.c \
testton.c \
mncc_console.c \
mncc_sock.c \
hagelbarger.c \
display_status.c \

File diff suppressed because it is too large Load Diff

@ -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);

@ -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);

@ -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" },

@ -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();
}

@ -0,0 +1,473 @@
/* built-in console to talk to a phone
*
* (C) 2017 by Andreas Eversberg <jolly@eversberg.eu>
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#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;
}