Files
ofono-vendor-qti-radio-plugin/src/vendor_qti_ims_radio.c
2024-01-25 00:51:42 +08:00

297 lines
9.8 KiB
C

#include <ofono/log.h>
#include <gbinder.h>
#include <glib.h>
#include <gutil_idlepool.h>
#include <glib-object.h>
#include "vendor_qti_ims_radio.h"
#define DEFAULT_INTERFACE IMS_RADIO_INTERFACE_1_2
static const GBinderClientIfaceInfo ims_radio_iface_info[] = {
{IMS_RADIO_1_2, IMS_RADIO_1_2_REQ_LAST },
{IMS_RADIO_1_1, IMS_RADIO_1_1_REQ_LAST },
{IMS_RADIO_1_0, IMS_RADIO_1_0_REQ_LAST }
};
G_STATIC_ASSERT(G_N_ELEMENTS(ims_radio_iface_info) == IMS_RADIO_INTERFACE_COUNT);
static const char* const ims_radio_indication_ifaces[] = {
IMS_RADIO_INDICATION_1_2,
IMS_RADIO_INDICATION_1_1,
IMS_RADIO_INDICATION_1_0,
NULL
};
G_STATIC_ASSERT(G_N_ELEMENTS(ims_radio_indication_ifaces) == IMS_RADIO_INTERFACE_COUNT + 1);
static const char* const ims_radio_response_ifaces[] = {
IMS_RADIO_RESPONSE_1_2,
IMS_RADIO_RESPONSE_1_1,
IMS_RADIO_RESPONSE_1_0,
NULL
};
G_STATIC_ASSERT(G_N_ELEMENTS(ims_radio_response_ifaces) == IMS_RADIO_INTERFACE_COUNT + 1);
typedef struct ims_radio_interface_desc {
RADIO_INTERFACE version;
const char* radio_iface;
const char* const* ind_ifaces;
const char* const* resp_ifaces;
} ImsRadioInterfaceDesc;
#define IMS_RADIO_INTERFACE_INDEX(x) (IMS_RADIO_INTERFACE_COUNT - x - 1)
#define IMS_RADIO_INTERFACE_DESC(v) \
IMS_RADIO_INTERFACE_##v, IMS_RADIO_##v, \
ims_radio_indication_ifaces + IMS_RADIO_INTERFACE_INDEX(IMS_RADIO_INTERFACE_##v), \
ims_radio_response_ifaces + IMS_RADIO_INTERFACE_INDEX(IMS_RADIO_INTERFACE_##v)
static const ImsRadioInterfaceDesc ims_radio_interfaces[] = {
{ IMS_RADIO_INTERFACE_DESC(1_2) },
{ IMS_RADIO_INTERFACE_DESC(1_1) },
{ IMS_RADIO_INTERFACE_DESC(1_0) }
};
G_STATIC_ASSERT(G_N_ELEMENTS(ims_radio_interfaces) == IMS_RADIO_INTERFACE_COUNT);
typedef GObjectClass VendorQtiImsRadioClass;
struct qti_ims_radio {
GObject parent;
char* name;
GBinderClient* client;
GBinderRemoteObject* remote;
GBinderLocalObject* response;
GBinderLocalObject* indication;
GUtilIdlePool* idle;
GHashTable* table;
};
G_DEFINE_TYPE(VendorQtiImsRadio, qti_ims_radio, G_TYPE_OBJECT)
#define THIS_TYPE qti_ims_radio_get_type()
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, THIS_TYPE, VendorQtiImsRadio)
#define IS_THIS(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, THIS_TYPE)
#define PARENT_CLASS qti_ims_radio_parent_class
enum qti_ims_radio_signal {
SIGNAL_REG_STATE_CHANGED,
SIGNAL_INCOMING_SMS,
SIGNAL_SMS_STATUS_REPORT,
SIGNAL_CALL_RING,
SIGNAL_CALL_STATE_CHANGED,
SIGNAL_SUPP_SERVICE_NOTIFY,
SIGNAL_CONFERENCE_INFO,
SIGNAL_COUNT
};
#define SIGNAL_REG_STATE_CHANGED_NAME "qti-ims-radio-reg-state-changed"
#define SIGNAL_INCOMING_SMS_NAME "qti-ims-radio-incoming-sms"
#define SIGNAL_SMS_STATUS_REPORT_NAME "qti-ims-radio-sms-status-report"
#define SIGNAL_CALL_RING_NAME "qti-ims-radio-call-ring"
#define SIGNAL_CALL_STATE_CHANGED_NAME "qti-ims-radio-call-state-changed"
#define SIGNAL_SUPP_SERVICE_NOTIFY_NAME "qti-ims-radio-supp-service-notify"
#define SIGNAL_CONFERENCE_INFO_NAME "qti-ims-radio-conference-info"
static guint qti_ims_radio_signals[SIGNAL_COUNT] = { 0 };
/*==========================================================================*
* Internals
*==========================================================================*/
static
void
qti_ims_radio_finalize(
GObject* object)
{
VendorQtiImsRadio* self = THIS(object);
g_hash_table_unref(self->table);
gbinder_client_unref(self->client);
gutil_idle_pool_destroy(self->idle);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static void destroy_value(gpointer hash_data) {
//printf("destroy value:%s\n",hash_data);
//因为我这里的值是数组形式不是指针所以不用释放内存。我就直接清空吧
/* free(hash_data);
hash_data = NULL;*/
//memset(hash_data,0,sizeof(hash_data));
}
static
void
qti_ims_radio_init(
VendorQtiImsRadio* self)
{
self->idle = gutil_idle_pool_new();
self->table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_value);
}
static
void
qti_ims_radio_class_init(
VendorQtiImsRadioClass* klass)
{
G_OBJECT_CLASS(klass)->finalize = qti_ims_radio_finalize;
qti_ims_radio_signals[SIGNAL_REG_STATE_CHANGED] =
g_signal_new(SIGNAL_REG_STATE_CHANGED_NAME,
G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, 28LL);
qti_ims_radio_signals[SIGNAL_INCOMING_SMS] =
g_signal_new(SIGNAL_INCOMING_SMS_NAME,
G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 4, 64LL);
qti_ims_radio_signals[SIGNAL_SMS_STATUS_REPORT] =
g_signal_new(SIGNAL_SMS_STATUS_REPORT_NAME,
G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 4, 64LL);
qti_ims_radio_signals[SIGNAL_CALL_RING] =
g_signal_new(SIGNAL_CALL_RING_NAME,
G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
qti_ims_radio_signals[SIGNAL_CALL_STATE_CHANGED] =
g_signal_new(SIGNAL_CALL_STATE_CHANGED_NAME,
G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, 68LL);
qti_ims_radio_signals[SIGNAL_SUPP_SERVICE_NOTIFY] =
g_signal_new(SIGNAL_SUPP_SERVICE_NOTIFY_NAME,
G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, 68LL);
qti_ims_radio_signals[SIGNAL_CONFERENCE_INFO] =
g_signal_new(SIGNAL_CONFERENCE_INFO_NAME,
G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, 68LL);
}
/**
vendor_qti_ims_radio_registration_info
vendor_qti_ims_radio_get_reg_state_response
vendor_qti_ims_radio_send_ims_sms_response
vendor_qti_ims_radio_sip_result_response
vendor_qti_ims_radio_handle_supp_service_notification
vendor_qti_ims_radio_handle_call_state_changed
vendor_qti_ims_radio_handle_sms_status_report
vendor_qti_ims_radio_handle_incoming_ims_sms
*/
static
GBinderLocalReply*
vendor_qti_ims_radio_response(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
VendorQtiImsRadio* self = THIS(user_data);
const char* iface = gbinder_remote_request_interface(req);
if(gutil_strv_contains((const GStrV*)ims_radio_response_ifaces, iface)){
GBinderReader reader;
gbinder_remote_request_init_reader(req, &reader);
gint32 serial;
if (gbinder_reader_read_int32(&reader, &serial)) {
g_hash_table_lookup(self->table,serial);
}
*status = GBINDER_STATUS_OK;
}else{
GINFO("[%s] Unexpected %s %u", self->name,iface,code);
*status = GBINDER_STATUS_FAILED;
}
return NULL;
}
static
GBinderLocalReply*
vendor_qti_ims_radio_indication(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
VendorQtiImsRadio* self = THIS(user_data);
const char* iface = gbinder_remote_request_interface(req);
return NULL;
}
/*==========================================================================*
* API
*==========================================================================*/
VendorQtiImsRadio* vendor_qti_ims_radio_create(
GBinderServiceManager* sm,
GBinderRemoteObject* remote,
const char* dev,
const char* name,
const ImsRadioInterfaceDesc* desc)
{
VendorQtiImsRadio* self = g_object_new(THIS_TYPE, NULL);
GBinderLocalRequest* req;
GBinderWriter writer;
int status;
self->name = g_strdup(name);
self->client = gbinder_client_new2(remote, ims_radio_iface_info, G_N_ELEMENTS(ims_radio_iface_info));
self->response = gbinder_servicemanager_new_local_object2(sm, desc->resp_ifaces, vendor_qti_ims_radio_response, self);
self->indication = gbinder_servicemanager_new_local_object2(sm, desc->ind_ifaces, vendor_qti_ims_radio_indication, self);
/* IImsRadio::setCallback */
req = gbinder_client_new_request2(self->client,
IMS_RADIO_REQ_SET_CALLBACK);
gbinder_local_request_init_writer(req, &writer);
gbinder_writer_append_local_object(&writer, self->response);
gbinder_writer_append_local_object(&writer, self->indication);
// log
gbinder_remote_reply_unref(gbinder_client_transact_sync_reply(self->client,
IMS_RADIO_REQ_SET_CALLBACK, req, &status));
GINFO("setCallback %s status %d", self->name, status);
gbinder_local_request_unref(req);
return self;
}
VendorQtiImsRadio* vendor_qti_ims_radio_new_with_version(
const char* dev,
const char* name,
RADIO_INTERFACE max_version) /* Since 1.2.1 */
{
VendorQtiImsRadio* self = NULL;
GBinderServiceManager* sm = gbinder_servicemanager_new(dev);
if (sm) {
guint i;
for (i = 0; i < G_N_ELEMENTS(ims_radio_interfaces) && !self; i++) {
const ImsRadioInterfaceDesc* desc = ims_radio_interfaces + i;
if (desc->version <= max_version) {
char* fqname = g_strconcat(desc->radio_iface, "/", name, NULL);
GBinderRemoteObject* obj = gbinder_servicemanager_get_service_sync(sm, fqname, NULL);
if (obj) {
GINFO("Connected to %s", fqname);
self = vendor_qti_ims_radio_create(sm, obj, dev, name, desc);
}
g_free(fqname);
}
}
gbinder_servicemanager_unref(sm);
}
return self;
}
VendorQtiImsRadio* vendor_qti_ims_radio_new(const char* dev, const char* name)
{
return vendor_qti_ims_radio_new_with_version(dev, name, DEFAULT_INTERFACE);
}
VendorQtiImsRadio*
vendor_qti_ims_radio_ref(
VendorQtiImsRadio* self)
{
if (G_LIKELY(self)) {
g_object_ref(self);
}
return self;
}
void
vendor_qti_ims_radio_unref(
VendorQtiImsRadio* self)
{
if (G_LIKELY(self)) {
g_object_unref(self);
}
}