#include "e_mod_main.h"
#include "Pulse.h"
-//#define BAD_CH_MAPPING 1
#define PULSE_BUS "org.PulseAudio.Core1"
#define PULSE_PATH "/org/pulseaudio/core1"
static Eina_List *sinks = NULL;
static Eina_List *sources = NULL;
static Ecore_Poller *pulse_poller = NULL;
+static Eina_Hash *queue_states = NULL;
static E_DBus_Connection *dbus = NULL;
static E_DBus_Signal_Handler *dbus_handler = NULL;
static Ecore_Timer *disc_timer = NULL;
static unsigned int disc_count = 0;
+static unsigned int update_count = 0;
+static Ecore_Timer *update_timer = NULL;
static Eina_Bool
_pulse_poller_cb(void *d __UNUSED__)
e_mod_mixer_pulse_ready(EINA_TRUE);
}
+static Eina_Bool
+_pulse_update_timer(void *d EINA_UNUSED)
+{
+ e_mod_mixer_pulse_update();
+ update_timer = NULL;
+ return EINA_FALSE;
+}
+
static Eina_Bool
_pulse_update(Pulse *d __UNUSED__, int type __UNUSED__, Pulse_Sink *ev __UNUSED__)
{
id = pulse_server_info_get(conn);
if (id)
pulse_cb_set(conn, id, (Pulse_Cb)_pulse_info_get);
- e_mod_mixer_pulse_update();
+ if (update_timer) ecore_timer_reset(update_timer);
+ else update_timer = ecore_timer_add(0.2, _pulse_update_timer, NULL);
return EINA_TRUE;
}
e_mixer_default_setup();
return ECORE_CALLBACK_RENEW;
}
+ if (!queue_states)
+ queue_states = eina_hash_stringshared_new(free);
pulse_cb_set(conn, id, (Pulse_Cb)_pulse_sinks_get);
id = pulse_sources_get(conn);
if (id)
EINA_LIST_FREE(sources, sink)
pulse_sink_free(sink);
pulse_server_info_free(info);
+ if (queue_states) eina_hash_free(queue_states);
+ queue_states = NULL;
info = NULL;
default_sink = NULL;
+ if (update_timer) ecore_timer_del(update_timer);
+ update_timer = NULL;
// printf("PULSEAUDIO: disconnected at %g\n", ecore_time_unix_get());
return ECORE_CALLBACK_RENEW;
}
+static void
+_pulse_state_queue(Pulse_Sink *sink, int left, int right, int mute)
+{
+ E_Mixer_Channel_State *state = NULL;
+
+ if (queue_states)
+ state = eina_hash_find(queue_states, pulse_sink_name_get(sink));
+ else
+ queue_states = eina_hash_stringshared_new(free);
+ if (!state)
+ {
+ state = E_NEW(E_Mixer_Channel_State, 1);
+ eina_hash_direct_add(queue_states, pulse_sink_name_get(sink), state);
+ state->left = state->right = state->mute = -1;
+ }
+ if (left >= 0)
+ state->left = left;
+ if (right >= 0)
+ state->right = right;
+ if (mute >= 0)
+ state->mute = mute;
+}
+
static Pulse_Sink *
_pulse_sink_find(const char *name)
{
return NULL;
}
+static Eina_Bool
+_pulse_queue_process(const Eina_Hash *h EINA_UNUSED, const char *key, E_Mixer_Channel_State *state, void *d EINA_UNUSED)
+{
+ Eina_List *l, *list[2] = {sinks, sources};
+ void *s, *ch;
+ int x;
+
+ if ((state->mute == -1) && (state->left == -1) && (state->right == -1)) return EINA_TRUE;
+ ch = (void*)1;
+ for (x = 0; x < 2; x++)
+ EINA_LIST_FOREACH(list[x], l, s)
+ {
+ if (key != pulse_sink_name_get(s)) continue;
+ if ((state->left >= 0) || (state->right >= 0))
+ e_mixer_pulse_set_volume(s, &ch, state->left, state->right);
+ if (state->mute >= 0)
+ e_mixer_pulse_set_mute(s, &ch, state->mute);
+ state->left = state->right = state->mute = -1;
+ return EINA_FALSE;
+ }
+ return EINA_TRUE;
+}
+
static void
_pulse_result_cb(Pulse *p __UNUSED__, Pulse_Tag_Id id, void *ev)
{
if (!ev) fprintf(stderr, "Command %u failed!\n", id);
+ if (!update_count) return;
+ if (--update_count) return;
+ if (!queue_states) return;
+ eina_hash_foreach(queue_states, (Eina_Hash_Foreach)_pulse_queue_process, NULL);
}
Eina_Bool
pulse_server_info_free(info);
info = NULL;
default_sink = NULL;
+ update_count = 0;
+ if (update_timer) ecore_timer_del(update_timer);
+ update_timer = NULL;
pulse_free(conn);
conn = NULL;
pch = NULL;
if (pdh) ecore_event_handler_del(pdh);
pdh = NULL;
+ if (queue_states) eina_hash_free(queue_states);
+ queue_states = NULL;
if (dbus_handler)
{
e_dbus_signal_handler_del(dbus, dbus_handler);
}
Eina_List *
-e_mixer_pulse_get_channels(E_Mixer_System *self)
-{
- Eina_List *ret = NULL;
-
-#ifdef BAD_CH_MAPPING
- uintptr_t id;
- for (id = 0; id < pulse_sink_channels_count((void *)self); id++)
- ret = eina_list_append(ret, (void *)(id + 1));
-#else
- (void)self;
- ret = eina_list_append(ret, (void *)(1));
-#endif
- return ret;
+e_mixer_pulse_get_channels(E_Mixer_System *self EINA_UNUSED)
+{
+ return eina_list_append(NULL, (void *)(1));
}
void
}
Eina_List *
-e_mixer_pulse_get_channels_names(E_Mixer_System *self)
+e_mixer_pulse_get_channels_names(E_Mixer_System *self EINA_UNUSED)
{
-#ifdef BAD_CH_MAPPING
- return pulse_sink_channel_names_get((void *)self);
-#else
- (void)self;
return eina_list_append(NULL, eina_stringshare_add("Output"));
-#endif
}
void
}
const char *
-e_mixer_pulse_get_default_channel_name(E_Mixer_System *self)
+e_mixer_pulse_get_default_channel_name(E_Mixer_System *self EINA_UNUSED)
{
-#ifdef BAD_CH_MAPPING
- return e_mixer_pulse_get_channel_name(self, 0);
-#else
- (void)self;
return eina_stringshare_add("Output");
-#endif
}
E_Mixer_Channel *
-e_mixer_pulse_get_channel_by_name(E_Mixer_System *self, const char *name)
-{
-#ifdef BAD_CH_MAPPING
- unsigned int x;
- x = pulse_sink_channel_name_get_id((void *)self, name);
- if (x == UINT_MAX) return NULL;
- return (E_Mixer_Channel *)((uintptr_t)(x + 1));
-#else
- (void)self, (void)name;
+e_mixer_pulse_get_channel_by_name(E_Mixer_System *self EINA_UNUSED, const char *name EINA_UNUSED)
+{
return (E_Mixer_Channel *)1;
-#endif
}
void
}
const char *
-e_mixer_pulse_get_channel_name(E_Mixer_System *self, E_Mixer_Channel *channel)
+e_mixer_pulse_get_channel_name(E_Mixer_System *self EINA_UNUSED, E_Mixer_Channel *channel)
{
if (!channel) return NULL;
-#ifdef BAD_CH_MAPPING
- return pulse_sink_channel_id_get_name((void *)self,
- ((uintptr_t)channel) - 1);
-#else
- (void)self;
return eina_stringshare_add("Output");
-#endif
}
int
e_mixer_pulse_get_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int *left, int *right)
{
double volume;
-
-#ifdef BAD_CH_MAPPING
- if (!channel) return 0;
- volume = pulse_sink_channel_volume_get((void *)self,
- ((uintptr_t)channel) - 1);
- if (left) *left = (int)volume;
- if (right) *right = (int)volume;
-#else
int x, n;
if (!channel) return 0;
for (x = 0; x < n; x++)
{
volume = pulse_sink_channel_volume_get((void *)self,
- ((uintptr_t)channel) - 1);
+ ((uintptr_t)x));
if (x == 0)
{
if (left) *left = (int)volume;
if (right) *right = (int)volume;
}
}
-#endif
return 1;
}
e_mixer_pulse_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int left, int right)
{
uint32_t id = 0;
-
-#ifdef BAD_CH_MAPPING
- if (!channel) return 0;
- id = pulse_type_channel_volume_set(conn, (void *)self,
- ((uintptr_t)channel) - 1,
- (left + right) / 2, source);
- if (!id) return 0;
- pulse_cb_set(conn, id, (Pulse_Cb)_pulse_result_cb);
-#else
int x, n;
if (!channel) return 0;
+ if (update_count > 1)
+ {
+ _pulse_state_queue((void*)self, left, right, -1);
+ return 1;
+ }
n = pulse_sink_channels_count((void *)self);
- for (x = 0; x < n; x++)
+ for (x = 0; x < n; x++, id = 0)
{
double vol;
if (x == 0)
{
if (vol != left)
- id |= pulse_sink_channel_volume_set(conn, (void *)self, x, left);
+ id = pulse_sink_channel_volume_set(conn, (void *)self, x, left);
}
else if (x == 1)
{
if (vol != right)
- id |= pulse_sink_channel_volume_set(conn, (void *)self, x, right);
+ id = pulse_sink_channel_volume_set(conn, (void *)self, x, right);
+ }
+ if (id)
+ {
+ pulse_cb_set(conn, id, (Pulse_Cb)_pulse_result_cb);
+ update_count++;
}
}
-#endif
return 1;
}
uint32_t id;
Eina_Bool source = EINA_FALSE;
+ if (update_count > 2)
+ {
+ _pulse_state_queue((void*)self, -1, -1, mute);
+ return 1;
+ }
source = !!eina_list_data_find(sources, self);
id = pulse_type_mute_set(conn, pulse_sink_idx_get((void *)self), mute, source);
if (!id) return 0;
+ update_count++;
pulse_cb_set(conn, id, (Pulse_Cb)_pulse_result_cb);
return 1;
}
int
e_mixer_pulse_get_state(E_Mixer_System *self, E_Mixer_Channel *channel, E_Mixer_Channel_State *state)
{
-#ifdef BAD_CH_MAPPING
- double vol;
- if (!state) return 0;
- if (!channel) return 0;
- vol = pulse_sink_channel_volume_get((void *)self,
- ((uintptr_t)channel) - 1);
- state->mute = pulse_sink_muted_get((void *)self);
- state->left = state->right = (int)vol;
-#else
if (!state) return 0;
if (!channel) return 0;
e_mixer_pulse_get_mute(self, channel, &(state->mute));
e_mixer_pulse_get_volume(self, channel, &(state->left), &(state->right));
-#endif
return 1;
}
int
e_mixer_pulse_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_Mixer_Channel_State *state)
{
-#ifdef BAD_CH_MAPPING
- uint32_t id;
- Eina_Bool source = EINA_FALSE;
- if (!channel) return 0;
- source = !!eina_list_data_find(sources, self);
- id = pulse_type_channel_volume_set(conn, (void *)self,
- ((uintptr_t)channel) - 1,
- (state->left + state->right) / 2, source);
- if (!id) return 0;
- pulse_cb_set(conn, id, (Pulse_Cb)_pulse_result_cb);
-#else
e_mixer_pulse_set_volume(self, channel, state->left, state->right);
e_mixer_pulse_set_mute(self, channel, state->mute);
-#endif
return 1;
}