297 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			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);
 | 
						|
    }
 | 
						|
} |