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