enlightenment/src/modules/mixer/sink.c

358 lines
12 KiB
C

#include "pa.h"
/** Makes a bit mask from a channel position. \since 0.9.16 */
#define PA_CHANNEL_POSITION_MASK(f) ((pa_channel_position_mask_t) (1ULL << (f)))
#define PA_CHANNEL_POSITION_MASK_LEFT \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT)) \
#define PA_CHANNEL_POSITION_MASK_RIGHT \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT))
#define PA_CHANNEL_POSITION_MASK_CENTER \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
#define PA_CHANNEL_POSITION_MASK_FRONT \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER))
#define PA_CHANNEL_POSITION_MASK_REAR \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
#define PA_CHANNEL_POSITION_MASK_SIDE_OR_TOP_CENTER \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER))
#define PA_CHANNEL_POSITION_MASK_TOP \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
#define PA_CHANNEL_POSITION_MASK_ALL \
((pa_channel_position_mask_t) (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_MAX)-1))
const char *const channel_name_table[PA_CHANNEL_POSITION_MAX] = {
[PA_CHANNEL_POSITION_MONO] = _("Mono"),
[PA_CHANNEL_POSITION_FRONT_CENTER] = _("Front Center"),
[PA_CHANNEL_POSITION_FRONT_LEFT] = _("Front Left"),
[PA_CHANNEL_POSITION_FRONT_RIGHT] = _("Front Right"),
[PA_CHANNEL_POSITION_REAR_CENTER] = _("Rear Center"),
[PA_CHANNEL_POSITION_REAR_LEFT] = _("Rear Left"),
[PA_CHANNEL_POSITION_REAR_RIGHT] = _("Rear Right"),
[PA_CHANNEL_POSITION_LFE] = _("Subwoofer"),
[PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = _("Front Left-of-center"),
[PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = _("Front Right-of-center"),
[PA_CHANNEL_POSITION_SIDE_LEFT] = _("Side Left"),
[PA_CHANNEL_POSITION_SIDE_RIGHT] = _("Side Right"),
[PA_CHANNEL_POSITION_AUX0] = _("Auxiliary 0"),
[PA_CHANNEL_POSITION_AUX1] = _("Auxiliary 1"),
[PA_CHANNEL_POSITION_AUX2] = _("Auxiliary 2"),
[PA_CHANNEL_POSITION_AUX3] = _("Auxiliary 3"),
[PA_CHANNEL_POSITION_AUX4] = _("Auxiliary 4"),
[PA_CHANNEL_POSITION_AUX5] = _("Auxiliary 5"),
[PA_CHANNEL_POSITION_AUX6] = _("Auxiliary 6"),
[PA_CHANNEL_POSITION_AUX7] = _("Auxiliary 7"),
[PA_CHANNEL_POSITION_AUX8] = _("Auxiliary 8"),
[PA_CHANNEL_POSITION_AUX9] = _("Auxiliary 9"),
[PA_CHANNEL_POSITION_AUX10] = _("Auxiliary 10"),
[PA_CHANNEL_POSITION_AUX11] = _("Auxiliary 11"),
[PA_CHANNEL_POSITION_AUX12] = _("Auxiliary 12"),
[PA_CHANNEL_POSITION_AUX13] = _("Auxiliary 13"),
[PA_CHANNEL_POSITION_AUX14] = _("Auxiliary 14"),
[PA_CHANNEL_POSITION_AUX15] = _("Auxiliary 15"),
[PA_CHANNEL_POSITION_AUX16] = _("Auxiliary 16"),
[PA_CHANNEL_POSITION_AUX17] = _("Auxiliary 17"),
[PA_CHANNEL_POSITION_AUX18] = _("Auxiliary 18"),
[PA_CHANNEL_POSITION_AUX19] = _("Auxiliary 19"),
[PA_CHANNEL_POSITION_AUX20] = _("Auxiliary 20"),
[PA_CHANNEL_POSITION_AUX21] = _("Auxiliary 21"),
[PA_CHANNEL_POSITION_AUX22] = _("Auxiliary 22"),
[PA_CHANNEL_POSITION_AUX23] = _("Auxiliary 23"),
[PA_CHANNEL_POSITION_AUX24] = _("Auxiliary 24"),
[PA_CHANNEL_POSITION_AUX25] = _("Auxiliary 25"),
[PA_CHANNEL_POSITION_AUX26] = _("Auxiliary 26"),
[PA_CHANNEL_POSITION_AUX27] = _("Auxiliary 27"),
[PA_CHANNEL_POSITION_AUX28] = _("Auxiliary 28"),
[PA_CHANNEL_POSITION_AUX29] = _("Auxiliary 29"),
[PA_CHANNEL_POSITION_AUX30] = _("Auxiliary 30"),
[PA_CHANNEL_POSITION_AUX31] = _("Auxiliary 31"),
[PA_CHANNEL_POSITION_TOP_CENTER] = _("Top Center"),
[PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = _("Top Front Center"),
[PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = _("Top Front Left"),
[PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = _("Top Front Right"),
[PA_CHANNEL_POSITION_TOP_REAR_CENTER] = _("Top Rear Center"),
[PA_CHANNEL_POSITION_TOP_REAR_LEFT] = _("Top Rear Left"),
[PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = _("Top Rear Right")
};
static Eina_Bool on_left(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_LEFT);
}
static Eina_Bool on_right(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_RIGHT);
}
#if 0
static Eina_Bool on_center(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_CENTER);
}
static Eina_Bool on_lfe(pa_channel_position_t p) {
return p == PA_CHANNEL_POSITION_LFE;
}
#endif
static Eina_Bool on_front(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_FRONT);
}
static Eina_Bool on_rear(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
}
static void
pulse_sink_port_info_free(Pulse_Sink_Port_Info *pi)
{
if (!pi) return;
eina_stringshare_del(pi->name);
eina_stringshare_del(pi->description);
free(pi);
}
void
pulse_sink_free(Pulse_Sink *sink)
{
Pulse_Sink_Port_Info *pi;
if (!sink) return;
if (!sink->deleted)
{
sink->deleted = EINA_TRUE;
if (sink->source)
{
eina_hash_del_by_key(pulse_sources, (uintptr_t*)&sink->index);
return;
}
else
{
eina_hash_del_by_key(pulse_sinks, (uintptr_t*)&sink->index);
return;
}
}
eina_stringshare_del(sink->name);
eina_stringshare_del(sink->description);
EINA_LIST_FREE(sink->ports, pi)
pulse_sink_port_info_free(pi);
eina_stringshare_del(sink->active_port);
free(sink);
}
const Eina_List *
pulse_sink_ports_get(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
return sink->ports;
}
const char *
pulse_sink_port_active_get(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
return sink->active_port;
}
const char *
pulse_sink_name_get(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
return sink->name;
}
const char *
pulse_sink_desc_get(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
return sink->description;
}
uint32_t
pulse_sink_idx_get(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, 0);
return sink->index;
}
Eina_Bool
pulse_sink_muted_get(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, EINA_FALSE);
return sink->mute;
}
uint8_t
pulse_sink_channels_count(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, 0);
return sink->volume.channels;
}
double
pulse_sink_avg_get_pct(Pulse_Sink *sink)
{
double avg;
int x;
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, -1.0);
for (avg = 0, x = 0; x < sink->volume.channels; x++)
avg += sink->volume.values[x];
avg /= sink->volume.channels;
if (avg <= PA_VOLUME_MUTED) return 0.0;
if (avg == PA_VOLUME_NORM) return 100.0;
return (avg * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM;
}
Eina_List *
pulse_sink_channel_names_get(Pulse_Sink *sink)
{
Eina_List *ret = NULL;
unsigned int x;
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
for (x = 0; x < sink->volume.channels; x++)
ret = eina_list_append(ret, pulse_sink_channel_id_get_name(sink, x));
return ret;
}
unsigned int
pulse_sink_channel_name_get_id(Pulse_Sink *sink, const char *name)
{
unsigned int x;
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, UINT_MAX);
EINA_SAFETY_ON_NULL_RETURN_VAL(name, UINT_MAX);
for (x = 0; x < sink->channel_map.channels; x++)
{
if (!strcmp(name, channel_name_table[sink->channel_map.map[x]]))
return x;
}
return UINT_MAX;
}
const char *
pulse_sink_channel_id_get_name(Pulse_Sink *sink, unsigned int id)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, NULL);
return eina_stringshare_add(channel_name_table[sink->channel_map.map[id]]);
}
double
pulse_sink_channel_volume_get(Pulse_Sink *sink, unsigned int id)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, -1);
EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, -1);
return (sink->volume.values[id] * 100 + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM;
}
float
pulse_sink_channel_balance_get(Pulse_Sink *sink, unsigned int id)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, -1.0);
EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, -1.0);
if (on_left(sink->channel_map.map[id])) return 0.0;
if (on_right(sink->channel_map.map[id])) return 1.0;
return 0.5;
}
float
pulse_sink_channel_depth_get(Pulse_Sink *sink, unsigned int id)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, -1.0);
EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, -1.0);
if (on_rear(sink->channel_map.map[id])) return 0.0;
if (on_front(sink->channel_map.map[id])) return 1.0;
return 0.5;
}
float
pulse_sink_balance_get(Pulse_Sink *sink)
{
int c;
float l, r;
pa_volume_t left = 0, right = 0;
unsigned n_left = 0, n_right = 0;
for (c = 0; c < sink->channel_map.channels; c++) {
if (on_left(sink->channel_map.map[c])) {
left += sink->volume.values[c];
n_left++;
} else if (on_right(sink->channel_map.map[c])) {
right += sink->volume.values[c];
n_right++;
}
}
if (n_left <= 0)
l = PA_VOLUME_NORM;
else
l = left / n_left;
if (n_right <= 0)
r = PA_VOLUME_NORM;
else
r = right / n_right;
l /= (float)PA_VOLUME_NORM;
r /= (float)PA_VOLUME_NORM;
return r - l;
}