add dbus command to allow checking of wether hardware is currently exported
[a2jmidid.git] / port_thread.c
blob5d4d218d934da2c07965c336e2c4af6234d1c7f3
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * ALSA SEQ < - > JACK MIDI bridge
5 * Copyright (c) 2006,2007 Dmitry S. Baikov <c0ff@konstruktiv.org>
6 * Copyright (c) 2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <stdbool.h>
23 #include <semaphore.h>
24 #include <alsa/asoundlib.h>
25 #include <jack/jack.h>
26 #include <jack/ringbuffer.h>
28 #include "list.h"
29 #include "structs.h"
30 #include "port.h"
31 #include "port_hash.h"
32 #include "log.h"
33 #include "port_thread.h"
34 #include "conf.h"
36 struct a2j_port *
37 a2j_find_port_by_addr(
38 struct a2j_stream * stream_ptr,
39 snd_seq_addr_t addr)
41 struct list_head * node_ptr;
42 struct a2j_port * port_ptr;
44 list_for_each(node_ptr, &stream_ptr->list)
46 port_ptr = list_entry(node_ptr, struct a2j_port, siblings);
47 if (port_ptr->remote.client == addr.client && port_ptr->remote.port == addr.port)
49 return port_ptr;
53 return NULL;
56 struct a2j_port *
57 a2j_find_port_by_jack_port_name(
58 struct a2j_stream * stream_ptr,
59 const char * jack_port)
61 struct list_head * node_ptr;
62 struct a2j_port * port_ptr;
64 list_for_each(node_ptr, &stream_ptr->list)
66 port_ptr = list_entry(node_ptr, struct a2j_port, siblings);
67 if (strcmp(port_ptr->name, jack_port) == 0)
69 return port_ptr;
73 return NULL;
77 * ==================== Port add/del handling thread ==============================
79 static
80 void
81 a2j_update_port_type(
82 struct a2j * self,
83 int type,
84 snd_seq_addr_t addr,
85 int caps,
86 const snd_seq_port_info_t * info)
88 struct a2j_stream * stream_ptr;
89 int alsa_mask;
90 struct a2j_port * port_ptr;
92 a2j_debug("update_port_type(%d:%d)", addr.client, addr.port);
94 stream_ptr = &self->stream[type];
95 port_ptr = a2j_find_port_by_addr(stream_ptr, addr);
97 if (type == A2J_PORT_CAPTURE)
99 alsa_mask = SND_SEQ_PORT_CAP_SUBS_READ;
101 else
103 alsa_mask = SND_SEQ_PORT_CAP_SUBS_WRITE;
106 if (port_ptr != NULL && (caps & alsa_mask) != alsa_mask)
108 a2j_debug("setdead: %s", port_ptr->name);
109 port_ptr->is_dead = true;
112 if (port_ptr == NULL && (caps & alsa_mask) == alsa_mask)
114 if(jack_ringbuffer_write_space(stream_ptr->new_ports) >= sizeof(port_ptr)) {
115 port_ptr = a2j_port_create(self, type, addr, info);
116 if (port_ptr != NULL)
118 jack_ringbuffer_write(stream_ptr->new_ports, (char *)&port_ptr, sizeof(port_ptr));
120 } else {
121 a2j_error( "dropping new port event... increase MAX_PORTS" );
126 void
127 a2j_update_port(
128 struct a2j * self,
129 snd_seq_addr_t addr,
130 const snd_seq_port_info_t * info)
132 unsigned int port_caps = snd_seq_port_info_get_capability(info);
133 unsigned int port_type = snd_seq_port_info_get_type(info);
135 a2j_debug("port %u:%u", addr.client, addr.port);
136 a2j_debug("port type: 0x%08X", port_type);
137 a2j_debug("port caps: 0x%08X", port_caps);
139 if (port_type & SND_SEQ_PORT_TYPE_SPECIFIC)
141 a2j_debug("SPECIFIC");
144 if (port_type & SND_SEQ_PORT_TYPE_MIDI_GENERIC)
146 a2j_debug("MIDI_GENERIC");
149 if (port_type & SND_SEQ_PORT_TYPE_MIDI_GM)
151 a2j_debug("MIDI_GM");
154 if (port_type & SND_SEQ_PORT_TYPE_MIDI_GS)
156 a2j_debug("MIDI_GS");
159 if (port_type & SND_SEQ_PORT_TYPE_MIDI_XG)
161 a2j_debug("MIDI_XG");
164 if (port_type & SND_SEQ_PORT_TYPE_MIDI_MT32)
166 a2j_debug("MIDI_MT32");
169 if (port_type & SND_SEQ_PORT_TYPE_MIDI_GM2)
171 a2j_debug("MIDI_GM2");
174 if (port_type & SND_SEQ_PORT_TYPE_SYNTH)
176 a2j_debug("SYNTH");
179 if (port_type & SND_SEQ_PORT_TYPE_DIRECT_SAMPLE)
181 a2j_debug("DIRECT_SAMPLE");
184 if (port_type & SND_SEQ_PORT_TYPE_SAMPLE)
186 a2j_debug("SAMPLE");
189 if (port_type & SND_SEQ_PORT_TYPE_HARDWARE)
191 a2j_debug("HARDWARE");
194 if (port_type & SND_SEQ_PORT_TYPE_SOFTWARE)
196 a2j_debug("SOFTWARE");
199 if (port_type & SND_SEQ_PORT_TYPE_SYNTHESIZER)
201 a2j_debug("SYNTHESIZER");
204 if (port_type & SND_SEQ_PORT_TYPE_PORT)
206 a2j_debug("PORT");
209 if (port_type & SND_SEQ_PORT_TYPE_APPLICATION)
211 a2j_debug("APPLICATION");
214 if (port_type == 0)
216 a2j_debug("Ignoring port of type 0");
217 return;
220 if ((port_type & SND_SEQ_PORT_TYPE_HARDWARE) && !g_a2j_export_hw_ports)
222 a2j_debug("Ignoring hardware port");
223 return;
226 if (port_caps & SND_SEQ_PORT_CAP_NO_EXPORT)
228 a2j_debug("Ignoring no-export port");
229 return;
232 a2j_update_port_type(self, A2J_PORT_CAPTURE, addr, port_caps, info);
233 a2j_update_port_type(self, A2J_PORT_PLAYBACK, addr, port_caps, info);
236 void
237 a2j_free_ports(
238 jack_ringbuffer_t * ports)
240 struct a2j_port *port;
241 int sz;
242 while ((sz = jack_ringbuffer_read(ports, (char*)&port, sizeof(port)))) {
243 assert (sz == sizeof(port));
244 a2j_info("port deleted: %s", port->name);
245 list_del(&port->siblings);
246 a2j_port_free(port);
250 void
251 a2j_update_ports(
252 struct a2j * self)
254 snd_seq_addr_t addr;
255 int size;
257 while ((size = jack_ringbuffer_read(self->port_add, (char *)&addr, sizeof(addr))) != 0)
259 snd_seq_port_info_t * info;
260 int err;
262 snd_seq_port_info_alloca(&info);
263 assert(size == sizeof(addr));
264 assert(addr.client != self->client_id);
265 if ((err = snd_seq_get_any_port_info(self->seq, addr.client, addr.port, info)) >= 0)
267 a2j_update_port(self, addr, info);
269 else
271 //a2j_port_setdead(self->stream[A2J_PORT_CAPTURE].ports, addr);
272 //a2j_port_setdead(self->stream[A2J_PORT_PLAYBACK].ports, addr);