struct lcr_gsm *gsm_bs = NULL;
+#define PAYLOAD_TYPE_GSM 3
+
/*
* DTMF stuff
*/
PDEBUG(DEBUG_GSM, "Destroyed GSM BS process(%s).\n", p_name);
}
+/* PROCEEDING INDICATION (from MS) */
+void Pgsm_bs::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+ int media_types[8];
+ unsigned char payload_types[8];
+ int payloads = 0;
+
+ gsm_trace_header(p_g_interface_name, this, msg_type, DIRECTION_IN);
+ if (mncc->fields & MNCC_F_CAUSE) {
+ add_trace("cause", "coding", "%d", mncc->cause.coding);
+ add_trace("cause", "location", "%", mncc->cause.location);
+ add_trace("cause", "value", "%", mncc->cause.value);
+ }
+ end_trace();
+
+ new_state(PORT_STATE_OUT_PROCEEDING);
+
+ /* get list of offered payload types
+ * if list ist empty, the FR V1 is selected */
+ select_payload_type(mncc, payload_types, media_types, &payloads, sizeof(payload_types));
+ /* if no given payload type is supported, we assume */
+ if (!payloads) {
+ media_types[0] = MEDIA_TYPE_GSM;
+ payload_types[0] = PAYLOAD_TYPE_GSM;
+ payloads = 1;
+ }
+
+ /* select first payload type that matches the rtp list */
+ if (p_g_rtp_bridge) {
+ int i, j;
+
+ for (i = 0; i < p_g_rtp_payloads; i++) {
+ for (j = 0; j < payloads; j++) {
+ if (p_g_rtp_media_types[i] == media_types[j])
+ break;
+ }
+ if (j < payloads)
+ break;
+ }
+ if (i == p_g_rtp_payloads) {
+ struct lcr_msg *message;
+
+ /* payload offered by remote RTP is not supported */
+ message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = 65;
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+ /* send release */
+ mncc = create_mncc(MNCC_REL_REQ, p_g_callref);
+ gsm_trace_header(p_g_interface_name, this, MNCC_REL_REQ, DIRECTION_OUT);
+ mncc->fields |= MNCC_F_CAUSE;
+ mncc->cause.coding = 3;
+ mncc->cause.location = LOCATION_PRIVATE_LOCAL;
+ mncc->cause.value = 65;
+ add_trace("cause", "coding", "%d", mncc->cause.coding);
+ add_trace("cause", "location", "%d", mncc->cause.location);
+ add_trace("cause", "value", "%d", mncc->cause.value);
+ add_trace("reason", NULL, "None of the payload types are supported by MS");
+ end_trace();
+ send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
+ new_state(PORT_STATE_RELEASE);
+ trigger_work(&p_g_delete);
+
+ return;
+ }
+ modify_lchan(p_g_rtp_media_types[i]);
+ /* use the payload type from received rtp list, not from locally generated payload types */
+ p_g_payload_type = p_g_rtp_payload_types[i];
+ } else {
+ /* modify to first given payload */
+ modify_lchan(media_types[0]);
+ p_g_payload_type = payload_types[0];
+ }
+}
+
/* DTMF INDICATION */
void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
{
}
/*
+ * select payload type by given list or GSM V1 FR
+ * return the payload type or 0 if not given
+ */
+
+void Pgsm_bs::select_payload_type(struct gsm_mncc *mncc, unsigned char *payload_types, int *media_types, int *payloads, int max_payloads)
+{
+ int media_type;
+ unsigned char payload_type;
+
+ *payloads = 0;
+
+ gsm_trace_header(p_g_interface_name, this, 1 /* codec negotioation */, DIRECTION_NONE);
+ if ((mncc->fields & MNCC_F_BEARER_CAP)) {
+ /* select preferred payload type from list */
+ int i;
+ uint8_t dynamic_type = 96;
+
+ add_trace("bearer", "capa", "given by MS");
+ for (i = 0; mncc->bearer_cap.speech_ver[i] >= 0; i++) {
+ /* select payload type we support */
+ switch (mncc->bearer_cap.speech_ver[i]) {
+ case 0:
+ add_trace("speech", "version", "Full Rate given");
+ media_type = MEDIA_TYPE_GSM;
+ payload_type = PAYLOAD_TYPE_GSM;
+ break;
+ case 2:
+ add_trace("speech", "version", "EFR given");
+ media_type = MEDIA_TYPE_GSM_EFR;
+ payload_type = dynamic_type++;
+ break;
+ case 4:
+ add_trace("speech", "version", "AMR given");
+ media_type = MEDIA_TYPE_AMR;
+ payload_type = dynamic_type++;
+ break;
+ case 1:
+ add_trace("speech", "version", "Half Rate given");
+ media_type = MEDIA_TYPE_GSM_HR;
+ payload_type = dynamic_type++;
+ break;
+ default:
+ add_trace("speech", "version", "%d given", mncc->bearer_cap.speech_ver[i]);
+ media_type = 0;
+ payload_type = 0;
+ }
+ /* wen don't support it, so we check the next */
+ if (!media_type) {
+ add_trace("speech", "ignored", "Not supported by LCR");
+ continue;
+ }
+ if (!p_g_rtp_bridge) {
+ if (media_type != MEDIA_TYPE_GSM) {
+ add_trace("speech", "ignored", "Not suitable for LCR");
+ continue;
+ }
+ }
+ if (*payloads <= max_payloads) {
+ media_types[*payloads] = media_type;
+ payload_types[*payloads] = payload_type;
+ (*payloads)++;
+ }
+ }
+ } else {
+ add_trace("bearer", "capa", "not given by MS");
+ add_trace("speech", "version", "Full Rate given");
+ media_types[0] = MEDIA_TYPE_GSM;
+ payload_types[0] = PAYLOAD_TYPE_GSM;
+ *payloads = 1;
+ }
+ if (!(*payloads))
+ add_trace("error", "", "All given payload types unsupported");
+ end_trace();
+}
+
+/*
* handles all indications
*/
/* SETUP INDICATION */
{
class Endpoint *epoint;
struct lcr_msg *message;
- struct gsm_mncc *mode, *proceeding, *frame;
+ struct gsm_mncc *proceeding, *frame;
struct interface *interface;
+ int media_types[8];
+ unsigned char payload_types[8];
+ int payloads = 0;
interface = getinterfacebyname(p_g_interface_name);
if (!interface) {
p_dialinginfo.sending_complete = 1;
/* bearer capability */
- // todo
p_capainfo.bearer_capa = INFO_BC_SPEECH;
p_capainfo.bearer_info1 = (options.law=='a')?3:2;
p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
p_capainfo.source_mode = B_MODE_TRANSPARENT;
p_g_mode = p_capainfo.source_mode;
+ /* get list of offered payload types
+ * if list ist empty, the FR V1 is selected */
+ select_payload_type(mncc, payload_types, media_types, &payloads, sizeof(payload_types));
+ /* if no given payload type is supported, we assume */
+ if (!payloads) {
+ media_types[0] = MEDIA_TYPE_GSM;
+ payload_types[0] = PAYLOAD_TYPE_GSM;
+ payloads = 1;
+ }
+#if 0
+ /* if no given payload type is supported, we reject the call */
+ if (!payloads) {
+ mncc = create_mncc(MNCC_REJ_REQ, callref);
+ gsm_trace_header(p_g_interface_name, this, MNCC_REJ_REQ, DIRECTION_OUT);
+ mncc->fields |= MNCC_F_CAUSE;
+ mncc->cause.coding = 3;
+ mncc->cause.location = 1;
+ mncc->cause.value = 65;
+ add_trace("cause", "coding", "%d", mncc->cause.coding);
+ add_trace("cause", "location", "%d", mncc->cause.location);
+ add_trace("cause", "value", "%d", mncc->cause.value);
+ add_trace("reason", NULL, "Given speech codec(s) not supported");
+ end_trace();
+ send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
+ new_state(PORT_STATE_RELEASE);
+ trigger_work(&p_g_delete);
+ return;
+ }
+#endif
+
/* useruser */
/* what infos did we got ... */
epoint->ep_app = new_endpointapp(epoint, 0, interface->app); //incoming
epointlist_new(epoint->ep_serial);
- /* modify lchan to GSM codec V1 */
- gsm_trace_header(p_g_interface_name, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
- mode = create_mncc(MNCC_LCHAN_MODIFY, p_g_callref);
- mode->lchan_mode = 0x01; /* GSM V1 */
- mode->lchan_type = 0x02;
- add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
- end_trace();
- send_and_free_mncc(p_g_lcr_gsm, mode->msg_type, mode);
+ /* modify lchan in case of no rtp bridge */
+ if (!p_g_rtp_bridge)
+ modify_lchan(media_types[0]);
/* send call proceeding */
gsm_trace_header(p_g_interface_name, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT);
SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
message->param.setup.useruser.len = strlen(mncc->useruser.info);
message->param.setup.useruser.protocol = mncc->useruser.proto;
- message->param.setup.rtpinfo.payload_type = 3; /* FIXME: receive payload type from peer */
-
if (p_g_rtp_bridge) {
struct gsm_mncc_rtp *rtp;
+ int i;
PDEBUG(DEBUG_GSM, "Request RTP peer info, before forwarding setup\n");
p_g_setup_pending = message;
rtp = (struct gsm_mncc_rtp *) create_mncc(MNCC_RTP_CREATE, p_g_callref);
send_and_free_mncc(p_g_lcr_gsm, rtp->msg_type, rtp);
+
+ for (i = 0; i < (int)sizeof(message->param.setup.rtpinfo.payload_types) && i < payloads; i++) {
+ message->param.setup.rtpinfo.media_types[i] = media_types[i];
+ message->param.setup.rtpinfo.payload_types[i] = payload_types[i];
+ message->param.setup.rtpinfo.payloads++;
+ }
+
} else
message_put(message);
port = port->next;
}
- if (msg_type == GSM_TCHF_FRAME) {
+ if (msg_type == GSM_TCHF_FRAME
+ || msg_type == GSM_TCHF_BAD_FRAME) {
if (port) {
/* inject DTMF, if enabled */
if (pgsm_bs->p_g_dtmf) {
} else
pgsm_bs->frame_receive(arg);
/* if we do not bridge we need to inject audio, if available */
- if (!pgsm_bs->p_bridge) {
+ if (!pgsm_bs->p_bridge || pgsm_bs->p_tone_name[0]) {
unsigned char data[160];
int i;
i = pgsm_bs->read_audio(data, 160);
if (i)
- pgsm_bs->bridge_rx(data, i);
+ pgsm_bs->audio_send(data, i);
}
}
return 0;
return;
}
+ /* unsupported codec for RTP bridge */
+ if (param->setup.rtpinfo.port) {
+ int i;
+
+ p_g_rtp_payloads = 0;
+ gsm_trace_header(p_g_interface_name, this, 1 /* codec negotioation */, DIRECTION_NONE);
+ for (i = 0; i < param->setup.rtpinfo.payloads; i++) {
+ switch (param->setup.rtpinfo.media_types[i]) {
+ case MEDIA_TYPE_GSM:
+ case MEDIA_TYPE_GSM_EFR:
+ case MEDIA_TYPE_AMR:
+ case MEDIA_TYPE_GSM_HR:
+ add_trace("rtp", "payload", "%s:%d supported", media_type2name(param->setup.rtpinfo.media_types[i]), param->setup.rtpinfo.payload_types[i]);
+ if (p_g_rtp_payloads < (int)sizeof(p_g_rtp_payload_types)) {
+ p_g_rtp_media_types[p_g_rtp_payloads] = param->setup.rtpinfo.media_types[i];
+ p_g_rtp_payload_types[p_g_rtp_payloads] = param->setup.rtpinfo.payload_types[i];
+ p_g_rtp_payloads++;
+ }
+ break;
+ default:
+ add_trace("rtp", "payload", "%s:%d unsupported", media_type2name(param->setup.rtpinfo.media_types[i]), param->setup.rtpinfo.payload_types[i]);
+ }
+ }
+ end_trace();
+ if (!p_g_rtp_payloads) {
+ gsm_trace_header(p_g_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
+ add_trace("failure", NULL, "No payload given that is supported by GSM");
+ end_trace();
+ message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+ message->param.disconnectinfo.cause = 65;
+ message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+ message_put(message);
+ new_state(PORT_STATE_RELEASE);
+ trigger_work(&p_g_delete);
+ return;
+ }
+ }
+
// SCPY(&p_m_tones_dir, param->setup.ext.tones_dir);
/* screen outgoing caller id */
do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_g_interface_name);
add_trace("redir", "screen", "%d", mncc->redirecting.screen);
add_trace("redir", "number", "%s", mncc->redirecting.number);
}
- /* bearer capability */
- //todo
end_trace();
send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
message_put(message);
- new_state(PORT_STATE_OUT_PROCEEDING);
-
/* RTP bridge */
if (param->setup.rtpinfo.port) {
p_g_rtp_bridge = 1;