[ofono-binder] Add support for IRadioVoice interface

This commit is contained in:
Matti Lehtimäki
2024-08-19 11:42:10 +03:00
parent 46db487a09
commit 4ccfd647c9
4 changed files with 393 additions and 121 deletions

View File

@@ -47,6 +47,7 @@
#include <ofono/watch.h>
#include <radio_client.h>
#include <radio_instance.h>
#include <radio_request.h>
#include <radio_request_group.h>
@@ -503,6 +504,7 @@ binder_modem_remove(
radio_client_unref(modem->messaging_client);
radio_client_unref(modem->network_client);
radio_client_unref(modem->sim_client);
radio_client_unref(modem->voice_client);
radio_instance_unref(modem->instance);
g_free(self->last_known_iccid);
@@ -549,6 +551,7 @@ binder_modem_create(
RadioClient* messaging_client,
RadioClient* network_client,
RadioClient* sim_client,
RadioClient* voice_client,
const char* log_prefix,
const char* path,
const char* imei,
@@ -595,6 +598,7 @@ binder_modem_create(
modem->messaging_client = radio_client_ref(messaging_client);
modem->network_client = radio_client_ref(network_client);
modem->sim_client = radio_client_ref(sim_client);
modem->voice_client = radio_client_ref(voice_client);
modem->ims = binder_ims_reg_new(client, ext, log_prefix);
modem->ext = binder_ext_slot_ref(ext);
self->g = radio_request_group_new(client);

View File

@@ -28,6 +28,7 @@ struct binder_modem {
RadioClient* messaging_client;
RadioClient* network_client;
RadioClient* sim_client;
RadioClient* voice_client;
const char* path;
const char* log_prefix;
const char* imei;
@@ -64,6 +65,7 @@ binder_modem_create(
RadioClient* messaging_client,
RadioClient* network_client,
RadioClient* sim_client,
RadioClient* voice_client,
const char* name,
const char* path,
const char* imei,

View File

@@ -60,6 +60,7 @@
#include <radio_data_types.h>
#include <radio_modem_types.h>
#include <radio_voice_types.h>
#include <gbinder_servicemanager.h>
#include <gbinder_reader.h>
@@ -737,6 +738,9 @@ binder_plugin_modem_check(
RADIO_AIDL_INTERFACE sim_interface =
modem_interface != RADIO_AIDL_INTERFACE_NONE ?
RADIO_SIM_INTERFACE : RADIO_AIDL_INTERFACE_NONE;
RADIO_AIDL_INTERFACE voice_interface =
modem_interface != RADIO_AIDL_INTERFACE_NONE ?
RADIO_VOICE_INTERFACE : RADIO_AIDL_INTERFACE_NONE;
if (!slot->modem && slot->handle && slot->handle->enabled &&
radio_client_connected(slot->client[modem_interface])) {
@@ -749,6 +753,7 @@ binder_plugin_modem_check(
slot->client[messaging_interface],
slot->client[network_interface],
slot->client[sim_interface],
slot->client[voice_interface],
slot->name, slot->path, slot->imei, slot->imeisv, &slot->config,
slot->ext_slot, slot->radio, slot->network, slot->sim_card,
slot->data, slot->sim_settings, slot->cell_info);
@@ -1403,6 +1408,7 @@ binder_plugin_slot_check_radio_client(
binder_plugin_connect_to_interface(slot, dev, RADIO_MESSAGING_INTERFACE);
binder_plugin_connect_to_interface(slot, dev, RADIO_NETWORK_INTERFACE);
binder_plugin_connect_to_interface(slot, dev, RADIO_SIM_INTERFACE);
binder_plugin_connect_to_interface(slot, dev, RADIO_VOICE_INTERFACE);
}
binder_plugin_check_data_manager(plugin);

View File

@@ -67,6 +67,8 @@ typedef struct binder_voicecall {
BinderImsReg* ims_reg;
RadioInstance* instance;
RadioRequestGroup* g;
RadioClient* network_client;
RADIO_AIDL_INTERFACE interface_aidl;
ofono_voicecall_cb_t cb;
void* data;
GUtilIntArray* local_release_ids;
@@ -264,6 +266,70 @@ binder_voicecall_info_new(
return call;
}
static
BinderVoiceCallInfo*
binder_voicecall_info_new_aidl(
GBinderReader* reader)
{
BinderVoiceCallInfo* call = g_slice_new0(BinderVoiceCallInfo);
struct ofono_call* oc = &call->oc;
gboolean is_mt;
gboolean is_voice;
char* name;
char* number;
gsize address_parcel_size = binder_read_parcelable_size(reader);
ofono_call_init(oc);
if (address_parcel_size) {
gsize address_data_read;
gsize address_initial_size = gbinder_reader_bytes_read(reader);
gbinder_reader_read_uint32(reader, &oc->status);
gbinder_reader_read_uint32(reader, &oc->id);
gbinder_reader_read_int32(reader, &oc->phone_number.type);
gbinder_reader_read_bool(reader, NULL); /* isMpty */
gbinder_reader_read_bool(reader, &is_mt);
oc->direction = is_mt ?
OFONO_CALL_DIRECTION_MOBILE_TERMINATED :
OFONO_CALL_DIRECTION_MOBILE_ORIGINATED;
gbinder_reader_read_int32(reader, NULL); /* als */
gbinder_reader_read_bool(reader, &is_voice);
oc->type = is_voice ?
OFONO_CALL_MODE_VOICE :
OFONO_CALL_MODE_UNKNOWN;
gbinder_reader_read_bool(reader, NULL);
number = gbinder_reader_read_string16(reader);
if (number && strlen(number)) {
oc->clip_validity = OFONO_CLIP_VALIDITY_VALID;
g_strlcpy(oc->phone_number.number, number,
OFONO_MAX_PHONE_NUMBER_LENGTH);
} else {
oc->clip_validity = OFONO_CLIP_VALIDITY_NOT_AVAILABLE;
}
gbinder_reader_read_int32(reader, NULL); /* als */
name = gbinder_reader_read_string16(reader);
if (name && strlen(name)) {
g_strlcpy(oc->name, name, OFONO_MAX_CALLER_NAME_LENGTH);
}
// Ignore rest of values for now
address_data_read = gbinder_reader_bytes_read(reader) - address_initial_size;
while (address_data_read < address_parcel_size) {
gbinder_reader_read_uint32(reader, NULL);
address_data_read += sizeof(guint32);
}
DBG("[id=%d,status=%d,type=%d,number=%s,name=%s]", oc->id,
oc->status, oc->type, oc->phone_number.number, oc->name);
g_free(name);
g_free(number);
}
return call;
}
static
BinderVoiceCallInfo*
binder_voicecall_info_ext_new(
@@ -486,23 +552,34 @@ binder_voicecall_lastcause_cb(
if (status == RADIO_TX_STATUS_OK) {
if (error == RADIO_ERROR_NONE) {
if (resp == RADIO_RESP_GET_LAST_CALL_FAIL_CAUSE) {
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_RESP_GET_LAST_CALL_FAIL_CAUSE :
RADIO_RESP_GET_LAST_CALL_FAIL_CAUSE;
if (resp == code) {
GBinderReader reader;
const RadioLastCallFailCauseInfo* info;
gint32 cause_code;
/*
* getLastCallFailCauseResponse(RadioResponseInfo,
* LastCallFailCauseInfo failCauseinfo);
*/
gbinder_reader_copy(&reader, args);
info = gbinder_reader_read_hidl_struct(&reader,
RadioLastCallFailCauseInfo);
if (self->interface_aidl == RADIO_AIDL_INTERFACE_NONE) {
info = gbinder_reader_read_hidl_struct(&reader,
RadioLastCallFailCauseInfo);
cause_code = info->causeCode;
} else {
gbinder_reader_read_int32(&reader, &cause_code);
gbinder_reader_skip_string16(&reader);
}
if (info) {
enum ofono_disconnect_reason reason =
binder_voicecall_map_cause(self, cid, info->causeCode);
binder_voicecall_map_cause(self, cid, cause_code);
ofono_info("Call %d ended with cause %d -> ofono reason %d",
cid, info->causeCode, reason);
cid, cause_code, reason);
ofono_voicecall_disconnected(vc, cid, reason, NULL);
return;
}
@@ -547,8 +624,11 @@ binder_voicecall_set_calls(
BinderVoiceCallLastCauseData* reqdata =
g_new0(BinderVoiceCallLastCauseData, 1);
/* getLastCallFailCause(int32 serial); */
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_GET_LAST_CALL_FAIL_CAUSE :
RADIO_REQ_GET_LAST_CALL_FAIL_CAUSE;
RadioRequest* req2 = radio_request_new2(self->g,
RADIO_REQ_GET_LAST_CALL_FAIL_CAUSE, NULL,
code, NULL,
binder_voicecall_lastcause_cb, g_free, reqdata);
reqdata->self = self;
@@ -611,38 +691,54 @@ binder_voicecall_clcc_poll_cb(
if (status == RADIO_TX_STATUS_OK) {
if (error == RADIO_ERROR_NONE) {
GBinderReader reader;
gsize i, count = 0;
gsize i;
/* getCurrentCallsResponse(RadioResponseInfo, vec<Call> calls); */
gbinder_reader_copy(&reader, args);
if (resp == RADIO_RESP_GET_CURRENT_CALLS) {
const RadioCall* calls =
gbinder_reader_read_hidl_type_vec(&reader,
RadioCall, &count);
if (calls) {
/* Build sorted list */
for (i = 0; i < count; i++) {
list = g_slist_insert_sorted(list,
binder_voicecall_info_new(calls + i),
binder_voicecall_info_compare);
}
}
} else if (resp == RADIO_RESP_GET_CURRENT_CALLS_1_2) {
const RadioCall_1_2* calls =
gbinder_reader_read_hidl_type_vec(&reader,
RadioCall_1_2, &count);
if (self->interface_aidl == RADIO_AIDL_INTERFACE_NONE) {
gsize count = 0;
if (resp == RADIO_RESP_GET_CURRENT_CALLS) {
const RadioCall* calls =
gbinder_reader_read_hidl_type_vec(&reader,
RadioCall, &count);
if (calls) {
/* Build sorted list */
for (i = 0; i < count; i++) {
list = g_slist_insert_sorted(list,
binder_voicecall_info_new(&calls[i].base),
binder_voicecall_info_compare);
if (calls) {
/* Build sorted list */
for (i = 0; i < count; i++) {
list = g_slist_insert_sorted(list,
binder_voicecall_info_new(calls + i),
binder_voicecall_info_compare);
}
}
} else if (resp == RADIO_RESP_GET_CURRENT_CALLS_1_2) {
const RadioCall_1_2* calls =
gbinder_reader_read_hidl_type_vec(&reader,
RadioCall_1_2, &count);
if (calls) {
/* Build sorted list */
for (i = 0; i < count; i++) {
list = g_slist_insert_sorted(list,
binder_voicecall_info_new(&calls[i].base),
binder_voicecall_info_compare);
}
}
} else {
ofono_error("Unexpected getCurrentCalls response %d", resp);
}
} else {
ofono_error("Unexpected getCurrentCalls response %d", resp);
if ((RADIO_VOICE_RESP)resp == RADIO_VOICE_RESP_GET_CURRENT_CALLS) {
gint32 count = 0;
gbinder_reader_read_int32(&reader, &count);
for (i = 0; i < count; i++) {
list = g_slist_insert_sorted(list,
binder_voicecall_info_new_aidl(&reader),
binder_voicecall_info_compare);
}
} else {
ofono_error("Unexpected getCurrentCalls response %d", resp);
}
}
} else {
/*
@@ -688,8 +784,11 @@ binder_voicecall_clcc_poll(
{
if (!self->clcc_poll_req) {
/* getCurrentCalls(int32 serial); */
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_GET_CURRENT_CALLS :
RADIO_REQ_GET_CURRENT_CALLS;
RadioRequest* req = radio_request_new2(self->g,
RADIO_REQ_GET_CURRENT_CALLS, NULL,
code, NULL,
binder_voicecall_clcc_poll_cb, NULL, self);
radio_request_set_retry(req, BINDER_RETRY_MS, -1);
@@ -814,7 +913,10 @@ binder_voicecall_dial_cb(
if (status == RADIO_TX_STATUS_OK) {
if (error == RADIO_ERROR_NONE) {
if (resp == RADIO_RESP_DIAL) {
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_RESP_DIAL :
RADIO_RESP_DIAL;
if (resp == code) {
if (self->cb) {
/*
* CLCC will update the oFono call list with
@@ -914,6 +1016,8 @@ binder_voicecall_dial(
RadioDial* dialInfo;
GBinderWriter writer;
RadioRequest* req;
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_DIAL : RADIO_REQ_DIAL;
ofono_info("dialing \"%s\"", phstr);
DBG_(self, "%s,%d,0", phstr, clir);
@@ -933,24 +1037,40 @@ binder_voicecall_dial(
}
/* dial(int32 serial, Dial dialInfo) */
req = radio_request_new2(self->g, RADIO_REQ_DIAL, &writer,
req = radio_request_new2(self->g, code, &writer,
binder_voicecall_dial_cb, NULL, self);
/* Prepare the Dial structure */
dialInfo = gbinder_writer_new0(&writer, RadioDial);
dialInfo->clir = clir;
binder_copy_hidl_string(&writer, &dialInfo->address, phstr);
if (self->interface_aidl == RADIO_AIDL_INTERFACE_NONE) {
/* Prepare the Dial structure */
dialInfo = gbinder_writer_new0(&writer, RadioDial);
dialInfo->clir = clir;
binder_copy_hidl_string(&writer, &dialInfo->address, phstr);
/* Write the parent structure */
parent.index = gbinder_writer_append_buffer_object(&writer, dialInfo,
sizeof(*dialInfo));
/* Write the parent structure */
parent.index = gbinder_writer_append_buffer_object(&writer, dialInfo,
sizeof(*dialInfo));
/* Write the string data */
binder_append_hidl_string_data(&writer, dialInfo, address, parent.index);
/* Write the string data */
binder_append_hidl_string_data(&writer, dialInfo, address, parent.index);
/* UUS information is empty but we still need to write a buffer */
parent.offset = G_STRUCT_OFFSET(RadioDial, uusInfo.data.ptr);
gbinder_writer_append_buffer_object_with_parent(&writer, NULL, 0, &parent);
/* UUS information is empty but we still need to write a buffer */
parent.offset = G_STRUCT_OFFSET(RadioDial, uusInfo.data.ptr);
gbinder_writer_append_buffer_object_with_parent(&writer, NULL, 0, &parent);
} else {
gint32 initial_size;
/* Non-null parcelable */
gbinder_writer_append_int32(&writer, 1);
initial_size = gbinder_writer_bytes_written(&writer);
/* Dummy parcelable size, replaced at the end */
gbinder_writer_append_int32(&writer, -1);
gbinder_writer_append_string16(&writer, phstr);
gbinder_writer_append_int32(&writer, clir);
/* UUS information array size */
gbinder_writer_append_int32(&writer, 0);
/* Overwrite parcelable size */
gbinder_writer_overwrite_int32(&writer, initial_size,
gbinder_writer_bytes_written(&writer) - initial_size);
}
/* Submit the request */
if (radio_request_submit(req)) {
@@ -984,15 +1104,20 @@ binder_voicecall_submit_hangup_req(
* work better.
*/
if (call && call->oc.status == OFONO_CALL_STATUS_INCOMING) {
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_HANGUP_WAITING_OR_BACKGROUND :
RADIO_REQ_HANGUP_WAITING_OR_BACKGROUND;
/* hangupWaitingOrBackground(int32_t serial) */
req = radio_request_new2(self->g,
RADIO_REQ_HANGUP_WAITING_OR_BACKGROUND, NULL,
code, NULL,
binder_voicecall_cbd_complete, binder_voicecall_cbd_destroy, cbd);
} else {
/* hangup(int32 serial, int32 index) */
GBinderWriter writer;
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_HANGUP : RADIO_REQ_HANGUP;
req = radio_request_new2(self->g, RADIO_REQ_HANGUP, &writer,
req = radio_request_new2(self->g, code, &writer,
binder_voicecall_cbd_complete, binder_voicecall_cbd_destroy, cbd);
gbinder_writer_append_int32(&writer, cid);
}
@@ -1208,8 +1333,10 @@ binder_voicecall_call_state_changed_event(
gpointer user_data)
{
BinderVoiceCall* self = user_data;
guint32 ind_code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_IND_CALL_STATE_CHANGED : RADIO_IND_CALL_STATE_CHANGED;
GASSERT(code == RADIO_IND_CALL_STATE_CHANGED);
GASSERT(code == ind_code);
/* Just need to request the call list again */
binder_voicecall_clcc_poll(self);
@@ -1259,27 +1386,62 @@ binder_voicecall_supp_svc_notification(
GBinderReader reader;
gbinder_reader_copy(&reader, args);
ssn = gbinder_reader_read_hidl_struct(&reader, RadioSuppSvcNotification);
if (ssn) {
if (ssn->isMT) {
struct ofono_phone_number ph;
if (self->interface_aidl == RADIO_AIDL_INTERFACE_NONE) {
ssn = gbinder_reader_read_hidl_struct(&reader, RadioSuppSvcNotification);
if (ssn) {
if (ssn->isMT) {
struct ofono_phone_number ph;
/* MT unsolicited result code */
DBG_(self, "MT code: %d, index: %d type: %d number: %s", ssn->code,
ssn->index, ssn->type, ssn->number.data.str);
if (ssn->number.data.str && ssn->number.len) {
ph.type = ssn->type;
g_strlcpy(ph.number, ssn->number.data.str, sizeof(ph.number));
/* MT unsolicited result code */
DBG_(self, "MT code: %d, index: %d type: %d number: %s", ssn->code,
ssn->index, ssn->type, ssn->number.data.str);
if (ssn->number.data.str && ssn->number.len) {
ph.type = ssn->type;
g_strlcpy(ph.number, ssn->number.data.str, sizeof(ph.number));
} else {
ph.type = OFONO_NUMBER_TYPE_UNKNOWN;
ph.number[0] = 0;
}
ofono_voicecall_ssn_mt_notify(self->vc, 0, ssn->code,
ssn->index, &ph);
} else {
ph.type = OFONO_NUMBER_TYPE_UNKNOWN;
ph.number[0] = 0;
/* MO intermediate result code */
ofono_voicecall_ssn_mo_notify(self->vc, 0, ssn->code, ssn->index);
}
}
} else {
if (binder_read_parcelable_size(&reader)) {
gboolean is_mt;
gint32 code, index, type;
char* number;
ofono_voicecall_ssn_mt_notify(self->vc, 0, ssn->code,
ssn->index, &ph);
} else {
/* MO intermediate result code */
ofono_voicecall_ssn_mo_notify(self->vc, 0, ssn->code, ssn->index);
gbinder_reader_read_bool(&reader, &is_mt);
gbinder_reader_read_int32(&reader, &code);
gbinder_reader_read_int32(&reader, &index);
gbinder_reader_read_int32(&reader, &type);
number = gbinder_reader_read_string16(&reader);
if (is_mt) {
struct ofono_phone_number ph;
/* MT unsolicited result code */
DBG_(self, "MT code: %d, index: %d type: %d number: %s", code,
index, type, number);
if (number && strlen(number)) {
ph.type = type;
g_strlcpy(ph.number, number, sizeof(ph.number));
} else {
ph.type = OFONO_NUMBER_TYPE_UNKNOWN;
ph.number[0] = 0;
}
ofono_voicecall_ssn_mt_notify(self->vc, 0, code,
index, &ph);
} else {
/* MO intermediate result code */
ofono_voicecall_ssn_mo_notify(self->vc, 0, code, index);
}
g_free(number);
}
}
}
@@ -1327,7 +1489,9 @@ binder_voicecall_answer(
} else {
/* Default action */
DBG_(self, "answering current call");
binder_voicecall_request_submit(self, RADIO_REQ_ACCEPT_CALL, cbd);
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_ACCEPT_CALL : RADIO_REQ_ACCEPT_CALL;
binder_voicecall_request_submit(self, code, cbd);
}
binder_voicecall_cbd_unref(cbd);
}
@@ -1350,7 +1514,9 @@ binder_voicecall_send_dtmf_cb(
if (status == RADIO_TX_STATUS_OK) {
if (error == RADIO_ERROR_NONE) {
if (resp == RADIO_RESP_SEND_DTMF) {
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_RESP_SEND_DTMF : RADIO_RESP_SEND_DTMF;
if (resp == code) {
/* Send the next one */
binder_voicecall_send_one_dtmf(self);
return;
@@ -1406,11 +1572,17 @@ binder_voicecall_send_one_dtmf(
if (!self->ext_send_dtmf_id) {
/* sendDtmf(int32 serial, string tones) */
GBinderWriter writer;
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_SEND_DTMF : RADIO_REQ_SEND_DTMF;
RadioRequest* req = radio_request_new2(self->g,
RADIO_REQ_SEND_DTMF, &writer,
code, &writer,
binder_voicecall_send_dtmf_cb, NULL, self);
gbinder_writer_append_hidl_string_copy(&writer, tone);
if (self->interface_aidl == RADIO_AIDL_INTERFACE_NONE) {
gbinder_writer_append_hidl_string_copy(&writer, tone);
} else {
gbinder_writer_append_string16(&writer, tone);
}
if (radio_request_submit(req)) {
self->send_dtmf_req = req;
} else {
@@ -1475,7 +1647,8 @@ binder_voicecall_create_multiparty(
{
BinderVoiceCall* self = binder_voicecall_get_data(vc);
BinderVoiceCallCbData* cbd = binder_voicecall_cbd_new(self, cb, data);
const RADIO_REQ req = RADIO_REQ_CONFERENCE;
const guint32 req = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_CONFERENCE : RADIO_REQ_CONFERENCE;
if (binder_voicecall_have_ext_call(self)) {
if (!binder_voicecall_ext_conference(self, cbd)) {
@@ -1519,7 +1692,9 @@ binder_voicecall_transfer(
{
BinderVoiceCall* self = binder_voicecall_get_data(vc);
BinderVoiceCallCbData* cbd = binder_voicecall_cbd_new(self, cb, data);
const RADIO_REQ req = RADIO_REQ_EXPLICIT_CALL_TRANSFER;
const guint32 req = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_EXPLICIT_CALL_TRANSFER :
RADIO_REQ_EXPLICIT_CALL_TRANSFER;
if (binder_voicecall_have_ext_call(self)) {
if (!binder_voicecall_ext_transfer(self, cbd)) {
@@ -1547,8 +1722,11 @@ binder_voicecall_private_chat(
/* separateConnection(int32 serial, int32 index) */
GBinderWriter writer;
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_SEPARATE_CONNECTION :
RADIO_REQ_SEPARATE_CONNECTION;
RadioRequest* req = radio_request_new2(self->g,
RADIO_REQ_SEPARATE_CONNECTION, &writer,
code, &writer,
binder_voicecall_cbd_complete, binder_voicecall_cbd_destroy, cbd);
DBG_(self, "Private chat with id %d", cid);
@@ -1611,8 +1789,12 @@ binder_voicecall_swap_without_accept(
ofono_voicecall_cb_t cb,
void* data)
{
BinderVoiceCall* self = binder_voicecall_get_data(vc);
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE :
RADIO_REQ_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE;
binder_voicecall_swap_with_fallback(vc, BINDER_EXT_CALL_SWAP_NO_FLAGS,
RADIO_REQ_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, cb, data);
code, cb, data);
}
static
@@ -1622,8 +1804,12 @@ binder_voicecall_hold_all_active(
ofono_voicecall_cb_t cb,
void* data)
{
BinderVoiceCall* self = binder_voicecall_get_data(vc);
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE :
RADIO_REQ_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE;
binder_voicecall_swap_with_fallback(vc, BINDER_EXT_CALL_SWAP_NO_FLAGS,
RADIO_REQ_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, cb, data);
code, cb, data);
}
static
@@ -1633,8 +1819,12 @@ binder_voicecall_release_all_active(
ofono_voicecall_cb_t cb,
void* data)
{
BinderVoiceCall* self = binder_voicecall_get_data(vc);
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_HANGUP_FOREGROUND_RESUME_BACKGROUND :
RADIO_REQ_HANGUP_FOREGROUND_RESUME_BACKGROUND;
binder_voicecall_swap_with_fallback(vc, BINDER_EXT_CALL_SWAP_FLAG_HANGUP,
RADIO_REQ_HANGUP_FOREGROUND_RESUME_BACKGROUND, cb, data);
code, cb, data);
}
static
@@ -1702,10 +1892,14 @@ binder_voicecall_release_all_held(
void* data)
{
DBG__(vc, "");
BinderVoiceCall* self = binder_voicecall_get_data(vc);
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_HANGUP_WAITING_OR_BACKGROUND :
RADIO_REQ_HANGUP_WAITING_OR_BACKGROUND;
binder_voicecall_hangup_with_fallback(vc,
binder_voicecall_hangup_filter_held,
BINDER_EXT_CALL_HANGUP_REJECT,
RADIO_REQ_HANGUP_WAITING_OR_BACKGROUND, cb, data);
code, cb, data);
}
static
@@ -1716,10 +1910,13 @@ binder_voicecall_set_udub(
void* data)
{
DBG__(vc, "");
BinderVoiceCall* self = binder_voicecall_get_data(vc);
guint32 code = self->interface_aidl == RADIO_VOICE_INTERFACE ?
RADIO_VOICE_REQ_REJECT_CALL : RADIO_REQ_REJECT_CALL;
binder_voicecall_hangup_with_fallback(vc,
binder_voicecall_hangup_filter_incoming_waiting,
BINDER_EXT_CALL_HANGUP_REJECT,
RADIO_REQ_REJECT_CALL, cb, data);
code, cb, data);
}
static
@@ -1728,8 +1925,13 @@ binder_voicecall_enable_supp_svc(
BinderVoiceCall* self)
{
GBinderWriter writer;
RadioRequest* req = radio_request_new2(self->g,
RADIO_REQ_SET_SUPP_SERVICE_NOTIFICATIONS, &writer,
const RADIO_AIDL_INTERFACE iface_aidl =
radio_client_aidl_interface(self->network_client);
guint32 code = iface_aidl == RADIO_NETWORK_INTERFACE ?
RADIO_NETWORK_REQ_SET_SUPP_SERVICE_NOTIFICATIONS :
RADIO_REQ_SET_SUPP_SERVICE_NOTIFICATIONS;
RadioRequest* req = radio_request_new(self->network_client,
code, &writer,
NULL, NULL, NULL);
/* setSuppServiceNotifications(int32 serial, bool enable); */
@@ -1770,29 +1972,58 @@ binder_voicecall_ecclist_changed(
{
BinderVoiceCall* self = user_data;
GBinderReader reader;
gsize count = 0;
const RadioEmergencyNumber* list;
const char** en_list = NULL;
/* currentEmergencyNumberList(RadioIndicationType,vec<EmergencyNumber>); */
gbinder_reader_copy(&reader, args);
list = gbinder_reader_read_hidl_type_vec(&reader,
RadioEmergencyNumber, &count);
if (self->interface_aidl == RADIO_AIDL_INTERFACE_NONE) {
/* currentEmergencyNumberList(RadioIndicationType,vec<EmergencyNumber>); */
gsize count = 0;
const char** en_list = NULL;
const RadioEmergencyNumber* list;
list = gbinder_reader_read_hidl_type_vec(&reader,
RadioEmergencyNumber, &count);
DBG_(self, "%u emergency number(s)", (guint) count);
if (count) {
guint i;
DBG_(self, "%zu emergency number(s)", count);
if (count) {
guint i;
en_list = g_new(const char*, count + 1);
for (i = 0; i < count; i++) {
en_list[i] = list[i].number.data.str;
DBG("%s", en_list[i]);
en_list = g_new0(const char*, count + 1);
for (i = 0; i < count; i++) {
en_list[i] = list[i].number.data.str;
DBG("%s", en_list[i]);
}
}
en_list[i] = NULL;
}
ofono_voicecall_en_list_notify(self->vc, (char**) en_list);
g_free(en_list);
} else {
/* currentEmergencyNumberList(RadioIndicationType,EmergencyNumber[]); */
gint32 count = 0;
gbinder_reader_read_int32(&reader, &count);
char** en_list = NULL;
ofono_voicecall_en_list_notify(self->vc, (char**) en_list);
g_free(en_list);
DBG_(self, "%zu emergency number(s)", count);
if (count) {
guint i;
en_list = g_new0(char*, count + 1);
for (i = 0; i < count; i++) {
gsize data_read;
gsize parcel_size = binder_read_parcelable_size(&reader);
gsize initial_size = gbinder_reader_bytes_read(&reader);
en_list[i] = gbinder_reader_read_string16(&reader);
// Ignore rest of values for now
data_read = gbinder_reader_bytes_read(&reader) - initial_size;
while (data_read < parcel_size) {
gbinder_reader_read_uint32(&reader, NULL);
data_read += sizeof(guint32);
}
DBG("%s", en_list[i]);
}
}
ofono_voicecall_en_list_notify(self->vc, (char**) en_list);
g_strfreev(en_list);
}
}
static
@@ -1865,33 +2096,59 @@ binder_voicecall_register(
/* Request supplementary service notifications*/
binder_voicecall_enable_supp_svc(self);
/* Unsol when call state changes */
self->radio_event[VOICECALL_EVENT_CALL_STATE_CHANGED] =
radio_client_add_indication_handler(client,
RADIO_IND_CALL_STATE_CHANGED,
binder_voicecall_call_state_changed_event, self);
if (self->interface_aidl == RADIO_AIDL_INTERFACE_NONE) {
/* Unsol when call state changes */
self->radio_event[VOICECALL_EVENT_CALL_STATE_CHANGED] =
radio_client_add_indication_handler(client,
RADIO_IND_CALL_STATE_CHANGED,
binder_voicecall_call_state_changed_event, self);
/* Unsol when call set in hold */
self->radio_event[VOICECALL_EVENT_SUPP_SVC_NOTIFICATION] =
radio_client_add_indication_handler(client,
RADIO_IND_SUPP_SVC_NOTIFY,
binder_voicecall_supp_svc_notification, self);
/* Unsol when call set in hold */
self->radio_event[VOICECALL_EVENT_SUPP_SVC_NOTIFICATION] =
radio_client_add_indication_handler(client,
RADIO_IND_SUPP_SVC_NOTIFY,
binder_voicecall_supp_svc_notification, self);
/* Register for ringback tone notifications */
self->radio_event[VOICECALL_EVENT_RINGBACK_TONE] =
radio_client_add_indication_handler(client,
RADIO_IND_INDICATE_RINGBACK_TONE,
binder_voicecall_ringback_tone_event, self);
/* Register for ringback tone notifications */
self->radio_event[VOICECALL_EVENT_RINGBACK_TONE] =
radio_client_add_indication_handler(client,
RADIO_IND_INDICATE_RINGBACK_TONE,
binder_voicecall_ringback_tone_event, self);
/*
* This one is IRadio 1.4 specific and we won't actually receive
* it unless IRadio 1.4 is actually in use. It's OK to register
* the handler unconditionally, though.
*/
self->radio_event[VOICECALL_EVENT_ECCLIST_CHANGED] =
radio_client_add_indication_handler(client,
RADIO_IND_CURRENT_EMERGENCY_NUMBER_LIST,
binder_voicecall_ecclist_changed, self);
/*
* This one is IRadio 1.4 specific and we won't actually receive
* it unless IRadio 1.4 is actually in use. It's OK to register
* the handler unconditionally, though.
*/
self->radio_event[VOICECALL_EVENT_ECCLIST_CHANGED] =
radio_client_add_indication_handler(client,
RADIO_IND_CURRENT_EMERGENCY_NUMBER_LIST,
binder_voicecall_ecclist_changed, self);
} else {
/* Unsol when call state changes */
self->radio_event[VOICECALL_EVENT_CALL_STATE_CHANGED] =
radio_client_add_indication_handler(client,
RADIO_VOICE_IND_CALL_STATE_CHANGED,
binder_voicecall_call_state_changed_event, self);
/* Unsol when call set in hold */
self->radio_event[VOICECALL_EVENT_SUPP_SVC_NOTIFICATION] =
radio_client_add_indication_handler(self->network_client,
RADIO_NETWORK_IND_SUPP_SVC_NOTIFY,
binder_voicecall_supp_svc_notification, self);
/* Register for ringback tone notifications */
self->radio_event[VOICECALL_EVENT_RINGBACK_TONE] =
radio_client_add_indication_handler(client,
RADIO_VOICE_IND_INDICATE_RINGBACK_TONE,
binder_voicecall_ringback_tone_event, self);
/* Register for emergency number list notifications */
self->radio_event[VOICECALL_EVENT_ECCLIST_CHANGED] =
radio_client_add_indication_handler(client,
RADIO_VOICE_IND_CURRENT_EMERGENCY_NUMBER_LIST,
binder_voicecall_ecclist_changed, self);
}
/* Register extension event handlers if there is an extension */
if (self->ext) {
@@ -1924,7 +2181,9 @@ binder_voicecall_probe(
self->vc = vc;
self->dtmf_queue = gutil_ring_new();
self->instance = radio_instance_ref(modem->instance);
self->g = radio_request_group_new(modem->client); /* Keeps ref to client */
self->g = radio_request_group_new(modem->voice_client); /* Keeps ref to client */
self->network_client = radio_client_ref(modem->network_client);
self->interface_aidl = radio_client_aidl_interface(modem->voice_client);
self->local_hangup_reasons = gutil_ints_ref(cfg->local_hangup_reasons);
self->remote_hangup_reasons = gutil_ints_ref(cfg->remote_hangup_reasons);
self->local_release_ids = gutil_int_array_new();
@@ -1959,6 +2218,7 @@ binder_voicecall_remove(
radio_client_remove_all_handlers(self->g->client, self->radio_event);
radio_request_group_cancel(self->g);
radio_request_group_unref(self->g);
radio_client_unref(self->network_client);
radio_instance_unref(self->instance);
gutil_ring_unref(self->dtmf_queue);