首先我們來看Linphone的簡單介紹:
Linphone for smartphones, tablets and mobile devices.
Make audio and video calls in HD.
Create audio conferences.
Record and store calls.
View real-time presence status.
Manage your address book.
Communicate securely.
而我們?nèi)绾慰焖賹⒆钚掳姹綥inphone SDK移植到我們的個人項目呢?我將其分為三個步驟:
一 . 首先我們需要自己編譯一份最新的Linphone SDK
在此非常感謝作者"whiteking"為我們整理的編譯流程,大致分為一下幾個步驟,最新版本的Linphone SDK也可以按照下面的步驟進行:
1.安裝 HomeBrew
2.下載linphone-iphone項目:
3.配置環(huán)境路徑
4.Build SDK
相關(guān)命令在編譯流程中提到, 在此不過多贅述. 需要提醒一點的就是, 下載過程異常得慢, 本人足足花了一個晚上才下載成功的, 可以睡覺前下載一份, 睡醒應(yīng)該就能編譯了git submodule sync && git submodule update --init --recursive ←這個是submodule即子模塊下載, 執(zhí)行這個命令比較久,睡一覺應(yīng)該就能下好了.
編譯成功后, 我們需要的SDK就在下面的這個文件里面:
而我們只需要apple-darwin這個文件就可以了.
二. 熟悉Linphone Demo項目, 熟悉SDK的接口調(diào)用
可以打開我們剛才編譯好的demo, 然后看一下Linphone的架構(gòu), 關(guān)于架構(gòu)分析的有作者"杭研融合通信iOS"分享的文章linphone-iphone的安裝與調(diào)試. 里面也有安裝和編譯的教程, 可以借鑒一下.
熟悉Linphone Demo項目, 需要花點時間去熟悉, 所有接口都是用C語言進行封裝的, 因此我們需要熟悉如何調(diào)用C語言, C語言沒有內(nèi)存管理的概念, 因此我們創(chuàng)建一個對象的同時, 記得用完要把它銷毀掉.
Linphone Demo使用的控制器跳轉(zhuǎn)用的是古老的跳轉(zhuǎn)方式, 還有xib用的是古老的Autoresizing, 有興趣的童鞋可以去了解一下, 不過這些古老的方式在今天的開發(fā)已經(jīng)被廢棄, 從側(cè)面可以看出Linphone這個開源庫的歷史悠久.
Linphone Demo核心業(yè)務(wù)層在于LinphoneManager, 所有核心的操作都在這里面, 因此我們關(guān)心的重點在這個文件里面.
對于呼出或者呼入, 都需要進行以下的步驟:
1. 初始化
2.用戶的注冊
3.呼入, 呼出
熟悉相關(guān)流程之后, 接下來我們就可以進行Linphone的移植了.
三. Linphone最新版SDK的移植
首先感謝作者"江湖度"的貢獻, 為我們貢獻了這篇Linphone-iOS-移植 移植教程. 這里本人在移植的過程與作者"江湖度"移植的前四步基本相同, 在第五步開始有些差異, 本人在第五步用到了Linphone Demo里的幾個類文件:
如下:
ColorSpaceUtilities//顏色相關(guān)工具
Contact//聯(lián)系人
FastAddressBook//通訊錄
FileTransferDelegate//文件傳輸
LinphoneManager//核心業(yè)務(wù)管理
Log//Log
ProviderDelegate//適配iOS 10 Callkit
UILabel+Boldify//UILabel粗體
Utils//工具類
當(dāng)然上面的文件不可能一下子全部挪過來, 因為綁定了很多Linphone Demo本身很多的東西, 所以需要自己剔除掉沒用的東西, 一個一個文件地挪過來, 可以從Log開始, 然后Utils, 然后Contact.... 這部分工作量其實還是蠻大的, 也是需要耐心的工作.
對了, 記得還要把兩個配置文件拖入到我們的工程里面, 里面可以直接通過設(shè)置0,1修改配置, 還有一些聲音文件也拖入到我們自己的工程里面:
工程里面打開Voip的開關(guān):
既然用到Voip, 我們還需要配置一個Voip的推送證書. 具體百度一下Voip證書配置.
萬事俱備, 接下來我們就可以調(diào)用LinphoneManager還有SDK里面的一些方法了.
初始化:
[[LinphoneManager instance] startLinphoneCore];
注冊:
- (void)registeByUserName:(NSString *)userName pwd:(NSString *)pwd domain:(NSString *)domain tramsport:(NSString *)transport{
//設(shè)置超時
linphone_core_set_inc_timeout(LC, 60);
//創(chuàng)建配置表
LinphoneProxyConfig *proxyCfg = linphone_core_create_proxy_config(LC);
//初始化電話號碼
linphone_proxy_config_normalize_phone_number(proxyCfg,userName.UTF8String);
//創(chuàng)建地址
NSString *address = [NSString stringWithFormat:@"sip:%@@%@",userName,domain];//如:sip:123456@sip.com
LinphoneAddress *identify = linphone_address_new(address.UTF8String);
linphone_proxy_config_set_identity_address(proxyCfg, identify);
linphone_proxy_config_set_route(
proxyCfg,
[NSString stringWithFormat:@"%s;transport=%s", domain.UTF8String, transport.lowercaseString.UTF8String]
.UTF8String);
linphone_proxy_config_set_server_addr(
proxyCfg,
[NSString stringWithFormat:@"%s;transport=%s", domain.UTF8String, transport.lowercaseString.UTF8String]
.UTF8String);
linphone_proxy_config_enable_register(proxyCfg, TRUE);
//創(chuàng)建證書
LinphoneAuthInfo *info = linphone_auth_info_new(userName.UTF8String, nil, pwd.UTF8String, nil, nil, linphone_address_get_domain(identify));
//添加證書
linphone_core_add_auth_info(LC, info);
//銷毀地址
linphone_address_unref(identify);
//注冊
linphone_proxy_config_enable_register(proxyCfg, 1);
//添加到配置表,添加到linphone_core
linphone_core_add_proxy_config(LC, proxyCfg);
//設(shè)置成默認(rèn)配置表
linphone_core_set_default_proxy_config(LC, proxyCfg);
//設(shè)置音頻編碼格式
[self synchronizeCodecs:linphone_core_get_audio_codecs(LC)];
}
#pragma mark - 設(shè)置音頻編碼格式
- (void)synchronizeCodecs:(const MSList *)codecs {
PayloadType *pt;
const MSList *elem;
for (elem = codecs; elem != NULL; elem = elem->next) {
pt = (PayloadType *)elem->data;
NSString *sreung = [NSString stringWithFormat:@"%s", pt->mime_type];
if ([sreung isEqualToString:@"G729"]) {
linphone_core_enable_payload_type(LC, pt, 1);
}else {
linphone_core_enable_payload_type(LC, pt, 0);
}
}
}
獲取注冊的狀態(tài):
- (IBAction)getRegistState:(id)sender {
LinphoneProxyConfig *cfg = linphone_core_get_default_proxy_config(LC);
LinphoneRegistrationState state = linphone_proxy_config_get_state(cfg);
switch (state) {
case LinphoneRegistrationNone:{
self.msgLabel.text = @"LinphoneRegistrationNone";
}
break;
case LinphoneRegistrationOk:{
self.msgLabel.text = @"LinphoneRegistrationOk";
}
break;
case LinphoneRegistrationFailed:{
self.msgLabel.text = @"LinphoneRegistrationFailed";
}
break;
case LinphoneRegistrationCleared:{
self.msgLabel.text = @"LinphoneRegistrationCleared";
}
break;
case LinphoneRegistrationProgress:{
self.msgLabel.text = @"LinphoneRegistrationProgress";
}
default:
break;
}
}
撥打電話:
#pragma mark - 撥打電話
- (void)callPhoneWithPhoneNumber:(NSString *)phone{
LinphoneAddress *addr = [LinphoneUtils normalizeSipOrPhoneAddress:phone];
[LinphoneManager.instance call:addr];
if (addr) {
linphone_address_unref(addr);
}
}
接聽電話:
LinphoneCall *call = linphone_core_get_current_call(LC);
if (call) {
[[LinphoneManager instance] acceptCall:call evenWithVideo:NO];
}
掛斷電話
LinphoneCall *call = linphone_core_get_current_call(LC);
if (call) {
linphone_call_terminate(call);
}
清除配置表
#pragma mark - 清除配置表, 切換賬號時會用到
- (void)clearProxyConfig {
linphone_core_clear_proxy_config([LinphoneManager getLc]);
linphone_core_clear_all_auth_info([LinphoneManager getLc]);
}
前前后后搗鼓Linphone也有一段時間, 苦于Linphone官網(wǎng)沒有標(biāo)準(zhǔn)的文檔, 也沒有最新的SDK說明, 只能網(wǎng)上大量查閱資料, 還有研究Linphone Demo, 才最終調(diào)通. 因此, 本人建了個QQ群, 群號: 578410849. 如有什么問題, 歡迎加群咨詢.