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


#include <pjsua-lib/pjsua.h>
#include <pjsua-lib/pjsua_internal.h> // Обязательно для доступа к open_snd_dev и create_aud_param

/* 
 * Функция принудительно закрывает текущий звуковой порт и открывает его заново 
 * с точными параметрами частоты (clock_rate) и фрейма (samples_per_frame).
 */
static pj_status_t force_reopen_sound_device(unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame)
{
    pj_status_t status = PJ_SUCCESS;

    printf("[AUDIO_REOPEN] Force closing old sound device...\n");

    /* 1. Если звуковой порт уже открыт, корректно закрываем его */
    if (pjsua_var.snd_port) {
        pjmedia_snd_port_destroy(pjsua_var.snd_port);
        pjsua_var.snd_port = NULL;
    }

    /* 2. Настраиваем параметры для нового звукового порта на основе параметров кодека */
    if (pjsua_var.cap_dev != PJSUA_SND_NULL_DEV) {
        pjmedia_snd_port_param param;

        pjmedia_snd_port_param_default(&param);
        param.ec_options = pjsua_var.media_cfg.ec_options;

        /* Заполняем параметры аудио-девайса под нужную частоту дискретизации */
        status = create_aud_param(&param.base, 
                                  pjsua_var.cap_dev,
                                  pjsua_var.play_dev,
                                  clock_rate,
                                  channel_count,
                                  samples_per_frame,
                                  16, /* bits_per_sample (стандарт для PCM) */
                                  PJ_FALSE);
        if (status != PJ_SUCCESS) {
            printf("[AUDIO_REOPEN] Error: create_aud_param failed with status %d\n", status);
            return status;
        }

        param.options = 0;

        printf("[AUDIO_REOPEN] Opening sound device: %u Hz, %u channels, SPF: %u\n", 
               clock_rate, channel_count, samples_per_frame);

        /* 3. Вызываем низкоуровневое открытие аудио-устройства */
        status = open_snd_dev(&param);
        if (status != PJ_SUCCESS) {
            printf("[AUDIO_REOPEN] Error: open_snd_dev failed with status %d\n", status);
            return status;
        }
    } else {
        /* Если используется Null-audio бэкенд */
        status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev);
    }

    return status;
}
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.strm.a.media_port;
            if (media_port) {
                /* Узнаем параметры, которые согласовал кодек (например, Speex 8000 или 16000) */
                pjmedia_audio_format_detail *afd;
                afd = pjmedia_format_get_audio_format_detail(&media_port->info.fmt, 1);
                
                if (afd) {
                    unsigned codec_rate = afd->clock_rate;
                    unsigned codec_channels = afd->channel_count;
                    unsigned codec_spf = PJMEDIA_AFD_SPF(afd);

                    /* Получаем текущую конфигурацию Порта 0 (Звуковой карты) из моста */
                    pjmedia_conf_port_info port0_info;
                    if (pjmedia_conf_get_port_info(pjsua_var.mconf, 0, &port0_info) == PJ_SUCCESS) {
                        
                        /* Если частота звуковой карты не совпадает с частотой кодека — переоткрываем аппаратуру */
                        if (port0_info.clock_rate != codec_rate) {
                            printf("[MEDIA_ALIGN] Rate mismatch! Port0=%u Hz, Codec=%u Hz. Forcing reopen...\n", 
                                   port0_info.clock_rate, codec_rate);
                            
                            /* 
                             * Также синхронизируем дефолтные переменные pjsua, чтобы мост при 
                             * последующих вызовах connect знал новую целевую частоту.
                             */
                            pjsua_var.media_cfg.snd_clock_rate = codec_rate;
                            pjsua_var.media_cfg.samples_per_frame = codec_spf;

                            /* Вызываем принудительный аппаратный перезапуск */
                            force_reopen_sound_device(codec_rate, codec_channels, codec_spf);
                        } else {
                            printf("[MEDIA_ALIGN] Rates already match: %u Hz. No action needed.\n", codec_rate);
                        }
                    }
                }
            }
        }
#endif
        // Выполняем коммутацию портов в мосту. 
        // Так как Port 0 только что переоткрылся (или уже соответствовал) нужной частоте кодека,
        // внутренний механизм PJSIP свяжет их напрямую 1:1 без создания ресемплеров!
        pjsua_conf_connect(ci.conf_slot, 0);
        pjsua_conf_connect(0, ci.conf_slot);
    }
}