Jack2
1.9.7
|
00001 /* 00002 Copyright (C) 2001 Paul Davis 00003 Copyright (C) 2004 Grame 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00018 00019 */ 00020 00021 #define __STDC_FORMAT_MACROS // For inttypes.h to work in C++ 00022 00023 #include <iostream> 00024 #include <math.h> 00025 #include <stdio.h> 00026 #include <memory.h> 00027 #include <unistd.h> 00028 #include <stdlib.h> 00029 #include <errno.h> 00030 #include <stdarg.h> 00031 #include <signal.h> 00032 #include <sys/types.h> 00033 #include <sys/time.h> 00034 #include <regex.h> 00035 #include <string.h> 00036 00037 #include "JackAlsaDriver.h" 00038 #include "JackEngineControl.h" 00039 #include "JackClientControl.h" 00040 #include "JackPort.h" 00041 #include "JackGraphManager.h" 00042 #include "JackLockedEngine.h" 00043 #include "JackPosixThread.h" 00044 #include "JackCompilerDeps.h" 00045 #include "JackServerGlobals.h" 00046 00047 namespace Jack 00048 { 00049 00050 int JackAlsaDriver::SetBufferSize(jack_nframes_t buffer_size) 00051 { 00052 jack_log("JackAlsaDriver::SetBufferSize %ld", buffer_size); 00053 int res = alsa_driver_reset_parameters((alsa_driver_t *)fDriver, buffer_size, 00054 ((alsa_driver_t *)fDriver)->user_nperiods, 00055 ((alsa_driver_t *)fDriver)->frame_rate); 00056 00057 if (res == 0) { // update fEngineControl and fGraphManager 00058 JackAudioDriver::SetBufferSize(buffer_size); // never fails 00059 } else { 00060 alsa_driver_reset_parameters((alsa_driver_t *)fDriver, fEngineControl->fBufferSize, 00061 ((alsa_driver_t *)fDriver)->user_nperiods, 00062 ((alsa_driver_t *)fDriver)->frame_rate); 00063 } 00064 00065 return res; 00066 } 00067 00068 int JackAlsaDriver::Attach() 00069 { 00070 JackPort* port; 00071 int port_index; 00072 unsigned long port_flags = (unsigned long)CaptureDriverFlags; 00073 char name[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; 00074 char alias[JACK_CLIENT_NAME_SIZE + JACK_PORT_NAME_SIZE]; 00075 jack_latency_range_t range; 00076 00077 assert(fCaptureChannels < DRIVER_PORT_NUM); 00078 assert(fPlaybackChannels < DRIVER_PORT_NUM); 00079 00080 alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver; 00081 00082 if (alsa_driver->has_hw_monitoring) 00083 port_flags |= JackPortCanMonitor; 00084 00085 // ALSA driver may have changed the values 00086 JackAudioDriver::SetBufferSize(alsa_driver->frames_per_cycle); 00087 JackAudioDriver::SetSampleRate(alsa_driver->frame_rate); 00088 00089 jack_log("JackAlsaDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate); 00090 00091 for (int i = 0; i < fCaptureChannels; i++) { 00092 snprintf(alias, sizeof(alias) - 1, "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1); 00093 snprintf(name, sizeof(name) - 1, "%s:capture_%d", fClientControl.fName, i + 1); 00094 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) { 00095 jack_error("driver: cannot register port for %s", name); 00096 return -1; 00097 } 00098 port = fGraphManager->GetPort(port_index); 00099 port->SetAlias(alias); 00100 range.min = range.max = alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency; 00101 port->SetLatencyRange(JackCaptureLatency, &range); 00102 fCapturePortList[i] = port_index; 00103 jack_log("JackAlsaDriver::Attach fCapturePortList[i] %ld ", port_index); 00104 } 00105 00106 port_flags = (unsigned long)PlaybackDriverFlags; 00107 00108 for (int i = 0; i < fPlaybackChannels; i++) { 00109 snprintf(alias, sizeof(alias) - 1, "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1); 00110 snprintf(name, sizeof(name) - 1, "%s:playback_%d", fClientControl.fName, i + 1); 00111 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize)) == NO_PORT) { 00112 jack_error("driver: cannot register port for %s", name); 00113 return -1; 00114 } 00115 port = fGraphManager->GetPort(port_index); 00116 port->SetAlias(alias); 00117 // Add one buffer more latency if "async" mode is used... 00118 range.min = range.max = (alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + 00119 ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + alsa_driver->playback_frame_latency; 00120 00121 port->SetLatencyRange(JackPlaybackLatency, &range); 00122 fPlaybackPortList[i] = port_index; 00123 jack_log("JackAlsaDriver::Attach fPlaybackPortList[i] %ld ", port_index); 00124 00125 // Monitor ports 00126 if (fWithMonitorPorts) { 00127 jack_log("Create monitor port"); 00128 snprintf(name, sizeof(name) - 1, "%s:monitor_%d", fClientControl.fName, i + 1); 00129 if ((port_index = fGraphManager->AllocatePort(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize)) == NO_PORT) { 00130 jack_error ("ALSA: cannot register monitor port for %s", name); 00131 } else { 00132 port = fGraphManager->GetPort(port_index); 00133 range.min = range.max = alsa_driver->frames_per_cycle; 00134 port->SetLatencyRange(JackCaptureLatency, &range); 00135 fMonitorPortList[i] = port_index; 00136 } 00137 } 00138 } 00139 00140 if (alsa_driver->midi) { 00141 int err = (alsa_driver->midi->attach)(alsa_driver->midi); 00142 if (err) 00143 jack_error ("ALSA: cannot attach MIDI: %d", err); 00144 } 00145 00146 return 0; 00147 } 00148 00149 int JackAlsaDriver::Detach() 00150 { 00151 alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver; 00152 if (alsa_driver->midi) 00153 (alsa_driver->midi->detach)(alsa_driver->midi); 00154 00155 return JackAudioDriver::Detach(); 00156 } 00157 00158 static char* get_control_device_name(const char * device_name) 00159 { 00160 char * ctl_name; 00161 regex_t expression; 00162 00163 regcomp(&expression, "(plug)?hw:[0-9](,[0-9])?", REG_ICASE | REG_EXTENDED); 00164 00165 if (!regexec(&expression, device_name, 0, NULL, 0)) { 00166 /* the user wants a hw or plughw device, the ctl name 00167 * should be hw:x where x is the card number */ 00168 00169 char tmp[5]; 00170 strncpy(tmp, strstr(device_name, "hw"), 4); 00171 tmp[4] = '\0'; 00172 jack_info("control device %s",tmp); 00173 ctl_name = strdup(tmp); 00174 } else { 00175 ctl_name = strdup(device_name); 00176 } 00177 00178 regfree(&expression); 00179 00180 if (ctl_name == NULL) { 00181 jack_error("strdup(\"%s\") failed.", ctl_name); 00182 } 00183 00184 return ctl_name; 00185 } 00186 00187 static int card_to_num(const char* device) 00188 { 00189 int err; 00190 char* ctl_name; 00191 snd_ctl_card_info_t *card_info; 00192 snd_ctl_t* ctl_handle; 00193 int i = -1; 00194 00195 snd_ctl_card_info_alloca (&card_info); 00196 00197 ctl_name = get_control_device_name(device); 00198 if (ctl_name == NULL) { 00199 jack_error("get_control_device_name() failed."); 00200 goto fail; 00201 } 00202 00203 if ((err = snd_ctl_open (&ctl_handle, ctl_name, 0)) < 0) { 00204 jack_error ("control open \"%s\" (%s)", ctl_name, 00205 snd_strerror(err)); 00206 goto free; 00207 } 00208 00209 if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) { 00210 jack_error ("control hardware info \"%s\" (%s)", 00211 device, snd_strerror (err)); 00212 goto close; 00213 } 00214 00215 i = snd_ctl_card_info_get_card(card_info); 00216 00217 close: 00218 snd_ctl_close(ctl_handle); 00219 00220 free: 00221 free(ctl_name); 00222 00223 fail: 00224 return i; 00225 } 00226 00227 int JackAlsaDriver::Open(jack_nframes_t nframes, 00228 jack_nframes_t user_nperiods, 00229 jack_nframes_t samplerate, 00230 bool hw_monitoring, 00231 bool hw_metering, 00232 bool capturing, 00233 bool playing, 00234 DitherAlgorithm dither, 00235 bool soft_mode, 00236 bool monitor, 00237 int inchannels, 00238 int outchannels, 00239 bool shorts_first, 00240 const char* capture_driver_name, 00241 const char* playback_driver_name, 00242 jack_nframes_t capture_latency, 00243 jack_nframes_t playback_latency, 00244 const char* midi_driver_name) 00245 { 00246 // Generic JackAudioDriver Open 00247 if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, 00248 inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, 00249 capture_latency, playback_latency) != 0) { 00250 return -1; 00251 } 00252 00253 alsa_midi_t *midi = 0; 00254 if (strcmp(midi_driver_name, "seq") == 0) 00255 midi = alsa_seqmidi_new((jack_client_t*)this, 0); 00256 else if (strcmp(midi_driver_name, "raw") == 0) 00257 midi = alsa_rawmidi_new((jack_client_t*)this); 00258 00259 if (JackServerGlobals::on_device_acquire != NULL) 00260 { 00261 int capture_card = card_to_num(capture_driver_name); 00262 int playback_card = card_to_num(playback_driver_name); 00263 char audio_name[32]; 00264 00265 snprintf(audio_name, sizeof(audio_name) - 1, "Audio%d", capture_card); 00266 if (!JackServerGlobals::on_device_acquire(audio_name)) { 00267 jack_error("Audio device %s cannot be acquired, trying to open it anyway...", capture_driver_name); 00268 } 00269 00270 if (playback_card != capture_card) { 00271 snprintf(audio_name, sizeof(audio_name) - 1, "Audio%d", playback_card); 00272 if (!JackServerGlobals::on_device_acquire(audio_name)) { 00273 jack_error("Audio device %s cannot be acquired, trying to open it anyway...", playback_driver_name); 00274 } 00275 } 00276 } 00277 00278 fDriver = alsa_driver_new ("alsa_pcm", (char*)playback_driver_name, (char*)capture_driver_name, 00279 NULL, 00280 nframes, 00281 user_nperiods, 00282 samplerate, 00283 hw_monitoring, 00284 hw_metering, 00285 capturing, 00286 playing, 00287 dither, 00288 soft_mode, 00289 monitor, 00290 inchannels, 00291 outchannels, 00292 shorts_first, 00293 capture_latency, 00294 playback_latency, 00295 midi); 00296 if (fDriver) { 00297 // ALSA driver may have changed the in/out values 00298 fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels; 00299 fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels; 00300 return 0; 00301 } else { 00302 JackAudioDriver::Close(); 00303 return -1; 00304 } 00305 } 00306 00307 int JackAlsaDriver::Close() 00308 { 00309 // Generic audio driver close 00310 int res = JackAudioDriver::Close(); 00311 00312 alsa_driver_delete((alsa_driver_t*)fDriver); 00313 00314 if (JackServerGlobals::on_device_release != NULL) 00315 { 00316 char audio_name[32]; 00317 int capture_card = card_to_num(fCaptureDriverName); 00318 if (capture_card >= 0) { 00319 snprintf(audio_name, sizeof(audio_name) - 1, "Audio%d", capture_card); 00320 JackServerGlobals::on_device_release(audio_name); 00321 } 00322 00323 int playback_card = card_to_num(fPlaybackDriverName); 00324 if (playback_card >= 0 && playback_card != capture_card) { 00325 snprintf(audio_name, sizeof(audio_name) - 1, "Audio%d", playback_card); 00326 JackServerGlobals::on_device_release(audio_name); 00327 } 00328 } 00329 00330 return res; 00331 } 00332 00333 int JackAlsaDriver::Start() 00334 { 00335 int res = JackAudioDriver::Start(); 00336 if (res >= 0) { 00337 res = alsa_driver_start((alsa_driver_t *)fDriver); 00338 if (res < 0) { 00339 JackAudioDriver::Stop(); 00340 } 00341 } 00342 return res; 00343 } 00344 00345 int JackAlsaDriver::Stop() 00346 { 00347 int res = alsa_driver_stop((alsa_driver_t *)fDriver); 00348 if (JackAudioDriver::Stop() < 0) { 00349 res = -1; 00350 } 00351 return res; 00352 } 00353 00354 int JackAlsaDriver::Read() 00355 { 00356 /* Taken from alsa_driver_run_cycle */ 00357 int wait_status; 00358 jack_nframes_t nframes; 00359 fDelayedUsecs = 0.f; 00360 00361 retry: 00362 00363 nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); 00364 00365 if (wait_status < 0) 00366 return -1; /* driver failed */ 00367 00368 if (nframes == 0) { 00369 /* we detected an xrun and restarted: notify 00370 * clients about the delay. 00371 */ 00372 jack_log("ALSA XRun wait_status = %d", wait_status); 00373 NotifyXRun(fBeginDateUst, fDelayedUsecs); 00374 goto retry; /* recoverable error*/ 00375 } 00376 00377 if (nframes != fEngineControl->fBufferSize) 00378 jack_log("JackAlsaDriver::Read warning fBufferSize = %ld nframes = %ld", fEngineControl->fBufferSize, nframes); 00379 00380 // Has to be done before read 00381 JackDriver::CycleIncTime(); 00382 00383 return alsa_driver_read((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); 00384 } 00385 00386 int JackAlsaDriver::Write() 00387 { 00388 return alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); 00389 } 00390 00391 void JackAlsaDriver::ReadInputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread) 00392 { 00393 for (int chn = 0; chn < fCaptureChannels; chn++) { 00394 if (fGraphManager->GetConnectionsNum(fCapturePortList[chn]) > 0) { 00395 jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[chn], orig_nframes); 00396 alsa_driver_read_from_channel((alsa_driver_t *)fDriver, chn, buf + nread, contiguous); 00397 } 00398 } 00399 } 00400 00401 void JackAlsaDriver::MonitorInputAux() 00402 { 00403 for (int chn = 0; chn < fCaptureChannels; chn++) { 00404 JackPort* port = fGraphManager->GetPort(fCapturePortList[chn]); 00405 if (port->MonitoringInput()) { 00406 ((alsa_driver_t *)fDriver)->input_monitor_mask |= (1 << chn); 00407 } 00408 } 00409 } 00410 00411 void JackAlsaDriver::ClearOutputAux() 00412 { 00413 for (int chn = 0; chn < fPlaybackChannels; chn++) { 00414 jack_default_audio_sample_t* buf = 00415 (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], fEngineControl->fBufferSize); 00416 memset(buf, 0, sizeof (jack_default_audio_sample_t) * fEngineControl->fBufferSize); 00417 } 00418 } 00419 00420 void JackAlsaDriver::SetTimetAux(jack_time_t time) 00421 { 00422 fBeginDateUst = time; 00423 } 00424 00425 void JackAlsaDriver::WriteOutputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten) 00426 { 00427 for (int chn = 0; chn < fPlaybackChannels; chn++) { 00428 // Output ports 00429 if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chn]) > 0) { 00430 jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], orig_nframes); 00431 alsa_driver_write_to_channel(((alsa_driver_t *)fDriver), chn, buf + nwritten, contiguous); 00432 // Monitor ports 00433 if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[chn]) > 0) { 00434 jack_default_audio_sample_t* monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[chn], orig_nframes); 00435 memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); 00436 } 00437 } 00438 } 00439 } 00440 00441 int JackAlsaDriver::is_realtime() const 00442 { 00443 return fEngineControl->fRealTime; 00444 } 00445 00446 int JackAlsaDriver::create_thread(pthread_t *thread, int priority, int realtime, void *(*start_routine)(void*), void *arg) 00447 { 00448 return JackPosixThread::StartImp(thread, priority, realtime, start_routine, arg); 00449 } 00450 00451 jack_port_id_t JackAlsaDriver::port_register(const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size) 00452 { 00453 jack_port_id_t port_index; 00454 int res = fEngine->PortRegister(fClientControl.fRefNum, port_name, port_type, flags, buffer_size, &port_index); 00455 return (res == 0) ? port_index : 0; 00456 } 00457 00458 int JackAlsaDriver::port_unregister(jack_port_id_t port_index) 00459 { 00460 return fEngine->PortUnRegister(fClientControl.fRefNum, port_index); 00461 } 00462 00463 void* JackAlsaDriver::port_get_buffer(int port, jack_nframes_t nframes) 00464 { 00465 return fGraphManager->GetBuffer(port, nframes); 00466 } 00467 00468 int JackAlsaDriver::port_set_alias(int port, const char* name) 00469 { 00470 return fGraphManager->GetPort(port)->SetAlias(name); 00471 } 00472 00473 jack_nframes_t JackAlsaDriver::get_sample_rate() const 00474 { 00475 return fEngineControl->fSampleRate; 00476 } 00477 00478 jack_nframes_t JackAlsaDriver::frame_time() const 00479 { 00480 JackTimer timer; 00481 fEngineControl->ReadFrameTime(&timer); 00482 return timer.Time2Frames(GetMicroSeconds(), fEngineControl->fBufferSize); 00483 } 00484 00485 jack_nframes_t JackAlsaDriver::last_frame_time() const 00486 { 00487 JackTimer timer; 00488 fEngineControl->ReadFrameTime(&timer); 00489 return timer.CurFrame(); 00490 } 00491 00492 } // end of namespace 00493 00494 00495 #ifdef __cplusplus 00496 extern "C" 00497 { 00498 #endif 00499 00500 static 00501 void 00502 fill_device( 00503 jack_driver_param_constraint_desc_t ** constraint_ptr_ptr, 00504 uint32_t * array_size_ptr, 00505 const char * device_id, 00506 const char * device_description) 00507 { 00508 jack_driver_param_value_enum_t * possible_value_ptr; 00509 00510 //jack_info("%6s - %s", device_id, device_description); 00511 00512 if (*constraint_ptr_ptr == NULL) 00513 { 00514 *constraint_ptr_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t)); 00515 *array_size_ptr = 0; 00516 } 00517 00518 if ((*constraint_ptr_ptr)->constraint.enumeration.count == *array_size_ptr) 00519 { 00520 *array_size_ptr += 10; 00521 (*constraint_ptr_ptr)->constraint.enumeration.possible_values_array = 00522 (jack_driver_param_value_enum_t *)realloc( 00523 (*constraint_ptr_ptr)->constraint.enumeration.possible_values_array, 00524 sizeof(jack_driver_param_value_enum_t) * *array_size_ptr); 00525 } 00526 00527 possible_value_ptr = (*constraint_ptr_ptr)->constraint.enumeration.possible_values_array + (*constraint_ptr_ptr)->constraint.enumeration.count; 00528 (*constraint_ptr_ptr)->constraint.enumeration.count++; 00529 strcpy(possible_value_ptr->value.str, device_id); 00530 strcpy(possible_value_ptr->short_desc, device_description); 00531 } 00532 00533 static 00534 jack_driver_param_constraint_desc_t * 00535 enum_alsa_devices() 00536 { 00537 snd_ctl_t * handle; 00538 snd_ctl_card_info_t * info; 00539 snd_pcm_info_t * pcminfo_capture; 00540 snd_pcm_info_t * pcminfo_playback; 00541 int card_no = -1; 00542 char card_id[JACK_DRIVER_PARAM_STRING_MAX + 1]; 00543 char device_id[JACK_DRIVER_PARAM_STRING_MAX + 1]; 00544 char description[64]; 00545 int device_no; 00546 bool has_capture; 00547 bool has_playback; 00548 jack_driver_param_constraint_desc_t * constraint_ptr; 00549 uint32_t array_size = 0; 00550 00551 snd_ctl_card_info_alloca(&info); 00552 snd_pcm_info_alloca(&pcminfo_capture); 00553 snd_pcm_info_alloca(&pcminfo_playback); 00554 00555 constraint_ptr = NULL; 00556 00557 while(snd_card_next(&card_no) >= 0 && card_no >= 0) 00558 { 00559 sprintf(card_id, "hw:%d", card_no); 00560 00561 if (snd_ctl_open(&handle, card_id, 0) >= 0 && 00562 snd_ctl_card_info(handle, info) >= 0) 00563 { 00564 fill_device(&constraint_ptr, &array_size, card_id, snd_ctl_card_info_get_name(info)); 00565 00566 device_no = -1; 00567 00568 while (snd_ctl_pcm_next_device(handle, &device_no) >= 0 && device_no != -1) 00569 { 00570 sprintf(device_id, "%s,%d", card_id, device_no); 00571 00572 snd_pcm_info_set_device(pcminfo_capture, device_no); 00573 snd_pcm_info_set_subdevice(pcminfo_capture, 0); 00574 snd_pcm_info_set_stream(pcminfo_capture, SND_PCM_STREAM_CAPTURE); 00575 has_capture = snd_ctl_pcm_info(handle, pcminfo_capture) >= 0; 00576 00577 snd_pcm_info_set_device(pcminfo_playback, device_no); 00578 snd_pcm_info_set_subdevice(pcminfo_playback, 0); 00579 snd_pcm_info_set_stream(pcminfo_playback, SND_PCM_STREAM_PLAYBACK); 00580 has_playback = snd_ctl_pcm_info(handle, pcminfo_playback) >= 0; 00581 00582 if (has_capture && has_playback) 00583 { 00584 snprintf(description, sizeof(description),"%s (duplex)", snd_pcm_info_get_name(pcminfo_capture)); 00585 } 00586 else if (has_capture) 00587 { 00588 snprintf(description, sizeof(description),"%s (capture)", snd_pcm_info_get_name(pcminfo_capture)); 00589 } 00590 else if (has_playback) 00591 { 00592 snprintf(description, sizeof(description),"%s (playback)", snd_pcm_info_get_name(pcminfo_playback)); 00593 } 00594 else 00595 { 00596 continue; 00597 } 00598 00599 fill_device(&constraint_ptr, &array_size, device_id, description); 00600 } 00601 00602 snd_ctl_close(handle); 00603 } 00604 } 00605 00606 return constraint_ptr; 00607 } 00608 00609 static 00610 jack_driver_param_constraint_desc_t * 00611 get_midi_driver_constraint() 00612 { 00613 jack_driver_param_constraint_desc_t * constraint_ptr; 00614 jack_driver_param_value_enum_t * possible_value_ptr; 00615 00616 //jack_info("%6s - %s", device_id, device_description); 00617 00618 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t)); 00619 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE; 00620 00621 constraint_ptr->constraint.enumeration.possible_values_array = (jack_driver_param_value_enum_t *)malloc(3 * sizeof(jack_driver_param_value_enum_t)); 00622 constraint_ptr->constraint.enumeration.count = 3; 00623 00624 possible_value_ptr = constraint_ptr->constraint.enumeration.possible_values_array; 00625 00626 strcpy(possible_value_ptr->value.str, "none"); 00627 strcpy(possible_value_ptr->short_desc, "no MIDI driver"); 00628 00629 possible_value_ptr++; 00630 00631 strcpy(possible_value_ptr->value.str, "seq"); 00632 strcpy(possible_value_ptr->short_desc, "ALSA Sequencer driver"); 00633 00634 possible_value_ptr++; 00635 00636 strcpy(possible_value_ptr->value.str, "raw"); 00637 strcpy(possible_value_ptr->short_desc, "ALSA RawMIDI driver"); 00638 00639 return constraint_ptr; 00640 } 00641 00642 static 00643 jack_driver_param_constraint_desc_t * 00644 get_dither_constraint() 00645 { 00646 jack_driver_param_constraint_desc_t * constraint_ptr; 00647 jack_driver_param_value_enum_t * possible_value_ptr; 00648 00649 //jack_info("%6s - %s", device_id, device_description); 00650 00651 constraint_ptr = (jack_driver_param_constraint_desc_t *)calloc(1, sizeof(jack_driver_param_value_enum_t)); 00652 constraint_ptr->flags = JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE; 00653 00654 constraint_ptr->constraint.enumeration.possible_values_array = (jack_driver_param_value_enum_t *)malloc(4 * sizeof(jack_driver_param_value_enum_t)); 00655 constraint_ptr->constraint.enumeration.count = 4; 00656 00657 possible_value_ptr = constraint_ptr->constraint.enumeration.possible_values_array; 00658 00659 possible_value_ptr->value.c = 'n'; 00660 strcpy(possible_value_ptr->short_desc, "none"); 00661 00662 possible_value_ptr++; 00663 00664 possible_value_ptr->value.c = 'r'; 00665 strcpy(possible_value_ptr->short_desc, "rectangular"); 00666 00667 possible_value_ptr++; 00668 00669 possible_value_ptr->value.c = 's'; 00670 strcpy(possible_value_ptr->short_desc, "shaped"); 00671 00672 possible_value_ptr++; 00673 00674 possible_value_ptr->value.c = 't'; 00675 strcpy(possible_value_ptr->short_desc, "triangular"); 00676 00677 return constraint_ptr; 00678 } 00679 00680 static int 00681 dither_opt (char c, DitherAlgorithm* dither) 00682 { 00683 switch (c) { 00684 case '-': 00685 case 'n': 00686 *dither = None; 00687 break; 00688 00689 case 'r': 00690 *dither = Rectangular; 00691 break; 00692 00693 case 's': 00694 *dither = Shaped; 00695 break; 00696 00697 case 't': 00698 *dither = Triangular; 00699 break; 00700 00701 default: 00702 fprintf (stderr, "ALSA driver: illegal dithering mode %c\n", c); 00703 return -1; 00704 } 00705 return 0; 00706 } 00707 00708 SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor () 00709 { 00710 jack_driver_desc_t * desc; 00711 jack_driver_param_desc_t * params; 00712 unsigned int i; 00713 00714 desc = (jack_driver_desc_t*)calloc (1, sizeof (jack_driver_desc_t)); 00715 00716 strcpy(desc->name, "alsa"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 00717 strcpy(desc->desc, "Linux ALSA API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 00718 00719 desc->nparams = 18; 00720 params = (jack_driver_param_desc_t*)calloc (desc->nparams, sizeof (jack_driver_param_desc_t)); 00721 00722 i = 0; 00723 strcpy (params[i].name, "capture"); 00724 params[i].character = 'C'; 00725 params[i].type = JackDriverParamString; 00726 strcpy (params[i].value.str, "none"); 00727 strcpy (params[i].short_desc, 00728 "Provide capture ports. Optionally set device"); 00729 strcpy (params[i].long_desc, params[i].short_desc); 00730 00731 i++; 00732 strcpy (params[i].name, "playback"); 00733 params[i].character = 'P'; 00734 params[i].type = JackDriverParamString; 00735 strcpy (params[i].value.str, "none"); 00736 strcpy (params[i].short_desc, 00737 "Provide playback ports. Optionally set device"); 00738 strcpy (params[i].long_desc, params[i].short_desc); 00739 00740 i++; 00741 strcpy (params[i].name, "device"); 00742 params[i].character = 'd'; 00743 params[i].type = JackDriverParamString; 00744 strcpy (params[i].value.str, "hw:0"); 00745 strcpy (params[i].short_desc, "ALSA device name"); 00746 strcpy (params[i].long_desc, params[i].short_desc); 00747 params[i].constraint = enum_alsa_devices(); 00748 00749 i++; 00750 strcpy (params[i].name, "rate"); 00751 params[i].character = 'r'; 00752 params[i].type = JackDriverParamUInt; 00753 params[i].value.ui = 48000U; 00754 strcpy (params[i].short_desc, "Sample rate"); 00755 strcpy (params[i].long_desc, params[i].short_desc); 00756 00757 i++; 00758 strcpy (params[i].name, "period"); 00759 params[i].character = 'p'; 00760 params[i].type = JackDriverParamUInt; 00761 params[i].value.ui = 1024U; 00762 strcpy (params[i].short_desc, "Frames per period"); 00763 strcpy (params[i].long_desc, params[i].short_desc); 00764 00765 i++; 00766 strcpy (params[i].name, "nperiods"); 00767 params[i].character = 'n'; 00768 params[i].type = JackDriverParamUInt; 00769 params[i].value.ui = 2U; 00770 strcpy (params[i].short_desc, "Number of periods of playback latency"); 00771 strcpy (params[i].long_desc, params[i].short_desc); 00772 00773 i++; 00774 strcpy (params[i].name, "hwmon"); 00775 params[i].character = 'H'; 00776 params[i].type = JackDriverParamBool; 00777 params[i].value.i = 0; 00778 strcpy (params[i].short_desc, "Hardware monitoring, if available"); 00779 strcpy (params[i].long_desc, params[i].short_desc); 00780 00781 i++; 00782 strcpy (params[i].name, "hwmeter"); 00783 params[i].character = 'M'; 00784 params[i].type = JackDriverParamBool; 00785 params[i].value.i = 0; 00786 strcpy (params[i].short_desc, "Hardware metering, if available"); 00787 strcpy (params[i].long_desc, params[i].short_desc); 00788 00789 i++; 00790 strcpy (params[i].name, "duplex"); 00791 params[i].character = 'D'; 00792 params[i].type = JackDriverParamBool; 00793 params[i].value.i = 1; 00794 strcpy (params[i].short_desc, 00795 "Provide both capture and playback ports"); 00796 strcpy (params[i].long_desc, params[i].short_desc); 00797 00798 i++; 00799 strcpy (params[i].name, "softmode"); 00800 params[i].character = 's'; 00801 params[i].type = JackDriverParamBool; 00802 params[i].value.i = 0; 00803 strcpy (params[i].short_desc, "Soft-mode, no xrun handling"); 00804 strcpy (params[i].long_desc, params[i].short_desc); 00805 00806 i++; 00807 strcpy (params[i].name, "monitor"); 00808 params[i].character = 'm'; 00809 params[i].type = JackDriverParamBool; 00810 params[i].value.i = 0; 00811 strcpy (params[i].short_desc, "Provide monitor ports for the output"); 00812 strcpy (params[i].long_desc, params[i].short_desc); 00813 00814 i++; 00815 strcpy (params[i].name, "dither"); 00816 params[i].character = 'z'; 00817 params[i].type = JackDriverParamChar; 00818 params[i].value.c = 'n'; 00819 strcpy (params[i].short_desc, "Dithering mode"); 00820 strcpy (params[i].long_desc, 00821 "Dithering mode:\n" 00822 " n - none\n" 00823 " r - rectangular\n" 00824 " s - shaped\n" 00825 " t - triangular"); 00826 params[i].constraint = get_dither_constraint(); 00827 00828 i++; 00829 strcpy (params[i].name, "inchannels"); 00830 params[i].character = 'i'; 00831 params[i].type = JackDriverParamUInt; 00832 params[i].value.i = 0; 00833 strcpy (params[i].short_desc, 00834 "Number of capture channels (defaults to hardware max)"); 00835 strcpy (params[i].long_desc, params[i].short_desc); 00836 00837 i++; 00838 strcpy (params[i].name, "outchannels"); 00839 params[i].character = 'o'; 00840 params[i].type = JackDriverParamUInt; 00841 params[i].value.i = 0; 00842 strcpy (params[i].short_desc, 00843 "Number of playback channels (defaults to hardware max)"); 00844 strcpy (params[i].long_desc, params[i].short_desc); 00845 00846 i++; 00847 strcpy (params[i].name, "shorts"); 00848 params[i].character = 'S'; 00849 params[i].type = JackDriverParamBool; 00850 params[i].value.i = FALSE; 00851 strcpy (params[i].short_desc, "Try 16-bit samples before 32-bit"); 00852 strcpy (params[i].long_desc, params[i].short_desc); 00853 00854 i++; 00855 strcpy (params[i].name, "input-latency"); 00856 params[i].character = 'I'; 00857 params[i].type = JackDriverParamUInt; 00858 params[i].value.i = 0; 00859 strcpy (params[i].short_desc, "Extra input latency (frames)"); 00860 strcpy (params[i].long_desc, params[i].short_desc); 00861 00862 i++; 00863 strcpy (params[i].name, "output-latency"); 00864 params[i].character = 'O'; 00865 params[i].type = JackDriverParamUInt; 00866 params[i].value.i = 0; 00867 strcpy (params[i].short_desc, "Extra output latency (frames)"); 00868 strcpy (params[i].long_desc, params[i].short_desc); 00869 00870 i++; 00871 strcpy (params[i].name, "midi-driver"); 00872 params[i].character = 'X'; 00873 params[i].type = JackDriverParamString; 00874 strcpy (params[i].value.str, "none"); 00875 strcpy (params[i].short_desc, "ALSA MIDI driver name (seq|raw)"); 00876 strcpy (params[i].long_desc, 00877 "ALSA MIDI driver:\n" 00878 " none - no MIDI driver\n" 00879 " seq - ALSA Sequencer driver\n" 00880 " raw - ALSA RawMIDI driver\n"); 00881 params[i].constraint = get_midi_driver_constraint(); 00882 00883 desc->params = params; 00884 return desc; 00885 } 00886 00887 static Jack::JackAlsaDriver* g_alsa_driver; 00888 00889 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) 00890 { 00891 jack_nframes_t srate = 48000; 00892 jack_nframes_t frames_per_interrupt = 1024; 00893 unsigned long user_nperiods = 2; 00894 const char *playback_pcm_name = "hw:0"; 00895 const char *capture_pcm_name = "hw:0"; 00896 int hw_monitoring = FALSE; 00897 int hw_metering = FALSE; 00898 int capture = FALSE; 00899 int playback = FALSE; 00900 int soft_mode = FALSE; 00901 int monitor = FALSE; 00902 DitherAlgorithm dither = None; 00903 int user_capture_nchnls = 0; 00904 int user_playback_nchnls = 0; 00905 int shorts_first = FALSE; 00906 jack_nframes_t systemic_input_latency = 0; 00907 jack_nframes_t systemic_output_latency = 0; 00908 const JSList * node; 00909 const jack_driver_param_t * param; 00910 const char *midi_driver = "none"; 00911 00912 for (node = params; node; node = jack_slist_next (node)) { 00913 param = (const jack_driver_param_t *) node->data; 00914 00915 switch (param->character) { 00916 00917 case 'C': 00918 capture = TRUE; 00919 if (strcmp (param->value.str, "none") != 0) { 00920 capture_pcm_name = strdup (param->value.str); 00921 jack_log("capture device %s", capture_pcm_name); 00922 } 00923 break; 00924 00925 case 'P': 00926 playback = TRUE; 00927 if (strcmp (param->value.str, "none") != 0) { 00928 playback_pcm_name = strdup (param->value.str); 00929 jack_log("playback device %s", playback_pcm_name); 00930 } 00931 break; 00932 00933 case 'D': 00934 playback = TRUE; 00935 capture = TRUE; 00936 break; 00937 00938 case 'd': 00939 playback_pcm_name = strdup (param->value.str); 00940 capture_pcm_name = strdup (param->value.str); 00941 jack_log("playback device %s", playback_pcm_name); 00942 jack_log("capture device %s", capture_pcm_name); 00943 break; 00944 00945 case 'H': 00946 hw_monitoring = param->value.i; 00947 break; 00948 00949 case 'm': 00950 monitor = param->value.i; 00951 break; 00952 00953 case 'M': 00954 hw_metering = param->value.i; 00955 break; 00956 00957 case 'r': 00958 srate = param->value.ui; 00959 jack_log("apparent rate = %d", srate); 00960 break; 00961 00962 case 'p': 00963 frames_per_interrupt = param->value.ui; 00964 jack_log("frames per period = %d", frames_per_interrupt); 00965 break; 00966 00967 case 'n': 00968 user_nperiods = param->value.ui; 00969 if (user_nperiods < 2) /* enforce minimum value */ 00970 user_nperiods = 2; 00971 break; 00972 00973 case 's': 00974 soft_mode = param->value.i; 00975 break; 00976 00977 case 'z': 00978 if (dither_opt (param->value.c, &dither)) { 00979 return NULL; 00980 } 00981 break; 00982 00983 case 'i': 00984 user_capture_nchnls = param->value.ui; 00985 break; 00986 00987 case 'o': 00988 user_playback_nchnls = param->value.ui; 00989 break; 00990 00991 case 'S': 00992 shorts_first = param->value.i; 00993 break; 00994 00995 case 'I': 00996 systemic_input_latency = param->value.ui; 00997 break; 00998 00999 case 'O': 01000 systemic_output_latency = param->value.ui; 01001 break; 01002 01003 case 'X': 01004 midi_driver = strdup(param->value.str); 01005 break; 01006 } 01007 } 01008 01009 /* duplex is the default */ 01010 if (!capture && !playback) { 01011 capture = TRUE; 01012 playback = TRUE; 01013 } 01014 01015 g_alsa_driver = new Jack::JackAlsaDriver("system", "alsa_pcm", engine, table); 01016 Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(g_alsa_driver); 01017 // Special open for ALSA driver... 01018 if (g_alsa_driver->Open(frames_per_interrupt, user_nperiods, srate, hw_monitoring, hw_metering, capture, playback, dither, soft_mode, monitor, 01019 user_capture_nchnls, user_playback_nchnls, shorts_first, capture_pcm_name, playback_pcm_name, 01020 systemic_input_latency, systemic_output_latency, midi_driver) == 0) { 01021 return threaded_driver; 01022 } else { 01023 delete threaded_driver; // Delete the decorated driver 01024 return NULL; 01025 } 01026 } 01027 01028 // Code to be used in alsa_driver.c 01029 01030 void ReadInput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread) 01031 { 01032 g_alsa_driver->ReadInputAux(orig_nframes, contiguous, nread); 01033 } 01034 void MonitorInput() 01035 { 01036 g_alsa_driver->MonitorInputAux(); 01037 } 01038 void ClearOutput() 01039 { 01040 g_alsa_driver->ClearOutputAux(); 01041 } 01042 void WriteOutput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten) 01043 { 01044 g_alsa_driver->WriteOutputAux(orig_nframes, contiguous, nwritten); 01045 } 01046 void SetTime(jack_time_t time) 01047 { 01048 g_alsa_driver->SetTimetAux(time); 01049 } 01050 01051 int Restart() 01052 { 01053 int res; 01054 if ((res = g_alsa_driver->Stop()) == 0) 01055 res = g_alsa_driver->Start(); 01056 return res; 01057 } 01058 01059 #ifdef __cplusplus 01060 } 01061 #endif 01062 01063