LinphoneLauncherActivity 是APP的入口组件,在这个组件里,它会启动LinphoneService这个后台服务,然后不断地判断这个后台服务是否已经启动完毕,如果已经启动完毕后,才让APP进入直接的功能组件LinphoneActivity。

LinphoneService是标准的android后台服务,这个后台服务非常的关键,它需要完成的工作包括以下的内容。加载APP需要使用的资源,启动LinphoneManager这个APP的全局管理器,LinphoneManager 这个全局管理器会一方面管理LinphoneService 的实例,另一方面管理LinphoneCore这个核心实例,同时生成目前需要处理的事件通知的LinphoneCoreListenerBase实例并注册到LinphoneCore这个核心实例的事件监听器中。目前的LinphoneCoreListenerBase 实例只监听callState,globalState,registrationState这三个事件。如果这个时候有电话呼入,那么callState事件触发,callState事件当中state会是LinphoneCall.State.IncomingReceived,APP需要切换到电话呼入的操作界面。registrationState这个事件反馈的是用户的SIP账号到SIP服务器的注册状态,是成功注册还是注册失败等。

LinphoneManager实现了LinphoneCoreListener, LinphoneChatMessage.LinphoneChatMessageListener这两个接口的部分方法,负责系统需要使用的资源的管理与初始化,管理着LinphoneCore的实例,负责了LinphoneCore的初始化和它的整个生命周期,同时又响应接收到文件消息与文件消息的响应,感觉它的整体职责是有点混乱的,可能作者开始是把它作为全局的统一资源管理器的,可是后来开发着开发着就什么东西都往里面放,就成了这样了。

LinphoneActivity是整个APP的核心界面组件,它采用了容器的结构模式来组织它所要包含的各个Fragment。它维护了一个专门用于存放各个Fragment实例的Fragment列表。它采用的布局文件是main.xml,针对手机与平板电脑分别做了一套布局文件,呵呵。这个布局文件主要是分为上下两个部分,然后上边部分主要是菜单与状态栏,下边那部分再分为两大个部分,一个部分是Fragment的容器,另一个部分是代表功能模块的TAB形式的工具栏。LinphoneActivity也会生成一个LinphoneCoreListenerBase的实例并注册到LinphoneCore这个核心实例的事件监听器中,它监听的事件是messageReceived(有用户给自己发信息,这个信息可能是文件也可能是文本),registrationState,callState。当有电话呼入的时候,这个时间当前的组件也会接收到这个事件,然后将界面切换到CallIncomingActivity这个界面组件。

CallIncomingActivity界面组件就是提供一个界面给用户选择接听还是挂断,并设置相关的接听参数。这个界面组件当中也生成一个LinphoneCoreListenerBase的实例并注册到LinphoneCore这个核心实例的事件监听器中,它监听的事件是callState,状态是State.CallEnd,这样在对方结束了电话呼入时好通知当前界面对方已经结束通话,不再呼入,那个APP应该结束当前界面,回到主界面状态。在CallIncomingActivity界面组件下,用户选择了接听电话,那么APP将切换到CallActivity这个界面组件下,同时判断当前用户是否接受视频电话,从而决定是视频通话,还是语音通话。

CallActivity这个界面组件是通话界面,这个界面组件当中也生成一个LinphoneCoreListenerBase的实例并注册到LinphoneCore这个核心实例的事件监听器中,它监听的事件是callState,callEncryptionChanged。callState会通知新的来电呼入,对方暂停通话,对方更新通话设置等相应的事件消息,发便当前界面针对这些消息作出相应的反馈。这个通话界面主要是控制两个Fragment的动态切换,一个是语音通话的CallAudioFragment,在这个Fragment里,用户可以启用不启用麦克风和摄像头等。同时还可以向新的用户发起电话呼叫,不过从目前的界面看是只允许当前用户向某一个用户进行通话的,如果再邀请一个用户进入通话的话,它是把上一个通话的用户设置为暂停通话状态,然后当前用户与多个用户通话的话,就是不断地切换当前通话的用户。另一个是视频通话的CallVideoFragment,这个Fragment主要是展现两个视频流的窗口,一个是当前用户自己的视频在界面的右下角,另一个是通话对方的视频。默认是展现CallVideoFragment,当用户点击CallVideoFragment这个界面的时候,又切换回CallAudioFragment,这样用户才能看到功能栏方便操作。

CallVideoFragment里有两个关键的SurfaceView,分别用户展现当前用户的视频和对方用户的视频。private SurfaceView mVideoView; 这个是对方用户的视频展现控件。private SurfaceView mCaptureView;这个是当前用户的视频展现控件。首先CallVideoFragment 会生成一个androidVideoWindowImpl的实例,这个实例再通过LinphoneManager.getLc().setVideoWindow(androidVideoWindowImpl)传入到linphone的核心当中,androidVideoWindowImpl的实例当中的相关事件监听器后续就能接收到内核的想着事件消息通知,从而将视频流传递到对应的SurfaceView当中,设置对方用户视频流到SurfaceView 当中的方法是LinphoneManager.getLc().setVideoWindow(vw),设置当前用户视频流到SurfaceView 当中的方法是LinphoneManager.getLc().setPreviewWindow(mCaptureView)。

DialerFragment界面组件,提供一个拨号的键盘,用来输入需要呼叫的SIP号码,然后进行呼叫。拨号呼叫调用的是LinphoneManager.getInstance().newOutgoingCall(mAddress)这个方法,传递的参数是对方的SIP号码或是SIP地址。newOutgoingCall这个方法里会先对当前使用的网络类型进行检测,用的是LinphoneUtils.isHighBandwidthConnection()方法。然后最终调用CallManager.inviteAddress()方法进行呼叫,这个方法最终又调用的LinphoneCore.inviteAddressWithParams(lAddress, params)方法进行呼叫。当LinphoneActivity 订阅的callState事件的state == State.OutgoingInit || state == State.OutgoingProgress的时候,APP界面组件切换到CallOutgoingActivity,由这个界面来展现正在呼出的状态。

CallOutgoingActivity这个界面组件,当中也生成一个LinphoneCoreListenerBase的实例并注册到LinphoneCore这个核心实例的事件监听器中,它监听的事件是callState,状态是State=Connected或是StreamsRunning的时候,说明对方接听成功,界面组件再切换回CallActivity,并显示是语音通话界面还是视频通话界面。

CallManager是专门用来进行电话呼叫的管理者类,专门负责对进行呼叫,或是对当前进行的呼叫进行参数设置的更新。

PreferencesListFragment和SettingsFragment界面组件是负责APP的参数设置,设置的参数非常的丰富,有账号,网络,音频,视频等。它们采用的是android框架自带的PreferenceScreen技术来建立整个参数设置的界面与功能,这样就省去了自己来做界面一个个实现相应的参数设置的功能。定义PreferenceScreen最关键的就是编写它对应的XML文件,这个XML文件编写好后,系统会根据它的内容来生成相应的设置界面,非常的方便,相应的技术点可以百度一下。一个PreferenceScreen里还可以嵌套多个PreferenceScreen,从而构建多层级的设置界面。系统里自带有多种类型的设置界面,如ListPreference,CheckBoxPreference等。但是这个PreferenceScreen它并不会保存相关的配置信息,所以这些配置参数的保存还是得由外部来进行保存,随后加载PreferenceScreen界面的时候,重新给里面的各个组件设置上相应的状态。目前在APP中是由LinphonePreferences这个类来负责了配置信息的保存的,而这个类又是依赖LpConfig这个具体负责读写配置文件的类来提供相应的功能,它真正的保存配置的文件是一个类似ini配置文件的文本文件,也就是讲linphone是自己实现的配置保存与读取功能,呵呵,没有用系统自带的,那我们也就沿用它的吧。默认的配置文件就在工程的res/raw下边,而PreferenceScreen配置文件就是在工程的res/xml下。

HistoryListFragment是呼入呼出历史列表的展现界面组件,这些呼入呼出的历史记录数据LinphoneCore是直接自己用数据记录下来了的,所以APP不需要考虑记录这些信息,除非需要自己定制地保存这些信息,不想用LinphoneCore的。通过LinphoneManager.getLc().getCallLogs()可以获得呼入呼出的历史记录。

LinphoneCore是整个linphone内核基于JNI的封装接口,LinphoneCoreImpl是linphone内核针对JAVA开发语言的封装。所有linphone内核的相关方法都是通过它来向android系统暴露。它里面有方法非常的多,这里需要关注几个关键的方法。

public void iterate();最为关键的主循环方法,应用程序应该经常调用它,因为它在后台会完成多件事情,如接收SIP指令,注册,认证,超时检测等,它必须要运行在LihpnoCore其它的方法所运行的线程里,说白了就是要保证LinphoneCore的方法运行在一至的线程里,不然就出错了。

public LinphoneCall invite(LinphoneAddress to)throws LinphoneCoreException;向对方发起一个电话呼叫请求。

public void terminateCall(LinphoneCall aCall);结束当前的电话呼叫。

public void declineCall(LinphoneCall call, Reason reason);直接挂断当前正在呼入的电话请求。

public LinphoneCall getCurrentCall();获取当前正在进行电话通话的实例。

public LinphoneAddress getRemoteAddress();获取当前通话下对方的SIP地址或是SIP电话号码。

public boolean isIncall();当前是不是处在通话状态下,这个通话要么在是进行的,也可能是暂停的,但没有挂断,还是连接着的。

public void acceptCall(LinphoneCall aCall) throws LinphoneCoreException;接收正在向自己电话呼入的通话。

public void acceptCallUpdate(LinphoneCall aCall, LinphoneCallParams params) throws LinphoneCoreException;接收通话的另一方对当前通话配置的修改,这样就能保证自己的通话配置与对方的一至。

public void deferCallUpdate(LinphoneCall aCall) throws LinphoneCoreException;拒绝通话的另一方对当前通话配置的修改,这样自己的通话配置就不会自动被修改了。

public LinphoneCallLog[] getCallLogs();获得通话日志列表。

public LinphoneCallLog getLastOutgoingCallLog();获得最近的通话日志列表。

public boolean isNetworkReachable();获取当前网络连接状态是否可连接。

void muteMic(boolean isMuted);禁用或是启用麦克风。

void enableAdaptiveRateControl(boolean enable);启用或禁用自适应速率控制,这个是根据网络带宽来自动调整传输速率的,小心慎用。

void enableEchoCancellation(boolean enable);启用或禁用语音的回声消除,这个是利用降噪的,echo limiter是回声门限。

void enableSpeaker(boolean value);启用或禁用扬声器。

void setVideoDevice(int id);设置某个摄像头为当前使用的摄像头。

int getVideoDevice();获取摄像头列表。

boolean isVideoSupported();检测客户是否支持视频通话

void enableVideo(boolean vcap_enabled, boolean display_enabled);启用或禁用视频,可以设置自己与对方视频的状态,但是如果通话已经建立正在通话中,那么调用这个方法是没有任何作用的,它必须在通话前调用。

int updateCall(LinphoneCall call, LinphoneCallParams params);修改已经建立的通话的状态,但是这个并不是能改通话的所有状态,针对视频在通话中的设置修改是无效的,如通话中不能修改视频的分辨率。

int getUploadBandwidth();获取最大上行网络带宽,单位是kbit/s.

void setUploadBandwidth(int bw);设置最大上行网络带宽,单位是kbit/s。

int getDownloadBandwidth();获取最大下行网络带宽,单位是kbit/s。

void setDownloadBandwidth(int bw);设置最大下行网络带宽,单位是kbit/s.

boolean pauseCall(LinphoneCall call);暂停当前的通话。

boolean resumeCall(LinphoneCall call);恢复当前的通话。

boolean pauseAllCalls();暂停全部当前的通话。

void terminateAllCalls();结束全部的通话。

LinphoneCall[] getCalls();获取当前的全部通话。

void transferCall(LinphoneCall call, String referTo);把当前与自己连接的通话转接到别的用户那里,自己的通话结束掉。

void transferCallToAnother(LinphoneCall callToTransfer, LinphoneCall destination);把当前的通话转接到另一个正在进行的通话当中。

void setPlayFile(String path);设置播放给对方听的音乐,通话还在呼入的状态下。

linphone-android-客户端APP-工程解读的更多相关文章

  1. android客户端app和服务端交互token的作用

    Android客户端和服务端如何使用Token和Session niceheart关注1人评论34644人阅读2014-09-16 16:38:44   对于初学者来说,对Token和Session的 ...

  2. 【原创】轻量级即时通讯技术MobileIMSDK:Android客户端开发指南

    申明:MobileIMSDK 目前为个人维护的原创开源工程,现陆续整理了一些资料,希望对需要的人有用.如需与作者交流,见文章底签名处,互相学习. MobileIMSDK开源工程的代码托管地址请进入 G ...

  3. 爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结

    本文由爱奇艺技术团队原创分享,原题<爱奇艺Android客户端启动优化与分析>. 1.引言 互联网领域里有个八秒定律,如果网页打开时间超过8秒,便会有超过70%的用户放弃等待,对Andro ...

  4. Android客户端性能优化(魅族资深工程师毫无保留奉献)

    本文由魅族科技有限公司资深Android开发工程师degao(嵌入式企鹅圈原创团队成员)撰写,是degao在嵌入式企鹅圈发表的第一篇原创文章,毫无保留地总结分享其在领导魅族多个项目开发中的Androi ...

  5. 微信Android客户端架构演进之路

    这是一个典型的Android应用在从小到大的成长过程中的“踩坑”与“填坑”的历史.互联网的变化速度如此之快,1年的时间里,可以发生翻天覆地的变化.今天在这里,重新和大家回顾微信客户端架构的演进过程,以 ...

  6. 转:微信Android客户端架构演进之路

    转自: http://www.infoq.com/cn/articles/wechat-android-app-architecture 微信Android客户端架构演进之路 作者 赵原 发布于 20 ...

  7. 接入新浪、腾讯微博和人人网的Android客户端实例 接入新浪、腾讯微博和人人网的Android客户端实例

    做了个Android项目,需要接入新浪微博,实现时也顺带着研究了下腾讯微博和人人网的Android客户端接入,本文就跟大家分享下三者的Android客户端接入方法. 一.实例概述 说白了,接入微博就是 ...

  8. 高仿优酷Android客户端图片左右滑动(自动切换)

    本例是用ViewPager去做的实现,支持自动滑动和手动滑动,不仅优酷网,实际上有很多商城和门户网站都有类似的实现: 具体思路: 1. 工程中需要添加android-support-v4.jar,才能 ...

  9. 用Jersey为Android客户端开发Restful Web Service

    平时在做Android客户端的时候经常要与服务器之间通信,客户端通过服务端提供的接口获取数据,然后再展示在客户端的界面上,作为Android开发者,我们平时更多的是关注客户端的开发,而对服务端开发的关 ...

  10. Android客户端和服务器端数据交互

    网上有很多例子来演示Android客户端和服务器端数据如何实现交互不过这些例子大多比较繁杂,对于初学者来说这是不利的,现在介绍几种代码简单.逻辑清晰的交互例子,本篇博客介绍第四种: 一.服务器端: 代 ...

随机推荐

  1. k-近邻算法实例

    1. 简单例子 步骤 1.1 计算已知点和被求点的距离 1.2 按距离递增排序 1.3 求出距离最近的前k个点的类别最大值作为目标分类 from numpy import * import opera ...

  2. 模板引擎(smarty)知识点总结II

    今天咱们继续来学习smarty!!! 知识点1:对于三种变量 常量的引用 有哪三种变量?a.assign赋值 b.系统保留变量(包括:$smarty.get,$smarty.post,$smarty. ...

  3. ES6 let和const命令(4)

    const声明的常量只在当前代码块有效.如果想设置跨模块的常量,可以采用下面的写法. //constants.js模块 export const A = 1; export const B = 3; ...

  4. Linux第九讲随笔 -进程管理 、ps aux 、

    Linux第九讲1,进程管理 Linux在执行每一个程序时,就会在内存中为这个程序建立一个进程,以便让内核可以管理这个运行中的进程,进程是系统分配各种资源,进程调度的基本单位. 怎么查看进程 一.ps ...

  5. Kotlin——最详细的抽象类(abstract)、内部类(嵌套类)详解

    如果您对Kotlin很有兴趣,或者很想学好这门语言,可以关注我的掘金,或者进入我的QQ群大家一起学习.进步. 欢迎各位大佬进群共同研究.探索QQ群号:497071402 进入正题 在前面几个章节中,详 ...

  6. centos7 部署 ELK 日志系统

    =============================================== 2017/12/24_第3次修改                       ccb_warlock 更 ...

  7. 从0到上线开发企业级电商项目_前端_01_sublime使用技巧

    一.用户设置 { "color_scheme": "Packages/Color Scheme - Default/Monokai.tmTheme", &quo ...

  8. windows10合并分区

    删除无用分区 将分区D合并到分区C,"计算机"---右键"管理"--"磁盘管理" 点击分区名,右键选择删除卷,如果有数据,提前备份 扩展分区 ...

  9. Head First设计模式之模板方法模式

    一.定义 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法结构的情况下,重定义该算法中的某些特定步骤. 比较通俗的说法,子类决定如何实现算法中的某些步骤,比如两个一连串 ...

  10. select超链接跳转A

    客户端页面 实现 下拉菜单 跳转链接 如图 遂使用 select option来展现.开始想到添加 a标签,结果,不行.渲染不出来 搜索查询得知 如下方法实现 ================== & ...