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