mirror of
https://gitlab.com/ubports/development/core/hybris-support/ofono-binder-plugin-ext-qti
synced 2025-11-03 20:45:53 +08:00
treewide: Inital call support (unstable)
This commit is contained in:
3
Makefile
3
Makefile
@@ -40,7 +40,8 @@ SRC = \
|
||||
qti_ims.c \
|
||||
qti_plugin.c \
|
||||
qti_slot.c \
|
||||
qti_radio_ext.c
|
||||
qti_radio_ext.c \
|
||||
qti_ims_call.c
|
||||
|
||||
#
|
||||
# Directories
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
#include <gbinder.h>
|
||||
|
||||
#define DBG(fmt, ...) \
|
||||
gutil_log(GLOG_MODULE_CURRENT, GLOG_LEVEL_ALWAYS, fmt, ##__VA_ARGS__)
|
||||
gutil_log(GLOG_MODULE_CURRENT, GLOG_LEVEL_ALWAYS, "ims:"fmt, ##__VA_ARGS__)
|
||||
|
||||
|
||||
typedef GObjectClass QtiImsClass;
|
||||
typedef struct qti_ims {
|
||||
@@ -118,6 +119,7 @@ void
|
||||
qti_ims_result_request_complete(
|
||||
QtiRadioExt* radio_ext,
|
||||
int result,
|
||||
GBinderReader* reader,
|
||||
void* user_data)
|
||||
{
|
||||
QtiImsResultRequest* req = user_data;
|
||||
@@ -169,6 +171,41 @@ qti_ims_reg_status_changed(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_reg_status_response(
|
||||
QtiRadioExt* radio_ext,
|
||||
int result,
|
||||
GBinderReader* reader,
|
||||
void* user_data)
|
||||
{
|
||||
DBG("qti_ims_reg_status_response");
|
||||
QtiImsResultRequest* req = user_data;
|
||||
|
||||
QTI_RADIO_REG_STATE state = QTI_RADIO_REG_STATE_INVALID;
|
||||
GBinderReader reader_copy;
|
||||
|
||||
gbinder_reader_copy(&reader_copy, reader);
|
||||
const QtiRadioRegInfo* info = qti_radio_ext_read_ims_reg_status_info(radio_ext, &reader_copy);
|
||||
|
||||
if (info) {
|
||||
state = info->state;
|
||||
}
|
||||
|
||||
const char *uri = info->uri.data.str ? info->uri.data.str : "";
|
||||
const char *error_msg = info->error_message.data.str ? info->error_message.data.str : "";
|
||||
DBG("%s: QtiRadioRegInfo response state:%d radiotech:%d"
|
||||
" error_code:%d\n"
|
||||
" uri:%s error_msg:%s",
|
||||
info->state,
|
||||
info->radio_tech,
|
||||
info->error_code,
|
||||
uri, error_msg);
|
||||
|
||||
qti_ims_reg_status_changed(radio_ext, state, req->ext);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* BinderExtImsInterface
|
||||
*==========================================================================*/
|
||||
@@ -250,6 +287,7 @@ qti_ims_iface_init(
|
||||
BinderExtImsInterface* iface)
|
||||
{
|
||||
iface->version = BINDER_EXT_IMS_INTERFACE_VERSION;
|
||||
iface->flags = BINDER_EXT_IMS_INTERFACE_FLAG_VOICE_SUPPORT;
|
||||
iface->get_state = qti_ims_get_state;
|
||||
iface->set_registration = qti_ims_set_registration;
|
||||
iface->cancel = qti_ims_cancel;
|
||||
@@ -273,11 +311,18 @@ qti_ims_new(
|
||||
*/
|
||||
self->slot = g_strdup(slot);
|
||||
self->radio_ext = qti_radio_ext_ref(radio_ext);
|
||||
self->ims_state = BINDER_EXT_IMS_STATE_NOT_REGISTERED;
|
||||
self->ims_state = BINDER_EXT_IMS_STATE_UNKNOWN;
|
||||
|
||||
if (self->radio_ext) {
|
||||
qti_radio_ext_add_ims_reg_status_handler(self->radio_ext,
|
||||
qti_ims_reg_status_changed, self);
|
||||
|
||||
// get updated state
|
||||
//QtiImsResultRequest* req = qti_ims_result_request_new(self,
|
||||
// complete, destroy, user_data);
|
||||
//qti_radio_ext_get_ims_reg_state(self->radio_ext,
|
||||
// qti_ims_reg_status_response,
|
||||
// qti_ims_result_request_destroy, NULL);
|
||||
}
|
||||
|
||||
return BINDER_EXT_IMS(self);
|
||||
|
||||
491
src/qti_ims_call.c
Normal file
491
src/qti_ims_call.c
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - binder based adaptation QTI plugin
|
||||
*
|
||||
* Copyright (C) 2022 Jolla Ltd.
|
||||
* Copyright (C) 2024 TheKit <thekit@disroot.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "qti_ims_call.h"
|
||||
#include "qti_radio_ext.h"
|
||||
#include "qti_radio_ext_types.h"
|
||||
|
||||
#include <binder_ext_call_impl.h>
|
||||
#include <gbinder.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
|
||||
#include <gutil_idlepool.h>
|
||||
#include <gutil_macros.h>
|
||||
#include <gutil_misc.h>
|
||||
#include <gutil_log.h>
|
||||
|
||||
#define DBG(fmt, ...) \
|
||||
gutil_log(GLOG_MODULE_CURRENT, GLOG_LEVEL_ALWAYS, "ims:"fmt, ##__VA_ARGS__)
|
||||
|
||||
typedef GObjectClass QtiImsCallClass;
|
||||
typedef struct qti_ims_call {
|
||||
GObject parent;
|
||||
GUtilIdlePool* pool;
|
||||
QtiRadioExt* radio_ext;
|
||||
GPtrArray* calls;
|
||||
GHashTable* id_map;
|
||||
} QtiImsCall;
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_iface_init(
|
||||
BinderExtCallInterface* iface);
|
||||
|
||||
GType qti_ims_call_get_type() G_GNUC_INTERNAL;
|
||||
G_DEFINE_TYPE_WITH_CODE(QtiImsCall, qti_ims_call, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE(BINDER_EXT_TYPE_CALL, qti_ims_call_iface_init))
|
||||
|
||||
#define THIS_TYPE qti_ims_call_get_type()
|
||||
#define THIS(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, THIS_TYPE, QtiImsCall)
|
||||
#define PARENT_CLASS qti_ims_call_parent_class
|
||||
|
||||
#define ID_KEY(id) GUINT_TO_POINTER(id)
|
||||
#define ID_VALUE(id) GUINT_TO_POINTER(id)
|
||||
|
||||
typedef struct qti_ims_call_result_request {
|
||||
int ref_count;
|
||||
guint id;
|
||||
guint id_mapped;
|
||||
guint param;
|
||||
BinderExtCall* ext;
|
||||
BinderExtCallResultFunc complete;
|
||||
GDestroyNotify destroy;
|
||||
void* user_data;
|
||||
} QtiImsCallResultRequest;
|
||||
|
||||
enum qti_ims_call_signal {
|
||||
SIGNAL_CALL_STATE_CHANGED,
|
||||
SIGNAL_CALL_END,
|
||||
SIGNAL_CALL_RING,
|
||||
SIGNAL_CALL_SUPP_SVC_NOTIFY,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_CALL_STATE_CHANGED_NAME "qti-ims-call-state-changed"
|
||||
#define SIGNAL_CALL_END_NAME "qti-ims-call-end"
|
||||
#define SIGNAL_CALL_RING_NAME "qti-ims-call-ring"
|
||||
#define SIGNAL_CALL_SUPP_SVC_NOTIFY_NAME "qti-ims-call-supp-svc-notify"
|
||||
|
||||
static guint qti_ims_call_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
static
|
||||
QtiImsCallResultRequest*
|
||||
qti_ims_call_result_request_new(
|
||||
BinderExtCall* ext,
|
||||
BinderExtCallResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
QtiImsCallResultRequest* req =
|
||||
g_slice_new0(QtiImsCallResultRequest);
|
||||
|
||||
req->ref_count = 1;
|
||||
req->ext = binder_ext_call_ref(ext);
|
||||
req->complete = complete;
|
||||
req->destroy = destroy;
|
||||
req->user_data = user_data;
|
||||
return req;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_result_request_free(
|
||||
QtiImsCallResultRequest* req)
|
||||
{
|
||||
BinderExtCall* ext = req->ext;
|
||||
|
||||
if (req->destroy) {
|
||||
req->destroy(req->user_data);
|
||||
}
|
||||
if (req->id_mapped) {
|
||||
g_hash_table_remove(THIS(ext)->id_map, ID_KEY(req->id_mapped));
|
||||
}
|
||||
binder_ext_call_unref(ext);
|
||||
gutil_slice_free(req);
|
||||
}
|
||||
|
||||
static
|
||||
gboolean
|
||||
qti_ims_call_result_request_unref(
|
||||
QtiImsCallResultRequest* req)
|
||||
{
|
||||
if (!--(req->ref_count)) {
|
||||
qti_ims_call_result_request_free(req);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_result_request_destroy(
|
||||
gpointer req)
|
||||
{
|
||||
qti_ims_call_result_request_unref(req);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* BinderExtCallInterface
|
||||
*==========================================================================*/
|
||||
|
||||
// find call by id
|
||||
static
|
||||
BinderExtCallInfo*
|
||||
qti_ims_call_info_find(
|
||||
QtiImsCall* self,
|
||||
guint call_id)
|
||||
{
|
||||
for (int i = 0; i < self->calls->len; i++) {
|
||||
BinderExtCallInfo* info =
|
||||
(BinderExtCallInfo*) g_ptr_array_index(self->calls, i);
|
||||
if (info->call_id == call_id) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_handle_call_info(
|
||||
QtiRadioExt* radio,
|
||||
GPtrArray* updated_calls,
|
||||
void* user_data)
|
||||
{
|
||||
QtiImsCall* self = THIS(user_data);
|
||||
|
||||
// loop over the updated calls
|
||||
for (int i = 0; i < updated_calls->len; i++) {
|
||||
BinderExtCallInfo* info = g_ptr_array_index(updated_calls, i);
|
||||
BinderExtCallInfo* call = qti_ims_call_info_find(self, info->call_id);
|
||||
|
||||
if (call->state == BINDER_EXT_CALL_STATE_END) {
|
||||
g_signal_emit(THIS(user_data),
|
||||
qti_ims_call_signals[SIGNAL_CALL_END], 0, call->call_id, "");
|
||||
|
||||
if (call)
|
||||
g_ptr_array_remove(self->calls, call);
|
||||
|
||||
continue;
|
||||
} else if (call) {
|
||||
// update the existing call
|
||||
call->state = info->state;
|
||||
} else {
|
||||
// add a new call
|
||||
g_ptr_array_add(self->calls, g_memdup(info, sizeof(BinderExtCallInfo)));
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_emit(THIS(user_data),
|
||||
qti_ims_call_signals[SIGNAL_CALL_STATE_CHANGED], 0);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
const BinderExtCallInfo* const*
|
||||
qti_ims_call_get_calls(
|
||||
BinderExtCall* ext)
|
||||
{
|
||||
static const BinderExtCallInfo* none = NULL;
|
||||
QtiImsCall* self = THIS(ext);
|
||||
|
||||
return self->calls->len ? (const BinderExtCallInfo**)self->calls->pdata : &none;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_result_response(
|
||||
QtiRadioExt* radio,
|
||||
int result,
|
||||
GBinderReader* reader,
|
||||
void* user_data)
|
||||
{
|
||||
QtiImsCallResultRequest* req = user_data;
|
||||
BinderExtCallResultFunc complete = req->complete;
|
||||
|
||||
if (complete) {
|
||||
complete(req->ext, result ? BINDER_EXT_CALL_RESULT_ERROR :
|
||||
BINDER_EXT_CALL_RESULT_OK, req->user_data);
|
||||
}
|
||||
|
||||
DBG("qti_ims_call_result_response %d", result);
|
||||
|
||||
qti_ims_call_result_request_unref(req);
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
qti_ims_call_dial(
|
||||
BinderExtCall* ext,
|
||||
const char* number,
|
||||
BINDER_EXT_TOA toa,
|
||||
BINDER_EXT_CALL_CLIR clir,
|
||||
BINDER_EXT_CALL_DIAL_FLAGS flags,
|
||||
BinderExtCallResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
QtiImsCall* self = THIS(ext);
|
||||
|
||||
QtiImsCallResultRequest* req = qti_ims_call_result_request_new(ext,
|
||||
complete, destroy, user_data);
|
||||
guint id = qti_radio_ext_dial(self->radio_ext, number, toa, clir, flags,
|
||||
qti_ims_call_result_response, qti_ims_call_result_request_destroy, req);
|
||||
|
||||
if (id) {
|
||||
req->id = id;
|
||||
req->id_mapped = id;
|
||||
g_hash_table_insert(self->id_map, ID_KEY(id), ID_VALUE(id));
|
||||
} else {
|
||||
qti_ims_call_result_request_free(req);
|
||||
}
|
||||
|
||||
DBG("Dialing return %d", id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
qti_ims_call_answer(
|
||||
BinderExtCall* ext,
|
||||
BINDER_EXT_CALL_ANSWER_FLAGS flags,
|
||||
BinderExtCallResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
DBG("answer is not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
qti_ims_call_swap(
|
||||
BinderExtCall* ext,
|
||||
BINDER_EXT_CALL_SWAP_FLAGS swap_flags,
|
||||
BINDER_EXT_CALL_ANSWER_FLAGS answer_flags,
|
||||
BinderExtCallResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
DBG("swap is not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
qti_ims_call_hangup(
|
||||
BinderExtCall* ext,
|
||||
guint call_id,
|
||||
BINDER_EXT_CALL_HANGUP_REASON reason,
|
||||
BINDER_EXT_CALL_HANGUP_FLAGS flags,
|
||||
BinderExtCallResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
DBG("hangup is not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
qti_ims_call_conference(
|
||||
BinderExtCall* ext,
|
||||
BINDER_EXT_CALL_CONFERENCE_FLAGS flags,
|
||||
BinderExtCallResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
DBG("conference is not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
guint
|
||||
qti_ims_call_send_dtmf(
|
||||
BinderExtCall* ext,
|
||||
const char* tones,
|
||||
BinderExtCallResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
DBG("send_dtmf is not implemented yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_cancel(
|
||||
BinderExtCall* ext,
|
||||
guint id)
|
||||
{
|
||||
QtiImsCall* self = THIS(ext);
|
||||
const guint mapped = GPOINTER_TO_UINT(g_hash_table_lookup(self->id_map,
|
||||
ID_KEY(id)));
|
||||
|
||||
qti_radio_ext_cancel(self->radio_ext, mapped ? mapped : id);
|
||||
}
|
||||
|
||||
static
|
||||
gulong
|
||||
qti_ims_call_add_calls_changed_handler(
|
||||
BinderExtCall* ext,
|
||||
BinderExtCallFunc cb,
|
||||
void* user_data)
|
||||
{
|
||||
return G_LIKELY(cb) ? g_signal_connect(THIS(ext),
|
||||
SIGNAL_CALL_STATE_CHANGED_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
static
|
||||
gulong
|
||||
qti_ims_call_add_disconnect_handler(
|
||||
BinderExtCall* ext,
|
||||
BinderExtCallDisconnectFunc cb,
|
||||
void* user_data)
|
||||
{
|
||||
return G_LIKELY(cb) ? g_signal_connect(THIS(ext),
|
||||
SIGNAL_CALL_END_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
static
|
||||
gulong
|
||||
qti_ims_call_add_ring_handler(
|
||||
BinderExtCall* ext,
|
||||
BinderExtCallFunc cb,
|
||||
void* user_data)
|
||||
{
|
||||
return G_LIKELY(cb) ? g_signal_connect(THIS(ext),
|
||||
SIGNAL_CALL_RING_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
static
|
||||
gulong
|
||||
qti_ims_call_add_ssn_handler(
|
||||
BinderExtCall* ext,
|
||||
BinderExtCallSuppSvcNotifyFunc cb,
|
||||
void* user_data)
|
||||
{
|
||||
return G_LIKELY(cb) ? g_signal_connect(THIS(ext),
|
||||
SIGNAL_CALL_SUPP_SVC_NOTIFY_NAME, G_CALLBACK(cb), user_data) : 0;
|
||||
}
|
||||
|
||||
void
|
||||
qti_ims_call_iface_init(
|
||||
BinderExtCallInterface* iface)
|
||||
{
|
||||
iface->flags |= BINDER_EXT_CALL_INTERFACE_FLAG_IMS_SUPPORT |
|
||||
BINDER_EXT_CALL_INTERFACE_FLAG_IMS_REQUIRED;
|
||||
iface->version = BINDER_EXT_CALL_INTERFACE_VERSION;
|
||||
iface->get_calls = qti_ims_call_get_calls;
|
||||
iface->dial = qti_ims_call_dial;
|
||||
iface->answer = qti_ims_call_answer;
|
||||
iface->swap = qti_ims_call_swap;
|
||||
iface->conference = qti_ims_call_conference;
|
||||
iface->send_dtmf = qti_ims_call_send_dtmf;
|
||||
iface->hangup = qti_ims_call_hangup;
|
||||
iface->cancel = qti_ims_call_cancel;
|
||||
iface->add_calls_changed_handler =
|
||||
qti_ims_call_add_calls_changed_handler;
|
||||
iface->add_disconnect_handler = qti_ims_call_add_disconnect_handler;
|
||||
iface->add_ring_handler = qti_ims_call_add_ring_handler;
|
||||
iface->add_ssn_handler = qti_ims_call_add_ssn_handler;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* API
|
||||
*==========================================================================*/
|
||||
|
||||
BinderExtCall*
|
||||
qti_ims_call_new(
|
||||
QtiRadioExt* radio_ext)
|
||||
{
|
||||
if (G_LIKELY(radio_ext)) {
|
||||
QtiImsCall* self = g_object_new(THIS_TYPE, NULL);
|
||||
|
||||
self->radio_ext = qti_radio_ext_ref(radio_ext);
|
||||
self->calls = g_ptr_array_new_with_free_func(g_free);
|
||||
|
||||
qti_radio_ext_add_call_state_handler(radio_ext,
|
||||
qti_ims_call_handle_call_info, self);
|
||||
|
||||
return BINDER_EXT_CALL(self);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internals
|
||||
*==========================================================================*/
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_finalize(
|
||||
GObject* object)
|
||||
{
|
||||
QtiImsCall* self = THIS(object);
|
||||
|
||||
qti_radio_ext_unref(self->radio_ext);
|
||||
gutil_idle_pool_destroy(self->pool);
|
||||
gutil_ptrv_free((void**)self->calls);
|
||||
g_hash_table_unref(self->id_map);
|
||||
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_init(
|
||||
QtiImsCall* self)
|
||||
{
|
||||
self->pool = gutil_idle_pool_new();
|
||||
self->id_map = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
qti_ims_call_class_init(
|
||||
QtiImsCallClass* klass)
|
||||
{
|
||||
GType type = G_OBJECT_CLASS_TYPE(klass);
|
||||
|
||||
G_OBJECT_CLASS(klass)->finalize = qti_ims_call_finalize;
|
||||
qti_ims_call_signals[SIGNAL_CALL_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_CALL_STATE_CHANGED_NAME, type,
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
qti_ims_call_signals[SIGNAL_CALL_END] =
|
||||
g_signal_new(SIGNAL_CALL_END_NAME, type,
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
|
||||
2, G_TYPE_INT, G_TYPE_INT);
|
||||
qti_ims_call_signals[SIGNAL_CALL_RING] =
|
||||
g_signal_new(SIGNAL_CALL_RING_NAME, type, G_SIGNAL_RUN_FIRST, 0,
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
qti_ims_call_signals[SIGNAL_CALL_SUPP_SVC_NOTIFY] =
|
||||
g_signal_new(SIGNAL_CALL_SUPP_SVC_NOTIFY_NAME, type,
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
|
||||
1, G_TYPE_POINTER);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
36
src/qti_ims_call.h
Normal file
36
src/qti_ims_call.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* oFono - Open Source Telephony - binder based adaptation QTI plugin
|
||||
*
|
||||
* Copyright (C) 2024 TheKit <thekit@disroot.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef QTI_IMS_CALL_H
|
||||
#define QTI_IMS_CALL_H
|
||||
|
||||
#include <binder_ext_call.h>
|
||||
|
||||
typedef struct qti_radio_ext QtiRadioExt;
|
||||
|
||||
BinderExtCall*
|
||||
qti_ims_call_new(
|
||||
QtiRadioExt* ims_radio)
|
||||
G_GNUC_INTERNAL;
|
||||
|
||||
#endif /* QTI_IMS_CALL_H */
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: C
|
||||
* c-basic-offset: 4
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <radio_types.h>
|
||||
#include <binder_ext_ims_impl.h>
|
||||
#include <binder_ext_call_impl.h>
|
||||
|
||||
#include <ofono/log.h>
|
||||
#include <gbinder.h>
|
||||
@@ -30,7 +31,7 @@
|
||||
#include <gutil_macros.h>
|
||||
|
||||
#define DBG(fmt, ...) \
|
||||
gutil_log(GLOG_MODULE_CURRENT, GLOG_LEVEL_ALWAYS, fmt, ##__VA_ARGS__)
|
||||
gutil_log(GLOG_MODULE_CURRENT, GLOG_LEVEL_ALWAYS, "ims:"fmt, ##__VA_ARGS__)
|
||||
|
||||
|
||||
#define QTI_RADIO_CALL_TIMEOUT (3*1000) /* ms */
|
||||
@@ -68,6 +69,7 @@ typedef void (*QtiRadioExtRequestHandlerFunc)(
|
||||
typedef void (*QtiRadioExtResultFunc)(
|
||||
QtiRadioExt* radio,
|
||||
int result,
|
||||
GBinderReader* reader,
|
||||
void* user_data);
|
||||
|
||||
struct qti_radio_ext_request {
|
||||
@@ -88,10 +90,12 @@ typedef struct qti_radio_ext_result_request {
|
||||
|
||||
enum qti_radio_ext_signal {
|
||||
SIGNAL_IMS_REG_STATUS_CHANGED,
|
||||
SIGNAL_EXT_CALL_STATE_CHANGED,
|
||||
SIGNAL_COUNT
|
||||
};
|
||||
|
||||
#define SIGNAL_IMS_REG_STATUS_CHANGED_NAME "qti-radio-ext-ims-reg-status-changed"
|
||||
#define SIGNAL_IMS_REG_STATUS_CHANGED_NAME "qti-radio-ext-ims-reg-status-changed"
|
||||
#define SIGNAL_EXT_CALL_STATE_CHANGED_NAME "qti-radio-ext-call-state-changed"
|
||||
|
||||
static guint qti_radio_ext_signals[SIGNAL_COUNT] = { 0 };
|
||||
|
||||
@@ -246,7 +250,6 @@ qti_radio_ext_dump_request(
|
||||
gutil_log_dump(log, level, " ", data, size);
|
||||
}
|
||||
|
||||
static
|
||||
const QtiRadioRegInfo*
|
||||
qti_radio_ext_read_ims_reg_status_info(
|
||||
QtiRadioExt* self,
|
||||
@@ -291,6 +294,103 @@ qti_radio_ext_handle_ims_reg_status_report(
|
||||
0, info->state);
|
||||
}
|
||||
|
||||
static
|
||||
BINDER_EXT_CALL_STATE
|
||||
qti_ims_call_radio_state_to_state(
|
||||
QTI_RADIO_CALL_STATE state)
|
||||
{
|
||||
switch (state) {
|
||||
case QTI_RADIO_CALL_STATE_INCOMING:
|
||||
return BINDER_EXT_CALL_STATE_INCOMING;
|
||||
case QTI_RADIO_CALL_STATE_ALERTING:
|
||||
return BINDER_EXT_CALL_STATE_ALERTING;
|
||||
case QTI_RADIO_CALL_STATE_HOLDING:
|
||||
return BINDER_EXT_CALL_STATE_HOLDING;
|
||||
case QTI_RADIO_CALL_STATE_WAITING:
|
||||
return BINDER_EXT_CALL_STATE_WAITING;
|
||||
case QTI_RADIO_CALL_STATE_ACTIVE:
|
||||
return BINDER_EXT_CALL_STATE_ACTIVE;
|
||||
case QTI_RADIO_CALL_STATE_END:
|
||||
return BINDER_EXT_CALL_STATE_END;
|
||||
case QTI_RADIO_CALL_STATE_DIALING:
|
||||
return BINDER_EXT_CALL_STATE_DIALING;
|
||||
default:
|
||||
return BINDER_EXT_CALL_STATE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
GPtrArray*
|
||||
qti_radio_ext_read_call_state_info(
|
||||
QtiRadioCallInfo* call_info_array,
|
||||
gsize count)
|
||||
{
|
||||
// array of QtiRadioCallInfo
|
||||
GPtrArray* call_ext_info_array = g_ptr_array_new_with_free_func(g_free);
|
||||
|
||||
for (gsize i = 0; i < count; i++) {
|
||||
QtiRadioCallInfo* call_info = &call_info_array[i];
|
||||
|
||||
const gsize total = G_ALIGN8(sizeof(BinderExtCallInfo)) +
|
||||
G_ALIGN8(call_info->number.len + 1) + G_ALIGN8(call_info->name.len + 1);
|
||||
BinderExtCallInfo* dest = g_malloc0(total);
|
||||
|
||||
char* ptr_number = ((char*)dest) + G_ALIGN8(sizeof(BinderExtCallInfo));
|
||||
char* ptr_name = ptr_number + G_ALIGN8(call_info->number.len + 1);
|
||||
|
||||
dest->call_id = call_info->index;
|
||||
dest->state = qti_ims_call_radio_state_to_state(call_info->state);
|
||||
dest->type = BINDER_EXT_CALL_TYPE_VOICE;
|
||||
dest->flags = BINDER_EXT_CALL_FLAG_IMS | BINDER_EXT_CALL_FLAG_INCOMING;
|
||||
|
||||
dest->number = ptr_number;
|
||||
dest->name = ptr_name;
|
||||
|
||||
memcpy(ptr_name, call_info->name.data.str, call_info->name.len);
|
||||
ptr_name += G_ALIGN8(call_info->name.len + 1);
|
||||
|
||||
memcpy(ptr_number, call_info->number.data.str, call_info->number.len);
|
||||
ptr_number += G_ALIGN8(call_info->number.len + 1);
|
||||
|
||||
g_ptr_array_add(call_ext_info_array, dest);
|
||||
|
||||
// print call_info
|
||||
const char* number = call_info->number.data.str ? call_info->number.data.str : "";
|
||||
const char* name = call_info->name.data.str ? call_info->name.data.str : "";
|
||||
DBG("callInfoIndication state:%d index:%d name:%s number:%s",
|
||||
call_info->state, call_info->index, name, number);
|
||||
|
||||
}
|
||||
|
||||
return call_ext_info_array;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
qti_radio_ext_handle_call_state_indication(
|
||||
QtiRadioExt* self,
|
||||
const GBinderReader* args)
|
||||
{
|
||||
/* callInfoIndication(vec<CallInfo> callList) */
|
||||
QtiRadioCallInfo* call_infos;
|
||||
GBinderReader reader;
|
||||
gsize count;
|
||||
|
||||
gbinder_reader_copy(&reader, args);
|
||||
call_infos = gbinder_reader_read_hidl_type_vec(&reader, QtiRadioCallInfo, &count);
|
||||
|
||||
if (call_infos) {
|
||||
GPtrArray* call_info_ptr = qti_radio_ext_read_call_state_info(call_infos, count);
|
||||
|
||||
g_signal_emit(self, qti_radio_ext_signals[SIGNAL_EXT_CALL_STATE_CHANGED],
|
||||
0, call_info_ptr);
|
||||
|
||||
g_free(call_infos);
|
||||
} else {
|
||||
DBG("%s: failed to parse call state data", self->slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
@@ -315,6 +415,9 @@ qti_radio_ext_indication(
|
||||
case QTI_RADIO_IND_REG_STATE_INDICATION:
|
||||
qti_radio_ext_handle_ims_reg_status_report(self, &args);
|
||||
return NULL;
|
||||
case QTI_RADIO_IND_CALL_STATE_INDICATION:
|
||||
qti_radio_ext_handle_call_state_indication(self, &args);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,6 +435,16 @@ qti_radio_ext_add_ims_reg_status_handler(
|
||||
SIGNAL_IMS_REG_STATUS_CHANGED_NAME, G_CALLBACK(handler), user_data) : 0;
|
||||
}
|
||||
|
||||
gulong
|
||||
qti_radio_ext_add_call_state_handler(
|
||||
QtiRadioExt* self,
|
||||
QtiRadioExtCallStateFunc handler,
|
||||
void* user_data)
|
||||
{
|
||||
return (G_LIKELY(self) && G_LIKELY(handler)) ? g_signal_connect(self,
|
||||
SIGNAL_EXT_CALL_STATE_CHANGED_NAME, G_CALLBACK(handler), user_data) : 0;
|
||||
}
|
||||
|
||||
static
|
||||
GBinderLocalReply*
|
||||
qti_radio_ext_response(
|
||||
@@ -391,7 +504,7 @@ qti_radio_ext_result_response(
|
||||
result = -1;
|
||||
}
|
||||
if (result_req->complete) {
|
||||
result_req->complete(self, result, req->user_data);
|
||||
result_req->complete(self, result, args, req->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,6 +600,17 @@ qti_radio_ext_call(
|
||||
GBINDER_TX_FLAG_ONEWAY, req, reply, destroy, user_data);
|
||||
}
|
||||
|
||||
void
|
||||
qti_radio_ext_cancel(
|
||||
QtiRadioExt* self,
|
||||
guint id)
|
||||
{
|
||||
if (G_LIKELY(self) && G_LIKELY(id)) {
|
||||
g_hash_table_remove(self->requests, KEY(id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
gulong
|
||||
qti_radio_ext_submit_request(
|
||||
@@ -542,6 +666,7 @@ qti_radio_ext_result_request_submit(
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
QtiRadioExt*
|
||||
qti_radio_ext_create(
|
||||
@@ -674,6 +799,269 @@ qti_radio_ext_set_reg_state(
|
||||
reg_state);
|
||||
}
|
||||
|
||||
/* From ofono-binder-plugin's binder-util.c */
|
||||
static
|
||||
void
|
||||
binder_copy_hidl_string(
|
||||
GBinderWriter* writer,
|
||||
GBinderHidlString* dest,
|
||||
const char* src)
|
||||
{
|
||||
gssize len = src ? strlen(src) : 0;
|
||||
dest->owns_buffer = TRUE;
|
||||
if (len > 0) {
|
||||
/* GBinderWriter takes ownership of the string contents */
|
||||
dest->len = (guint32) len;
|
||||
dest->data.str = gbinder_writer_memdup(writer, src, len + 1);
|
||||
} else {
|
||||
/* Replace NULL strings with empty strings */
|
||||
dest->data.str = "";
|
||||
dest->len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
binder_append_hidl_string_with_parent(
|
||||
GBinderWriter* writer,
|
||||
const GBinderHidlString* str,
|
||||
guint32 index,
|
||||
guint32 offset)
|
||||
{
|
||||
GBinderParent parent;
|
||||
|
||||
parent.index = index;
|
||||
parent.offset = offset;
|
||||
|
||||
/* Strings are NULL-terminated, hence len + 1 */
|
||||
gbinder_writer_append_buffer_object_with_parent(writer, str->data.str,
|
||||
str->len + 1, &parent);
|
||||
}
|
||||
|
||||
#define binder_append_hidl_string_data(writer,ptr,field,index) \
|
||||
binder_append_hidl_string_with_parent(writer, &ptr->field, index, \
|
||||
((guint8*)(&ptr->field) - (guint8*)ptr))
|
||||
|
||||
static
|
||||
void
|
||||
binder_append_hidl_vec_with_parent(
|
||||
GBinderWriter* writer,
|
||||
const GBinderHidlVec* vec,
|
||||
guint32 index,
|
||||
guint32 offset)
|
||||
{
|
||||
GBinderParent parent;
|
||||
|
||||
parent.index = index;
|
||||
parent.offset = offset;
|
||||
|
||||
gbinder_writer_append_buffer_object_with_parent(writer, vec->data.ptr,
|
||||
vec->count, &parent);
|
||||
}
|
||||
|
||||
#define binder_append_hidl_vec_data(writer,ptr,field,index) \
|
||||
binder_append_hidl_vec_with_parent(writer, &ptr->field, index, \
|
||||
((guint8*)(&ptr->field) - (guint8*)ptr))
|
||||
|
||||
#define CLIR_DEFAULT 0 // "use subscription default value"
|
||||
#define CLIR_INVOCATION 1 // (restrict CLI presentation)
|
||||
#define CLIR_SUPPRESSION 2 // (allow CLI presentation)
|
||||
|
||||
|
||||
static const GBinderWriterField qti_radio_dial_request_f[] = {
|
||||
GBINDER_WRITER_FIELD_HIDL_STRING
|
||||
(QtiRadioDialRequest, address),
|
||||
GBINDER_WRITER_FIELD_HIDL_VEC_BYTE
|
||||
(QtiRadioDialRequest, call_details.extras),
|
||||
GBINDER_WRITER_FIELD_HIDL_VEC_BYTE
|
||||
(QtiRadioDialRequest, call_details.local_ability),
|
||||
GBINDER_WRITER_FIELD_HIDL_VEC_BYTE
|
||||
(QtiRadioDialRequest, call_details.peer_ability),
|
||||
GBINDER_WRITER_FIELD_HIDL_STRING
|
||||
(QtiRadioDialRequest, call_details.sip_alternate_uri),
|
||||
GBINDER_WRITER_FIELD_END()
|
||||
};
|
||||
static const GBinderWriterType qti_radio_dial_request_t = {
|
||||
GBINDER_WRITER_STRUCT_NAME_AND_SIZE(QtiRadioDialRequest),
|
||||
qti_radio_dial_request_f
|
||||
};
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
qti_radio_ext_dial_args(
|
||||
GBinderWriter* args,
|
||||
va_list va)
|
||||
{
|
||||
QtiRadioDialRequest* dial_request_writer;
|
||||
|
||||
const char* number = va_arg(va, const char*);
|
||||
gint32 clir = va_arg(va, gint32);
|
||||
|
||||
dial_request_writer = gbinder_writer_new0(args, QtiRadioDialRequest);
|
||||
|
||||
GBinderHidlVec* empty_vec1 = gbinder_writer_new0(args, GBinderHidlVec);
|
||||
GBinderHidlVec* empty_vec2 = gbinder_writer_new0(args, GBinderHidlVec);
|
||||
GBinderHidlVec* empty_vec3 = gbinder_writer_new0(args, GBinderHidlVec);
|
||||
|
||||
dial_request_writer->clir_mode = clir;
|
||||
switch (clir)
|
||||
{
|
||||
case CLIR_SUPPRESSION:
|
||||
dial_request_writer->presentation = QTI_RADIO_IP_PRESENTATION_NUM_RESTRICTED;
|
||||
break;
|
||||
default:
|
||||
dial_request_writer->presentation = QTI_RADIO_IP_PRESENTATION_NUM_ALLOWED;
|
||||
break;
|
||||
}
|
||||
dial_request_writer->call_details.call_type = QTI_RADIO_CALL_TYPE_VOICE;
|
||||
dial_request_writer->call_details.call_domain = QTI_RADIO_CALL_DOMAIN_CS;
|
||||
dial_request_writer->call_details.extras_length = 0;
|
||||
dial_request_writer->call_details.extras.count = 0;
|
||||
dial_request_writer->call_details.extras.data.ptr = empty_vec1;
|
||||
dial_request_writer->call_details.extras.owns_buffer = TRUE;
|
||||
dial_request_writer->call_details.local_ability.count = 0;
|
||||
dial_request_writer->call_details.local_ability.data.ptr = empty_vec2;
|
||||
dial_request_writer->call_details.local_ability.owns_buffer = TRUE;
|
||||
dial_request_writer->call_details.peer_ability.count = 0;
|
||||
dial_request_writer->call_details.peer_ability.data.ptr = empty_vec3;
|
||||
dial_request_writer->call_details.peer_ability.owns_buffer = TRUE;
|
||||
|
||||
dial_request_writer->call_details.call_substate = 0; // none
|
||||
dial_request_writer->call_details.media_id = -1; // unknown
|
||||
dial_request_writer->call_details.cause_code = 0; // none
|
||||
dial_request_writer->call_details.rtt_mode = 0;
|
||||
|
||||
binder_copy_hidl_string(args, &dial_request_writer->address, number);
|
||||
binder_copy_hidl_string(args, &dial_request_writer->call_details.sip_alternate_uri, NULL);
|
||||
|
||||
gbinder_writer_append_struct(&args, dial_request_writer,
|
||||
&qti_radio_dial_request_t, NULL);
|
||||
|
||||
DBG("Dialing in args New %s", number);
|
||||
}
|
||||
|
||||
/*
|
||||
// dail
|
||||
static
|
||||
void
|
||||
qti_radio_ext_dial_args(
|
||||
GBinderWriter* args,
|
||||
va_list va)
|
||||
{
|
||||
GBinderParent parent;
|
||||
QtiRadioDialRequest* dial_request_writer;
|
||||
|
||||
const char* number = va_arg(va, const char*);
|
||||
gint32 clir = va_arg(va, gint32);
|
||||
|
||||
dial_request_writer = gbinder_writer_new0(args, QtiRadioDialRequest);
|
||||
|
||||
GBinderHidlVec* empty_vec1 = gbinder_writer_new0(args, GBinderHidlVec);
|
||||
GBinderHidlVec* empty_vec2 = gbinder_writer_new0(args, GBinderHidlVec);
|
||||
GBinderHidlVec* empty_vec3 = gbinder_writer_new0(args, GBinderHidlVec);
|
||||
|
||||
dial_request_writer->clir_mode = clir;
|
||||
switch (clir)
|
||||
{
|
||||
case CLIR_SUPPRESSION:
|
||||
dial_request_writer->presentation = QTI_RADIO_IP_PRESENTATION_NUM_RESTRICTED;
|
||||
break;
|
||||
default:
|
||||
dial_request_writer->presentation = QTI_RADIO_IP_PRESENTATION_NUM_ALLOWED;
|
||||
break;
|
||||
}
|
||||
dial_request_writer->call_details.call_type = QTI_RADIO_CALL_TYPE_VOICE;
|
||||
dial_request_writer->call_details.call_domain = QTI_RADIO_CALL_DOMAIN_CS;
|
||||
dial_request_writer->call_details.extras_length = 0;
|
||||
dial_request_writer->call_details.extras.count = 0;
|
||||
dial_request_writer->call_details.extras.data.ptr = empty_vec1;
|
||||
dial_request_writer->call_details.extras.owns_buffer = TRUE;
|
||||
dial_request_writer->call_details.local_ability.count = 0;
|
||||
dial_request_writer->call_details.local_ability.data.ptr = empty_vec2;
|
||||
dial_request_writer->call_details.local_ability.owns_buffer = TRUE;
|
||||
dial_request_writer->call_details.peer_ability.count = 0;
|
||||
dial_request_writer->call_details.peer_ability.data.ptr = empty_vec3;
|
||||
dial_request_writer->call_details.peer_ability.owns_buffer = TRUE;
|
||||
|
||||
dial_request_writer->call_details.call_substate = 0; // none
|
||||
dial_request_writer->call_details.media_id = -1; // unknown
|
||||
dial_request_writer->call_details.cause_code = 0; // none
|
||||
dial_request_writer->call_details.rtt_mode = 0;
|
||||
|
||||
binder_copy_hidl_string(args, &dial_request_writer->address, number);
|
||||
binder_copy_hidl_string(args, &dial_request_writer->call_details.sip_alternate_uri, NULL);
|
||||
|
||||
/* Write the parent structure
|
||||
parent.index = gbinder_writer_append_buffer_object(args, dial_request_writer,
|
||||
sizeof(*dial_request_writer));
|
||||
|
||||
/* Write the string data
|
||||
binder_append_hidl_string_data(args, dial_request_writer, address, parent.index);
|
||||
|
||||
// find right index after
|
||||
guint32 index = G_STRUCT_OFFSET(QtiRadioDialRequest, call_details.call_type);
|
||||
binder_append_hidl_string_data(args, dial_request_writer, call_details.sip_alternate_uri, parent.index);
|
||||
binder_append_hidl_vec_data(args, dial_request_writer, call_details.extras, parent.index);
|
||||
|
||||
/* UUS information is empty but we still need to write a buffer
|
||||
//parent.offset = G_STRUCT_OFFSET(QtiRadioDialRequest, call_details.extras.data.ptr);
|
||||
//gbinder_writer_append_buffer_object_with_parent(args, NULL, 0, &parent);
|
||||
|
||||
//parent.offset = G_STRUCT_OFFSET(QtiRadioDialRequest, call_details.local_ability.data.ptr);
|
||||
//gbinder_writer_append_buffer_object_with_parent(args, NULL, 0, &parent);
|
||||
|
||||
//parent.offset = G_STRUCT_OFFSET(QtiRadioDialRequest, call_details.peer_ability.data.ptr);
|
||||
//gbinder_writer_append_buffer_object_with_parent(args, NULL, 0, &parent);
|
||||
|
||||
DBG("Dialing in args YAY %s", number);
|
||||
}
|
||||
*/
|
||||
|
||||
guint
|
||||
qti_radio_ext_dial(
|
||||
QtiRadioExt* self,
|
||||
const char* number,
|
||||
BINDER_EXT_TOA toa,
|
||||
BINDER_EXT_CALL_CLIR clir,
|
||||
BINDER_EXT_CALL_DIAL_FLAGS flags,
|
||||
QtiRadioExtResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
return qti_radio_ext_result_request_submit(self,
|
||||
QTI_RADIO_REQ_DAIL,
|
||||
QTI_RADIO_RESP_DAIL,
|
||||
qti_radio_ext_dial_args,
|
||||
complete, destroy, user_data,
|
||||
number, clir);
|
||||
}
|
||||
|
||||
// GET_IMS_REG_STATE
|
||||
|
||||
static
|
||||
void
|
||||
qti_radio_ext_get_ims_reg_state_args(
|
||||
GBinderWriter* args,
|
||||
va_list va)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
guint
|
||||
qti_radio_ext_get_ims_reg_state(
|
||||
QtiRadioExt* self,
|
||||
QtiRadioExtResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data)
|
||||
{
|
||||
return qti_radio_ext_result_request_submit(self,
|
||||
QTI_RADIO_REQ_GET_IMS_REG_STATE,
|
||||
QTI_RADIO_RESP_GET_IMS_REG_STATE,
|
||||
qti_radio_ext_get_ims_reg_state_args,
|
||||
complete, destroy, user_data);
|
||||
}
|
||||
|
||||
/*==========================================================================*
|
||||
* Internals
|
||||
*==========================================================================*/
|
||||
@@ -709,6 +1097,10 @@ qti_radio_ext_class_init(
|
||||
g_signal_new(SIGNAL_IMS_REG_STATUS_CHANGED_NAME, G_OBJECT_CLASS_TYPE(klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
|
||||
1, G_TYPE_UINT);
|
||||
qti_radio_ext_signals[SIGNAL_EXT_CALL_STATE_CHANGED] =
|
||||
g_signal_new(SIGNAL_EXT_CALL_STATE_CHANGED_NAME, G_OBJECT_CLASS_TYPE(klass),
|
||||
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
|
||||
1, G_TYPE_PTR_ARRAY);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -18,15 +18,18 @@
|
||||
|
||||
#include <radio_types.h>
|
||||
#include <binder_ext_ims_impl.h>
|
||||
#include <binder_ext_call_impl.h>
|
||||
|
||||
#include "qti_radio_ext_types.h"
|
||||
|
||||
#define BINDER_EXT_CALL_STATE_END (BINDER_EXT_CALL_STATE_INVALID - 1)
|
||||
|
||||
typedef struct qti_radio_ext QtiRadioExt;
|
||||
|
||||
typedef void (*QtiRadioExtResultFunc)(
|
||||
QtiRadioExt* radio,
|
||||
int result,
|
||||
GBinderReader* reader,
|
||||
void* user_data);
|
||||
|
||||
typedef void (*QtiRadioExtImsRegStatusFunc)(
|
||||
@@ -34,6 +37,11 @@ typedef void (*QtiRadioExtImsRegStatusFunc)(
|
||||
guint32 status,
|
||||
void* user_data);
|
||||
|
||||
typedef void (*QtiRadioExtCallStateFunc)(
|
||||
QtiRadioExt* radio,
|
||||
GPtrArray* updated_calls,
|
||||
void* user_data);
|
||||
|
||||
QtiRadioExt*
|
||||
qti_radio_ext_new(
|
||||
const char* dev,
|
||||
@@ -47,6 +55,16 @@ void
|
||||
qti_radio_ext_unref(
|
||||
QtiRadioExt* self);
|
||||
|
||||
void
|
||||
qti_radio_ext_cancel(
|
||||
QtiRadioExt* self,
|
||||
guint id);
|
||||
|
||||
const QtiRadioRegInfo*
|
||||
qti_radio_ext_read_ims_reg_status_info(
|
||||
QtiRadioExt* self,
|
||||
GBinderReader* reader);
|
||||
|
||||
guint
|
||||
qti_radio_ext_set_reg_state(
|
||||
QtiRadioExt* self,
|
||||
@@ -55,12 +73,35 @@ qti_radio_ext_set_reg_state(
|
||||
GDestroyNotify destroy,
|
||||
void* user_data);
|
||||
|
||||
guint
|
||||
qti_radio_ext_dial(
|
||||
QtiRadioExt* self,
|
||||
const char* number,
|
||||
BINDER_EXT_TOA toa,
|
||||
BINDER_EXT_CALL_CLIR clir,
|
||||
BINDER_EXT_CALL_DIAL_FLAGS flags,
|
||||
QtiRadioExtResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data);
|
||||
|
||||
guint
|
||||
qti_radio_ext_get_ims_reg_state(
|
||||
QtiRadioExt* self,
|
||||
QtiRadioExtResultFunc complete,
|
||||
GDestroyNotify destroy,
|
||||
void* user_data);
|
||||
|
||||
gulong
|
||||
qti_radio_ext_add_ims_reg_status_handler(
|
||||
QtiRadioExt* self,
|
||||
QtiRadioExtImsRegStatusFunc handler,
|
||||
void* user_data);
|
||||
|
||||
gulong
|
||||
qti_radio_ext_add_call_state_handler(
|
||||
QtiRadioExt* self,
|
||||
QtiRadioExtCallStateFunc handler,
|
||||
void* user_data);
|
||||
|
||||
#endif /* QTI_RADIO_EXT_H */
|
||||
|
||||
|
||||
@@ -85,6 +85,103 @@ typedef enum qti_radio_service_status {
|
||||
QTI_RADIO_SERVICE_STATUS_INVALID = 2,
|
||||
} QTI_RADIO_SERVICE_STATUS;
|
||||
|
||||
/*
|
||||
enum CallState : int32_t {
|
||||
CALL_ACTIVE,
|
||||
CALL_HOLDING,
|
||||
CALL_DIALING,
|
||||
CALL_ALERTING,
|
||||
CALL_INCOMING,
|
||||
CALL_WAITING,
|
||||
CALL_END,
|
||||
CALL_STATE_INVALID,
|
||||
};
|
||||
*/
|
||||
|
||||
typedef enum qti_radio_call_state {
|
||||
QTI_RADIO_CALL_STATE_ACTIVE = 0,
|
||||
QTI_RADIO_CALL_STATE_HOLDING = 1,
|
||||
QTI_RADIO_CALL_STATE_DIALING = 2,
|
||||
QTI_RADIO_CALL_STATE_ALERTING = 3,
|
||||
QTI_RADIO_CALL_STATE_INCOMING = 4,
|
||||
QTI_RADIO_CALL_STATE_WAITING = 5,
|
||||
QTI_RADIO_CALL_STATE_END = 6,
|
||||
QTI_RADIO_CALL_STATE_INVALID = 7,
|
||||
} QTI_RADIO_CALL_STATE;
|
||||
|
||||
/*
|
||||
enum IpPresentation : int32_t {
|
||||
IP_PRESENTATION_NUM_ALLOWED,
|
||||
IP_PRESENTATION_NUM_RESTRICTED,
|
||||
IP_PRESENTATION_NUM_DEFAULT,
|
||||
IP_PRESENTATION_INVALID,
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
typedef enum qti_radio_ip_presentation {
|
||||
QTI_RADIO_IP_PRESENTATION_NUM_ALLOWED = 0,
|
||||
QTI_RADIO_IP_PRESENTATION_NUM_RESTRICTED = 1,
|
||||
QTI_RADIO_IP_PRESENTATION_NUM_DEFAULT = 2,
|
||||
QTI_RADIO_IP_PRESENTATION_INVALID = 3,
|
||||
} QTI_RADIO_IP_PRESENTATION;
|
||||
|
||||
/*
|
||||
enum CallType : int32_t {
|
||||
CALL_TYPE_VOICE,
|
||||
CALL_TYPE_VT_TX,
|
||||
CALL_TYPE_VT_RX,
|
||||
CALL_TYPE_VT,
|
||||
CALL_TYPE_VT_NODIR,
|
||||
CALL_TYPE_CS_VS_TX,
|
||||
CALL_TYPE_CS_VS_RX,
|
||||
CALL_TYPE_PS_VS_TX,
|
||||
CALL_TYPE_PS_VS_RX,
|
||||
CALL_TYPE_UNKNOWN,
|
||||
CALL_TYPE_SMS,
|
||||
CALL_TYPE_UT,
|
||||
CALL_TYPE_INVALID,
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
typedef enum qti_radio_call_type {
|
||||
QTI_RADIO_CALL_TYPE_VOICE = 0,
|
||||
QTI_RADIO_CALL_TYPE_VT_TX = 1,
|
||||
QTI_RADIO_CALL_TYPE_VT_RX = 2,
|
||||
QTI_RADIO_CALL_TYPE_VT = 3,
|
||||
QTI_RADIO_CALL_TYPE_VT_NODIR = 4,
|
||||
QTI_RADIO_CALL_TYPE_CS_VS_TX = 5,
|
||||
QTI_RADIO_CALL_TYPE_CS_VS_RX = 6,
|
||||
QTI_RADIO_CALL_TYPE_PS_VS_TX = 7,
|
||||
QTI_RADIO_CALL_TYPE_PS_VS_RX = 8,
|
||||
QTI_RADIO_CALL_TYPE_UNKNOWN = 9,
|
||||
QTI_RADIO_CALL_TYPE_SMS = 10,
|
||||
QTI_RADIO_CALL_TYPE_UT = 11,
|
||||
QTI_RADIO_CALL_TYPE_INVALID = 12,
|
||||
} QTI_RADIO_CALL_TYPE;
|
||||
|
||||
/*
|
||||
|
||||
enum CallDomain : int32_t {
|
||||
CALL_DOMAIN_UNKNOWN,
|
||||
CALL_DOMAIN_CS,
|
||||
CALL_DOMAIN_PS,
|
||||
CALL_DOMAIN_AUTOMATIC,
|
||||
CALL_DOMAIN_NOT_SET,
|
||||
CALL_DOMAIN_INVALID,
|
||||
};
|
||||
*/
|
||||
|
||||
typedef enum qti_radio_call_domain {
|
||||
QTI_RADIO_CALL_DOMAIN_UNKNOWN = 0,
|
||||
QTI_RADIO_CALL_DOMAIN_CS = 1,
|
||||
QTI_RADIO_CALL_DOMAIN_PS = 2,
|
||||
QTI_RADIO_CALL_DOMAIN_AUTOMATIC = 3,
|
||||
QTI_RADIO_CALL_DOMAIN_NOT_SET = 4,
|
||||
QTI_RADIO_CALL_DOMAIN_INVALID = 5,
|
||||
} QTI_RADIO_CALL_DOMAIN;
|
||||
|
||||
/*
|
||||
|
||||
struct RegistrationInfo {
|
||||
@@ -104,6 +201,141 @@ typedef struct qti_radio_reg_info {
|
||||
GBinderHidlString uri RADIO_ALIGNED(8);
|
||||
} QtiRadioRegInfo;
|
||||
|
||||
/*
|
||||
struct CallInfo {
|
||||
CallState state;
|
||||
uint32_t index;
|
||||
uint32_t toa;
|
||||
bool hasIsMpty;
|
||||
bool isMpty;
|
||||
bool hasIsMT;
|
||||
bool isMT;
|
||||
uint32_t als;
|
||||
bool hasIsVoice;
|
||||
bool isVoice;
|
||||
bool hasIsVoicePrivacy;
|
||||
bool isVoicePrivacy;
|
||||
string number;
|
||||
uint32_t numberPresentation;
|
||||
string name;
|
||||
uint32_t namePresentation;
|
||||
bool hasCallDetails;
|
||||
};
|
||||
*/
|
||||
|
||||
typedef struct qti_radio_call_info {
|
||||
QTI_RADIO_CALL_STATE state RADIO_ALIGNED(4);
|
||||
guint32 index RADIO_ALIGNED(4);
|
||||
guint32 toa RADIO_ALIGNED(4);
|
||||
gboolean has_is_mpty RADIO_ALIGNED(4);
|
||||
gboolean is_mpty RADIO_ALIGNED(4);
|
||||
gboolean has_is_mt RADIO_ALIGNED(4);
|
||||
gboolean is_mt RADIO_ALIGNED(4);
|
||||
guint32 als RADIO_ALIGNED(4);
|
||||
gboolean has_is_voice RADIO_ALIGNED(4);
|
||||
gboolean is_voice RADIO_ALIGNED(4);
|
||||
gboolean has_is_voice_privacy RADIO_ALIGNED(4);
|
||||
gboolean is_voice_privacy RADIO_ALIGNED(4);
|
||||
GBinderHidlString number RADIO_ALIGNED(8);
|
||||
guint32 number_presentation RADIO_ALIGNED(4);
|
||||
GBinderHidlString name RADIO_ALIGNED(8);
|
||||
guint32 name_presentation RADIO_ALIGNED(4);
|
||||
gboolean has_call_details RADIO_ALIGNED(4);
|
||||
} QtiRadioCallInfo;
|
||||
|
||||
/*
|
||||
|
||||
struct ServiceStatusInfo {
|
||||
bool hasIsValid;
|
||||
bool isValid;
|
||||
ServiceType type;
|
||||
CallType callType;
|
||||
StatusType status;
|
||||
vec<uint8_t> userdata;
|
||||
uint32_t restrictCause;
|
||||
vec<StatusForAccessTech> accTechStatus;
|
||||
RttMode rttMode;
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
typedef struct qti_radio_service_status_info {
|
||||
gboolean has_is_valid RADIO_ALIGNED(4);
|
||||
gboolean is_valid RADIO_ALIGNED(4);
|
||||
guint32 type RADIO_ALIGNED(4);
|
||||
guint32 call_type RADIO_ALIGNED(4);
|
||||
guint32 status RADIO_ALIGNED(4);
|
||||
GBinderHidlVec userdata RADIO_ALIGNED(8);
|
||||
guint32 restrict_cause RADIO_ALIGNED(4);
|
||||
GBinderHidlVec acc_tech_status RADIO_ALIGNED(8);
|
||||
guint32 rtt_mode RADIO_ALIGNED(4);
|
||||
} QtiRadioServiceStatusInfo;
|
||||
|
||||
/*
|
||||
struct CallDetails {
|
||||
CallType callType;
|
||||
CallDomain callDomain;
|
||||
uint32_t extrasLength;
|
||||
vec<string> extras;
|
||||
|
||||
vec<ServiceStatusInfo> localAbility;
|
||||
vec<ServiceStatusInfo> peerAbility;
|
||||
uint32_t callSubstate;
|
||||
uint32_t mediaId;
|
||||
uint32_t causeCode;
|
||||
RttMode rttMode;
|
||||
string sipAlternateUri;
|
||||
};
|
||||
*/
|
||||
|
||||
typedef struct qti_radio_call_details {
|
||||
guint32 call_type RADIO_ALIGNED(4);
|
||||
guint32 call_domain RADIO_ALIGNED(4);
|
||||
guint32 extras_length RADIO_ALIGNED(4);
|
||||
|
||||
GBinderHidlVec extras RADIO_ALIGNED(8);
|
||||
GBinderHidlVec local_ability RADIO_ALIGNED(8);
|
||||
GBinderHidlVec peer_ability RADIO_ALIGNED(8);
|
||||
|
||||
guint32 call_substate RADIO_ALIGNED(4);
|
||||
guint32 media_id RADIO_ALIGNED(4);
|
||||
guint32 cause_code RADIO_ALIGNED(4);
|
||||
guint32 rtt_mode RADIO_ALIGNED(4);
|
||||
GBinderHidlString sip_alternate_uri RADIO_ALIGNED(8);
|
||||
} RADIO_ALIGNED(8) QtiRadioCallDetails;
|
||||
|
||||
/*
|
||||
struct DialRequest {
|
||||
string address;
|
||||
uint32_t clirMode;
|
||||
IpPresentation presentation;
|
||||
bool hasCallDetails;
|
||||
CallDetails callDetails;
|
||||
bool hasIsConferenceUri;
|
||||
bool isConferenceUri;
|
||||
bool hasIsCallPull;
|
||||
bool isCallPull;
|
||||
bool hasIsEncrypted;
|
||||
bool isEncrypted;
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
typedef struct qti_radio_dial_request {
|
||||
GBinderHidlString address RADIO_ALIGNED(8);
|
||||
guint32 clir_mode RADIO_ALIGNED(4);
|
||||
guint32 presentation RADIO_ALIGNED(4);
|
||||
guint8 has_call_details RADIO_ALIGNED(1);
|
||||
QtiRadioCallDetails call_details RADIO_ALIGNED(8);
|
||||
guint8 has_is_conference_uri RADIO_ALIGNED(1);
|
||||
guint8 is_conference_uri RADIO_ALIGNED(1);
|
||||
guint8 has_is_call_pull RADIO_ALIGNED(1);
|
||||
guint8 is_call_pull RADIO_ALIGNED(1);
|
||||
guint8 has_is_encrypted RADIO_ALIGNED(1);
|
||||
guint8 is_encrypted RADIO_ALIGNED(1);
|
||||
} RADIO_ALIGNED(8) QtiRadioDialRequest;
|
||||
|
||||
|
||||
/* c(req, resp, callName, CALL_NAME) */
|
||||
#define QTI_RADIO_EXT_IMS_CALL_1_0(c) \
|
||||
c(2, 1, dail, DAIL) \
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "qti_slot.h"
|
||||
#include "qti_ims.h"
|
||||
#include "qti_radio_ext.h"
|
||||
#include "qti_ims_call.h"
|
||||
|
||||
#include <binder_ext_slot_impl.h>
|
||||
|
||||
@@ -48,6 +49,7 @@ typedef struct qti_slot {
|
||||
BinderExtSlot parent;
|
||||
BinderExtIms* ims;
|
||||
QtiRadioExt* radio_ext;
|
||||
BinderExtCall* call;
|
||||
} QtiSlot;
|
||||
|
||||
GType qti_slot_get_type() G_GNUC_INTERNAL;
|
||||
@@ -82,6 +84,8 @@ qti_slot_get_interface(
|
||||
|
||||
if (iface == BINDER_EXT_TYPE_IMS) {
|
||||
return self->ims;
|
||||
} else if (iface == BINDER_EXT_TYPE_CALL) {
|
||||
return self->call;
|
||||
} else {
|
||||
return BINDER_EXT_SLOT_CLASS(PARENT_CLASS)->get_interface(slot, iface);
|
||||
}
|
||||
@@ -112,6 +116,7 @@ qti_slot_new(
|
||||
self->radio_ext = qti_radio_ext_new(radio->dev, radio_slot);
|
||||
if (self->radio_ext) {
|
||||
self->ims = qti_ims_new(radio_slot, self->radio_ext);
|
||||
self->call = qti_ims_call_new(self->radio_ext);
|
||||
}
|
||||
|
||||
return slot;
|
||||
|
||||
Reference in New Issue
Block a user