Загрузка данных


/* Структура для передачи параметров в таймер */
struct reinvite_ctx {
    pjsua_call_id call_id;
};

/* Callback, который безопасно выполнится в контексте главного потока PJSIP */
static void async_reinvite_cb(pj_timer_heap_t *timer_heap, struct pj_timer_entry *entry)
{
    struct reinvite_ctx *ctx = (struct reinvite_ctx *) entry->user_data;
    
    printf("[MEDIA_ALIGN] Executing delayed pjsua_call_reinvite for Call %d...\n", ctx->call_id);
    
    // Безопасно инициируем пересоздание медиа-стримов
    pjsua_call_reinvite(ctx->call_id, PJ_TRUE, NULL);

    // Освобождаем память, выделенную под контекст
    pj_pool_t *pool = pjsua_get_pool(); // Берём глобальный или любой временный пул
    // Так как это куча PJSIP, если выделили через malloc, используйте free(). 
    // Ниже мы выделим через malloc для простоты, чтобы не трогать пулы.
    free(ctx);
    free(entry);
}
/* Callback called by the library when call's media state has changed */
static void on_call_media_state(pjsua_call_id call_id)
{
    pjsua_call_info ci;
    pjsua_call_get_info(call_id, &ci);

    if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
#ifdef USE_DYNAMIC_AUDIO_RATE
        pjsua_call_media_info *media = &ci.media;
        if (media->type == PJMEDIA_TYPE_AUDIO) {
            pjmedia_port *media_port = NULL;

            media_port = pjsua_var.calls[call_id].media[0].strm.a.media_port;
            if (!media_port) {
                printf("[MEDIA] Error: Failed to get call media port\n");
                return;
            }

            unsigned negotiated_rate = media_port->info.fmt.det.aud.clock_rate;
            unsigned current_bridge_rate = pjsua_var.mconf->clock_rate; // Текущий рейт моста

            printf("Detected sound codec rate=%u Hz (Current Bridge=%u Hz)\n", negotiated_rate, current_bridge_rate);

            // Проверяем: если рейт кодека отличается от рейта, под который создавались стримы
            if (negotiated_rate != current_bridge_rate) {
                printf("[MEDIA_ALIGN] Rate mismatch! Scheduling async pjsua_call_reinvite...\n");

                // Выделяем память под структуру задачи
                struct reinvite_ctx *ctx = malloc(sizeof(struct reinvite_ctx));
                pj_timer_entry *timer_entry = malloc(sizeof(pj_timer_entry));

                if (ctx && timer_entry) {
                    ctx->call_id = call_id;
                    
                    pj_timer_entry_init(timer_entry, 0, ctx, &async_reinvite_cb);
                    
                    // Задаем минимальную задержку (например, 10 мс), чтобы дать текущему 
                    // обработчику on_call_media_state спокойно завершиться и разблокировать мьютексы
                    pj_time_val delay = {0, 10}; 
                    
                    pjsua_schedule_timer(timer_entry, &delay);
                } else {
                    printf("[MEDIA_ALIGN] Error: OOM allocation for reinvite task failed\n");
                }
            } else {
                pjsua_var.media_cfg.snd_clock_rate = negotiated_rate;
                printf("Rates match. Set snd_clock_rate=%u\n", pjsua_var.media_cfg.snd_clock_rate);
            }
        }
#endif
        // When media is active, connect call to sound device.
        pjsua_conf_connect(ci.conf_slot, 0);
        pjsua_conf_connect(0, ci.conf_slot);
    }
}