美文网首页iOSiOS DeveloperiOS Developer
怎样将Linphone移植到自己的项目

怎样将Linphone移植到自己的项目

作者: 树深不闻钟 | 来源:发表于2016-07-12 18:07 被阅读10524次

我自己集成的Demo & SDK源码路径

最新版SDK下载地址

开始前先安利下江湖哥简书,当初都是照着这一步步摸索的http://www.jianshu.com/p/2ba2d4aa168e


更新ipv6

见文末


正文开始。
很多场景下,我们的App会使用到VOIP通话,虽然目前各大通讯公司都推出了各自的SDK,相比Linphone,它们对开发者更为友好(体现在有更及时的技术支持、丰富的开发文档),但有些时候,迫于某些需求,也只有掏出Linphone SDK,硬着头皮上了。而我是为了实现纯SIP通话,以及客户需求,所以进行了对Linphone SDK的集成、开发,本文的目的一为记录以便日后翻阅,二为了让后来的开发者少跳一些坑,白白耽误时间。

首先我们要下载一个重要的Linphone Demo,需要CSDN的2积分,如果没有可以留言问我要。只能在真机上运行。

1. 准备工作

1.1 添加依赖库

为支持新版ipv6 SDK,需要再添加VideoToolBox.framework

1.2 相关配置
1.3 http请求设置

从iOS9开始,苹果建议所有的网络请求都要使用https,如果还想保留原有的http请求方式,开发者需要修改配置文件(注:xcode7.0以下则不需要修改),在工程名的文件夹下面的Supporting Files文件夹中找到并且选择(工程名)lnfo.pList在右边出现的窗口中添加Key:NSAppTransportSecurity,在下面添加项:NSAllowsArbitraryLoads,设置Boolean值为YES,这样平台SDK内部工程才能支持http请求方式。

1.4 后台运行

一般的iOS程序进入后台后会被系统挂起,就会停止执行,不能执行任何操作。

  • 从iOS4开始,苹果增加了特性,很好的支持了语音通话功能:

  • 苹果支持应用可以在后台播放和录制声音;

  • 苹果支持网络托管,保证应用在后台时,还能保持网络连接,能接收到来电;

  • 应用可以设置一个超时处理,程序在后台运行时,周期性地唤醒应用,保证客户端和服务器有长连接,使网络不断开。

  • SDK封装了这些特性,保证了在iOS平台上,有很好的语音通话体验。
    开发者需要修改配置文件,这样iOS工程才能支持这些特性。

在工程名的文件夹下面的Supporting Files文件夹中找到并且选择(工程名)lnfo.pList在右边出现的窗口中添加Key: Required background modes,在下面添加两个项:App plays audio和App provides Voice over IP services。(注:如果只是使用发起通话,并无接听功能,则不需要添加App provides Voice over IP services)

2. 导入Linphone SDK

上面工作做完后就可以开始导入Linphone SDK了。

2.1 首先再回到这个熟悉的页面,点击Add Other
2.2 找到下载好的sdk目录,把所有.a库都选择,如下图。

2.3 查看是否关联

Build Settings搜索 Search Paths,在下列两个选项下观察是否已经关联,如图


顺带说一下这个libxml2,大多数时候是不需要的,如果报一些莫名其妙的错误不妨将其导入,且在Build Phases里添加相应库libxml2.tbd

2.4 编译

如果出现了形如“file not found”的错误提示,回到第三步,检查头文件、静态库是否关联成功

3. 功能实现

这一部分可以参考CSDN Linphone Demo(以下统称为CDemo),也可以直接下载我在github代码里的SDK代码部分,更为直接。

3.1 初始化

需要关注CSDN Demo里的主要功能类LinphoneManage.m
实现如下方法即可

/**
 @author Jozo, 16-06-30 11:06:18
 
 初始化
 */
- (void)startUCSphone {
    
    [[LinphoneManager instance] startLibLinphone];
    [UCSIPCCSDKLog saveDemoLogInfo:@"初始化成功" withDetail:nil];
    
}
3.2 注册

注册方法在CDemo的manager类里没有直接的体现,值得注意的是我标注“三个大坑”的地方,如果有需要用到displayName这个参数的同学一定要注意了,设置好displayName后一定要通过linphone_address_as_string(..)方法再次获取identity,然后再调用linphone_proxy_config_set_identity(proxyCfg, identity);将新的identity设置到设置文件中,因为我开始没理清这个proxyCfg的实现逻辑,始终没注意到这一步,还有就是使用了另一个函数linphone_address_as_string_uri_only误导,是误导,后者获取到的仅有“sip:”以及之后的那个字符串,并不会将昵称也带进去传入proxyCfg,导致displayName一直设置不成功,掉坑三日终于在某个狂风乱作的下午解决此bug,导致天气都变得风和日丽起来。

注:以下账号、密码、IP、端口需要自己注册。

/**
 @author Jozo, 16-06-30 11:06:13
 
 登陆
 
 @param username  用户名
 @param password  密码
 @param displayName  昵称
 @param domain    域名或IP
 @param port      端口
 @param transport 连接方式

 */
- (BOOL)addProxyConfig:(NSString*)username password:(NSString*)password displayName:(NSString *)displayName domain:(NSString*)domain port:(NSString *)port withTransport:(NSString*)transport {
    LinphoneCore* lc = [LinphoneManager getLc];
    
    if (lc == nil) {
        [self startUCSphone];
        lc = [LinphoneManager getLc];
    }
    
    LinphoneProxyConfig* proxyCfg = linphone_core_create_proxy_config(lc);
    NSString* server_address = domain;
    
    char normalizedUserName[256];
    linphone_proxy_config_normalize_number(proxyCfg, [username cStringUsingEncoding:[NSString defaultCStringEncoding]], normalizedUserName, sizeof(normalizedUserName));
    
    
    const char *identity = [[NSString stringWithFormat:@"sip:%@@%@", username, domain] cStringUsingEncoding:NSUTF8StringEncoding];
    
    LinphoneAddress* linphoneAddress = linphone_address_new(identity);
    linphone_address_set_username(linphoneAddress, normalizedUserName);
    if (displayName && displayName.length != 0) {
        linphone_address_set_display_name(linphoneAddress, (displayName.length ? displayName.UTF8String : NULL));
    }
    if( domain && [domain length] != 0) {
        if( transport != nil ){
            server_address = [NSString stringWithFormat:@"%@:%@;transport=%@", server_address, port, [transport lowercaseString]];
        }
        // when the domain is specified (for external login), take it as the server address
        linphone_proxy_config_set_server_addr(proxyCfg, [server_address UTF8String]);
        linphone_address_set_domain(linphoneAddress, [domain UTF8String]);
        
    }
    
    // 添加了昵称后的identity(此处是大坑!大坑!大坑)
    identity = linphone_address_as_string(linphoneAddress);
    
    linphone_address_destroy(linphoneAddress);
    
    LinphoneAuthInfo* info = linphone_auth_info_new([username UTF8String]
                                                    , NULL, [password UTF8String]
                                                    , NULL
                                                    , linphone_proxy_config_get_realm(proxyCfg)
                                                    ,linphone_proxy_config_get_domain(proxyCfg));
    
    [self setDefaultSettings:proxyCfg];
    
    [self clearProxyConfig];
    
    linphone_proxy_config_set_identity(proxyCfg, identity);
    linphone_proxy_config_set_expires(proxyCfg, 2000);
    linphone_proxy_config_enable_register(proxyCfg, true);
    linphone_core_add_auth_info(lc, info);
    linphone_core_add_proxy_config(lc, proxyCfg);
    linphone_core_set_default_proxy_config(lc, proxyCfg);
    ms_free(identity);

    
    [UCSIPCCSDKLog saveDemoLogInfo:@"登陆信息配置成功" withDetail:[NSString stringWithFormat:@"username:%@,\npassword:%@,\ndisplayName:%@\ndomain:%@,\nport:%@\ntransport:%@", username, password, displayName, domain, port, transport]];
    

    
    return TRUE;
}

3.3 拨打电话

接着简单的调用如下方法即可进行SIP呼叫。`

[[LinphoneManager instance] call:address displayName:displayName transfer:transfer];

值得注意的是,呼叫状态、登陆状态的回调都是通过通知来传递的,所以要想获取这些回调,可以监听这些回调,具体通知名在LinphoneManager.h里,形如“kLinphoneCallUpdate”,也可以像我一样,在LinphoneManager.m的各个回调处,将相应的通知改为自己想要设置的代理方法,并设置好代理,可以看我在Github Demo里的LinphoneManager.m处如下方法里的实现。

- (void)onRegister:(LinphoneCore *)lc cfg:(LinphoneProxyConfig*) cfg state:(LinphoneRegistrationState) state message:(const char*) message;

- (void)onCall:(LinphoneCall*)call StateChanged:(LinphoneCallState)state withMessage:(const char *)message;

4. 为支持ipv 6而导入新版Linphone SDK

旧版SDK不支持ipv6,更后到新版后linphonecore.h增加了一个新的宏LINPHONE_DEPRECATED,有此标记表示该函数已弃用,而我由于只用到了SIP电话,故直接替换sdk后只报了如下错误,下面一一解决

4.1 替换LINPHONE_DEPRECATED标识的函数

弃用的函数都有对应的新函数,在注释里可以轻易找到

/**
 * @return the default proxy configuration, that is the one used to determine the current identity.
 * @deprecated Use linphone_core_get_default_proxy_config() instead.
**/
LINPHONE_PUBLIC LINPHONE_DEPRECATED int linphone_core_get_default_proxy(LinphoneCore *lc, LinphoneProxyConfig **config);

/**
 * @ingroup media_parameters
 * Get default call parameters reflecting current linphone core configuration
 * @param lc LinphoneCore object
 * @return  LinphoneCallParams
 * @deprecated use linphone_core_create_call_params()
 */
LINPHONE_PUBLIC LINPHONE_DEPRECATED LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *lc);

4.2 删除弃用库的初始化

在上图中提现为“_libmsilbc_init”, referenced from:..这是因为新版linphone sdk里lib文件夹里的.a库变动,有删有减少,而libmsilbc.a则被移除了,故要在LinphoneManager createLinphoneCore]里删除libmsilbc_init();

4.3 第三个bug是上两个错误所导致

解决1、2,自然也会解决3。
(后续貌似还有些许问题,待续)

基本就是这么多了,其实回想起来也不是特别复杂,只是初次上手时网路上没有太多资料文档,大多靠自己摸索,以及在少得可怜的博客中慢慢领悟也是挺辛酸的,希望大家少走弯路吧。

如有其它麻烦可以电邮我 ischenzht@gmail.com

That's all, thank you.

相关文章

网友评论

  • 不想解释而已:楼主,求一个linphone demo,多谢了🙏,544848135@qq.com
  • 0e847f384767:楼主 需要Linphone Demo 1546220208@qq.com
  • 烟雨寒弦:楼主代码能发一份吗?846369914@qq.com
  • fe08d739313f:我基于免费的starRTC做的。
  • 提点九路节度使:您好?我在移植linphone的过程中遇到了一个问题: 在wifi状况下,我拨出电话失败,4g下则正常,可以正确呼出电话,请问可能的原因出在哪里呢?谢谢
    b8693145cbdf:@提点九路节度使 你好,想问下,头文件引入都设置了,还是file not found的错误,能帮忙解决下吗
    提点九路节度使:@烟雨寒弦 发了
    烟雨寒弦:能要您的一份Demo?
  • zhi5ai:又是iOS的。。白高兴了
  • zhi5ai:通讯公司提供的SDK相比,选Linphone的特别需求是什么啊
  • SapientiaWind:请问有没有遇到 拨打之后挂断 重复多次后crash , 这个crash不是必现的.
  • 发哥_李:楼主知道linphone的URL Schemes吗?不胜感激
  • 44b811bc27de:“****” requires the following capabilities which are not supported by “onle”的 iPhone:

    App plays audio
    App provides Voice over IP services
    请问这是什么问题?
  • 8409687398b6:Github 上的是不是缺文件啊,下载下来的工程目录根本没有 libucsipccsdk.a......
    42f48b8dd7d1:我下的也是这样
  • 沧海珠:VoIP background mode is deprecated and no longer supported
    ==========
    iOS10,禁了网络电话后台保活,请问大侠该问题如何应对的?
  • 爱上程序元:lz,怎么集成到自己项目中
  • 早上好先生:你好,大神,请问能做双向录音功能吗
  • SoulmateA:你好,请问demo支持ipv6么?
    树深不闻钟:@SoulmateA 替换了之后有一切废弃的接口 要重新对接新的SDK
    SoulmateA:@偶尔鸣叫的丹丹龙 那么只需要替换demo中的旧的SDK就可以了吗?
    树深不闻钟:@SoulmateA git上的版本不支持,要支持ipv6要使用心得linphone SDK
  • 6375b290d12c:libmsilbc_init 被棄用,需要iLBC的話,怎么解决 :sob:
  • 大好河山_:版主您好,请问下在下载好linphone的sdk以后,按照您上面的配置,然后在将sdk拖入工程就OK了吗???求指点下,谢谢
  • zziazm:您好,我在github上clone了demo,IPCC_SDK里的文件是红的,我把他们删除了之后,从工程里面重新拖入后还是红的,怎么解决啊
    树深不闻钟:@c608 可以加群 34575224,都是做Linphone的交流下
    c608:@爱上程序元 你好,我git上下载的没有sdk,sdk就是红色的,能给我一份sdk吗,在此谢谢了,QQ:2302147668, 你可以加下我扣扣,大兄弟,看到你最近回复的是
    爱上程序元:我开始也是托,没用,后面是复制到该文件夹然后再拖进去就有用了
  • breezeWarm:4.1 是什么意思看不懂?? 这样替换?
    树深不闻钟:@春风暖意_ 你可以全局搜一下“ LINPHONE_DEPRECATED”,带有这个标识的函数就是已经弃用了的,然后这个函数的注释中也标明了对应的新函数,然后使用这个新函数进行替换就好
  • tongvstong:您好!我下载了您在GitHub上的程序,按照您给的教程把飘红文件重新添加,但是仍然报错,134个错,求帮助!!在线急等= =
    爱上程序元:我的也是134个错误怎么解决
    树深不闻钟:@tongvstong 可以加这个QQ群:345752242,linphone交流的
  • davidrivasro:您好,我无法下载Linphone会演示,你能帮助我吗?
  • zhoutao:版主,你的demo是不是不支持64位框架,是哪一个静态库没有做全
    树深不闻钟:@zhoutao 支持啊,不过sdk只支持真机的,不能模拟器
  • b3a610fd5c29:版主,我想下载Linphone Demo没有积分,请版主告知下您的github地址,正在研究linphone,感谢版主分享
    树深不闻钟:@XcodeGoGoGo 我的demo里目前还没有做视频通话相关的内容,但基本的流程和音频是一致的,可能细节上要自己把握
    b3a610fd5c29:@陈迟Jz 请问版主,您的demo里如何实现视频通话呢
    树深不闻钟:@XcodeGoGoGo https://github.com/chenzht/JZPhone

本文标题:怎样将Linphone移植到自己的项目

本文链接:https://www.haomeiwen.com/subject/kjksjttx.html