447 |
447 |
return 0;
|
448 |
448 |
}
|
449 |
449 |
|
450 |
|
/* compatibility check for codecs.
|
451 |
|
* if so, the candidates for full rate and half rate are selected */
|
452 |
|
switch (lchan->tch_mode) {
|
453 |
|
case GSM48_CMODE_SPEECH_V1:
|
454 |
|
switch (lchan->type) {
|
455 |
|
case GSM_LCHAN_TCH_F: /* mandatory */
|
456 |
|
requirement |= REQUIREMENT_A_TCHF;
|
457 |
|
break;
|
458 |
|
case GSM_LCHAN_TCH_H:
|
459 |
|
if (!bts->codec.hr) {
|
460 |
|
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG,
|
461 |
|
"tch_mode='%s' type='%s' not supported\n",
|
462 |
|
get_value_string(gsm48_chan_mode_names,
|
463 |
|
lchan->tch_mode),
|
464 |
|
gsm_lchant_name(lchan->type));
|
465 |
|
break;
|
466 |
|
}
|
467 |
|
if (codec_type_is_supported(lchan->conn, GSM0808_SCT_HR1))
|
468 |
|
requirement |= REQUIREMENT_A_TCHH;
|
469 |
|
break;
|
470 |
|
default:
|
471 |
|
LOGPHOLCHAN(lchan, LOGL_ERROR, "Unexpected channel type: neither TCH/F nor TCH/H for %s\n",
|
472 |
|
get_value_string(gsm48_chan_mode_names, lchan->tch_mode));
|
473 |
|
return 0;
|
474 |
|
}
|
475 |
|
break;
|
476 |
|
case GSM48_CMODE_SPEECH_EFR:
|
477 |
|
if (!bts->codec.efr) {
|
478 |
|
LOGPHOBTS(bts, LOGL_DEBUG, "EFR not supported\n");
|
479 |
|
break;
|
480 |
|
}
|
481 |
|
if (codec_type_is_supported(lchan->conn, GSM0808_SCT_FR2))
|
482 |
|
requirement |= REQUIREMENT_A_TCHF;
|
483 |
|
break;
|
484 |
|
case GSM48_CMODE_SPEECH_AMR:
|
485 |
|
if (!bts->codec.amr) {
|
486 |
|
LOGPHOBTS(bts, LOGL_DEBUG, "AMR not supported\n");
|
487 |
|
break;
|
488 |
|
}
|
489 |
|
if (codec_type_is_supported(lchan->conn, GSM0808_SCT_FR3))
|
490 |
|
requirement |= REQUIREMENT_A_TCHF;
|
491 |
|
if (codec_type_is_supported(lchan->conn, GSM0808_SCT_HR3))
|
492 |
|
requirement |= REQUIREMENT_A_TCHH;
|
493 |
|
break;
|
494 |
|
default:
|
495 |
|
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG, "Not even considering: src is not a SPEECH mode lchan\n");
|
496 |
|
/* FIXME: should allow handover of non-speech lchans */
|
497 |
|
return 0;
|
|
450 |
/* To which TCH type and codec can we handover? Consider targets independently from the current lchan's TCH kind
|
|
451 |
* and codec, to support TCH/F <-> TCH/H handovers and those that switch the codec type. */
|
|
452 |
|
|
453 |
/* TCH/F target? */
|
|
454 |
if (tchf_count) {
|
|
455 |
/* TCH/F timeslots are available, and FR1 is always supported. Could also end up using EFR or AMR codecs. */
|
|
456 |
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG, "considering HO to TCH/F (%d available)\n", tchf_count);
|
|
457 |
requirement |= REQUIREMENT_A_TCHF;
|
|
458 |
} else {
|
|
459 |
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG, "not considering HO to TCH/F (0 available)\n");
|
498 |
460 |
}
|
|
461 |
/* If the EFR (FR2) codec is supported, we'd add requirement |= TCH/F. Since TCH/F is already always supported,
|
|
462 |
* there is no need to check for EFR here. */
|
499 |
463 |
|
500 |
|
/* no candidate, because new cell is incompatible */
|
501 |
|
if (!requirement) {
|
502 |
|
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG, "not a candidate, because codec of MS and BTS are incompatible\n");
|
503 |
|
return 0;
|
504 |
|
}
|
|
464 |
/* TCH/H target? */
|
|
465 |
if (tchh_count) {
|
|
466 |
/* TCH/H timeslots are available, check whether any half rate codec is supported. */
|
|
467 |
bool hr1_ms = codec_type_is_supported(lchan->conn, GSM0808_SCT_HR1);
|
|
468 |
bool hr1_bts = (bts->codec.hr != 0);
|
|
469 |
bool hr3_ms = codec_type_is_supported(lchan->conn, GSM0808_SCT_HR3);
|
|
470 |
bool hr3_bts = (bts->codec.amr != 0);
|
|
471 |
bool add_tchh = (hr1_ms && hr1_bts) || (hr3_ms && hr3_bts);
|
505 |
472 |
|
506 |
|
/* remove slot types that are not available */
|
507 |
|
if (!tchf_count && requirement & REQUIREMENT_A_TCHF) {
|
508 |
|
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG,
|
509 |
|
"removing TCH/F, since all TCH/F lchans are in use\n");
|
510 |
|
requirement &= ~(REQUIREMENT_A_TCHF);
|
511 |
|
}
|
512 |
|
if (!tchh_count && requirement & REQUIREMENT_A_TCHH) {
|
513 |
|
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG,
|
514 |
|
"removing TCH/H, since all TCH/H lchans are in use\n");
|
515 |
|
requirement &= ~(REQUIREMENT_A_TCHH);
|
|
473 |
if (add_tchh)
|
|
474 |
requirement |= REQUIREMENT_A_TCHH;
|
|
475 |
|
|
476 |
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG, "%s HO to TCH/H"
|
|
477 |
" (support by MS/BTS for HR1: %s/%s, HR3(AMR): %s/%s)\n",
|
|
478 |
add_tchh ? "considering" : "not considering",
|
|
479 |
hr1_ms ? "yes" : "no",
|
|
480 |
hr1_bts ? "yes" : "no",
|
|
481 |
hr3_ms ? "yes" : "no",
|
|
482 |
hr3_bts ? "yes" : "no");
|
|
483 |
} else {
|
|
484 |
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG, "not considering HO to TCH/H, none available\n");
|
516 |
485 |
}
|
517 |
486 |
|
|
487 |
/* no candidate, because new cell is incompatible */
|
518 |
488 |
if (!requirement) {
|
519 |
|
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG, "not a candidate, because no suitable slots available\n");
|
|
489 |
LOGPHOLCHANTOBTS(lchan, bts, LOGL_DEBUG,
|
|
490 |
"Not a candidate, no lchans matching codecs supported by both MS and BTS are available\n");
|
520 |
491 |
return 0;
|
521 |
492 |
}
|
522 |
493 |
|
... | ... | |
607 |
578 |
* free slots of the current cell _after_ handover/assignment */
|
608 |
579 |
count = bts_count_free_ts(current_bts,
|
609 |
580 |
(lchan->type == GSM_LCHAN_TCH_H) ?
|
610 |
|
GSM_PCHAN_TCH_H : GSM_PCHAN_TCH_F);
|
|
581 |
GSM_PCHAN_TCH_H : GSM_PCHAN_TCH_F);
|
|
582 |
|
611 |
583 |
if (requirement & REQUIREMENT_A_TCHF) {
|
612 |
584 |
if (tchf_count - 1 >= count + 1)
|
613 |
585 |
requirement |= REQUIREMENT_C_TCHF;
|