Jack2  1.9.9
JackAlsaDriver.cpp
1 /*
2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2004 Grame
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 
19 */
20 
21 #define __STDC_FORMAT_MACROS // For inttypes.h to work in C++
22 
23 #include <iostream>
24 #include <math.h>
25 #include <stdio.h>
26 #include <memory.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <stdarg.h>
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34 #include <string.h>
35 
36 #include "JackAlsaDriver.h"
37 #include "JackEngineControl.h"
38 #include "JackClientControl.h"
39 #include "JackPort.h"
40 #include "JackGraphManager.h"
41 #include "JackLockedEngine.h"
42 #include "JackPosixThread.h"
43 #include "JackCompilerDeps.h"
44 #include "JackServerGlobals.h"
45 
46 namespace Jack
47 {
48 
49 int JackAlsaDriver::SetBufferSize(jack_nframes_t buffer_size)
50 {
51  jack_log("JackAlsaDriver::SetBufferSize %ld", buffer_size);
52  int res = alsa_driver_reset_parameters((alsa_driver_t *)fDriver, buffer_size,
53  ((alsa_driver_t *)fDriver)->user_nperiods,
54  ((alsa_driver_t *)fDriver)->frame_rate);
55 
56  if (res == 0) { // update fEngineControl and fGraphManager
57  JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails
58  // ALSA specific
59  UpdateLatencies();
60  } else {
61  // Restore old values
62  alsa_driver_reset_parameters((alsa_driver_t *)fDriver, fEngineControl->fBufferSize,
63  ((alsa_driver_t *)fDriver)->user_nperiods,
64  ((alsa_driver_t *)fDriver)->frame_rate);
65  }
66 
67  return res;
68 }
69 
70 void JackAlsaDriver::UpdateLatencies()
71 {
73  alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver;
74 
75  for (int i = 0; i < fCaptureChannels; i++) {
76  range.min = range.max = alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency;
77  fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &range);
78  }
79 
80  for (int i = 0; i < fPlaybackChannels; i++) {
81  // Add one buffer more latency if "async" mode is used...
82  range.min = range.max = (alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) +
83  ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency;
84  fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &range);
85  // Monitor port
86  if (fWithMonitorPorts) {
87  range.min = range.max = alsa_driver->frames_per_cycle;
88  fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &range);
89  }
90  }
91 }
92 
93 int JackAlsaDriver::Attach()
94 {
95  JackPort* port;
96  jack_port_id_t port_index;
97  unsigned long port_flags = (unsigned long)CaptureDriverFlags;
98  char name[REAL_JACK_PORT_NAME_SIZE];
99  char alias[REAL_JACK_PORT_NAME_SIZE];
100 
101  assert(fCaptureChannels < DRIVER_PORT_NUM);
102  assert(fPlaybackChannels < DRIVER_PORT_NUM);
103 
104  alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver;
105 
106  if (alsa_driver->has_hw_monitoring)
107  port_flags |= JackPortCanMonitor;
108 
109  // ALSA driver may have changed the values
110  JackAudioDriver::SetBufferSize(alsa_driver->frames_per_cycle);
111  JackAudioDriver::SetSampleRate(alsa_driver->frame_rate);
112 
113  jack_log("JackAlsaDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
114 
115  for (int i = 0; i < fCaptureChannels; i++) {
116  snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
117  snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, i + 1);
118  if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_index) < 0) {
119  jack_error("driver: cannot register port for %s", name);
120  return -1;
121  }
122  port = fGraphManager->GetPort(port_index);
123  port->SetAlias(alias);
124  fCapturePortList[i] = port_index;
125  jack_log("JackAlsaDriver::Attach fCapturePortList[i] %ld ", port_index);
126  }
127 
128  port_flags = (unsigned long)PlaybackDriverFlags;
129 
130  for (int i = 0; i < fPlaybackChannels; i++) {
131  snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1);
132  snprintf(name, sizeof(name), "%s:playback_%d", fClientControl.fName, i + 1);
133  if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_index) < 0) {
134  jack_error("driver: cannot register port for %s", name);
135  return -1;
136  }
137  port = fGraphManager->GetPort(port_index);
138  port->SetAlias(alias);
139  fPlaybackPortList[i] = port_index;
140  jack_log("JackAlsaDriver::Attach fPlaybackPortList[i] %ld ", port_index);
141 
142  // Monitor ports
143  if (fWithMonitorPorts) {
144  jack_log("Create monitor port");
145  snprintf(name, sizeof(name), "%s:monitor_%d", fClientControl.fName, i + 1);
146  if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
147  jack_error("ALSA: cannot register monitor port for %s", name);
148  } else {
149  fMonitorPortList[i] = port_index;
150  }
151  }
152  }
153 
154  UpdateLatencies();
155 
156  if (alsa_driver->midi) {
157  int err = (alsa_driver->midi->attach)(alsa_driver->midi);
158  if (err)
159  jack_error ("ALSA: cannot attach MIDI: %d", err);
160  }
161 
162  return 0;
163 }
164 
165 int JackAlsaDriver::Detach()
166 {
167  alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver;
168  if (alsa_driver->midi)
169  (alsa_driver->midi->detach)(alsa_driver->midi);
170 
171  return JackAudioDriver::Detach();
172 }
173 
174 extern "C" char* get_control_device_name(const char * device_name)
175 {
176  char * ctl_name;
177  const char * comma;
178 
179  /* the user wants a hw or plughw device, the ctl name
180  * should be hw:x where x is the card identification.
181  * We skip the subdevice suffix that starts with comma */
182 
183  if (strncasecmp(device_name, "plughw:", 7) == 0) {
184  /* skip the "plug" prefix" */
185  device_name += 4;
186  }
187 
188  comma = strchr(device_name, ',');
189  if (comma == NULL) {
190  ctl_name = strdup(device_name);
191  if (ctl_name == NULL) {
192  jack_error("strdup(\"%s\") failed.", device_name);
193  }
194  } else {
195  ctl_name = strndup(device_name, comma - device_name);
196  if (ctl_name == NULL) {
197  jack_error("strndup(\"%s\", %u) failed.", device_name, (unsigned int)(comma - device_name));
198  }
199  }
200 
201  return ctl_name;
202 }
203 
204 static int card_to_num(const char* device)
205 {
206  int err;
207  char* ctl_name;
208  snd_ctl_card_info_t *card_info;
209  snd_ctl_t* ctl_handle;
210  int i = -1;
211 
212  snd_ctl_card_info_alloca (&card_info);
213 
214  ctl_name = get_control_device_name(device);
215  if (ctl_name == NULL) {
216  jack_error("get_control_device_name() failed.");
217  goto fail;
218  }
219 
220  if ((err = snd_ctl_open (&ctl_handle, ctl_name, 0)) < 0) {
221  jack_error ("control open \"%s\" (%s)", ctl_name,
222  snd_strerror(err));
223  goto free;
224  }
225 
226  if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) {
227  jack_error ("control hardware info \"%s\" (%s)",
228  device, snd_strerror (err));
229  goto close;
230  }
231 
232  i = snd_ctl_card_info_get_card(card_info);
233 
234 close:
235  snd_ctl_close(ctl_handle);
236 
237 free:
238  free(ctl_name);
239 
240 fail:
241  return i;
242 }
243 
244 int JackAlsaDriver::Open(jack_nframes_t nframes,
245  jack_nframes_t user_nperiods,
246  jack_nframes_t samplerate,
247  bool hw_monitoring,
248  bool hw_metering,
249  bool capturing,
250  bool playing,
251  DitherAlgorithm dither,
252  bool soft_mode,
253  bool monitor,
254  int inchannels,
255  int outchannels,
256  bool shorts_first,
257  const char* capture_driver_name,
258  const char* playback_driver_name,
259  jack_nframes_t capture_latency,
260  jack_nframes_t playback_latency,
261  const char* midi_driver_name)
262 {
263  // Generic JackAudioDriver Open
264  if (JackAudioDriver::Open(nframes, samplerate, capturing, playing,
265  inchannels, outchannels, monitor, capture_driver_name, playback_driver_name,
266  capture_latency, playback_latency) != 0) {
267  return -1;
268  }
269 
270  alsa_midi_t *midi = 0;
271  if (strcmp(midi_driver_name, "seq") == 0)
272  midi = alsa_seqmidi_new((jack_client_t*)this, 0);
273  else if (strcmp(midi_driver_name, "raw") == 0)
274  midi = alsa_rawmidi_new((jack_client_t*)this);
275 
276  if (JackServerGlobals::on_device_acquire != NULL) {
277  int capture_card = card_to_num(capture_driver_name);
278  int playback_card = card_to_num(playback_driver_name);
279  char audio_name[32];
280 
281  if (capture_card >= 0) {
282  snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card);
283  if (!JackServerGlobals::on_device_acquire(audio_name)) {
284  jack_error("Audio device %s cannot be acquired...", capture_driver_name);
285  return -1;
286  }
287  }
288 
289  if (playback_card >= 0 && playback_card != capture_card) {
290  snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card);
291  if (!JackServerGlobals::on_device_acquire(audio_name)) {
292  jack_error("Audio device %s cannot be acquired...", playback_driver_name);
293  if (capture_card >= 0) {
294  snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card);
295  JackServerGlobals::on_device_release(audio_name);
296  }
297  return -1;
298  }
299  }
300  }
301 
302  fDriver = alsa_driver_new ((char*)"alsa_pcm", (char*)playback_driver_name, (char*)capture_driver_name,
303  NULL,
304  nframes,
305  user_nperiods,
306  samplerate,
307  hw_monitoring,
308  hw_metering,
309  capturing,
310  playing,
311  dither,
312  soft_mode,
313  monitor,
314  inchannels,
315  outchannels,
316  shorts_first,
317  capture_latency,
318  playback_latency,
319  midi);
320  if (fDriver) {
321  // ALSA driver may have changed the in/out values
322  fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels;
323  fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels;
324  return 0;
325  } else {
326  JackAudioDriver::Close();
327  return -1;
328  }
329 }
330 
331 int JackAlsaDriver::Close()
332 {
333  // Generic audio driver close
334  int res = JackAudioDriver::Close();
335 
336  alsa_driver_delete((alsa_driver_t*)fDriver);
337 
338  if (JackServerGlobals::on_device_release != NULL)
339  {
340  char audio_name[32];
341  int capture_card = card_to_num(fCaptureDriverName);
342  if (capture_card >= 0) {
343  snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card);
344  JackServerGlobals::on_device_release(audio_name);
345  }
346 
347  int playback_card = card_to_num(fPlaybackDriverName);
348  if (playback_card >= 0 && playback_card != capture_card) {
349  snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card);
350  JackServerGlobals::on_device_release(audio_name);
351  }
352  }
353 
354  return res;
355 }
356 
357 int JackAlsaDriver::Start()
358 {
359  int res = JackAudioDriver::Start();
360  if (res >= 0) {
361  res = alsa_driver_start((alsa_driver_t *)fDriver);
362  if (res < 0) {
363  JackAudioDriver::Stop();
364  }
365  }
366  return res;
367 }
368 
369 int JackAlsaDriver::Stop()
370 {
371  int res = alsa_driver_stop((alsa_driver_t *)fDriver);
372  if (JackAudioDriver::Stop() < 0) {
373  res = -1;
374  }
375  return res;
376 }
377 
378 int JackAlsaDriver::Read()
379 {
380  /* Taken from alsa_driver_run_cycle */
381  int wait_status;
382  jack_nframes_t nframes;
383  fDelayedUsecs = 0.f;
384 
385 retry:
386 
387  nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs);
388 
389  if (wait_status < 0)
390  return -1; /* driver failed */
391 
392  if (nframes == 0) {
393  /* we detected an xrun and restarted: notify
394  * clients about the delay.
395  */
396  jack_log("ALSA XRun wait_status = %d", wait_status);
397  NotifyXRun(fBeginDateUst, fDelayedUsecs);
398  goto retry; /* recoverable error*/
399  }
400 
401  if (nframes != fEngineControl->fBufferSize)
402  jack_log("JackAlsaDriver::Read warning fBufferSize = %ld nframes = %ld", fEngineControl->fBufferSize, nframes);
403 
404  // Has to be done before read
405  JackDriver::CycleIncTime();
406 
407  return alsa_driver_read((alsa_driver_t *)fDriver, fEngineControl->fBufferSize);
408 }
409 
410 int JackAlsaDriver::Write()
411 {
412  return alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize);
413 }
414 
415 void JackAlsaDriver::ReadInputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread)
416 {
417  for (int chn = 0; chn < fCaptureChannels; chn++) {
418  if (fGraphManager->GetConnectionsNum(fCapturePortList[chn]) > 0) {
419  jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[chn], orig_nframes);
420  alsa_driver_read_from_channel((alsa_driver_t *)fDriver, chn, buf + nread, contiguous);
421  }
422  }
423 }
424 
425 void JackAlsaDriver::MonitorInputAux()
426 {
427  for (int chn = 0; chn < fCaptureChannels; chn++) {
428  JackPort* port = fGraphManager->GetPort(fCapturePortList[chn]);
429  if (port->MonitoringInput()) {
430  ((alsa_driver_t *)fDriver)->input_monitor_mask |= (1 << chn);
431  }
432  }
433 }
434 
435 void JackAlsaDriver::ClearOutputAux()
436 {
437  for (int chn = 0; chn < fPlaybackChannels; chn++) {
438  jack_default_audio_sample_t* buf =
439  (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], fEngineControl->fBufferSize);
440  memset(buf, 0, sizeof (jack_default_audio_sample_t) * fEngineControl->fBufferSize);
441  }
442 }
443 
444 void JackAlsaDriver::SetTimetAux(jack_time_t time)
445 {
446  fBeginDateUst = time;
447 }
448 
449 void JackAlsaDriver::WriteOutputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten)
450 {
451  for (int chn = 0; chn < fPlaybackChannels; chn++) {
452  // Output ports
453  if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chn]) > 0) {
454  jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], orig_nframes);
455  alsa_driver_write_to_channel(((alsa_driver_t *)fDriver), chn, buf + nwritten, contiguous);
456  // Monitor ports
457  if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[chn]) > 0) {
458  jack_default_audio_sample_t* monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[chn], orig_nframes);
459  memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t));
460  }
461  }
462  }
463 }
464 
465 int JackAlsaDriver::is_realtime() const
466 {
467  return fEngineControl->fRealTime;
468 }
469 
470 int JackAlsaDriver::create_thread(pthread_t *thread, int priority, int realtime, void *(*start_routine)(void*), void *arg)
471 {
472  return JackPosixThread::StartImp(thread, priority, realtime, start_routine, arg);
473 }
474 
475 jack_port_id_t JackAlsaDriver::port_register(const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size)
476 {
477  jack_port_id_t port_index;
478  int res = fEngine->PortRegister(fClientControl.fRefNum, port_name, port_type, flags, buffer_size, &port_index);
479  return (res == 0) ? port_index : 0;
480 }
481 
482 int JackAlsaDriver::port_unregister(jack_port_id_t port_index)
483 {
484  return fEngine->PortUnRegister(fClientControl.fRefNum, port_index);
485 }
486 
487 void* JackAlsaDriver::port_get_buffer(int port, jack_nframes_t nframes)
488 {
489  return fGraphManager->GetBuffer(port, nframes);
490 }
491 
492 int JackAlsaDriver::port_set_alias(int port, const char* name)
493 {
494  return fGraphManager->GetPort(port)->SetAlias(name);
495 }
496 
497 jack_nframes_t JackAlsaDriver::get_sample_rate() const
498 {
499  return fEngineControl->fSampleRate;
500 }
501 
502 jack_nframes_t JackAlsaDriver::frame_time() const
503 {
504  JackTimer timer;
505  fEngineControl->ReadFrameTime(&timer);
506  return timer.Time2Frames(GetMicroSeconds(), fEngineControl->fBufferSize);
507 }
508 
509 jack_nframes_t JackAlsaDriver::last_frame_time() const
510 {
511  JackTimer timer;
512  fEngineControl->ReadFrameTime(&timer);
513  return timer.CurFrame();
514 }
515 
516 } // end of namespace
517 
518 
519 #ifdef __cplusplus
520 extern "C"
521 {
522 #endif
523 
524 static
525 void
526 fill_device(
527  jack_driver_param_constraint_desc_t ** constraint_ptr_ptr,
528  uint32_t * array_size_ptr,
529  const char * device_id,
530  const char * device_description)
531 {
532  jack_driver_param_value_enum_t * possible_value_ptr;
533 
534  //jack_info("%6s - %s", device_id, device_description);
535 
536  if (*constraint_ptr_ptr == NULL)
537  {
538  *constraint_ptr_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
539  *array_size_ptr = 0;
540  }
541 
542  if ((*constraint_ptr_ptr)->constraint.enumeration.count == *array_size_ptr)
543  {
544  *array_size_ptr += 10;
545  (*constraint_ptr_ptr)->constraint.enumeration.possible_values_array =
547  (*constraint_ptr_ptr)->constraint.enumeration.possible_values_array,
548  sizeof(jack_driver_param_value_enum_t) * *array_size_ptr);
549  }
550 
551  possible_value_ptr = (*constraint_ptr_ptr)->constraint.enumeration.possible_values_array + (*constraint_ptr_ptr)->constraint.enumeration.count;
552  (*constraint_ptr_ptr)->constraint.enumeration.count++;
553  strcpy(possible_value_ptr->value.str, device_id);
554  strcpy(possible_value_ptr->short_desc, device_description);
555 }
556 
557 static
559 enum_alsa_devices()
560 {
561  snd_ctl_t * handle;
562  snd_ctl_card_info_t * info;
563  snd_pcm_info_t * pcminfo_capture;
564  snd_pcm_info_t * pcminfo_playback;
565  int card_no = -1;
566  char card_id[JACK_DRIVER_PARAM_STRING_MAX + 1];
567  char device_id[JACK_DRIVER_PARAM_STRING_MAX + 1];
568  char description[64];
569  int device_no;
570  bool has_capture;
571  bool has_playback;
572  jack_driver_param_constraint_desc_t * constraint_ptr;
573  uint32_t array_size = 0;
574 
575  snd_ctl_card_info_alloca(&info);
576  snd_pcm_info_alloca(&pcminfo_capture);
577  snd_pcm_info_alloca(&pcminfo_playback);
578 
579  constraint_ptr = NULL;
580 
581  while(snd_card_next(&card_no) >= 0 && card_no >= 0)
582  {
583  snprintf(card_id, sizeof(card_id), "hw:%d", card_no);
584 
585  if (snd_ctl_open(&handle, card_id, 0) >= 0 &&
586  snd_ctl_card_info(handle, info) >= 0)
587  {
588  snprintf(card_id, sizeof(card_id), "hw:%s", snd_ctl_card_info_get_id(info));
589  fill_device(&constraint_ptr, &array_size, card_id, snd_ctl_card_info_get_name(info));
590 
591  device_no = -1;
592 
593  while (snd_ctl_pcm_next_device(handle, &device_no) >= 0 && device_no != -1)
594  {
595  snprintf(device_id, sizeof(device_id), "%s,%d", card_id, device_no);
596 
597  snd_pcm_info_set_device(pcminfo_capture, device_no);
598  snd_pcm_info_set_subdevice(pcminfo_capture, 0);
599  snd_pcm_info_set_stream(pcminfo_capture, SND_PCM_STREAM_CAPTURE);
600  has_capture = snd_ctl_pcm_info(handle, pcminfo_capture) >= 0;
601 
602  snd_pcm_info_set_device(pcminfo_playback, device_no);
603  snd_pcm_info_set_subdevice(pcminfo_playback, 0);
604  snd_pcm_info_set_stream(pcminfo_playback, SND_PCM_STREAM_PLAYBACK);
605  has_playback = snd_ctl_pcm_info(handle, pcminfo_playback) >= 0;
606 
607  if (has_capture && has_playback)
608  {
609  snprintf(description, sizeof(description),"%s (duplex)", snd_pcm_info_get_name(pcminfo_capture));
610  }
611  else if (has_capture)
612  {
613  snprintf(description, sizeof(description),"%s (capture)", snd_pcm_info_get_name(pcminfo_capture));
614  }
615  else if (has_playback)
616  {
617  snprintf(description, sizeof(description),"%s (playback)", snd_pcm_info_get_name(pcminfo_playback));
618  }
619  else
620  {
621  continue;
622  }
623 
624  fill_device(&constraint_ptr, &array_size, device_id, description);
625  }
626 
627  snd_ctl_close(handle);
628  }
629  }
630 
631  return constraint_ptr;
632 }
633 
634 static
636 get_midi_driver_constraint()
637 {
638  jack_driver_param_constraint_desc_t * constraint_ptr;
639  jack_driver_param_value_enum_t * possible_value_ptr;
640 
641  //jack_info("%6s - %s", device_id, device_description);
642 
643  constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
644  constraint_ptr->flags = JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE;
645 
646  constraint_ptr->constraint.enumeration.possible_values_array = (jack_driver_param_value_enum_t *)malloc(3 * sizeof(jack_driver_param_value_enum_t));
647  constraint_ptr->constraint.enumeration.count = 3;
648 
649  possible_value_ptr = constraint_ptr->constraint.enumeration.possible_values_array;
650 
651  strcpy(possible_value_ptr->value.str, "none");
652  strcpy(possible_value_ptr->short_desc, "no MIDI driver");
653 
654  possible_value_ptr++;
655 
656  strcpy(possible_value_ptr->value.str, "seq");
657  strcpy(possible_value_ptr->short_desc, "ALSA Sequencer driver");
658 
659  possible_value_ptr++;
660 
661  strcpy(possible_value_ptr->value.str, "raw");
662  strcpy(possible_value_ptr->short_desc, "ALSA RawMIDI driver");
663 
664  return constraint_ptr;
665 }
666 
667 static
669 get_dither_constraint()
670 {
671  jack_driver_param_constraint_desc_t * constraint_ptr;
672  jack_driver_param_value_enum_t * possible_value_ptr;
673 
674  //jack_info("%6s - %s", device_id, device_description);
675 
676  constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t));
677  constraint_ptr->flags = JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE;
678 
679  constraint_ptr->constraint.enumeration.possible_values_array = (jack_driver_param_value_enum_t *)malloc(4 * sizeof(jack_driver_param_value_enum_t));
680  constraint_ptr->constraint.enumeration.count = 4;
681 
682  possible_value_ptr = constraint_ptr->constraint.enumeration.possible_values_array;
683 
684  possible_value_ptr->value.c = 'n';
685  strcpy(possible_value_ptr->short_desc, "none");
686 
687  possible_value_ptr++;
688 
689  possible_value_ptr->value.c = 'r';
690  strcpy(possible_value_ptr->short_desc, "rectangular");
691 
692  possible_value_ptr++;
693 
694  possible_value_ptr->value.c = 's';
695  strcpy(possible_value_ptr->short_desc, "shaped");
696 
697  possible_value_ptr++;
698 
699  possible_value_ptr->value.c = 't';
700  strcpy(possible_value_ptr->short_desc, "triangular");
701 
702  return constraint_ptr;
703 }
704 
705 static int
706 dither_opt (char c, DitherAlgorithm* dither)
707 {
708  switch (c) {
709  case '-':
710  case 'n':
711  *dither = None;
712  break;
713 
714  case 'r':
715  *dither = Rectangular;
716  break;
717 
718  case 's':
719  *dither = Shaped;
720  break;
721 
722  case 't':
723  *dither = Triangular;
724  break;
725 
726  default:
727  fprintf (stderr, "ALSA driver: illegal dithering mode %c\n", c);
728  return -1;
729  }
730  return 0;
731 }
732 
733 SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor ()
734 {
735  jack_driver_desc_t * desc;
738 
739  desc = jack_driver_descriptor_construct("alsa", JackDriverMaster, "Linux ALSA API based audio backend", &filler);
740 
741  strcpy(value.str, "hw:0");
742  jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, enum_alsa_devices(), "ALSA device name", NULL);
743 
744  strcpy(value.str, "none");
745  jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set device", NULL);
746  jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Provide playback ports. Optionally set device", NULL);
747 
748  value.ui = 48000U;
749  jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
750 
751  value.ui = 1024U;
752  jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
753 
754  value.ui = 2U;
755  jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods of playback latency", NULL);
756 
757  value.i = 0;
758  jack_driver_descriptor_add_parameter(desc, &filler, "hwmon", 'H', JackDriverParamBool, &value, NULL, "Hardware monitoring, if available", NULL);
759 
760  value.i = 0;
761  jack_driver_descriptor_add_parameter(desc, &filler, "hwmeter", 'M', JackDriverParamBool, &value, NULL, "Hardware metering, if available", NULL);
762 
763  value.i = 1;
764  jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL);
765 
766  value.i = 0;
767  jack_driver_descriptor_add_parameter(desc, &filler, "softmode", 's', JackDriverParamBool, &value, NULL, "Soft-mode, no xrun handling", NULL);
768 
769  value.i = 0;
770  jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL);
771 
772  value.c = 'n';
773  jack_driver_descriptor_add_parameter(
774  desc,
775  &filler,
776  "dither",
777  'z',
778  JackDriverParamChar,
779  &value,
780  get_dither_constraint(),
781  "Dithering mode",
782  "Dithering mode:\n"
783  " n - none\n"
784  " r - rectangular\n"
785  " s - shaped\n"
786  " t - triangular");
787 
788  value.ui = 0;
789  jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Number of capture channels (defaults to hardware max)", NULL);
790  jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Number of playback channels (defaults to hardware max)", NULL);
791 
792  value.i = FALSE;
793  jack_driver_descriptor_add_parameter(desc, &filler, "shorts", 'S', JackDriverParamBool, &value, NULL, "Try 16-bit samples before 32-bit", NULL);
794 
795  value.ui = 0;
796  jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency (frames)", NULL);
797  jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency (frames)", NULL);
798 
799  strcpy(value.str, "none");
800  jack_driver_descriptor_add_parameter(
801  desc,
802  &filler,
803  "midi-driver",
804  'X',
805  JackDriverParamString,
806  &value,
807  get_midi_driver_constraint(),
808  "ALSA device name",
809  "ALSA MIDI driver:\n"
810  " none - no MIDI driver\n"
811  " seq - ALSA Sequencer driver\n"
812  " raw - ALSA RawMIDI driver\n");
813 
814  return desc;
815 }
816 
817 static Jack::JackAlsaDriver* g_alsa_driver;
818 
819 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
820 {
821  jack_nframes_t srate = 48000;
822  jack_nframes_t frames_per_interrupt = 1024;
823  unsigned long user_nperiods = 2;
824  const char *playback_pcm_name = "hw:0";
825  const char *capture_pcm_name = "hw:0";
826  int hw_monitoring = FALSE;
827  int hw_metering = FALSE;
828  int capture = FALSE;
829  int playback = FALSE;
830  int soft_mode = FALSE;
831  int monitor = FALSE;
832  DitherAlgorithm dither = None;
833  int user_capture_nchnls = 0;
834  int user_playback_nchnls = 0;
835  int shorts_first = FALSE;
836  jack_nframes_t systemic_input_latency = 0;
837  jack_nframes_t systemic_output_latency = 0;
838  const JSList * node;
839  const jack_driver_param_t * param;
840  const char *midi_driver = "none";
841 
842  for (node = params; node; node = jack_slist_next (node)) {
843  param = (const jack_driver_param_t *) node->data;
844 
845  switch (param->character) {
846 
847  case 'C':
848  capture = TRUE;
849  if (strcmp (param->value.str, "none") != 0) {
850  capture_pcm_name = strdup (param->value.str);
851  jack_log("capture device %s", capture_pcm_name);
852  }
853  break;
854 
855  case 'P':
856  playback = TRUE;
857  if (strcmp (param->value.str, "none") != 0) {
858  playback_pcm_name = strdup (param->value.str);
859  jack_log("playback device %s", playback_pcm_name);
860  }
861  break;
862 
863  case 'D':
864  playback = TRUE;
865  capture = TRUE;
866  break;
867 
868  case 'd':
869  if (strcmp (param->value.str, "none") != 0) {
870  playback_pcm_name = strdup (param->value.str);
871  capture_pcm_name = strdup (param->value.str);
872  jack_log("playback device %s", playback_pcm_name);
873  jack_log("capture device %s", capture_pcm_name);
874  }
875  break;
876 
877  case 'H':
878  hw_monitoring = param->value.i;
879  break;
880 
881  case 'm':
882  monitor = param->value.i;
883  break;
884 
885  case 'M':
886  hw_metering = param->value.i;
887  break;
888 
889  case 'r':
890  srate = param->value.ui;
891  jack_log("apparent rate = %d", srate);
892  break;
893 
894  case 'p':
895  frames_per_interrupt = param->value.ui;
896  jack_log("frames per period = %d", frames_per_interrupt);
897  break;
898 
899  case 'n':
900  user_nperiods = param->value.ui;
901  if (user_nperiods < 2) { /* enforce minimum value */
902  user_nperiods = 2;
903  }
904  break;
905 
906  case 's':
907  soft_mode = param->value.i;
908  break;
909 
910  case 'z':
911  if (dither_opt (param->value.c, &dither)) {
912  return NULL;
913  }
914  break;
915 
916  case 'i':
917  user_capture_nchnls = param->value.ui;
918  break;
919 
920  case 'o':
921  user_playback_nchnls = param->value.ui;
922  break;
923 
924  case 'S':
925  shorts_first = param->value.i;
926  break;
927 
928  case 'I':
929  systemic_input_latency = param->value.ui;
930  break;
931 
932  case 'O':
933  systemic_output_latency = param->value.ui;
934  break;
935 
936  case 'X':
937  midi_driver = strdup(param->value.str);
938  break;
939  }
940  }
941 
942  /* duplex is the default */
943  if (!capture && !playback) {
944  capture = TRUE;
945  playback = TRUE;
946  }
947 
948  g_alsa_driver = new Jack::JackAlsaDriver("system", "alsa_pcm", engine, table);
949  Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(g_alsa_driver);
950  // Special open for ALSA driver...
951  if (g_alsa_driver->Open(frames_per_interrupt, user_nperiods, srate, hw_monitoring, hw_metering, capture, playback, dither, soft_mode, monitor,
952  user_capture_nchnls, user_playback_nchnls, shorts_first, capture_pcm_name, playback_pcm_name,
953  systemic_input_latency, systemic_output_latency, midi_driver) == 0) {
954  return threaded_driver;
955  } else {
956  delete threaded_driver; // Delete the decorated driver
957  return NULL;
958  }
959 }
960 
961 // Code to be used in alsa_driver.c
962 
963 void ReadInput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread)
964 {
965  g_alsa_driver->ReadInputAux(orig_nframes, contiguous, nread);
966 }
967 void MonitorInput()
968 {
969  g_alsa_driver->MonitorInputAux();
970 }
971 void ClearOutput()
972 {
973  g_alsa_driver->ClearOutputAux();
974 }
975 void WriteOutput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten)
976 {
977  g_alsa_driver->WriteOutputAux(orig_nframes, contiguous, nwritten);
978 }
979 void SetTime(jack_time_t time)
980 {
981  g_alsa_driver->SetTimetAux(time);
982 }
983 
984 int Restart()
985 {
986  int res;
987  if ((res = g_alsa_driver->Stop()) == 0) {
988  res = g_alsa_driver->Start();
989  }
990  return res;
991 }
992 
993 #ifdef __cplusplus
994 }
995 #endif
996 
997 
The base class for threaded drivers using a &quot;decorator&quot; pattern. Threaded drivers are used with block...
Inter process synchronization using using Mach semaphore.
Locked Engine, access to methods is serialized using a mutex.
The ALSA driver.
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:91
jack_nframes_t min
Definition: types.h:268
jack_nframes_t max
Definition: types.h:272
The base interface for drivers clients.
Definition: JackDriver.h:122
struct jack_driver_param_constraint_desc_t::@0::@2 enumeration
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:107