1 | //driver_jack.c: |
---|
2 | |
---|
3 | /* |
---|
4 | * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009-2011 |
---|
5 | * Copyright (C) Nedko Arnaudov <nedko@arnaudov.name> - 2010 |
---|
6 | * |
---|
7 | * This file is part of roard a part of RoarAudio, |
---|
8 | * a cross-platform sound system for both, home and professional use. |
---|
9 | * See README for details. |
---|
10 | * |
---|
11 | * This file is free software; you can redistribute it and/or modify |
---|
12 | * it under the terms of the GNU General Public License version 3 |
---|
13 | * as published by the Free Software Foundation. |
---|
14 | * |
---|
15 | * RoarAudio is distributed in the hope that it will be useful, |
---|
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
18 | * GNU General Public License for more details. |
---|
19 | * |
---|
20 | * You should have received a copy of the GNU General Public License |
---|
21 | * along with this software; see the file COPYING. If not, write to |
---|
22 | * the Free Software Foundation, 51 Franklin Street, Fifth Floor, |
---|
23 | * Boston, MA 02110-1301, USA. |
---|
24 | * |
---|
25 | */ |
---|
26 | |
---|
27 | #include "roard.h" |
---|
28 | |
---|
29 | #ifdef ROAR_HAVE_LIBJACK |
---|
30 | |
---|
31 | static void unregister_ports(struct driver_jack * self) { |
---|
32 | while(self->channels--) { |
---|
33 | if ( self->ports_in != NULL ) |
---|
34 | if ( self->ports_in [self->channels] != NULL ) |
---|
35 | jack_port_unregister(self->client, self->ports_in [self->channels]); |
---|
36 | if ( self->ports_out[self->channels] != NULL ) |
---|
37 | jack_port_unregister(self->client, self->ports_out[self->channels]); |
---|
38 | } |
---|
39 | } |
---|
40 | |
---|
41 | int driver_jack_open_vio (struct roar_vio_calls * inst, |
---|
42 | char * device, |
---|
43 | struct roar_audio_info * info, |
---|
44 | int fh, |
---|
45 | struct roar_stream_server * sstream) { |
---|
46 | struct driver_jack * self; |
---|
47 | char port_name[128]; |
---|
48 | jack_nframes_t new_rate; |
---|
49 | int autoconfig = 0; |
---|
50 | int recsource = 0; |
---|
51 | |
---|
52 | // we are not FH Safe, return error if fh != -1: |
---|
53 | if ( fh != -1 ) |
---|
54 | return -1; |
---|
55 | |
---|
56 | if ( sstream != NULL ) { |
---|
57 | autoconfig = streams_get_flag(ROAR_STREAM(sstream)->id, ROAR_FLAG_AUTOCONF); |
---|
58 | recsource = streams_get_flag(ROAR_STREAM(sstream)->id, ROAR_FLAG_RECSOURCE); |
---|
59 | } |
---|
60 | |
---|
61 | // set up VIO: |
---|
62 | memset(inst, 0, sizeof(struct roar_vio_calls)); |
---|
63 | |
---|
64 | inst->read = driver_jack_read; |
---|
65 | inst->write = driver_jack_write; |
---|
66 | inst->lseek = NULL; // no seeking on this device |
---|
67 | inst->sync = driver_jack_sync; |
---|
68 | inst->ctl = driver_jack_ctl; |
---|
69 | inst->close = driver_jack_close; |
---|
70 | |
---|
71 | // set up internal struct: |
---|
72 | if ( (self = roar_mm_malloc(sizeof(struct driver_jack))) == NULL ) |
---|
73 | return -1; |
---|
74 | |
---|
75 | memset(self, 0, sizeof(struct driver_jack)); |
---|
76 | |
---|
77 | inst->inst = self; |
---|
78 | |
---|
79 | if ( (self->client = jack_client_open("roard", JackNullOption, NULL)) == NULL ) { |
---|
80 | roar_mm_free(self); |
---|
81 | return -1; |
---|
82 | } |
---|
83 | |
---|
84 | new_rate = jack_get_sample_rate(self->client); |
---|
85 | |
---|
86 | // need to check if we need to change stream's parameters: |
---|
87 | if ( info->rate != new_rate || info->bits != 32 || info->codec != ROAR_CODEC_DEFAULT ) { |
---|
88 | if ( autoconfig ) { |
---|
89 | // we are allowed to change the parameters |
---|
90 | info->rate = new_rate; |
---|
91 | info->bits = 32; |
---|
92 | info->codec = ROAR_CODEC_DEFAULT; |
---|
93 | } else { |
---|
94 | // we are not allowed to change the parameters |
---|
95 | ROAR_WARN("driver_jack_open_vio(*): Can not open jack driver with given parameters, try -oO ...,autoconf"); |
---|
96 | goto free_close; |
---|
97 | } |
---|
98 | } |
---|
99 | |
---|
100 | if ( recsource ) |
---|
101 | if ( (self->ports_in = roar_mm_malloc(sizeof(jack_port_t *) * info->channels)) == NULL ) |
---|
102 | goto free_close; |
---|
103 | |
---|
104 | if ( (self->ports_out = roar_mm_malloc(sizeof(jack_port_t *) * info->channels)) == NULL ) |
---|
105 | goto free_ins; |
---|
106 | |
---|
107 | // NULL ports so we do not segfaul if something goes wrong. |
---|
108 | if ( self->ports_in != NULL ) |
---|
109 | memset(self->ports_in, 0, sizeof(jack_port_t *) * info->channels); |
---|
110 | memset(self->ports_in, 0, sizeof(jack_port_t *) * info->channels); |
---|
111 | |
---|
112 | for (self->channels = 0; self->channels < info->channels; self->channels++) { |
---|
113 | if ( recsource ) { |
---|
114 | snprintf(port_name, sizeof(port_name), "in_%03u", self->channels); |
---|
115 | if ( (self->ports_in [self->channels] = jack_port_register(self->client, port_name, |
---|
116 | JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == NULL ) |
---|
117 | goto unregister_ports; |
---|
118 | } |
---|
119 | |
---|
120 | snprintf(port_name, sizeof(port_name), "out_%03u", self->channels); |
---|
121 | if ( (self->ports_out[self->channels] = jack_port_register(self->client, port_name, |
---|
122 | JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL ) { |
---|
123 | jack_port_unregister(self->client, self->ports_in[self->channels]); |
---|
124 | goto unregister_ports; |
---|
125 | } |
---|
126 | } |
---|
127 | |
---|
128 | if (jack_activate(self->client) != 0) |
---|
129 | goto unregister_ports; |
---|
130 | |
---|
131 | return 0; |
---|
132 | |
---|
133 | unregister_ports: |
---|
134 | unregister_ports(self); |
---|
135 | free_ins: |
---|
136 | if ( self->ports_in != NULL ) |
---|
137 | roar_mm_free(self->ports_in); |
---|
138 | free_close: |
---|
139 | jack_client_close(self->client); |
---|
140 | roar_mm_free(self); |
---|
141 | return -1; // error |
---|
142 | } |
---|
143 | |
---|
144 | ssize_t driver_jack_read (struct roar_vio_calls * vio, void *buf, size_t count) { |
---|
145 | struct driver_jack * self = vio->inst; |
---|
146 | // read up to count bytes into buf. |
---|
147 | // return the number of bits read. |
---|
148 | return -1; |
---|
149 | } |
---|
150 | |
---|
151 | ssize_t driver_jack_write (struct roar_vio_calls * vio, void *buf, size_t count) { |
---|
152 | struct driver_jack * self = vio->inst; |
---|
153 | // write up to count bytes from buf. |
---|
154 | // return the number of written bytes. |
---|
155 | return -1; |
---|
156 | } |
---|
157 | |
---|
158 | int driver_jack_sync (struct roar_vio_calls * vio) { |
---|
159 | struct driver_jack * self = vio->inst; |
---|
160 | // init to sync data to device. |
---|
161 | // sync does not need to be complet when this function returns. |
---|
162 | return 0; |
---|
163 | } |
---|
164 | |
---|
165 | int driver_jack_ctl (struct roar_vio_calls * vio, roar_vio_ctl_t cmd, void * data) { |
---|
166 | struct driver_jack * self = vio->inst; |
---|
167 | // function for a lot control features. |
---|
168 | |
---|
169 | switch (cmd) { |
---|
170 | case ROAR_VIO_CTL_GET_NAME: |
---|
171 | if ( data == NULL ) |
---|
172 | return -1; |
---|
173 | |
---|
174 | *(char**)data = "driver_jack"; |
---|
175 | return 0; |
---|
176 | break; |
---|
177 | case ROAR_VIO_CTL_GET_FH: |
---|
178 | case ROAR_VIO_CTL_GET_READ_FH: |
---|
179 | case ROAR_VIO_CTL_GET_WRITE_FH: |
---|
180 | case ROAR_VIO_CTL_GET_SELECT_FH: |
---|
181 | case ROAR_VIO_CTL_GET_SELECT_READ_FH: |
---|
182 | case ROAR_VIO_CTL_GET_SELECT_WRITE_FH: |
---|
183 | /* Return FH if possible: |
---|
184 | *(int*)data = FH...; |
---|
185 | */ |
---|
186 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
187 | return -1; |
---|
188 | break; |
---|
189 | case ROAR_VIO_CTL_SET_NOSYNC: |
---|
190 | vio->sync = NULL; |
---|
191 | return 0; |
---|
192 | break; |
---|
193 | case ROAR_VIO_CTL_NONBLOCK: |
---|
194 | // control if read and write calls should block untill all data is read or written. |
---|
195 | // state is in *(int*)data and could be: |
---|
196 | // ROAR_SOCKET_BLOCK - Block untill the data is read or written |
---|
197 | // ROAR_SOCKET_NONBLOCK - Return as soon as possible |
---|
198 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
199 | return -1; |
---|
200 | break; |
---|
201 | case ROAR_VIO_CTL_GET_AUINFO: |
---|
202 | case ROAR_VIO_CTL_SET_AUINFO: |
---|
203 | // get or set audio info, data is a struct roar_audio_info*. |
---|
204 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
205 | return -1; |
---|
206 | break; |
---|
207 | case ROAR_VIO_CTL_GET_DBLKSIZE: |
---|
208 | case ROAR_VIO_CTL_SET_DBLKSIZE: |
---|
209 | // get or set block size used, data is uint_least32_t*, number of bytes. |
---|
210 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
211 | return -1; |
---|
212 | break; |
---|
213 | case ROAR_VIO_CTL_GET_DBLOCKS: |
---|
214 | case ROAR_VIO_CTL_SET_DBLOCKS: |
---|
215 | // get or set number of blocks used, data is uint_least32_t*. |
---|
216 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
217 | return -1; |
---|
218 | break; |
---|
219 | case ROAR_VIO_CTL_SET_SSTREAM: |
---|
220 | // set server stream object for this stream, data is struct roar_stream_server* |
---|
221 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
222 | return -1; |
---|
223 | break; |
---|
224 | case ROAR_VIO_CTL_SET_SSTREAMID: |
---|
225 | // set stream ID for this stream, data is int* |
---|
226 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
227 | return -1; |
---|
228 | break; |
---|
229 | case ROAR_VIO_CTL_SET_VOLUME: |
---|
230 | // set volume for this device, data is struct roar_mixer_settings* |
---|
231 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
232 | return -1; |
---|
233 | break; |
---|
234 | case ROAR_VIO_CTL_GET_DELAY: |
---|
235 | // get delay of this stream, data is uint_least32_t*, in bytes |
---|
236 | // there is more about delay. please ask. |
---|
237 | roar_err_set(ROAR_ERROR_NOTSUP); |
---|
238 | return -1; |
---|
239 | break; |
---|
240 | } |
---|
241 | |
---|
242 | roar_err_set(ROAR_ERROR_BADRQC); |
---|
243 | return -1; |
---|
244 | } |
---|
245 | |
---|
246 | int driver_jack_close (struct roar_vio_calls * vio) { |
---|
247 | struct driver_jack * self = vio->inst; |
---|
248 | // close and free everything in here... |
---|
249 | |
---|
250 | jack_deactivate(self->client); |
---|
251 | unregister_ports(self); |
---|
252 | jack_client_close(self->client); |
---|
253 | |
---|
254 | roar_mm_free(self); |
---|
255 | |
---|
256 | return 0; |
---|
257 | } |
---|
258 | |
---|
259 | #endif |
---|
260 | |
---|
261 | //ll |
---|