~vcs-imports/a2jmidid/master

« back to all changes in this revision

Viewing changes to a2jmidid.c

  • Committer: Torben Hohn
  • Date: 2009-12-29 04:25:00 UTC
  • mfrom: (145.1.1)
  • Revision ID: git-v1:b2d04be80f5bbfa18deb201e51bd6a9dd6d1da9b
Merge remote branch 'remotes/origin/master'

Show diffs side-by-side

added added

removed removed

Lines of Context:
101
101
}
102
102
 
103
103
static
104
 
void
 
104
bool
105
105
a2j_stream_init(
106
106
  struct a2j * self,
107
107
  int dir)
108
108
{
109
109
  struct a2j_stream *str = &self->stream[dir];
110
110
 
111
 
  str->new_ports = jack_ringbuffer_create(MAX_PORTS*sizeof(struct a2j_port*));
 
111
  str->new_ports = jack_ringbuffer_create(MAX_PORTS * sizeof(struct a2j_port *));
 
112
  if (str->new_ports == NULL)
 
113
  {
 
114
    return false;
 
115
  }
 
116
 
112
117
  snd_midi_event_new(MAX_EVENT_SIZE, &str->codec);
113
118
  INIT_LIST_HEAD(&str->list);
 
119
 
 
120
  return true;
114
121
}
115
122
 
116
123
static
152
159
    jack_ringbuffer_free(str->new_ports);
153
160
}
154
161
 
155
 
struct a2j *
156
 
a2j_new()
 
162
struct a2j * a2j_new(void)
157
163
{
158
164
  int error;
159
 
  extern void* a2j_alsa_input_thread (void*);
160
 
  extern void* a2j_alsa_output_thread (void*);
 
165
  void * thread_status;
161
166
 
162
167
  struct a2j *self = calloc(1, sizeof(struct a2j));
163
168
  a2j_debug("midi: new");
164
169
  if (!self)
165
 
    return NULL;
166
 
 
167
 
  self->port_add = jack_ringbuffer_create(2*MAX_PORTS*sizeof(snd_seq_addr_t));
168
 
  self->port_del = jack_ringbuffer_create(2*MAX_PORTS*sizeof(struct a2j_port*));
169
 
 
170
 
  self->outbound_events = jack_ringbuffer_create(MAX_EVENT_SIZE*16*sizeof(struct a2j_delivery_event));
171
 
 
172
 
  a2j_stream_init(self, A2J_PORT_CAPTURE);
173
 
  a2j_stream_init(self, A2J_PORT_PLAYBACK);
 
170
  {
 
171
    a2j_error("calloc() failed to allocate a2j struct");
 
172
    goto fail;
 
173
  }
 
174
 
 
175
  self->port_add = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(snd_seq_addr_t));
 
176
  if (self->port_add == NULL)
 
177
  {
 
178
    goto free_self;
 
179
  }
 
180
 
 
181
  self->port_del = jack_ringbuffer_create(2 * MAX_PORTS * sizeof(struct a2j_port *));
 
182
  if (self->port_del == NULL)
 
183
  {
 
184
    goto free_ringbuffer_add;
 
185
  }
 
186
 
 
187
  self->outbound_events = jack_ringbuffer_create(MAX_EVENT_SIZE * 16 * sizeof(struct a2j_delivery_event));
 
188
  if (self->outbound_events == NULL)
 
189
  {
 
190
    goto free_ringbuffer_del;
 
191
  }
 
192
 
 
193
  if (!a2j_stream_init(self, A2J_PORT_CAPTURE))
 
194
  {
 
195
    goto free_ringbuffer_outbound;
 
196
  }
 
197
 
 
198
  if (!a2j_stream_init(self, A2J_PORT_PLAYBACK))
 
199
  {
 
200
    goto close_capture_stream;
 
201
  }
174
202
 
175
203
  error = snd_seq_open(&self->seq, "hw", SND_SEQ_OPEN_DUPLEX, 0);
176
204
  if (error < 0)
177
205
  {
178
206
    a2j_error("failed to open alsa seq");
179
 
    free(self);
180
 
    return NULL;
181
 
  }
182
 
 
183
 
  snd_seq_set_client_name(self->seq, "a2jmidid");
 
207
    goto close_playback_stream;
 
208
  }
 
209
 
 
210
  error = snd_seq_set_client_name(self->seq, "a2jmidid");
 
211
  if (error < 0)
 
212
  {
 
213
    a2j_error("snd_seq_set_client_name() failed");
 
214
    goto close_seq_client;
 
215
  }
 
216
 
184
217
  self->port_id = snd_seq_create_simple_port(
185
218
    self->seq,
186
219
    "port",
189
222
    |SND_SEQ_PORT_CAP_NO_EXPORT
190
223
#endif
191
224
    ,SND_SEQ_PORT_TYPE_APPLICATION);
 
225
  if (self->port_id < 0)
 
226
  {
 
227
    a2j_error("snd_seq_create_simple_port() failed");
 
228
    goto close_seq_client;
 
229
  }
 
230
 
192
231
  self->client_id = snd_seq_client_id(self->seq);
 
232
  if (self->client_id < 0)
 
233
  {
 
234
    a2j_error("snd_seq_client_id() failed");
 
235
    goto close_seq_client;
 
236
  }
193
237
 
194
238
  self->queue = snd_seq_alloc_queue(self->seq);
 
239
  if (self->queue < 0)
 
240
  {
 
241
    a2j_error("snd_seq_alloc_queue() failed");
 
242
    goto close_seq_client;
 
243
  }
 
244
 
195
245
  snd_seq_start_queue(self->seq, self->queue, 0); 
196
246
 
197
247
  a2j_stream_attach(self->stream + A2J_PORT_CAPTURE);
198
248
  a2j_stream_attach(self->stream + A2J_PORT_PLAYBACK);
199
249
 
200
 
  snd_seq_nonblock(self->seq, 1);
201
 
 
202
 
  snd_seq_connect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
 
250
  error = snd_seq_nonblock(self->seq, 1);
 
251
  if (error < 0)
 
252
  {
 
253
    a2j_error("snd_seq_nonblock() failed");
 
254
    goto close_seq_client;
 
255
  }
 
256
 
 
257
  error = snd_seq_connect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
 
258
  if (error < 0)
 
259
  {
 
260
    a2j_error("snd_seq_connect_from() failed");
 
261
    goto close_seq_client;
 
262
  }
 
263
 
203
264
  snd_seq_drop_input(self->seq);
204
265
 
205
266
  a2j_add_ports(&self->stream[A2J_PORT_CAPTURE]);
208
269
  self->jack_client = a2j_jack_client_create(self, A2J_JACK_CLIENT_NAME, g_a2j_jack_server_name);
209
270
  if (self->jack_client == NULL)
210
271
  {
211
 
    free(self);
212
 
    return NULL;
 
272
    goto free_self;
213
273
  }
214
274
 
215
 
  if (sem_init (&self->io_semaphore, 0, 0) < 0) {
216
 
    a2j_error ("can't create IO semaphore");
217
 
    free (self);
218
 
    return NULL;
 
275
  if (sem_init(&self->io_semaphore, 0, 0) < 0)
 
276
  {
 
277
    a2j_error("can't create IO semaphore");
 
278
    goto close_jack_client;
219
279
  }
220
280
 
221
281
  if (jack_activate(self->jack_client))
222
282
  {
223
283
    a2j_error("can't activate jack client");
224
 
 
225
 
    error = jack_client_close(self->jack_client);
226
 
    if (error != 0)
227
 
    {
228
 
      a2j_error("Cannot close jack client");
229
 
    }
230
 
 
231
 
    free(self);
232
 
    return NULL;
 
284
    goto sem_destroy;
233
285
  }
234
286
 
235
287
  a2j_add_existing_ports(self);
236
288
 
237
289
  g_keep_alsa_walking = true;
238
290
 
239
 
  if (pthread_create (&self->alsa_input_thread, NULL, a2j_alsa_input_thread, self) < 0) {
240
 
    fprintf (stderr, "cannot start ALSA input thread\n");
241
 
    free (self);
242
 
    return NULL;
 
291
  if (pthread_create(&self->alsa_input_thread, NULL, a2j_alsa_input_thread, self) < 0)
 
292
  {
 
293
    a2j_error("cannot start ALSA input thread");
 
294
    goto sem_destroy;
243
295
  }
244
296
 
245
 
  if (pthread_create (&self->alsa_output_thread, NULL, a2j_alsa_output_thread, self) < 0) {
246
 
    fprintf (stderr, "cannot start ALSA output thread\n");
247
 
    free (self);
248
 
    return NULL;
 
297
  if (pthread_create(&self->alsa_output_thread, NULL, a2j_alsa_output_thread, self) < 0)
 
298
  {
 
299
    a2j_error("cannot start ALSA output thread");
 
300
    goto join_input_thread;
249
301
  }
250
302
 
251
303
  return self;
 
304
 
 
305
join_input_thread:
 
306
  g_keep_alsa_walking = false;  /* tell alsa threads to stop */
 
307
  snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
 
308
  pthread_join(self->alsa_input_thread, &thread_status);
 
309
sem_destroy:
 
310
  sem_destroy(&self->io_semaphore);
 
311
close_jack_client:
 
312
  error = jack_client_close(self->jack_client);
 
313
  if (error != 0)
 
314
  {
 
315
    a2j_error("Cannot close jack client");
 
316
  }
 
317
close_seq_client:
 
318
  snd_seq_close(self->seq);
 
319
close_playback_stream:
 
320
  a2j_stream_close(self, A2J_PORT_PLAYBACK);
 
321
close_capture_stream:
 
322
  a2j_stream_close(self, A2J_PORT_CAPTURE);
 
323
free_ringbuffer_outbound:
 
324
  jack_ringbuffer_free(self->outbound_events);
 
325
free_ringbuffer_del:
 
326
  jack_ringbuffer_free(self->port_del);
 
327
free_ringbuffer_add:
 
328
  jack_ringbuffer_free(self->port_add);
 
329
free_self:
 
330
  free(self);
 
331
fail:
 
332
  return NULL;
252
333
}
253
334
 
254
 
static
255
 
void
256
 
a2j_destroy(
257
 
  struct a2j * self)
 
335
static void a2j_destroy(struct a2j * self)
258
336
{
259
337
  int error;
260
 
  void* alsa_status;
 
338
  void * thread_status;
261
339
 
262
340
  a2j_debug("midi: delete");
263
341
 
264
342
  g_keep_alsa_walking = false;  /* tell alsa threads to stop */
265
343
 
266
344
  /* do something that we need to do anyway and will wake the input thread, then join */
267
 
 
268
345
  snd_seq_disconnect_from(self->seq, self->port_id, SND_SEQ_CLIENT_SYSTEM, SND_SEQ_PORT_SYSTEM_ANNOUNCE);
269
 
  pthread_join (self->alsa_input_thread, &alsa_status);
 
346
  pthread_join(self->alsa_input_thread, &thread_status);
270
347
 
271
348
  /* wake output thread and join, then destroy the semaphore */
272
 
 
273
 
  sem_post (&self->io_semaphore);
274
 
  pthread_join (self->alsa_output_thread, &alsa_status);
275
 
  sem_destroy (&self->io_semaphore);
 
349
  sem_post(&self->io_semaphore);
 
350
  pthread_join(self->alsa_output_thread, &thread_status);
 
351
  sem_destroy(&self->io_semaphore);
276
352
 
277
353
  jack_ringbuffer_reset(self->port_add);
278
354
 
293
369
  a2j_stream_close(self, A2J_PORT_PLAYBACK);
294
370
  a2j_stream_close(self, A2J_PORT_CAPTURE);
295
371
 
 
372
  jack_ringbuffer_free(self->outbound_events);
296
373
  jack_ringbuffer_free(self->port_add);
297
374
  jack_ringbuffer_free(self->port_del);
298
375
 
299
376
  free(self);
300
377
}
301
378
 
302
 
bool
303
 
a2j_start()
 
379
bool a2j_start(void)
304
380
{
305
381
  if (g_started)
306
382
  {
333
409
  return true;
334
410
}
335
411
 
336
 
bool
337
 
a2j_stop()
 
412
bool a2j_stop(void)
338
413
{
339
414
  if (!g_started)
340
415
  {