1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2009 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #include "compat.h"
22 #include "device-port.h"
23 #include "alsa-mixer.h"
24 
25 static const char *port_types[] = {
26 	[PA_DEVICE_PORT_TYPE_UNKNOWN] = "unknown",
27 	[PA_DEVICE_PORT_TYPE_AUX] = "aux",
28 	[PA_DEVICE_PORT_TYPE_SPEAKER] = "speaker",
29 	[PA_DEVICE_PORT_TYPE_HEADPHONES] = "headphones",
30 	[PA_DEVICE_PORT_TYPE_LINE] = "line",
31 	[PA_DEVICE_PORT_TYPE_MIC] = "mic",
32 	[PA_DEVICE_PORT_TYPE_HEADSET] = "headset",
33 	[PA_DEVICE_PORT_TYPE_HANDSET] = "handset",
34 	[PA_DEVICE_PORT_TYPE_EARPIECE] = "earpiece",
35 	[PA_DEVICE_PORT_TYPE_SPDIF] = "spdif",
36 	[PA_DEVICE_PORT_TYPE_HDMI] = "hdmi",
37 	[PA_DEVICE_PORT_TYPE_TV] = "tv",
38 	[PA_DEVICE_PORT_TYPE_RADIO] = "radio",
39 	[PA_DEVICE_PORT_TYPE_VIDEO] = "video",
40 	[PA_DEVICE_PORT_TYPE_USB] = "usb",
41 	[PA_DEVICE_PORT_TYPE_BLUETOOTH] = "bluetooth",
42 	[PA_DEVICE_PORT_TYPE_PORTABLE] = "portable",
43 	[PA_DEVICE_PORT_TYPE_HANDSFREE] = "handsfree",
44 	[PA_DEVICE_PORT_TYPE_CAR] = "car",
45 	[PA_DEVICE_PORT_TYPE_HIFI] = "hifi",
46 	[PA_DEVICE_PORT_TYPE_PHONE] = "phone",
47 	[PA_DEVICE_PORT_TYPE_NETWORK] = "network",
48 	[PA_DEVICE_PORT_TYPE_ANALOG] = "analog",
49 };
50 
str_port_type(pa_device_port_type_t type)51 static const char *str_port_type(pa_device_port_type_t type)
52 {
53 	int idx = (type < PA_ELEMENTSOF(port_types)) ? type : 0;
54 	return port_types[idx];
55 }
56 
pa_device_port_new_data_init(pa_device_port_new_data * data)57 pa_device_port_new_data *pa_device_port_new_data_init(pa_device_port_new_data *data)
58 {
59 	pa_assert(data);
60 	pa_zero(*data);
61 	data->type = PA_DEVICE_PORT_TYPE_UNKNOWN;
62 	data->available = PA_AVAILABLE_UNKNOWN;
63 	return data;
64 }
65 
pa_device_port_new_data_set_name(pa_device_port_new_data * data,const char * name)66 void pa_device_port_new_data_set_name(pa_device_port_new_data *data, const char *name)
67 {
68 	pa_assert(data);
69 	pa_xfree(data->name);
70 	data->name = pa_xstrdup(name);
71 }
72 
pa_device_port_new_data_set_description(pa_device_port_new_data * data,const char * description)73 void pa_device_port_new_data_set_description(pa_device_port_new_data *data, const char *description)
74 {
75 	pa_assert(data);
76 	pa_xfree(data->description);
77 	data->description = pa_xstrdup(description);
78 }
79 
pa_device_port_new_data_set_available(pa_device_port_new_data * data,pa_available_t available)80 void pa_device_port_new_data_set_available(pa_device_port_new_data *data, pa_available_t available)
81 {
82 	pa_assert(data);
83 	data->available = available;
84 }
85 
pa_device_port_new_data_set_availability_group(pa_device_port_new_data * data,const char * group)86 void pa_device_port_new_data_set_availability_group(pa_device_port_new_data *data, const char *group)
87 {
88 	pa_assert(data);
89 	pa_xfree(data->availability_group);
90 	data->availability_group = pa_xstrdup(group);
91 }
92 
pa_device_port_new_data_set_direction(pa_device_port_new_data * data,pa_direction_t direction)93 void pa_device_port_new_data_set_direction(pa_device_port_new_data *data, pa_direction_t direction)
94 {
95 	pa_assert(data);
96 	data->direction = direction;
97 }
98 
pa_device_port_new_data_set_type(pa_device_port_new_data * data,pa_device_port_type_t type)99 void pa_device_port_new_data_set_type(pa_device_port_new_data *data, pa_device_port_type_t type)
100 {
101 	pa_assert(data);
102 	data->type = type;
103 }
104 
pa_device_port_new_data_done(pa_device_port_new_data * data)105 void pa_device_port_new_data_done(pa_device_port_new_data *data)
106 {
107 	pa_assert(data);
108 	pa_xfree(data->name);
109 	pa_xfree(data->description);
110 	pa_xfree(data->availability_group);
111 }
112 
pa_device_port_new(pa_core * c,pa_device_port_new_data * data,size_t extra)113 pa_device_port *pa_device_port_new(pa_core *c, pa_device_port_new_data *data, size_t extra)
114 {
115 	pa_device_port *p;
116 
117 	pa_assert(data);
118 	pa_assert(data->name);
119 	pa_assert(data->description);
120 	pa_assert(data->direction == PA_DIRECTION_OUTPUT || data->direction == PA_DIRECTION_INPUT);
121 
122 	p = calloc(1, sizeof(pa_device_port) + extra);
123 
124 	p->port.name = p->name = data->name;
125 	data->name = NULL;
126 	p->port.description = p->description = data->description;
127 	data->description = NULL;
128 	p->priority = p->port.priority = 0;
129 	p->available = data->available;
130 	p->port.available = (enum acp_available) data->available;
131 	p->availability_group = data->availability_group;
132 	data->availability_group = NULL;
133 	p->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
134 	p->direction = data->direction;
135 	p->port.direction = data->direction == PA_DIRECTION_OUTPUT ?
136 		ACP_DIRECTION_PLAYBACK : ACP_DIRECTION_CAPTURE;
137 	p->type = data->type;
138 
139 	p->proplist = pa_proplist_new();
140 	pa_proplist_sets(p->proplist, ACP_KEY_PORT_TYPE, str_port_type(data->type));
141 	if (p->availability_group)
142 		pa_proplist_sets(p->proplist, ACP_KEY_PORT_AVAILABILITY_GROUP, p->availability_group);
143 
144 	p->user_data = (void*)((uint8_t*)p + sizeof(pa_device_port));
145 
146 	return p;
147 }
148 
pa_device_port_free(pa_device_port * port)149 void pa_device_port_free(pa_device_port *port)
150 {
151 	pa_xfree(port->name);
152 	pa_xfree(port->description);
153 	pa_xfree(port->availability_group);
154 	pa_hashmap_free(port->profiles);
155 	pa_proplist_free(port->proplist);
156 	if (port->impl_free)
157 	        port->impl_free (port);
158 	free(port);
159 }
160 
pa_device_port_set_available(pa_device_port * p,pa_available_t status)161 void pa_device_port_set_available(pa_device_port *p, pa_available_t status)
162 {
163 	pa_available_t old = p->available;
164 
165 	if (old == status)
166 		return;
167 	p->available = status;
168 	p->port.available = (enum acp_available) status;
169 
170 	if (p->card && p->card->events && p->card->events->port_available)
171 		p->card->events->port_available(p->card->user_data, p->port.index,
172 				(enum acp_available)old, p->port.available);
173 }
174 
pa_alsa_device_init_description(pa_proplist * p,pa_card * card)175 bool pa_alsa_device_init_description(pa_proplist *p, pa_card *card) {
176     const char *s, *d = NULL, *k;
177     pa_assert(p);
178 
179     if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
180         return true;
181 
182     if (card)
183         if ((s = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_DESCRIPTION)))
184             d = s;
185 
186     if (!d)
187         if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
188             if (pa_streq(s, "internal"))
189                 d = _("Built-in Audio");
190 
191     if (!d)
192         if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
193             if (pa_streq(s, "modem"))
194                 d = _("Modem");
195 
196     if (!d)
197         d = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME);
198 
199     if (!d)
200         return false;
201 
202     k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
203 
204     if (d && k)
205         pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, "%s %s", d, k);
206     else if (d)
207         pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
208 
209     return true;
210 }
211