Linphone callState 电话状态的监听状态
callState是一个观察者模式
接着上一篇的说, 这篇主要是涉及到linphone中c层的注册监听机制. 主要是代码追踪和代码过程.
linphonecore_jni.cc中的添加监听事件的方法
linphonecore_jni.cc中
extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addListener(JNIEnv* env, jobject thiz, jlong lc, jobject jlistener) {
LinphoneJavaBindings *ljb = (LinphoneJavaBindings *) linphone_core_get_user_data((LinphoneCore *)lc);
LinphoneCoreVTable *vTable = linphone_core_v_table_new();
LinphoneCoreData* ldata = new LinphoneCoreData(env, thiz, vTable, jlistener, ljb);
linphone_core_v_table_set_user_data(vTable, ldata);
linphone_core_add_listener((LinphoneCore*)lc, vTable);
}
LinphoneJavaBindings的代码及使用方法
说明
这个类绑定的是java类, 确定的是进行回调的监听机制.就是从c层回调至java层.
实现了LinphoneCoreListener中所有的方法.
代码
绑定了各种java的方法, 用于回调吧
class LinphoneJavaBindings {
public:
LinphoneJavaBindings(JNIEnv *env) {
listenerClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCoreListener"));
authMethodClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$AuthMethod"));
authMethodFromIntId = env->GetStaticMethodID(authMethodClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$AuthMethod;");
/*displayStatus(LinphoneCore lc,String message);*/
displayStatusId = env->GetMethodID(listenerClass,"displayStatus","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;)V");
/*void generalState(LinphoneCore lc,int state); */
globalStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$GlobalState"));
globalStateFromIntId = env->GetStaticMethodID(globalStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$GlobalState;");
globalStateId = env->GetMethodID(listenerClass,"globalState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$GlobalState;Ljava/lang/String;)V");
/*registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState cstate, String smessage);*/
registrationStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RegistrationState"));
registrationStateFromIntId = env->GetStaticMethodID(registrationStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RegistrationState;");
registrationStateId = env->GetMethodID(listenerClass,"registrationState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneProxyConfig;Lorg/linphone/core/LinphoneCore$RegistrationState;Ljava/lang/String;)V");
/*callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State cstate,String message);*/
callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State"));
callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;");
callStateId = env->GetMethodID(listenerClass,"callState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;Ljava/lang/String;)V");
transferStateId = env->GetMethodID(listenerClass,"transferState","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCall$State;)V");
/*callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);*/
callStatsUpdatedId = env->GetMethodID(listenerClass, "callStatsUpdated", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCallStats;)V");
/*callEncryption(LinphoneCore lc, LinphoneCall call, boolean encrypted,String auth_token);*/
callEncryptionChangedId = env->GetMethodID(listenerClass,"callEncryptionChanged","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;ZLjava/lang/String;)V");
/*void ecCalibrationStatus(LinphoneCore.EcCalibratorStatus status, int delay_ms, Object data);*/
ecCalibratorStatusClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$EcCalibratorStatus"));
ecCalibratorStatusFromIntId = env->GetStaticMethodID(ecCalibratorStatusClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;");
ecCalibrationStatusId = env->GetMethodID(listenerClass,"ecCalibrationStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$EcCalibratorStatus;ILjava/lang/Object;)V");
/*void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)*/
newSubscriptionRequestId = env->GetMethodID(listenerClass,"newSubscriptionRequest","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;Ljava/lang/String;)V");
authInfoRequestedId = env->GetMethodID(listenerClass,"authInfoRequested","(Lorg/linphone/core/LinphoneCore;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
authenticationRequestedId = env->GetMethodID(listenerClass,"authenticationRequested","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneAuthInfo;Lorg/linphone/core/LinphoneCore$AuthMethod;)V");
/*void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf);*/
notifyPresenceReceivedId = env->GetMethodID(listenerClass,"notifyPresenceReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneFriend;)V");
messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V");
messageReceivedUnableToDecryptedId = env->GetMethodID(listenerClass,"messageReceivedUnableToDecrypted","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V");
isComposingReceivedId = env->GetMethodID(listenerClass,"isComposingReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;)V");
dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V");
infoReceivedId = env->GetMethodID(listenerClass,"infoReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneInfoMessage;)V");
subscriptionStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/SubscriptionState"));
subscriptionStateFromIntId = env->GetStaticMethodID(subscriptionStateClass,"fromInt","(I)Lorg/linphone/core/SubscriptionState;");
subscriptionStateId = env->GetMethodID(listenerClass,"subscriptionStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/SubscriptionState;)V");
publishStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/PublishState"));
publishStateFromIntId = env->GetStaticMethodID(publishStateClass,"fromInt","(I)Lorg/linphone/core/PublishState;");
publishStateId = env->GetMethodID(listenerClass,"publishStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Lorg/linphone/core/PublishState;)V");
notifyRecvId = env->GetMethodID(listenerClass,"notifyReceived", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneEvent;Ljava/lang/String;Lorg/linphone/core/LinphoneContent;)V");
configuringStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$RemoteProvisioningState"));
configuringStateFromIntId = env->GetStaticMethodID(configuringStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;");
configuringStateId = env->GetMethodID(listenerClass,"configuringStatus","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$RemoteProvisioningState;Ljava/lang/String;)V");
fileTransferProgressIndicationId = env->GetMethodID(listenerClass, "fileTransferProgressIndication", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;I)V");
fileTransferSendId = env->GetMethodID(listenerClass, "fileTransferSend", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;Ljava/nio/ByteBuffer;I)I");
fileTransferRecvId = env->GetMethodID(listenerClass, "fileTransferRecv", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatMessage;Lorg/linphone/core/LinphoneContent;[BI)V");
logCollectionUploadStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCore$LogCollectionUploadState"));
logCollectionUploadStateFromIntId = env->GetStaticMethodID(logCollectionUploadStateClass, "fromInt", "(I)Lorg/linphone/core/LinphoneCore$LogCollectionUploadState;");
logCollectionUploadProgressId = env->GetMethodID(listenerClass, "uploadProgressIndication", "(Lorg/linphone/core/LinphoneCore;II)V");
logCollectionUploadStateId = env->GetMethodID(listenerClass, "uploadStateChanged", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCore$LogCollectionUploadState;Ljava/lang/String;)V");
}
}
创建
在linhonecore.c中
void *linphone_core_get_user_data(const LinphoneCore *lc){
return lc->data;
}
说明了具体的对象还是LinphoneCore中.
LinphoneCoreVTable的作用及代码
代码
/**
* This structure holds all callbacks that the application should implement.
* None is mandatory.
**/
typedef struct _LinphoneCoreVTable{
LinphoneCoreGlobalStateChangedCb global_state_changed; /**<Notifies global state changes*/
LinphoneCoreRegistrationStateChangedCb registration_state_changed;/**<Notifies registration state changes*/
LinphoneCoreCallStateChangedCb call_state_changed;/**<Notifies call state changes*/
LinphoneCoreNotifyPresenceReceivedCb notify_presence_received; /**< Notify received presence events*/
LinphoneCoreNotifyPresenceReceivedForUriOrTelCb notify_presence_received_for_uri_or_tel; /**< Notify received presence events*/
LinphoneCoreNewSubscriptionRequestedCb new_subscription_requested; /**< Notify about pending presence subscription request */
LINPHONE_DEPRECATED LinphoneCoreAuthInfoRequestedCb auth_info_requested; /**< @deprecated Use authentication_requested instead. Ask the application some authentication information */
LinphoneCoreAuthenticationRequestedCb authentication_requested; /**< Ask the application some authentication information */
LinphoneCoreCallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */
LinphoneCoreMessageReceivedCb message_received; /**< a message is received, can be text or external body*/
LinphoneCoreCbsMessageReceivedUnableDecryptCb message_received_unable_decrypt; /**< an encrypted message is received but we can't decrypt it*/
LinphoneCoreIsComposingReceivedCb is_composing_received; /**< An is-composing notification has been received */
LinphoneCoreDtmfReceivedCb dtmf_received; /**< A dtmf has been received received */
LinphoneCoreReferReceivedCb refer_received; /**< An out of call refer was received */
LinphoneCoreCallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
LinphoneCoreTransferStateChangedCb transfer_state_changed; /**<Notifies when a transfer is in progress */
LinphoneCoreBuddyInfoUpdatedCb buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
LinphoneCoreCallStatsUpdatedCb call_stats_updated; /**<Notifies on refreshing of call's statistics. */
LinphoneCoreInfoReceivedCb info_received; /**<Notifies an incoming informational message received.*/
LinphoneCoreSubscriptionStateChangedCb subscription_state_changed; /**<Notifies subscription state change */
LinphoneCoreNotifyReceivedCb notify_received; /**< Notifies a an event notification, see linphone_core_subscribe() */
LinphoneCorePublishStateChangedCb publish_state_changed;/**Notifies publish state change (only from #LinphoneEvent api)*/
LinphoneCoreConfiguringStatusCb configuring_status; /** Notifies configuring status changes */
LINPHONE_DEPRECATED DisplayStatusCb display_status; /**< @deprecated Callback that notifies various events with human readable text.*/
LINPHONE_DEPRECATED DisplayMessageCb display_message;/**< @deprecated Callback to display a message to the user */
LINPHONE_DEPRECATED DisplayMessageCb display_warning;/**< @deprecated Callback to display a warning to the user */
LINPHONE_DEPRECATED DisplayUrlCb display_url; /**< @deprecated */
LINPHONE_DEPRECATED ShowInterfaceCb show; /**< vNotifies the application that it should show up*/
LINPHONE_DEPRECATED LinphoneCoreTextMessageReceivedCb text_received; /**< @deprecated, use #message_received instead <br> A text message has been received */
LINPHONE_DEPRECATED LinphoneCoreFileTransferRecvCb file_transfer_recv; /**< @deprecated Callback to store file received attached to a #LinphoneChatMessage */
LINPHONE_DEPRECATED LinphoneCoreFileTransferSendCb file_transfer_send; /**< @deprecated Callback to collect file chunk to be sent for a #LinphoneChatMessage */
LINPHONE_DEPRECATED LinphoneCoreFileTransferProgressIndicationCb file_transfer_progress_indication; /**< @deprecated Callback to indicate file transfer progress */
LinphoneCoreNetworkReachableCb network_reachable; /**< Callback to report IP network status (I.E up/down )*/
LinphoneCoreLogCollectionUploadStateChangedCb log_collection_upload_state_changed; /**< Callback to upload collected logs */
LinphoneCoreLogCollectionUploadProgressIndicationCb log_collection_upload_progress_indication; /**< Callback to indicate log collection upload progress */
LinphoneCoreFriendListCreatedCb friend_list_created;
LinphoneCoreFriendListRemovedCb friend_list_removed;
void *user_data; /**<User data associated with the above callbacks */
} LinphoneCoreVTable;
说明
回调时应用的查询表. 创建内存空间后, 供下列函数使用.
创建
LinphoneCoreVTable *linphone_core_v_table_new() {
return ms_new0(LinphoneCoreVTable,1);
}
目的就是实例化一个table
class LinphoneCoreData的作用及代码
代码
LinphoneCoreData(JNIEnv *env, jobject lc, LinphoneCoreVTable *vTable, jobject alistener, LinphoneJavaBindings *ljb) {
core = env->NewGlobalRef(lc);
listener = env->NewGlobalRef(alistener);
memset(vTable, 0, sizeof(LinphoneCoreVTable));
if (ljb->displayStatusId) {
vTable->display_status = displayStatusCb;
}
if (ljb->globalStateId) {
vTable->global_state_changed = globalStateChange;
}
if (ljb->registrationStateId) {
vTable->registration_state_changed = registrationStateChange;
}
if (ljb->callStateId) {
vTable->call_state_changed = callStateChange;
}
if (ljb->transferStateId) {
vTable->transfer_state_changed = transferStateChanged;
}
if (ljb->callStatsUpdatedId) {
vTable->call_stats_updated = callStatsUpdated;
}
if (ljb->callEncryptionChangedId) {
vTable->call_encryption_changed = callEncryptionChange;
}
if (ljb->newSubscriptionRequestId) {
vTable->new_subscription_requested = new_subscription_requested;
}
if (ljb->authInfoRequestedId) {
vTable->auth_info_requested = authInfoRequested;
}
if (ljb->authenticationRequestedId) {
vTable->authentication_requested = authenticationRequested;
}
if (ljb->notifyPresenceReceivedId) {
vTable->notify_presence_received = notify_presence_received;
}
if (ljb->messageReceivedId) {
vTable->message_received = message_received;
}
if (ljb->messageReceivedUnableToDecryptedId) {
vTable->message_received_unable_decrypt = message_received_unable_decrypt;
}
if (ljb->isComposingReceivedId) {
vTable->is_composing_received = is_composing_received;
}
if (ljb->dtmfReceivedId) {
vTable->dtmf_received = dtmf_received;
}
if (ljb->infoReceivedId) {
vTable->info_received = infoReceived;
}
if (ljb->subscriptionStateId) {
vTable->subscription_state_changed = subscriptionStateChanged;
}
if (ljb->publishStateId) {
vTable->publish_state_changed = publishStateChanged;
}
if (ljb->notifyRecvId) {
vTable->notify_received = notifyReceived;
}
if (ljb->configuringStateId) {
vTable->configuring_status = configuringStatus;
}
if (ljb->fileTransferProgressIndicationId) {
vTable->file_transfer_progress_indication = fileTransferProgressIndication;
}
if (ljb->fileTransferSendId) {
vTable->file_transfer_send = fileTransferSend;
}
if (ljb->fileTransferRecvId) {
vTable->file_transfer_recv = fileTransferRecv;
}
if (ljb->logCollectionUploadProgressId) {
vTable->log_collection_upload_progress_indication = logCollectionUploadProgressIndication;
}
if (ljb->logCollectionUploadStateId) {
vTable->log_collection_upload_state_changed = logCollectionUploadStateChange;
}
if (ljb->friendListCreatedId) {
vTable->friend_list_created = friendListCreated;
}
if (ljb->friendListRemovedId) {
vTable->friend_list_removed = friendListRemoved;
}
}
说明
这是类是将VTable一一对应起来, 进行数据的操作. 通过调用相应的方法, 对上层java方法进行回调操作, 这里时ListenerCoreListener主要的操作实体类.
linphone_core_v_table_set_user_data()函数都干了什么
代码
void linphone_core_v_table_set_user_data(LinphoneCoreVTable *table, void *data) {
table->user_data = data;
}
说明
将数据赋值.
重点来了linphone_core_add_listener
代码
void linphone_core_add_listener(LinphoneCore *lc, LinphoneCoreVTable *vtable){
LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get());
_linphone_core_cbs_set_v_table(cbs, vtable, FALSE);
_linphone_core_add_callbacks(lc, cbs, FALSE);
linphone_core_cbs_unref(cbs);
}
说明
这个是真刀真枪的用道德时候了.
LinphoneCoreCbs
代码
struct _LinphoneCoreCbs {
belle_sip_object_t base;
LinphoneCoreVTable *vtable;
bool_t autorelease;
};
说明
这个路径好深啊, 我只能这么说了.
创建
linphone_factory_create_core_cbs()函数创建
LinphoneCore *linphone_factory_create_core(const LinphoneFactory *factory, LinphoneCoreCbs *cbs,
const char *config_path, const char *factory_config_path) {
LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path);
LinphoneCore *lc = _linphone_core_new_with_config(cbs, config, NULL);
lp_config_unref(config);
return lc;
}
东西很多,最后在找到了这个bctbx_list_append_link
bctbx_list_t *bctbx_list_append_link(bctbx_list_t *elem, bctbx_list_t *new_elem) {
bctbx_list_t *it = elem;
if (elem == NULL) return new_elem;
if (new_elem == NULL) return elem;
while (it->next != NULL) it = bctbx_list_next(it);
it->next = new_elem;
new_elem->prev = it;
return elem;
}
这个就是将监听时间添到了列表中.
但是什么时候回调的呢
关于这个问题, 我觉得应该会有很多地方调用. 但是总会有一个列表的, 猜测应该vtable.c中.
没错了,就应该是这个文件中.
会不会就是这个呢
#define NOTIFY_IF_EXIST_INTERNAL(function_name, internal_val, ...) \
bctbx_list_t* iterator; \
VTableReference *ref; \
lc->vtable_notify_recursion++;\
for (iterator=lc->vtable_refs; iterator!=NULL; iterator=iterator->next){\
if ((ref=(VTableReference*)iterator->data)->valid && (lc->current_cbs=ref->cbs)->vtable->function_name && (ref->internal == internal_val)) {\
lc->current_cbs->vtable->function_name(__VA_ARGS__);\
}\
}\
lc->vtable_notify_recursion--;
然后处理的方法应该在这里面
void linphone_core_notify_notify_received(LinphoneCore *lc, LinphoneEvent *lev, const char *notified_event, const LinphoneContent *body) {
NOTIFY_IF_EXIST_INTERNAL(notify_received, linphone_event_is_internal(lev), lc, lev, notified_event, body);
cleanup_dead_vtable_refs(lc);
}
void linphone_core_notify_subscription_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphoneSubscriptionState state) {
NOTIFY_IF_EXIST_INTERNAL(subscription_state_changed,linphone_event_is_internal(lev), lc,lev,state);
cleanup_dead_vtable_refs(lc);
}
void linphone_core_notify_publish_state_changed(LinphoneCore *lc, LinphoneEvent *lev, LinphonePublishState state) {
NOTIFY_IF_EXIST_INTERNAL(publish_state_changed, linphone_event_is_internal(lev), lc, lev, state);
cleanup_dead_vtable_refs(lc);
}