iOS 平台下Linphone的移植与使用
2020-03-02 本文已影响0人
133sheiya
背景
我想使用linphone的朋友都有下载官方的demo。但是里面真的是耦合度太高了。读了好多遍发现他控制器跳转的代码都是很旧的了,所以想把他功能给择出来是有一定的难度的。 我从网上找到ESSipManager
这个文件 。大家可以在github上搜索下。不过这个人封装的工程中引用的linphone
sdk比较旧了。好像官网上是把那个sdk删除了。所以下载下来会报错。我就是在他的基础上改了点东西。 感觉基本上可以实现常规的功能,所以分享给大家。
SDK的安装
目前SDK安装已经支持cocoaPods 所以在你原来的podfile代码里加上" pod 'linphone-sdk' , '4.3'
如果请求过程很慢的话 再把源指定下source "https://gitlab.linphone.org/BC/public/podspec.git"
使用
image.png image.png image.png//
// ESSipManager.m
// EasySip
// edit by ivna.evecom. 1361817133@qq.com
#import "ESSipManager.h"
#import "LinphoneManager.h"
#import "FastAddressBook.h"
#define LC ([LinphoneManager getLc])
NSString *const ES_ON_REMOTE_OPEN_CEMERA = @"ES_ON_REMOTE_OPEN_CEMERA";
NSString *const ES_ON_CALL_COMMING = @"ES_ON_CALL_COMMING";
NSString *const ES_ON_CALL_END = @"ES_ON_CALL_END";
NSString *const ES_ON_CALL_STREAM_UPDATE = @"ES_ON_CALL_STREAM_UPDATE";
NSString *const ES_ON_Call_StateOutgoingInit = @"ES_ON_CallStateOutgoingInit";
NSString *const ES_ON_REGISTER_STATE = @"ES_ON_REGISTER_STATE";
@implementation ESSipManager
static ESSipManager* _instance = nil;
+(instancetype) instance
{
static dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
_instance = [[super allocWithZone:NULL] init] ;
}) ;
return _instance ;
}
+(id)allocWithZone:(struct _NSZone *)zone
{
return [ESSipManager instance];
}
-(id)copyWithZone:(struct _NSZone *)zone
{
return [ESSipManager instance];
}
- (instancetype)init {
self = [super init];
if (self) {
[[LinphoneManager instance] startLinphoneCore];
LinphoneLoggingService * logService = linphone_logging_service_get();
linphone_logging_service_set_log_level(logService,LinphoneLogLevelFatal);
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onCallUpdate:) name:kLinphoneCallUpdate object:nil];
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(registrationUpdate:)
name:kLinphoneRegistrationUpdate
object:nil];
}
return self;
}
- (void)registrationUpdate:(NSNotification *)notif {
LinphoneRegistrationState state = [[notif.userInfo objectForKey:@"state"] intValue];
if (state == LinphoneRegistrationFailed &&
[UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
[[NSNotificationCenter defaultCenter]postNotificationName:ES_ON_REGISTER_STATE object:self userInfo:@{@"state":@"failed",@"message":[notif.userInfo objectForKey:@"message"]}];
} else if (state == LinphoneRegistrationOk) {
DLog(@"注册成功!");
[[NSNotificationCenter defaultCenter]postNotificationName:ES_ON_REGISTER_STATE object:self userInfo:@{@"state":@"success",@"message":[notif.userInfo objectForKey:@"message"]}];
}
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void) login: (NSString*) username password: (NSString*) password displayName: (NSString*) displayName domain: (NSString*) domain port: (NSString *) port withTransport: (NSString*) transport {
LinphoneProxyConfig *config = linphone_core_create_proxy_config(LC);
LinphoneAddress *addr = linphone_address_new(NULL);
LinphoneAddress *tmpAddr = linphone_address_new([NSString stringWithFormat:@"sip:%@",domain].UTF8String);
linphone_address_set_username(addr, username.UTF8String);
linphone_address_set_port(addr, linphone_address_get_port(tmpAddr));
linphone_address_set_domain(addr, linphone_address_get_domain(tmpAddr));
if (displayName && ![displayName isEqualToString:@""]) {
linphone_address_set_display_name(addr, displayName.UTF8String);
}
linphone_proxy_config_set_identity_address(config, addr);
if (transport) {
linphone_proxy_config_set_route(
config,
[NSString stringWithFormat:@"%s;transport=%s", domain.UTF8String, transport.lowercaseString.UTF8String]
.UTF8String);
linphone_proxy_config_set_server_addr(
config,
[NSString stringWithFormat:@"%s;transport=%s", domain.UTF8String, transport.lowercaseString.UTF8String]
.UTF8String);
}
linphone_proxy_config_enable_publish(config, FALSE);
linphone_proxy_config_enable_register(config, TRUE);
LinphoneAuthInfo *info =
linphone_auth_info_new(linphone_address_get_username(addr), // username
NULL, // user id
password.UTF8String, // passwd
NULL, // ha1
linphone_address_get_domain(addr), // realm - assumed to be domain
linphone_address_get_domain(addr) // domain
);
linphone_core_add_auth_info(LC, info);
linphone_address_unref(addr);
linphone_address_unref(tmpAddr);
LCSipTransports linp = {-1,-1,-1,-1};
//linphone_core_set_sip_transports
if (linphone_core_set_sip_transports(LC, &linp)) { //设置随机端口
}
if (config) {
[[LinphoneManager instance] configurePushTokenForProxyConfig:config];
if (linphone_core_add_proxy_config(LC, config) != -1) {
linphone_core_set_default_proxy_config(LC, config);
// reload address book to prepend proxy config domain to contacts' phone number
// todo: STOP doing that!
// [LinphoneManager instance]
// [[LinphoneManager.instance fastAddressBook] fetchContactsInBackGroundThread];
// [PhoneMainView.instance changeCurrentView:DialerView.compositeViewDescription];
} else {
// [self displayAssistantConfigurationError];
}
} else {
// [self displayAssistantConfigurationError];
}
NSLog(@"登陆信息配置成功!\nusername:%@,\npassword:%@,\ndisplayName:%@\ndomain:%@,\nport:%@\ntransport:%@", username, password, displayName, domain, port, transport);
}
- (void) logout {
[[LinphoneManager instance] lpConfigSetBool:FALSE forKey:@"pushnotification_preference"];
LinphoneCore *lc = [LinphoneManager getLc];
LCSipTransports transportValue = {5060,5060,-1,-1};
if (linphone_core_set_sip_transports(lc, &transportValue)) {
NSLog(@"cannot set transport");
}
[[LinphoneManager instance] lpConfigSetString:@"" forKey:@"sharing_server_preference"];
[[LinphoneManager instance] lpConfigSetBool:FALSE forKey:@"ice_preference"];
[[LinphoneManager instance] lpConfigSetString:@"" forKey:@"stun_preference"];
linphone_core_set_stun_server(lc, NULL);
linphone_core_set_firewall_policy(lc, LinphonePolicyNoFirewall);
// linphone_core_set_nat_policy()
// linphone_core_set_nat_policy(LC,&LinphonePolicyNoFirewall);
}
- (void) call: (NSString*) username displayName: (NSString*) displayName {
LinphoneCall *call = [[LinphoneManager instance] callByUsername:username];
if (call == nil) {
NSLog(@"拨打失败");
} else {
NSLog(@"正在拨叫...\naddress:%@,\ndisplayName:%@", username, displayName);
}
}
- (void) acceptCall: (LinphoneCall*) call {
[[LinphoneManager instance] acceptCall:call evenWithVideo:true];
NSLog(@"接听电话");
}
- (void) hangUpCall {
LinphoneCore* lc = [LinphoneManager getLc];
LinphoneCall* currentcall = linphone_core_get_current_call(lc);
if (linphone_core_is_in_conference(lc) || // In conference
(linphone_core_get_conference_size(lc) > 0) // Only one conf
) {
linphone_core_terminate_conference(lc);
} else if(currentcall != NULL) { // In a call
// linphone_core_terminate_call(lc, currentcall);
//linphone_call_terminate()
linphone_call_terminate(currentcall);
// linphone_core_terminate_all_calls(lc)
} else {
const MSList* calls = linphone_core_get_calls(lc);
//bctbx_list_size()
if (bctbx_list_size(calls) == 1) { // Only one call
// linphone_core_terminate_call(lc,(LinphoneCall*)(calls->data));
linphone_core_terminate_all_calls(lc);
}
}
NSLog(@"挂断");
}
- (void) configVideo: (UIView*) videoView cameraView: (UIView*) cameraView {
linphone_core_set_native_video_window_id([LinphoneManager getLc], (__bridge void *)(videoView));
linphone_core_set_native_preview_window_id([LinphoneManager getLc], (__bridge void *)(cameraView));
}
- (void) requestOpenCamera {
if (!linphone_core_video_display_enabled(LC)){
NSLog(@"1111");
return;
}
LinphoneCall *call = linphone_core_get_current_call(LC);
if (call) {
NSLog(@"2222");
LinphoneCallAppData *callAppData = (__bridge LinphoneCallAppData *)linphone_call_get_user_data(call);
callAppData->videoRequested = TRUE; /* will be used later to notify user if video was not activated because of the linphone core*/
LinphoneCallParams *call_params = linphone_core_create_call_params(LC,call);
linphone_call_params_enable_video(call_params, TRUE);
linphone_core_update_call(LC, call, call_params);
linphone_call_params_destroy(call_params);
} else {
NSLog(@"Cannot toggle video button, because no current call");
}
}
- (void) closeCamera {
if (!linphone_core_video_display_enabled(LC))
return;
[LinphoneManager.instance setSpeakerEnabled:FALSE];
LinphoneCall *call = linphone_core_get_current_call(LC);
if (call) {
LinphoneCallParams *call_params = linphone_core_create_call_params(LC,call);
linphone_call_params_enable_video(call_params, FALSE);
linphone_core_update_call(LC, call, call_params);
linphone_call_params_destroy(call_params);
} else {
NSLog(@"Cannot toggle video button, because no current call");
}
}
-(BOOL)isVideoEnabled{
bool video_enabled = false;
LinphoneCall *currentCall = linphone_core_get_current_call(LC);
if (linphone_core_video_supported(LC)) {
if (linphone_core_video_display_enabled(LC) && currentCall && !linphone_core_sound_resources_locked(LC) &&
linphone_call_get_state(currentCall) == LinphoneCallStreamsRunning) {
video_enabled = TRUE;
}
}
if (video_enabled) {
video_enabled = linphone_call_params_video_enabled(linphone_call_get_current_params(currentCall));
}
return video_enabled;
}
- (void) onCallUpdate: (NSNotification*) notification {
NSDictionary* userInfo = [notification userInfo];
NSValue* c = [userInfo valueForKey:@"call"];
// int state = (int)[userInfo valueForKey:@"state"];
LinphoneCallState state = [[userInfo objectForKey:@"state"] intValue];
NSString* message = [userInfo valueForKey:@"message"];
NSLog(@"========== state: %d, message: %@", state, message);
LinphoneCall* call = c.pointerValue;
NSDictionary *dict = @{@"call" : [NSValue valueWithPointer:call],
@"state" : [NSNumber numberWithInt:state],
@"message" : message};
switch (state) {
case LinphoneCallIncomingReceived:
[NSNotificationCenter.defaultCenter postNotificationName:ES_ON_CALL_COMMING object: self userInfo:dict];
case LinphoneCallOutgoingInit:
[NSNotificationCenter.defaultCenter postNotificationName:ES_ON_Call_StateOutgoingInit object:self userInfo:dict];
case LinphoneCallConnected:
case LinphoneCallStreamsRunning: {
// check video
if (![self isVideoEnabled]) {
const LinphoneCallParams *param = linphone_call_get_current_params(call);
const LinphoneCallAppData *callAppData =
(__bridge const LinphoneCallAppData *)(linphone_call_get_user_data(call));
if (state == LinphoneCallStreamsRunning && callAppData->videoRequested &&
linphone_call_params_low_bandwidth_enabled(param)) {
// too bad video was not enabled because low bandwidth
NSLog(@"带宽太低,无法开启视频通话");
callAppData->videoRequested = FALSE; /*reset field*/
}
}
[NSNotificationCenter.defaultCenter postNotificationName:ES_ON_CALL_STREAM_UPDATE object:self userInfo:dict];
break;
}
case LinphoneCallUpdatedByRemote: {
const LinphoneCallParams *current = linphone_call_get_current_params(call);
const LinphoneCallParams *remote = linphone_call_get_remote_params(call);
DLog(@"%d",(linphone_core_video_display_enabled([LinphoneManager getLc])));
DLog(@"%d",!linphone_call_params_video_enabled(current));
DLog(@"%d",linphone_call_params_video_enabled(remote));
DLog(@"%d",!linphone_core_get_video_policy([LinphoneManager getLc])->automatically_accept);
/* remote wants to add video */
if ((linphone_core_video_display_enabled([LinphoneManager getLc]) && !linphone_call_params_video_enabled(current) &&
linphone_call_params_video_enabled(remote)) &&
(!linphone_core_get_video_policy([LinphoneManager getLc])->automatically_accept ||
(([UIApplication sharedApplication].applicationState != UIApplicationStateActive) &&
floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max))) {
linphone_core_defer_call_update([LinphoneManager getLc], call);
[NSNotificationCenter.defaultCenter postNotificationName:ES_ON_REMOTE_OPEN_CEMERA object: self userInfo:dict];
} else if (linphone_call_params_video_enabled(current) && !linphone_call_params_video_enabled(remote)) {
}
break;
}
case LinphoneCallUpdating:
break;
case LinphoneCallPausing:
case LinphoneCallPaused:
break;
case LinphoneCallPausedByRemote:
break;
case LinphoneCallEnd://LinphoneCallEnd
[NSNotificationCenter.defaultCenter postNotificationName:ES_ON_CALL_END object: self userInfo:NULL];
case LinphoneCallError:
default:
break;
}
}
-(void) allowToOpenCameraByRemote: (LinphoneCall*)call {
LinphoneCallParams *params = linphone_core_create_call_params([LinphoneManager getLc], call);
linphone_call_params_enable_video(params, TRUE);
linphone_call_accept_update(call, params);
linphone_call_params_destroy(params);
}
-(void) refuseToOpenCameraByRemote: (LinphoneCall*)call {
LinphoneCallParams *params = linphone_core_create_call_params(LC, call);
linphone_call_params_enable_video(params, FALSE);
linphone_call_accept_update(call, params);
linphone_call_params_destroy(params);
}
-(void)switchCamera{
const char *currentCamId = (char *)linphone_core_get_video_device(LC);
const char **cameras = linphone_core_get_video_devices(LC);
const char *newCamId = NULL;
int i;
for (i = 0; cameras[i] != NULL; ++i) {
if (strcmp(cameras[i], "StaticImage: Static picture") == 0)
continue;
if (strcmp(cameras[i], currentCamId) != 0) {
newCamId = cameras[i];
break;
}
}
if (newCamId) {
// LOGI(@"Switching from [%s] to [%s]", currentCamId, newCamId);
linphone_core_set_video_device(LC, newCamId);
LinphoneCall *call = linphone_core_get_current_call(LC);
if (call != NULL) {
linphone_call_update(call, NULL);
}
}
}
-(BOOL)turnOnVideo{
if (!linphone_core_video_display_enabled(LC)){
DLog(@"执行到这里...");
return false;
}
LinphoneCall *call = linphone_core_get_current_call(LC);
if (call) {
LinphoneCallAppData *callAppData = (__bridge LinphoneCallAppData *)linphone_call_get_user_data(call);
callAppData->videoRequested =
TRUE; /* will be used later to notify user if video was not activated because of the linphone core*/
LinphoneCallParams *call_params = linphone_core_create_call_params(LC,call);
linphone_call_params_enable_video(call_params, TRUE);
linphone_call_update(call, call_params);
linphone_call_params_unref(call_params);
DLog(@"执行到这里...");
return true;
} else {
DLog(@"执行到这里...");
// LOGW(@"Cannot toggle video button, because no current call");
return false;
}
}
-(BOOL)turnOffVideo{
if (!linphone_core_video_display_enabled(LC))
return false;
[LinphoneManager.instance setSpeakerEnabled:FALSE];
// [self setEnabled:FALSE];
// [waitView startAnimating];
LinphoneCall *call = linphone_core_get_current_call(LC);
if (call) {
LinphoneCallParams *call_params = linphone_core_create_call_params(LC,call);
linphone_call_params_enable_video(call_params, FALSE);
linphone_core_update_call(LC, call, call_params);
linphone_call_params_destroy(call_params);
return true;
} else {
// LOGW(@"Cannot toggle video button, because no current call");
return false;
}
}
-(NSString*) getCallName: (LinphoneCall*)call {
if (call == NULL)
return NULL;
LinphoneAddress *addr = linphone_call_get_remote_address(call);
return [FastAddressBook displayNameForAddress:addr];
}
@end
如上图所示 每个方法都有介绍了。
注册 domin 填入你们自己的地址
func loginWithInfo(_ info:JSON){
let userInfo = info["userinfo"].stringValue
let dic = SimpleOperation.getDictionaryFromJSONString(jsonString:userInfo)
consoleLine(message: dic)
let videoPhone = dic["videophone"] as? String ?? ""
consoleLine(message: videoPhone)
let name = dic["name"] as? String ?? ""
ESSipManager.instance()?.login(videoPhone, password: "123456", displayName: name, domain: "", port: "5060", withTransport: "TCP")
}
func logOut(){
ESSipManager.instance()?.logout()
}
退出
func logOut(){
ESSipManager.instance()?.logout()
}
拨打电话
ESSipManager.instance()?.call(phone, displayName: name)
接听电话 注册一个通知 然后接听到之后 进行跳转
image.png最后.电脑端 下载一个Linphone 手机端运行下。俩端互拨 。慢慢调咯。祝各位好运。