Bootstrap

Sofia-SIP 使用教程

Sofia-SIP 是一个开源的 SIP 协议栈,广泛用于 VoIP 和即时通讯应用。以下是一些基本的使用教程,帮助你快速上手 Sofia-SIP。

1. 安装 Sofia-SIP

首先,你需要安装 Sofia-SIP 库。你可以从其官方 GitHub 仓库克隆源代码并编译安装:

git clone https://github.com/doubango/sofia-sip.git
cd sofia-sip
./bootstrap.sh
./configure
make
sudo make install
2. 初始化 Sofia-SIP

在使用 Sofia-SIP 之前,需要初始化库并创建一个 NUA(Network Unified Access)对象。NUA 是 Sofia-SIP 的核心对象,用于管理 SIP 会话。

#include <sofia-sip/su.h>
#include <sofia-sip/nua.h>

int main() {
    su_root_t *root;
    nua_t *nua;

    // 初始化 SU 根
    root = su_root_create(NULL);
    if (!root) {
        fprintf(stderr, "Failed to create SU root\n");
        return -1;
    }

    // 创建 NUA 对象
    nua = nua_create(root, NULL, NULL, 0, NULL, NULL);
    if (!nua) {
        fprintf(stderr, "Failed to create NUA object\n");
        su_root_destroy(root);
        return -1;
    }

    // 运行事件循环
    su_root_run(root);

    // 清理资源
    nua_destroy(nua);
    su_root_destroy(root);

    return 0;
}
3. 注册 SIP 用户

注册 SIP 用户涉及发送 REGISTER 请求。以下是一个简单的示例:

#include <sofia-sip/su.h>
#include <sofia-sip/nua.h>
#include <sofia-sip/sip.h>

void register_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]) {
    if (status == 200) {
        printf("Registration successful\n");
    } else {
        printf("Registration failed: %d %s\n", status, phrase);
    }
}

int main() {
    su_root_t *root;
    nua_t *nua;
    nua_handle_t *nh;

    // 初始化 SU 根
    root = su_root_create(NULL);
    if (!root) {
        fprintf(stderr, "Failed to create SU root\n");
        return -1;
    }

    // 创建 NUA 对象
    nua = nua_create(root, NULL, NULL, 0, NULL, NULL);
    if (!nua) {
        fprintf(stderr, "Failed to create NUA object\n");
        su_root_destroy(root);
        return -1;
    }

    // 创建 NUA 句柄
    nh = nua_handle(nua, NULL, NUTAG_URL("sip:example.com"), TAG_END());
    if (!nh) {
        fprintf(stderr, "Failed to create NUA handle\n");
        nua_destroy(nua);
        su_root_destroy(root);
        return -1;
    }

    // 发送 REGISTER 请求
    nua_register(nh, NUTAG_URL("sip:[email protected]"), SIPTAG_TO_STR("sip:[email protected]"), SIPTAG_FROM_STR("sip:[email protected]"), SIPTAG_CONTACT_STR("sip:[email protected]"), SIPTAG_EXPIRES_STR("3600"), NUTAG_REGISTRAR("sip:example.com"), TAG_END());

    // 运行事件循环
    su_root_run(root);

    // 清理资源
    nua_handle_destroy(nh);
    nua_destroy(nua);
    su_root_destroy(root);

    return 0;
}
4. 处理 SIP 消息

Sofia-SIP 提供了丰富的回调机制来处理 SIP 消息。你可以在回调函数中处理各种 SIP 事件,例如来电、挂断等

void incoming_call_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]) {
    if (event == NUA_I_INVITE) {
        printf("Incoming call from %s\n", sip->sip_from->a_url->url_user);
        // 接受来电
        nua_respond(nh, SIP_200_OK, SIPTAG_TO(sip->sip_to), TAG_END());
    }
}

int main() {
    su_root_t *root;
    nua_t *nua;
    nua_handle_t *nh;

    // 初始化 SU 根
    root = su_root_create(NULL);
    if (!root) {
        fprintf(stderr, "Failed to create SU root\n");
        return -1;
    }

    // 创建 NUA 对象
    nua = nua_create(root, incoming_call_callback, NULL, 0, NULL, NULL);
    if (!nua) {
        fprintf(stderr, "Failed to create NUA object\n");
        su_root_destroy(root);
        return -1;
    }

    // 创建 NUA 句柄
    nh = nua_handle(nua, NULL, NUTAG_URL("sip:example.com"), TAG_END());
    if (!nh) {
        fprintf(stderr, "Failed to create NUA handle\n");
        nua_destroy(nua);
        su_root_destroy(root);
        return -1;
    }

    // 运行事件循环
    su_root_run(root);

    // 清理资源
    nua_handle_destroy(nh);
    nua_destroy(nua);
    su_root_destroy(root);

    return 0;
}
5. 发送 SIP 消息

发送 SIP 消息(例如 INVITE 请求)可以通过 nua_invite 函数实现

void invite_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]) {
    if (event == NUA_R_INVITE) {
        if (status == 200) {
            printf("Call established\n");
        } else {
            printf("Call failed: %d %s\n", status, phrase);
        }
    }
}

int main() {
    su_root_t *root;
    nua_t *nua;
    nua_handle_t *nh;

    // 初始化 SU 根
    root = su_root_create(NULL);
    if (!root) {
        fprintf(stderr, "Failed to create SU root\n");
        return -1;
    }

    // 创建 NUA 对象
    nua = nua_create(root, invite_callback, NULL, 0, NULL, NULL);
    if (!nua) {
        fprintf(stderr, "Failed to create NUA object\n");
        su_root_destroy(root);
        return -1;
    }

    // 创建 NUA 句柄
    nh = nua_handle(nua, NULL, NUTAG_URL("sip:example.com"), TAG_END());
    if (!nh) {
        fprintf(stderr, "Failed to create NUA handle\n");
        nua_destroy(nua);
        su_root_destroy(root);
        return -1;
    }

    // 发送 INVITE 请求
    nua_invite(nh, NUTAG_URL("sip:[email protected]"), SIPTAG_TO_STR("sip:[email protected]"), SIPTAG_FROM_STR("sip:[email protected]"), SIPTAG_CONTACT_STR("sip:[email protected]"), TAG_END());

    // 运行事件循环
    su_root_run(root);

    // 清理资源
    nua_handle_destroy(nh);
    nua_destroy(nua);
    su_root_destroy(root);

    return 0;
}
6. 错误处理

在实际应用中,错误处理是非常重要的。Sofia-SIP 提供了详细的错误代码和描述,你可以在回调函数中进行处理。

void error_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, sip_t const *sip, tagi_t tags[]) {
    if (status != 200) {
        printf("Error: %d %s\n", status, phrase);
    }
}

int main() {
    su_root_t *root;
    nua_t *nua;
    nua_handle_t *nh;

    // 初始化 SU 根
    root = su_root_create(NULL);
    if (!root) {
        fprintf(stderr, "Failed to create SU root\n");
        return -1;
    }

    // 创建 NUA 对象
    nua = nua_create(root, error_callback, NULL, 0, NULL, NULL);
    if (!nua) {
        fprintf(stderr, "Failed to create NUA object\n");
        su_root_destroy(root);
        return -1;
    }

    // 创建 NUA 句柄
    nh = nua_handle(nua, NULL, NUTAG_URL("sip:example.com"), TAG_END());
    if (!nh) {
        fprintf(stderr, "Failed to create NUA handle\n");
        nua_destroy(nua);
        su_root_destroy(root);
        return -1;
    }

    // 发送 INVITE 请求
    nua_invite(nh, NUTAG_URL("sip:[email protected]"), SIPTAG_TO_STR("sip:[email protected]"), SIPTAG_FROM_STR("sip:[email protected]"), SIPTAG_CONTACT_STR("sip:[email protected]"), TAG_END());

    // 运行事件循环
    su_root_run(root);

    // 清理资源
    nua_handle_destroy(nh);
    nua_destroy(nua);
    su_root_destroy(root);

    return 0;
}
;