#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; }