Unverified Commit 159d1395 authored by Sebastian Krzyszkowiak's avatar Sebastian Krzyszkowiak
Browse files

Merge remote-tracking branch 'mobian/debian/latest' into pureos/amber-phone

parents 5ca806e6 f17420f6
......@@ -25,3 +25,16 @@ generated_dbus_sources += gnome.gdbus_codegen('callaudio-dbus',
dbus_header_dir = meson.current_build_dir()
dbus_inc = include_directories('.')
install_data(dbus_interfaces, install_dir: ifacedir)
# systemd service file
service_data = configuration_data()
service_data.set('bindir', bindir)
service_file = 'org.mobian_project.CallAudio.service'
configure_file(
input : service_file + '.in',
output : service_file,
configuration : service_data,
install : true,
install_dir: servicedir,
)
[D-BUS Service]
Name=org.mobian_project.CallAudio
Exec=@bindir@/callaudiod
......@@ -6,7 +6,7 @@
<!--
SelectMode:
@mode: 0 = default audio mode, 1 = voice call mode
@result: 0 = failure, 1 = success
@success: operation status
Sets the audio routing configuration according to the @mode
parameter.
......@@ -16,17 +16,17 @@
-->
<method name="SelectMode">
<arg direction="in" name="mode" type="u"/>
<arg direction="out" name="result" type="u"/>
<arg direction="out" name="success" type="b"/>
</method>
<method name="EnableSpeaker">
<arg direction="in" name="enable" type="b"/>
<arg direction="out" name="result" type="u"/>
<arg direction="out" name="success" type="b"/>
</method>
<method name="MuteMic">
<arg direction="in" name="mute" type="b"/>
<arg direction="out" name="result" type="u"/>
<arg direction="out" name="success" type="b"/>
</method>
</interface>
</node>
/usr/bin/callaudiod
/usr/share/dbus-1/interfaces
/usr/share/dbus-1
[Unit]
Description=Call audio routing daemon
StartLimitIntervalSec=0
Requires=pulseaudio.service
[Service]
ExecStart=/usr/bin/callaudiod
Restart=on-failure
RestartSec=500ms
[Install]
WantedBy=default.target
callaudiod (0.0.3-1) unstable; urgency=medium
* New upstream release 0.0.3
* debian: remove custom user service.
Upstream now provides a D-Bus service for automatic activation.
* debian: update symbols file
-- Arnaud Ferraris <arnaud.ferraris@gmail.com> Mon, 19 Oct 2020 19:50:10 +0200
callaudiod (0.0.2-1) unstable; urgency=medium
* New upstream release 0.0.2
......
......@@ -27,6 +27,9 @@ libcallaudio-0.so.0 libcallaudio-0-0 #MINVER#
call_audio_dbus_call_audio_skeleton_new@LIBCALLAUDIO_0_0_0 0.0.1
call_audio_deinit@LIBCALLAUDIO_0_0_0 0.0.1
call_audio_enable_speaker@LIBCALLAUDIO_0_0_0 0.0.1
call_audio_enable_speaker_async@LIBCALLAUDIO_0_0_0 0.0.3
call_audio_init@LIBCALLAUDIO_0_0_0 0.0.1
call_audio_mute_mic@LIBCALLAUDIO_0_0_0 0.0.1
call_audio_mute_mic_async@LIBCALLAUDIO_0_0_0 0.0.3
call_audio_select_mode@LIBCALLAUDIO_0_0_0 0.0.1
call_audio_select_mode_async@LIBCALLAUDIO_0_0_0 0.0.3
......@@ -48,18 +48,19 @@ static gboolean _initted;
*/
gboolean call_audio_init(GError **error)
{
if (_initted)
return TRUE;
if (_initted)
return TRUE;
_proxy = call_audio_dbus_call_audio_proxy_new_for_bus_sync(
CALLAUDIO_DBUS_TYPE, 0, CALLAUDIO_DBUS_NAME, CALLAUDIO_DBUS_PATH, NULL, error);
if (!_proxy)
return FALSE;
_proxy = call_audio_dbus_call_audio_proxy_new_for_bus_sync(
CALLAUDIO_DBUS_TYPE,0, CALLAUDIO_DBUS_NAME,
CALLAUDIO_DBUS_PATH, NULL, error);
if (!_proxy)
return FALSE;
g_object_add_weak_pointer(G_OBJECT(_proxy), (gpointer *)&_proxy);
g_object_add_weak_pointer(G_OBJECT(_proxy), (gpointer *)&_proxy);
_initted = TRUE;
return TRUE;
_initted = TRUE;
return TRUE;
}
/**
......@@ -70,81 +71,185 @@ gboolean call_audio_init(GError **error)
*/
void call_audio_deinit(void)
{
_initted = FALSE;
g_clear_object(&_proxy);
_initted = FALSE;
g_clear_object(&_proxy);
}
static void select_mode_done(GObject *object, GAsyncResult *result, gpointer data)
{
CallAudioDbusCallAudio *proxy = CALL_AUDIO_DBUS_CALL_AUDIO(object);
CallAudioCallback cb = data;
GError *error = NULL;
gboolean success = FALSE;
gboolean ret;
g_return_if_fail(CALL_AUDIO_DBUS_IS_CALL_AUDIO(proxy));
ret = call_audio_dbus_call_audio_call_select_mode_finish(proxy, &success,
result, &error);
if (!ret || !success) {
g_warning("SelectMode failed with code %d: %s", success, error->message);
}
g_debug("%s: D-bus call returned %d (success=%d)", __func__, ret, success);
if (cb)
cb(ret, error);
}
/**
* call_audio_select_mode:
* call_audio_select_mode_async:
* @mode: Audio mode to select
* @cb: Function to be called when operation completes
*
* Select the audio mode to use.
*/
void call_audio_select_mode_async(CallAudioMode mode, CallAudioCallback cb)
{
call_audio_dbus_call_audio_call_select_mode(_proxy, mode, NULL,
select_mode_done, cb);
}
/**
* call_audio_select_mode:
* @mode: Audio mode to select
*
* Select the audio mode to use. This function is synchronous, and will return
* only once the operation has been executed.
*
* Returns: %TRUE if successful, or %FALSE on error.
*/
gboolean call_audio_select_mode(CallAudioMode mode)
{
guint result;
GError *error = NULL;
gboolean success = FALSE;
gboolean ret;
ret = call_audio_dbus_call_audio_call_select_mode_sync(_proxy, mode, &success,
NULL, &error);
if (error)
g_critical("Couldn't set mode %u: %s", mode, error->message);
g_debug("SelectMode %s: success=%d", ret ? "succeeded" : "failed", success);
return (ret && success);
}
static void enable_speaker_done(GObject *object, GAsyncResult *result, gpointer data)
{
CallAudioDbusCallAudio *proxy = CALL_AUDIO_DBUS_CALL_AUDIO(object);
CallAudioCallback cb = data;
GError *error = NULL;
gboolean success = FALSE;
gboolean ret;
g_return_if_fail(CALL_AUDIO_DBUS_IS_CALL_AUDIO(proxy));
ret = call_audio_dbus_call_audio_call_select_mode_sync(_proxy, mode,
&result, NULL, &error);
if (error) {
g_critical("Couldn't set mode: %s", error->message);
ret = call_audio_dbus_call_audio_call_enable_speaker_finish(proxy, &success,
result, &error);
if (!ret || !success) {
g_warning("EnableSpeaker failed with code %d: %s", success, error->message);
}
g_debug("SelectMode %s: return %u", ret ? "succeeded" : "failed", result);
g_debug("%s: D-bus call returned %d (success=%d)", __func__, ret, success);
return ret;
if (cb)
cb(ret, error);
}
/**
* call_audio_enable_speaker:
* call_audio_enable_speaker_async:
* @enable: Desired speaker state
* @cb: Function to be called when operation completes
*
* Enable or disable speaker output.
*/
void call_audio_enable_speaker_async(gboolean enable, CallAudioCallback cb)
{
call_audio_dbus_call_audio_call_enable_speaker(_proxy, enable, NULL,
enable_speaker_done, cb);
}
/**
* call_audio_enable_speaker:
* @enable: Desired speaker state
*
* Enable or disable speaker output. This function is synchronous, and will
* return only once the operation has been executed.
*
* Returns: %TRUE if successful, or %FALSE on error.
*/
gboolean call_audio_enable_speaker(gboolean enable)
{
guint result;
gboolean ret;
GError *error = NULL;
gboolean success = FALSE;
gboolean ret;
ret = call_audio_dbus_call_audio_call_enable_speaker_sync(_proxy, enable,
&result, NULL, &error);
if (error) {
ret = call_audio_dbus_call_audio_call_enable_speaker_sync(_proxy, enable, &success,
NULL, &error);
if (error)
g_critical("Couldn't enable speaker: %s", error->message);
}
g_debug("EnableSpeaker %s: return %u", ret ? "succeeded" : "failed", result);
g_debug("EnableSpeaker %s: success=%d", ret ? "succeeded" : "failed", success);
return ret;
return (ret && success);
}
static void mute_mic_done(GObject *object, GAsyncResult *result, gpointer data)
{
CallAudioDbusCallAudio *proxy = CALL_AUDIO_DBUS_CALL_AUDIO(object);
CallAudioCallback cb = data;
GError *error = NULL;
gboolean success = 0;
gboolean ret;
g_return_if_fail(CALL_AUDIO_DBUS_IS_CALL_AUDIO(proxy));
ret = call_audio_dbus_call_audio_call_mute_mic_finish(proxy, &success,
result, &error);
if (!ret || !success)
g_warning("MuteMic failed with code %d: %s", success, error->message);
g_debug("%s: D-bus call returned %d (success=%d)", __func__, ret, success);
if (cb)
cb(success, error);
}
/**
* call_audio_mute_mic:
* call_audio_mute_mic_async:
* @mute: %TRUE to mute the microphone, or %FALSE to unmute it
* @cb: Function to be called when operation completes
*
* Mute or unmute microphone.
*/
void call_audio_mute_mic_async(gboolean mute, CallAudioCallback cb)
{
call_audio_dbus_call_audio_call_mute_mic(_proxy, mute, NULL,
mute_mic_done, cb);
}
/**
* call_audio_mute_mic:
* @mute: %TRUE to mute the microphone, or %FALSE to unmute it
*
* Mute or unmute microphone. This function is synchronous, and will return
* only once the operation has been executed.
*
* Returns: %TRUE if successful, or %FALSE on error.
*/
gboolean call_audio_mute_mic(gboolean mute)
{
guint result;
gboolean ret;
GError *error = NULL;
gboolean success = FALSE;
gboolean ret;
ret = call_audio_dbus_call_audio_call_mute_mic_sync(_proxy, mute,
&result, NULL, &error);
if (error) {
ret = call_audio_dbus_call_audio_call_mute_mic_sync(_proxy, mute, &success,
NULL, &error);
if (error)
g_critical("Couldn't mute mic: %s", error->message);
}
g_debug("MuteMic %s: return %u", ret ? "succeeded" : "failed", result);
g_debug("MuteMic %s: success=%d", ret ? "succeeded" : "failed", success);
return ret;
return (ret && success);
}
......@@ -24,11 +24,21 @@ typedef enum _CallAudioMode {
CALL_AUDIO_MODE_CALL,
} CallAudioMode;
gboolean call_audio_init(GError **error);
void call_audio_deinit(void);
typedef void (*CallAudioCallback)(gboolean success, GError *error);
gboolean call_audio_select_mode(CallAudioMode mode);
gboolean call_audio_enable_speaker(gboolean enable);
gboolean call_audio_mute_mic(gboolean mute);
gboolean call_audio_init(GError **error);
void call_audio_deinit(void);
gboolean call_audio_select_mode(CallAudioMode mode);
void call_audio_select_mode_async(CallAudioMode mode,
CallAudioCallback cb);
gboolean call_audio_enable_speaker(gboolean enable);
void call_audio_enable_speaker_async(gboolean enable,
CallAudioCallback cb);
gboolean call_audio_mute_mic(gboolean mute);
void call_audio_mute_mic_async(gboolean mute,
CallAudioCallback cb);
G_END_DECLS
......@@ -8,7 +8,7 @@
project (
'callaudiod',
'c',
version : '0.0.1',
version : '0.0.3',
license : 'LGPLv3+',
meson_version : '>= 0.50.0',
default_options :
......@@ -26,8 +26,10 @@ app_name = meson.project_name()
prefix = get_option('prefix')
datadir = get_option('datadir')
sysconfdir = get_option('sysconfdir')
bindir = join_paths(prefix, get_option('bindir'))
libdir = join_paths(prefix, get_option('libdir'))
ifacedir = join_paths(prefix, join_paths(datadir, 'dbus-1', 'interfaces'))
servicedir = join_paths(prefix, join_paths(datadir, 'dbus-1', 'services'))
if datadir.startswith('/')
full_datadir = datadir
......
......@@ -29,18 +29,25 @@ static void complete_command_cb(CadOperation *op)
if (!op)
return;
switch (op->type) {
case CAD_OPERATION_SELECT_MODE:
call_audio_dbus_call_audio_complete_select_mode(op->object, op->invocation, op->result);
break;
case CAD_OPERATION_ENABLE_SPEAKER:
call_audio_dbus_call_audio_complete_enable_speaker(op->object, op->invocation, op->result);
break;
case CAD_OPERATION_MUTE_MIC:
call_audio_dbus_call_audio_complete_mute_mic(op->object, op->invocation, op->result);
break;
default:
break;
if (op->success) {
switch (op->type) {
case CAD_OPERATION_SELECT_MODE:
call_audio_dbus_call_audio_complete_select_mode(op->object, op->invocation, op->success);
break;
case CAD_OPERATION_ENABLE_SPEAKER:
call_audio_dbus_call_audio_complete_enable_speaker(op->object, op->invocation, op->success);
break;
case CAD_OPERATION_MUTE_MIC:
call_audio_dbus_call_audio_complete_mute_mic(op->object, op->invocation, op->success);
break;
default:
g_critical("unknown operation %d", op->type);
break;
}
} else {
g_dbus_method_invocation_return_error(op->invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Operation failed");
}
free(op);
......@@ -59,13 +66,21 @@ static gboolean cad_manager_handle_select_mode(CallAudioDbusCallAudio *object,
return FALSE;
}
op = malloc(sizeof(CadOperation));
op = g_new(CadOperation, 1);
if (!op) {
g_critical("Unable to allocate memory for select mode operation");
g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
G_DBUS_ERROR_NO_MEMORY,
"Failed to allocate operation");
return FALSE;
}
op->type = CAD_OPERATION_SELECT_MODE;
op->object = object;
op->invocation = invocation;
op->callback = complete_command_cb;
g_message("Select mode: %u", mode);
g_debug("Select mode: %u", mode);
cad_pulse_select_mode(mode, op);
return TRUE;
}
......@@ -76,13 +91,21 @@ static gboolean cad_manager_handle_enable_speaker(CallAudioDbusCallAudio *object
{
CadOperation *op;
op = malloc(sizeof(CadOperation));
op = g_new(CadOperation, 1);
if (!op) {
g_critical("Unable to allocate memory for speaker operation");
g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
G_DBUS_ERROR_NO_MEMORY,
"Failed to allocate operation");
return FALSE;
}
op->type = CAD_OPERATION_ENABLE_SPEAKER;
op->object = object;
op->invocation = invocation;
op->callback = complete_command_cb;
g_message("Enable speaker: %d", enable);
g_debug("Enable speaker: %d", enable);
cad_pulse_enable_speaker(enable, op);
return TRUE;
}
......@@ -93,13 +116,21 @@ static gboolean cad_manager_handle_mute_mic(CallAudioDbusCallAudio *object,
{
CadOperation *op;
op = malloc(sizeof(CadOperation));
op = g_new(CadOperation, 1);
if (!op) {
g_critical("Unable to allocate memory for mic operation");
g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
G_DBUS_ERROR_NO_MEMORY,
"Failed to allocate operation");
return FALSE;
}
op->type = CAD_OPERATION_MUTE_MIC;
op->object = object;
op->invocation = invocation;
op->callback = complete_command_cb;
g_message("Mute mic: %d", mute);
g_debug("Mute mic: %d", mute);
cad_pulse_mute_mic(mute, op);
return TRUE;
}
......@@ -138,6 +169,7 @@ CadManager *cad_manager_get_default(void)
static CadManager *manager;
if (manager == NULL) {
g_debug("initializing manager...");
manager = g_object_new(CAD_TYPE_MANAGER, NULL);
g_object_add_weak_pointer(G_OBJECT(manager), (gpointer *)&manager);
}
......
......@@ -24,5 +24,5 @@ struct _CadOperation {
CallAudioDbusCallAudio *object;
GDBusMethodInvocation *invocation;
CadOperationCallback callback;
guint result;
gboolean success;
};
......@@ -9,6 +9,8 @@
#include "cad-pulse.h"
#include "libcallaudio.h"
#include <glib/gi18n.h>
#include <glib-object.h>
#include <pulse/pulseaudio.h>
......@@ -21,6 +23,11 @@
#define APPLICATION_NAME "CallAudio"
#define APPLICATION_ID "org.mobian-project.CallAudio"
#define SINK_CLASS "sound"
#define CARD_BUS_PATH "platform-sound"
#define CARD_FORM_FACTOR "internal"
#define CARD_MODEM_CLASS "modem"
struct _CadPulse
{
GObject parent_instance;
......@@ -34,6 +41,8 @@ struct _CadPulse
gboolean has_voice_profile;
gchar *speaker_port;
CallAudioMode current_mode;
};
G_DEFINE_TYPE(CadPulse, cad_pulse, G_TYPE_OBJECT);
......@@ -44,16 +53,13 @@ typedef struct _CadPulseOperation {
guint value;
} CadPulseOperation;
#define SINK_CLASS "sound"
#define CARD_BUS_PATH "platform-sound"
#define CARD_FORM_FACTOR "internal"
#define CARD_MODEM_CLASS "modem"
static const gchar *get_available_output(const pa_sink_info *sink, const gchar *exclude)
{
pa_sink_port_info *available_port = NULL;
guint i;
g_debug("looking for available port excluding '%s'", exclude);
for (i = 0; i < sink->n_ports; i++) {
pa_sink_port_info *port = sink->ports[i];
......@@ -66,8 +72,12 @@ static const gchar *get_available_output(const pa_sink_info *sink, const gchar *
available_port = port;
}
if (available_port)
if (available_port) {
g_debug("found available port '%s'", available_port->name);
return available_port->name;
}
g_warning("no available port found!");
return NULL;
}
......@@ -95,10 +105,12 @@ static void process_sink_ports(CadPulse *self, const pa_sink_info *info)
pa_sink_port_info *port = info->ports[i];
if (strstr(port->name, SND_USE_CASE_DEV_SPEAKER) != NULL) {
if (self->speaker_port && strcmp(port->name, self->speaker_port) != 0) {
g_free(self->speaker_port);
self->speaker_port = g_strdup(port->name);
} else if (!self->speaker_port) {
if (self->speaker_port) {
if (strcmp(port->name, self->speaker_port) != 0) {
g_free(self->speaker_port);
self->speaker_port = g_strdup(port->name);
}
} else {
self->speaker_port = g_strdup(port->name);
}
}
......@@ -184,6 +196,8 @@ static void init_card_info(pa_context *ctx, const pa_card_info *info, int eol, v
break;
}
}
g_debug("CARD: %s voice profile", self->has_voice_profile ? "has" : "doesn't have");
}
static void init_cards_list(CadPulse *self)
......@@ -209,16 +223,20 @@ static void changed_cb(pa_context *ctx, pa_subscription_event_type_t type, uint3
switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
case PA_SUBSCRIPTION_EVENT_SINK:
if (idx == self->sink_id && kind == PA_SUBSCRIPTION_EVENT_REMOVE) {
g_debug("sink %u removed", idx);
self->sink_id = -1;
} else if (kind == PA_SUBSCRIPTION_EVENT_NEW) {
g_debug("new sink %u", idx);
op = pa_context_get_sink_info_by_index(ctx, idx, init_sink_info, self);
pa_operation_unref(op);
}
break;
case PA_SUBSCRIPTION_EVENT_SOURCE:
if (idx == self->source_id && kind == PA_SUBSCRIPTION_EVENT_REMOVE) {
g_debug("source %u removed", idx);
self->source_id = -1;
} else if (kind == PA_SUBSCRIPTION_EVENT_NEW) {
g_debug("new sink %u", idx);
op = pa_context_get_source_info_by_index(ctx, idx, init_source_info, self);
pa_operation_unref(op);
}
......@@ -256,6 +274,7 @@ static void pulse_state_cb(pa_context *ctx, void *data)
pa_context_subscribe(ctx,
PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE,
subscribe_cb, self);
g_debug("PA is ready, initializing cards list");
init_cards_list(self);
break;
}
......@@ -329,6 +348,7 @@ CadPulse *cad_pulse_get_default(void)