Voip網(wǎng)絡(luò)電話之PJSIP(二)

不知道小伙伴們服務(wù)器搭建好了沒有,如果有什么問題可以加我QQ:294988383,驗(yàn)證:PJSIP。
接下來我們來編譯PJSIP,關(guān)于這么PJSIP編譯(坑很多):
首先官方的文檔:
https://trac.pjsip.org/repos/wiki/Getting-Started/iPhone
官方文檔什么鬼,全英文,不知道我英文不好么?所以我就找了別人的編譯翻譯:
http://blog.makeex.com/2014/06/28/pjsip-for-ios-build-mutil-target-support/
我是照著這個(gè)大神編譯過程來的,前面都沒有問題,編譯都完成了,卡在最后合并和連接靜態(tài)庫上了。不懂腳本語言,所以就使用最原始的方法合并和提取。至于怎么合并和提取請(qǐng)搜索,iOS靜態(tài)庫制作。

小伙伴們拿到最后的靜態(tài)庫和頭文件,接下來就要來實(shí)現(xiàn)了。
首先新建一個(gè)項(xiàng)目,把編譯好的靜態(tài)庫和頭文件拖進(jìn)去:

2.png

目錄就是這樣子,接下來我們command+b 編譯一下會(huì)報(bào)這樣的錯(cuò)誤:



這是因?yàn)轭^文件路徑錯(cuò)誤導(dǎo)致的,我們打開項(xiàng)目的setting設(shè)置一下就好了:

找到 Header Search Path 添加:

4.png

還要設(shè)置:


6.png

最后還有:


屏幕快照 2016-11-22 下午7.15.06.png

接下來我們開始正式的代碼編寫,首先新建一個(gè)PjsipManager的單利:
導(dǎo)入頭文件#import"pjsua.h",一個(gè)初始化Psjip的類方法:
+ (void)pjsipInit{
    ///狀態(tài)標(biāo)示
    pj_status_t status;
    
    ///注冊(cè)線程
    pj_bool_t bool_t = pj_thread_is_registered();
    if (!bool_t) {
        pj_thread_desc desc;
        pj_thread_t* thed;
        status = pj_thread_register(NULL,desc,&thed);
        if (status != PJ_SUCCESS)
        {
            NSLog(@"線程注冊(cè)失敗");
        }
    }
    
    status = pjsua_destroy();
    if (status != PJ_SUCCESS)
    {
        NSLog(@"清除信息");
    }
    
    ///初始化程序
    status = pjsua_create();
    if (status != PJ_SUCCESS){
        NSLog(@"pjsua初始化失敗");
    }
    else{//初始化pjsua配置
        
        ///初始化通話配置
        pjsua_config config;
        pjsua_config_default (&config);
        //設(shè)置登錄狀態(tài)改變回調(diào)
        config.cb.on_reg_state2 = &on_reg_state2;
        //設(shè)置來電回調(diào)
        config.cb.on_incoming_call = &on_incoming_call;
        //設(shè)置呼叫狀態(tài)改變回調(diào)
        config.cb.on_call_media_state = &on_call_media_state;
        //設(shè)置通話狀態(tài)改變回調(diào)
        config.cb.on_call_state = &on_call_state;
        
        //初始化日志配置
        pjsua_logging_config log_config;
        pjsua_logging_config_default(&log_config);
        //日記等級(jí)0不打印日記 4打印詳情日記
        log_config.console_level = 0;
        status = pjsua_init(&config, &log_config, NULL);
        //判斷是否初始化成功
        if (status != PJ_SUCCESS)
        {
            NSLog(@"創(chuàng)初始化pjsua配置失敗");
        }
    }
}

還有4個(gè)回調(diào)方法:

///登錄狀態(tài)改變回調(diào)
static void on_reg_state2(pjsua_acc_id acc_id, pjsua_reg_info *info){
    if (info->renew != 0) {
        if (info->cbparam->code == 200) {
            NSLog(@"登錄成功");
        }
        else{
            NSLog(@"登錄失敗code:%d ",info->cbparam->code);
        }
    }
    else{
        if (info->cbparam->code == 200)
        {
            NSLog(@"SIP退出登錄成功");
        }
    }
}

///來電回調(diào)
static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata){
    //獲取來電信息
    pjsua_call_info info;
    pjsua_call_get_info(call_id, &info);
    NSString *callStr = [NSString stringWithUTF8String:info.remote_info.ptr];
    //這里發(fā)送一個(gè)通知
    [[NSNotificationCenter defaultCenter] postNotificationName:@"calling" object:nil userInfo:@{@"calledCAcount":callStr}];
    NSLog(@"%@",callStr);
}

///呼叫回調(diào)
static void on_call_media_state(pjsua_call_id call_id)
{
    //獲取呼叫信息
    pjsua_call_info info;
    pjsua_call_get_info(call_id, &info);
    
    if (info.media_status == PJSUA_CALL_MEDIA_ACTIVE)
    {//呼叫接通
        
        //建立單向媒體流從源到匯
        pjsua_conf_connect(info.conf_slot, 0);
        pjsua_conf_connect(0, info.conf_slot);
        
        NSLog(@"呼叫成功,等待對(duì)方接聽");
    }
}

//通話狀態(tài)改變回調(diào)
static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
{
    
    // 通話狀態(tài):CALLING
    // 通話狀態(tài):EARLY
    // 通話狀態(tài):EARLY
    // 呼叫成功,等待對(duì)方接聽
    // 通話狀態(tài):CONNECTING
    // 通話狀態(tài):CONFIRMED
    // DISCONNCTD  對(duì)方掛斷
    //獲取通話信息
    pjsua_call_info ci;
    pjsua_call_get_info(call_id, &ci);
    
    NSString *status = [NSString stringWithUTF8String:ci.state_text.ptr];
    NSLog(@"通話狀態(tài):%@",status);
    
    
}

還有呼叫、接應(yīng)、掛斷方法,也要有:


///呼叫
- (void)callAccount:(NSString *)accountsString{
    
    char accountChar[50];
    sprintf(accountChar,"sip:%s@%s",[accountsString UTF8String],[self.ip UTF8String]);
    pj_str_t url = pj_str(accountChar);
    
    //初始化呼叫
    pjsua_call_setting  call_set;
    pjsua_call_setting_default(&call_set);
    
    pj_status_t status = pjsua_call_make_call(_acc_id, &url, &call_set, NULL, NULL, NULL);
    if (status != PJ_SUCCESS)
    {
        NSLog(@"呼叫失敗");
    }
}

///掛斷
- (void)hangUp{
    //獲賬戶信息
    pjsua_call_info config;
    pjsua_call_get_info(_acc_id, &config);
    
    ///判斷是否在通話中
    if (config.media_status == PJSUA_CALL_MEDIA_ACTIVE)
    {
        pjsua_call_hangup_all();
    }
}

///接電話
- (void)answerCall{
    pjsua_call_answer(_called_id, 200, NULL, NULL);
}

哈哈,以上功能基本能實(shí)現(xiàn)接打電話功能了,接下來我們來實(shí)戰(zhàn),首先在AppDelegate里項(xiàng)目啟動(dòng)的時(shí)候要初始化Pjsua,當(dāng)然了我們之前封裝好了的,直接調(diào)用就可以了。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //初始化pjsip設(shè)置回調(diào)
    [PjsipManager pjsipInit];
    return YES;
}

頁面的話,在SB里拖幾個(gè)控件就行了,像這樣:

Paste_Image.png

拖幾條線,然后實(shí)現(xiàn)功能就行了,哎呀,功能我們之前已經(jīng)封裝好的,直接調(diào)用就行,還有就是別忘了監(jiān)聽通知顯示來電號(hào)碼哦.

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo}p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo; color: #3d1d81}p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo; color: #294c50}p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo; min-height: 21.0px}span.s1 {font-variant-ligatures: no-common-ligatures}span.s2 {font-variant-ligatures: no-common-ligatures; color: #c32275}span.s3 {font-variant-ligatures: no-common-ligatures; color: #000000}span.s4 {font-variant-ligatures: no-common-ligatures; color: #539aa4}span.s5 {font-variant-ligatures: no-common-ligatures; color: #3c828c}span.s6 {font-variant-ligatures: no-common-ligatures; color: #6122ae}span.s7 {font-variant-ligatures: no-common-ligatures; color: #c91b13}span.s8 {font-variant-ligatures: no-common-ligatures; color: #703daa}span.s9 {font-variant-ligatures: no-common-ligatures; color: #3d1d81}span.s10 {font: 18.0px 'PingFang SC'; font-variant-ligatures: no-common-ligatures; color: #c91b13}

- (void)viewDidLoad {
    [super viewDidLoad];
    _manager = [PjsipManager sharedPjsipManager];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(calling:) name:@"calling" object:nil];
}

- (void)calling:(NSNotification *)notification{
    NSString *callId = notification.userInfo[@"calledCAcount"];
    _calledAccount.text = [NSString stringWithFormat:@"來電:%@",callId];
}

好了代碼功能已經(jīng)完成,小伙伴們已經(jīng)等不及測(cè)試了吧?好吧,那讓我們先啟動(dòng)sip服務(wù)器(有服務(wù)器的跳過了)控制臺(tái)輸入:
udo /usr/local/sbin/kamctl start

Paste_Image.png

啟動(dòng)成功,萬事俱備只欠東風(fēng)。

Paste_Image.png

看見控制臺(tái)打印那幾個(gè)字沒有,登錄成功,耶,登錄成功了啊。那讓我們來試試打電話吧,

Paste_Image.png

控制臺(tái)打印了,通話狀態(tài)calling 正在呼叫 disconnctd 通話斷開,怎么回事呢,是因?yàn)?,我另一個(gè)號(hào)lmt還沒有登錄,現(xiàn)在讓我手機(jī)上跑一個(gè)項(xiàng)目測(cè)試下打電話.

Paste_Image.png

WTF天公不作美啊,Xcode版本太低了,我現(xiàn)在就升級(jí),那么通話的測(cè)試就交給小伙伴們了。
demo我已經(jīng)上傳到github了,歡迎大家下載點(diǎn)贊。
https://github.com/SilmeLyy/PjsipDemo
另外這是實(shí)現(xiàn)了最基本的功能,還有好多bug,希望有大神看到了,完善項(xiàng)目,做一個(gè)帶視頻的,基于pjsip的Voip項(xiàng)目,期待大神的項(xiàng)目。
想使用linphone的小伙伴們有福了,linphone官網(wǎng)已經(jīng)有編譯好的庫文件,可以直接下載使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容