Jack2 1.9.10
|
00001 /* 00002 Copyright (C) 2008-2011 Torben Horn 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 #ifdef WIN32 00020 #include <malloc.h> 00021 #endif 00022 00023 #include "JackNetOneDriver.h" 00024 #include "JackEngineControl.h" 00025 #include "JackLockedEngine.h" 00026 #include "JackGraphManager.h" 00027 #include "JackWaitThreadedDriver.h" 00028 #include "JackTools.h" 00029 #include "driver_interface.h" 00030 00031 #include "netjack.h" 00032 #include "netjack_packet.h" 00033 00034 #if HAVE_SAMPLERATE 00035 #include <samplerate.h> 00036 #endif 00037 00038 #if HAVE_CELT 00039 #include <celt/celt.h> 00040 #endif 00041 00042 #if HAVE_OPUS 00043 #include <opus/opus.h> 00044 #include <opus/opus_custom.h> 00045 #endif 00046 00047 #define MIN(x,y) ((x)<(y) ? (x) : (y)) 00048 00049 using namespace std; 00050 00051 namespace Jack 00052 { 00053 JackNetOneDriver::JackNetOneDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table, 00054 int port, int mtu, int capture_ports, int playback_ports, int midi_input_ports, int midi_output_ports, 00055 int sample_rate, int period_size, int resample_factor, 00056 const char* net_name, uint transport_sync, int bitdepth, int use_autoconfig, 00057 int latency, int redundancy, int dont_htonl_floats, int always_deadline, int jitter_val) 00058 : JackWaiterDriver(name, alias, engine, table) 00059 { 00060 jack_log("JackNetOneDriver::JackNetOneDriver port %d", port); 00061 00062 #ifdef WIN32 00063 WSADATA wsa; 00064 WSAStartup(MAKEWORD(2, 0), &wsa); 00065 #endif 00066 00067 netjack_init(& (this->netj), 00068 NULL, // client 00069 name, 00070 capture_ports, 00071 playback_ports, 00072 midi_input_ports, 00073 midi_output_ports, 00074 sample_rate, 00075 period_size, 00076 port, 00077 transport_sync, 00078 resample_factor, 00079 0, 00080 bitdepth, 00081 use_autoconfig, 00082 latency, 00083 redundancy, 00084 dont_htonl_floats, 00085 always_deadline, 00086 jitter_val); 00087 } 00088 00089 JackNetOneDriver::~JackNetOneDriver() 00090 { 00091 // No destructor yet. 00092 } 00093 00094 //open, close, attach and detach------------------------------------------------------ 00095 00096 int JackNetOneDriver::Close() 00097 { 00098 // Generic audio driver close 00099 int res = JackWaiterDriver::Close(); 00100 00101 FreePorts(); 00102 netjack_release(&netj); 00103 return res; 00104 } 00105 00106 int JackNetOneDriver::Attach() 00107 { 00108 return 0; 00109 } 00110 00111 int JackNetOneDriver::Detach() 00112 { 00113 return 0; 00114 } 00115 00116 int JackNetOneDriver::AllocPorts() 00117 { 00118 jack_port_id_t port_index; 00119 char buf[64]; 00120 unsigned int chn; 00121 00122 //if (netj.handle_transport_sync) 00123 // jack_set_sync_callback(netj.client, (JackSyncCallback) net_driver_sync_cb, NULL); 00124 00125 for (chn = 0; chn < netj.capture_channels_audio; chn++) { 00126 snprintf (buf, sizeof(buf) - 1, "system:capture_%u", chn + 1); 00127 00128 if (fEngine->PortRegister(fClientControl.fRefNum, buf, JACK_DEFAULT_AUDIO_TYPE, 00129 CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) { 00130 jack_error("driver: cannot register port for %s", buf); 00131 return -1; 00132 } 00133 //port = fGraphManager->GetPort(port_index); 00134 00135 netj.capture_ports = jack_slist_append (netj.capture_ports, (void *)(intptr_t)port_index); 00136 00137 if (netj.bitdepth == CELT_MODE) { 00138 #if HAVE_CELT 00139 #if HAVE_CELT_API_0_11 00140 celt_int32 lookahead; 00141 CELTMode *celt_mode = celt_mode_create(netj.sample_rate, netj.period_size, NULL); 00142 netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create_custom(celt_mode, 1, NULL)); 00143 #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 00144 celt_int32 lookahead; 00145 CELTMode *celt_mode = celt_mode_create(netj.sample_rate, netj.period_size, NULL); 00146 netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create(celt_mode, 1, NULL)); 00147 #else 00148 celt_int32_t lookahead; 00149 CELTMode *celt_mode = celt_mode_create(netj.sample_rate, 1, netj.period_size, NULL); 00150 netj.capture_srcs = jack_slist_append(netj.capture_srcs, celt_decoder_create(celt_mode)); 00151 #endif 00152 celt_mode_info(celt_mode, CELT_GET_LOOKAHEAD, &lookahead); 00153 netj.codec_latency = 2 * lookahead; 00154 #endif 00155 } else if (netj.bitdepth == OPUS_MODE) { 00156 #if HAVE_OPUS 00157 OpusCustomMode *opus_mode = opus_custom_mode_create(netj.sample_rate, netj.period_size, NULL); // XXX free me in the end 00158 OpusCustomDecoder *decoder = opus_custom_decoder_create( opus_mode, 1, NULL ); 00159 netj.capture_srcs = jack_slist_append(netj.capture_srcs, decoder); 00160 #endif 00161 } else { 00162 #if HAVE_SAMPLERATE 00163 netj.capture_srcs = jack_slist_append(netj.capture_srcs, (void *)src_new(SRC_LINEAR, 1, NULL)); 00164 #endif 00165 } 00166 } 00167 00168 for (chn = netj.capture_channels_audio; chn < netj.capture_channels; chn++) { 00169 snprintf (buf, sizeof(buf) - 1, "system:capture_%u", chn + 1); 00170 00171 if (fEngine->PortRegister(fClientControl.fRefNum, buf, JACK_DEFAULT_MIDI_TYPE, 00172 CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) { 00173 jack_error("driver: cannot register port for %s", buf); 00174 return -1; 00175 } 00176 //port = fGraphManager->GetPort(port_index); 00177 00178 netj.capture_ports = 00179 jack_slist_append (netj.capture_ports, (void *)(intptr_t)port_index); 00180 } 00181 00182 for (chn = 0; chn < netj.playback_channels_audio; chn++) { 00183 snprintf (buf, sizeof(buf) - 1, "system:playback_%u", chn + 1); 00184 00185 if (fEngine->PortRegister(fClientControl.fRefNum, buf, JACK_DEFAULT_AUDIO_TYPE, 00186 PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) { 00187 jack_error("driver: cannot register port for %s", buf); 00188 return -1; 00189 } 00190 //port = fGraphManager->GetPort(port_index); 00191 00192 netj.playback_ports = jack_slist_append (netj.playback_ports, (void *)(intptr_t)port_index); 00193 if (netj.bitdepth == CELT_MODE) { 00194 #if HAVE_CELT 00195 #if HAVE_CELT_API_0_11 00196 CELTMode *celt_mode = celt_mode_create(netj.sample_rate, netj.period_size, NULL); 00197 netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create_custom(celt_mode, 1, NULL)); 00198 #elif HAVE_CELT_API_0_7 || HAVE_CELT_API_0_8 00199 CELTMode *celt_mode = celt_mode_create(netj.sample_rate, netj.period_size, NULL); 00200 netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create(celt_mode, 1, NULL)); 00201 #else 00202 CELTMode *celt_mode = celt_mode_create(netj.sample_rate, 1, netj.period_size, NULL); 00203 netj.playback_srcs = jack_slist_append(netj.playback_srcs, celt_encoder_create(celt_mode)); 00204 #endif 00205 #endif 00206 } else if (netj.bitdepth == OPUS_MODE) { 00207 #if HAVE_OPUS 00208 const int kbps = netj.resample_factor; 00209 jack_error("NEW ONE OPUS ENCODER 128 <> %d!!", kbps); 00210 int err; 00211 OpusCustomMode *opus_mode = opus_custom_mode_create( netj.sample_rate, netj.period_size, &err ); // XXX free me in the end 00212 if (err != OPUS_OK) { jack_error("opus mode failed"); } 00213 OpusCustomEncoder *oe = opus_custom_encoder_create( opus_mode, 1, &err ); 00214 if (err != OPUS_OK) { jack_error("opus mode failed"); } 00215 opus_custom_encoder_ctl(oe, OPUS_SET_BITRATE(kbps*1024)); // bits per second 00216 opus_custom_encoder_ctl(oe, OPUS_SET_COMPLEXITY(10)); 00217 opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_SIGNAL_MUSIC)); 00218 opus_custom_encoder_ctl(oe, OPUS_SET_SIGNAL(OPUS_APPLICATION_RESTRICTED_LOWDELAY)); 00219 netj.playback_srcs = jack_slist_append(netj.playback_srcs, oe); 00220 #endif 00221 } else { 00222 #if HAVE_SAMPLERATE 00223 netj.playback_srcs = jack_slist_append(netj.playback_srcs, (void *)src_new(SRC_LINEAR, 1, NULL)); 00224 #endif 00225 } 00226 } 00227 for (chn = netj.playback_channels_audio; chn < netj.playback_channels; chn++) { 00228 snprintf (buf, sizeof(buf) - 1, "system:playback_%u", chn + 1); 00229 00230 if (fEngine->PortRegister(fClientControl.fRefNum, buf, JACK_DEFAULT_MIDI_TYPE, 00231 PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) { 00232 jack_error("driver: cannot register port for %s", buf); 00233 return -1; 00234 } 00235 //port = fGraphManager->GetPort(port_index); 00236 00237 netj.playback_ports = 00238 jack_slist_append (netj.playback_ports, (void *)(intptr_t)port_index); 00239 } 00240 return 0; 00241 } 00242 00243 //init and restart-------------------------------------------------------------------- 00244 bool JackNetOneDriver::Initialize() 00245 { 00246 jack_log("JackNetOneDriver::Init"); 00247 00248 FreePorts(); 00249 netjack_release(&netj); 00250 00251 //display some additional infos 00252 jack_info("NetOne driver started"); 00253 if (netjack_startup(&netj)) { 00254 return false; 00255 } 00256 00257 //register jack ports 00258 if (AllocPorts() != 0) { 00259 jack_error("Can't allocate ports."); 00260 return false; 00261 } 00262 00263 //monitor 00264 //driver parametering 00265 JackTimedDriver::SetBufferSize(netj.period_size); 00266 JackTimedDriver::SetSampleRate(netj.sample_rate); 00267 00268 JackDriver::NotifyBufferSize(netj.period_size); 00269 JackDriver::NotifySampleRate(netj.sample_rate); 00270 00271 //transport engine parametering 00272 fEngineControl->fTransport.SetNetworkSync(true); 00273 return true; 00274 } 00275 00276 00277 //jack ports and buffers-------------------------------------------------------------- 00278 00279 //driver processes-------------------------------------------------------------------- 00280 00281 int JackNetOneDriver::Read() 00282 { 00283 int delay; 00284 delay = netjack_wait(&netj); 00285 if (delay) { 00286 NotifyXRun(fBeginDateUst, (float) delay); 00287 jack_error("netxruns... duration: %dms", delay / 1000); 00288 } 00289 00290 if ((netj.num_lost_packets * netj.period_size / netj.sample_rate) > 2) 00291 JackTools::ThrowJackNetException(); 00292 00293 //netjack_read(&netj, netj.period_size); 00294 JackDriver::CycleTakeBeginTime(); 00295 00296 jack_position_t local_trans_pos; 00297 jack_transport_state_t local_trans_state; 00298 00299 unsigned int *packet_buf, *packet_bufX; 00300 00301 if (! netj.packet_data_valid) { 00302 jack_log("data not valid"); 00303 render_payload_to_jack_ports (netj.bitdepth, NULL, netj.net_period_down, netj.capture_ports, netj.capture_srcs, netj.period_size, netj.dont_htonl_floats); 00304 return 0; 00305 } 00306 packet_buf = netj.rx_buf; 00307 00308 jacknet_packet_header *pkthdr = (jacknet_packet_header *)packet_buf; 00309 00310 packet_bufX = packet_buf + sizeof(jacknet_packet_header) / sizeof(jack_default_audio_sample_t); 00311 00312 netj.reply_port = pkthdr->reply_port; 00313 netj.latency = pkthdr->latency; 00314 00315 // Special handling for latency=0 00316 if (netj.latency == 0) 00317 netj.resync_threshold = 0; 00318 else 00319 netj.resync_threshold = MIN(15, pkthdr->latency - 1); 00320 00321 // check whether, we should handle the transport sync stuff, or leave trnasports untouched. 00322 if (netj.handle_transport_sync) { 00323 #if 1 00324 unsigned int compensated_tranport_pos = (pkthdr->transport_frame + (pkthdr->latency * netj.period_size) + netj.codec_latency); 00325 00326 // read local transport info.... 00327 //local_trans_state = jack_transport_query(netj.client, &local_trans_pos); 00328 00329 local_trans_state = fEngineControl->fTransport.Query(&local_trans_pos); 00330 00331 // Now check if we have to start or stop local transport to sync to remote... 00332 switch (pkthdr->transport_state) { 00333 00334 case JackTransportStarting: 00335 // the master transport is starting... so we set our reply to the sync_callback; 00336 if (local_trans_state == JackTransportStopped) { 00337 fEngineControl->fTransport.SetCommand(TransportCommandStart); 00338 //jack_transport_start(netj.client); 00339 //last_transport_state = JackTransportStopped; 00340 netj.sync_state = 0; 00341 jack_info("locally stopped... starting..."); 00342 } 00343 00344 if (local_trans_pos.frame != compensated_tranport_pos) { 00345 jack_position_t new_pos = local_trans_pos; 00346 new_pos.frame = compensated_tranport_pos + 2 * netj.period_size; 00347 new_pos.valid = (jack_position_bits_t) 0; 00348 00349 00350 fEngineControl->fTransport.RequestNewPos(&new_pos); 00351 //jack_transport_locate(netj.client, compensated_tranport_pos); 00352 //last_transport_state = JackTransportRolling; 00353 netj.sync_state = 0; 00354 jack_info("starting locate to %d", compensated_tranport_pos); 00355 } 00356 break; 00357 00358 case JackTransportStopped: 00359 netj.sync_state = 1; 00360 if (local_trans_pos.frame != (pkthdr->transport_frame)) { 00361 jack_position_t new_pos = local_trans_pos; 00362 new_pos.frame = pkthdr->transport_frame; 00363 new_pos.valid = (jack_position_bits_t)0; 00364 fEngineControl->fTransport.RequestNewPos(&new_pos); 00365 //jack_transport_locate(netj.client, (pkthdr->transport_frame)); 00366 jack_info("transport is stopped locate to %d", pkthdr->transport_frame); 00367 } 00368 if (local_trans_state != JackTransportStopped) 00369 //jack_transport_stop(netj.client); 00370 fEngineControl->fTransport.SetCommand(TransportCommandStop); 00371 break; 00372 00373 case JackTransportRolling: 00374 netj.sync_state = 1; 00375 // if(local_trans_pos.frame != (pkthdr->transport_frame + (pkthdr->latency) * netj.period_size)) { 00376 // jack_transport_locate(netj.client, (pkthdr->transport_frame + (pkthdr->latency + 2) * netj.period_size)); 00377 // jack_info("running locate to %d", pkthdr->transport_frame + (pkthdr->latency)*netj.period_size); 00378 // } 00379 if (local_trans_state != JackTransportRolling) 00380 fEngineControl->fTransport.SetState(JackTransportRolling); 00381 break; 00382 00383 case JackTransportLooping: 00384 break; 00385 } 00386 #endif 00387 } 00388 00389 render_payload_to_jack_ports (netj.bitdepth, packet_bufX, netj.net_period_down, netj.capture_ports, netj.capture_srcs, netj.period_size, netj.dont_htonl_floats); 00390 packet_cache_release_packet(netj.packcache, netj.expected_framecnt); 00391 return 0; 00392 } 00393 00394 int JackNetOneDriver::Write() 00395 { 00396 int syncstate = netj.sync_state | ((fEngineControl->fTransport.GetState() == JackTransportNetStarting) ? 1 : 0); 00397 uint32_t *packet_buf, *packet_bufX; 00398 00399 int packet_size = get_sample_size(netj.bitdepth) * netj.playback_channels * netj.net_period_up + sizeof(jacknet_packet_header); 00400 jacknet_packet_header *pkthdr; 00401 00402 packet_buf = (uint32_t *) alloca(packet_size); 00403 pkthdr = (jacknet_packet_header *)packet_buf; 00404 00405 if (netj.running_free) { 00406 return 0; 00407 } 00408 00409 // offset packet_bufX by the packetheader. 00410 packet_bufX = packet_buf + sizeof(jacknet_packet_header) / sizeof(jack_default_audio_sample_t); 00411 00412 pkthdr->sync_state = syncstate;; 00413 pkthdr->latency = netj.time_to_deadline; 00414 //printf("time to deadline = %d goodness=%d\n", (int)netj.time_to_deadline, netj.deadline_goodness); 00415 pkthdr->framecnt = netj.expected_framecnt; 00416 00417 render_jack_ports_to_payload(netj.bitdepth, netj.playback_ports, netj.playback_srcs, netj.period_size, packet_bufX, netj.net_period_up, netj.dont_htonl_floats); 00418 00419 packet_header_hton(pkthdr); 00420 if (netj.srcaddress_valid) { 00421 unsigned int r; 00422 static const int flag = 0; 00423 00424 if (netj.reply_port) 00425 netj.syncsource_address.sin_port = htons(netj.reply_port); 00426 00427 for (r = 0; r < netj.redundancy; r++) 00428 netjack_sendto(netj.sockfd, (char *)packet_buf, packet_size, 00429 flag, (struct sockaddr*) & (netj.syncsource_address), sizeof(struct sockaddr_in), netj.mtu); 00430 } 00431 return 0; 00432 } 00433 00434 void 00435 JackNetOneDriver::FreePorts () 00436 { 00437 JSList *node = netj.capture_ports; 00438 00439 while (node != NULL) { 00440 JSList *this_node = node; 00441 jack_port_id_t port_index = (jack_port_id_t)(intptr_t) node->data; 00442 node = jack_slist_remove_link(node, this_node); 00443 jack_slist_free_1(this_node); 00444 fEngine->PortUnRegister(fClientControl.fRefNum, port_index); 00445 } 00446 netj.capture_ports = NULL; 00447 00448 node = netj.playback_ports; 00449 while (node != NULL) { 00450 JSList *this_node = node; 00451 jack_port_id_t port_index = (jack_port_id_t)(intptr_t) node->data; 00452 node = jack_slist_remove_link(node, this_node); 00453 jack_slist_free_1(this_node); 00454 fEngine->PortUnRegister(fClientControl.fRefNum, port_index); 00455 } 00456 netj.playback_ports = NULL; 00457 00458 if (netj.bitdepth == CELT_MODE) { 00459 #if HAVE_CELT 00460 node = netj.playback_srcs; 00461 while (node != NULL) { 00462 JSList *this_node = node; 00463 CELTEncoder *enc = (CELTEncoder *) node->data; 00464 node = jack_slist_remove_link(node, this_node); 00465 jack_slist_free_1(this_node); 00466 celt_encoder_destroy(enc); 00467 } 00468 netj.playback_srcs = NULL; 00469 00470 node = netj.capture_srcs; 00471 while (node != NULL) { 00472 JSList *this_node = node; 00473 CELTDecoder *dec = (CELTDecoder *) node->data; 00474 node = jack_slist_remove_link(node, this_node); 00475 jack_slist_free_1(this_node); 00476 celt_decoder_destroy(dec); 00477 } 00478 netj.capture_srcs = NULL; 00479 #endif 00480 } else if (netj.bitdepth == OPUS_MODE) { 00481 #if HAVE_OPUS 00482 node = netj.playback_srcs; 00483 while (node != NULL) { 00484 JSList *this_node = node; 00485 OpusCustomEncoder *enc = (OpusCustomEncoder *) node->data; 00486 node = jack_slist_remove_link(node, this_node); 00487 jack_slist_free_1(this_node); 00488 opus_custom_encoder_destroy(enc); 00489 } 00490 netj.playback_srcs = NULL; 00491 00492 node = netj.capture_srcs; 00493 while (node != NULL) { 00494 JSList *this_node = node; 00495 OpusCustomDecoder *dec = (OpusCustomDecoder *) node->data; 00496 node = jack_slist_remove_link(node, this_node); 00497 jack_slist_free_1(this_node); 00498 opus_custom_decoder_destroy(dec); 00499 } 00500 netj.capture_srcs = NULL; 00501 #endif 00502 } else { 00503 #if HAVE_SAMPLERATE 00504 node = netj.playback_srcs; 00505 while (node != NULL) { 00506 JSList *this_node = node; 00507 SRC_STATE *state = (SRC_STATE *) node->data; 00508 node = jack_slist_remove_link(node, this_node); 00509 jack_slist_free_1(this_node); 00510 src_delete(state); 00511 } 00512 netj.playback_srcs = NULL; 00513 00514 node = netj.capture_srcs; 00515 while (node != NULL) { 00516 JSList *this_node = node; 00517 SRC_STATE *state = (SRC_STATE *) node->data; 00518 node = jack_slist_remove_link(node, this_node); 00519 jack_slist_free_1(this_node); 00520 src_delete(state); 00521 } 00522 netj.capture_srcs = NULL; 00523 #endif 00524 } 00525 } 00526 00527 //Render functions-------------------------------------------------------------------- 00528 00529 // render functions for float 00530 void 00531 JackNetOneDriver::render_payload_to_jack_ports_float(void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats) 00532 { 00533 uint32_t chn = 0; 00534 JSList *node = capture_ports; 00535 #if HAVE_SAMPLERATE 00536 JSList *src_node = capture_srcs; 00537 #endif 00538 00539 uint32_t *packet_bufX = (uint32_t *)packet_payload; 00540 00541 if (!packet_payload) 00542 return; 00543 00544 while (node != NULL) { 00545 unsigned int i; 00546 int_float_t val; 00547 #if HAVE_SAMPLERATE 00548 SRC_DATA src; 00549 #endif 00550 jack_port_id_t port_index = (jack_port_id_t)(intptr_t) node->data; 00551 JackPort *port = fGraphManager->GetPort(port_index); 00552 00553 jack_default_audio_sample_t* buf = 00554 (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize); 00555 00556 const char *porttype = port->GetType(); 00557 00558 if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { 00559 #if HAVE_SAMPLERATE 00560 // audio port, resample if necessary 00561 if (net_period_down != nframes) { 00562 SRC_STATE *src_state = (SRC_STATE *)src_node->data; 00563 for (i = 0; i < net_period_down; i++) { 00564 packet_bufX[i] = ntohl (packet_bufX[i]); 00565 } 00566 00567 src.data_in = (float *) packet_bufX; 00568 src.input_frames = net_period_down; 00569 00570 src.data_out = buf; 00571 src.output_frames = nframes; 00572 00573 src.src_ratio = (float) nframes / (float) net_period_down; 00574 src.end_of_input = 0; 00575 00576 src_set_ratio (src_state, src.src_ratio); 00577 src_process (src_state, &src); 00578 src_node = jack_slist_next (src_node); 00579 } else 00580 #endif 00581 { 00582 if (dont_htonl_floats) { 00583 memcpy(buf, packet_bufX, net_period_down * sizeof(jack_default_audio_sample_t)); 00584 } else { 00585 for (i = 0; i < net_period_down; i++) { 00586 val.i = packet_bufX[i]; 00587 val.i = ntohl (val.i); 00588 buf[i] = val.f; 00589 } 00590 } 00591 } 00592 } else if (strncmp (porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { 00593 // midi port, decode midi events 00594 // convert the data buffer to a standard format (uint32_t based) 00595 unsigned int buffer_size_uint32 = net_period_down; 00596 uint32_t * buffer_uint32 = (uint32_t*)packet_bufX; 00597 decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); 00598 } 00599 packet_bufX = (packet_bufX + net_period_down); 00600 node = jack_slist_next (node); 00601 chn++; 00602 } 00603 } 00604 00605 void 00606 JackNetOneDriver::render_jack_ports_to_payload_float (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats) 00607 { 00608 uint32_t chn = 0; 00609 JSList *node = playback_ports; 00610 #if HAVE_SAMPLERATE 00611 JSList *src_node = playback_srcs; 00612 #endif 00613 00614 uint32_t *packet_bufX = (uint32_t *) packet_payload; 00615 00616 while (node != NULL) { 00617 #if HAVE_SAMPLERATE 00618 SRC_DATA src; 00619 #endif 00620 unsigned int i; 00621 int_float_t val; 00622 jack_port_id_t port_index = (jack_port_id_t)(intptr_t) node->data; 00623 JackPort *port = fGraphManager->GetPort(port_index); 00624 00625 jack_default_audio_sample_t* buf = 00626 (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize); 00627 00628 const char *porttype = port->GetType(); 00629 00630 if (strncmp (porttype, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { 00631 // audio port, resample if necessary 00632 00633 #if HAVE_SAMPLERATE 00634 if (net_period_up != nframes) { 00635 SRC_STATE *src_state = (SRC_STATE *) src_node->data; 00636 src.data_in = buf; 00637 src.input_frames = nframes; 00638 00639 src.data_out = (float *) packet_bufX; 00640 src.output_frames = net_period_up; 00641 00642 src.src_ratio = (float) net_period_up / (float) nframes; 00643 src.end_of_input = 0; 00644 00645 src_set_ratio (src_state, src.src_ratio); 00646 src_process (src_state, &src); 00647 00648 for (i = 0; i < net_period_up; i++) { 00649 packet_bufX[i] = htonl (packet_bufX[i]); 00650 } 00651 src_node = jack_slist_next (src_node); 00652 } else 00653 #endif 00654 { 00655 if (dont_htonl_floats) { 00656 memcpy(packet_bufX, buf, net_period_up * sizeof(jack_default_audio_sample_t)); 00657 } else { 00658 for (i = 0; i < net_period_up; i++) { 00659 val.f = buf[i]; 00660 val.i = htonl (val.i); 00661 packet_bufX[i] = val.i; 00662 } 00663 } 00664 } 00665 } else if (strncmp(porttype, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { 00666 // encode midi events from port to packet 00667 // convert the data buffer to a standard format (uint32_t based) 00668 unsigned int buffer_size_uint32 = net_period_up; 00669 uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; 00670 encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); 00671 } 00672 packet_bufX = (packet_bufX + net_period_up); 00673 node = jack_slist_next (node); 00674 chn++; 00675 } 00676 } 00677 00678 #if HAVE_CELT 00679 // render functions for celt. 00680 void 00681 JackNetOneDriver::render_payload_to_jack_ports_celt (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes) 00682 { 00683 uint32_t chn = 0; 00684 JSList *node = capture_ports; 00685 JSList *src_node = capture_srcs; 00686 unsigned char *packet_bufX = (unsigned char *)packet_payload; 00687 00688 while (node != NULL) { 00689 jack_port_id_t port_index = (jack_port_id_t) (intptr_t)node->data; 00690 JackPort *port = fGraphManager->GetPort(port_index); 00691 00692 jack_default_audio_sample_t* buf = 00693 (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize); 00694 00695 const char *portname = port->GetType(); 00696 00697 if (strncmp(portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { 00698 // audio port, decode celt data. 00699 CELTDecoder *decoder = (CELTDecoder *)src_node->data; 00700 00701 #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 00702 if (!packet_payload) 00703 celt_decode_float(decoder, NULL, net_period_down, buf, nframes); 00704 else 00705 celt_decode_float(decoder, packet_bufX, net_period_down, buf, nframes); 00706 #else 00707 if (!packet_payload) 00708 celt_decode_float(decoder, NULL, net_period_down, buf); 00709 else 00710 celt_decode_float(decoder, packet_bufX, net_period_down, buf); 00711 #endif 00712 00713 src_node = jack_slist_next (src_node); 00714 } else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { 00715 // midi port, decode midi events 00716 // convert the data buffer to a standard format (uint32_t based) 00717 unsigned int buffer_size_uint32 = net_period_down / 2; 00718 uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; 00719 if (packet_payload) 00720 decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); 00721 } 00722 packet_bufX = (packet_bufX + net_period_down); 00723 node = jack_slist_next (node); 00724 chn++; 00725 } 00726 } 00727 00728 void 00729 JackNetOneDriver::render_jack_ports_to_payload_celt (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up) 00730 { 00731 uint32_t chn = 0; 00732 JSList *node = playback_ports; 00733 JSList *src_node = playback_srcs; 00734 00735 unsigned char *packet_bufX = (unsigned char *)packet_payload; 00736 00737 while (node != NULL) { 00738 jack_port_id_t port_index = (jack_port_id_t) (intptr_t) node->data; 00739 JackPort *port = fGraphManager->GetPort(port_index); 00740 00741 jack_default_audio_sample_t* buf = 00742 (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize); 00743 00744 const char *portname = port->GetType(); 00745 00746 if (strncmp (portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { 00747 // audio port, encode celt data. 00748 00749 int encoded_bytes; 00750 jack_default_audio_sample_t *floatbuf = (jack_default_audio_sample_t *)alloca (sizeof(jack_default_audio_sample_t) * nframes); 00751 memcpy(floatbuf, buf, nframes * sizeof(jack_default_audio_sample_t)); 00752 CELTEncoder *encoder = (CELTEncoder *)src_node->data; 00753 #if HAVE_CELT_API_0_8 || HAVE_CELT_API_0_11 00754 encoded_bytes = celt_encode_float(encoder, floatbuf, nframes, packet_bufX, net_period_up); 00755 #else 00756 encoded_bytes = celt_encode_float(encoder, floatbuf, NULL, packet_bufX, net_period_up); 00757 #endif 00758 if (encoded_bytes != (int)net_period_up) 00759 jack_error("something in celt changed. netjack needs to be changed to handle this."); 00760 src_node = jack_slist_next(src_node); 00761 } else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { 00762 // encode midi events from port to packet 00763 // convert the data buffer to a standard format (uint32_t based) 00764 unsigned int buffer_size_uint32 = net_period_up / 2; 00765 uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; 00766 encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); 00767 } 00768 packet_bufX = (packet_bufX + net_period_up); 00769 node = jack_slist_next (node); 00770 chn++; 00771 } 00772 } 00773 00774 #endif 00775 00776 #if HAVE_OPUS 00777 #define CDO (sizeof(short)) ///< compressed data offset (first 2 bytes are length) 00778 // render functions for Opus. 00779 void 00780 JackNetOneDriver::render_payload_to_jack_ports_opus (void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes) 00781 { 00782 int chn = 0; 00783 JSList *node = capture_ports; 00784 JSList *src_node = capture_srcs; 00785 00786 unsigned char *packet_bufX = (unsigned char *)packet_payload; 00787 00788 while (node != NULL) { 00789 jack_port_id_t port_index = (jack_port_id_t) (intptr_t)node->data; 00790 JackPort *port = fGraphManager->GetPort(port_index); 00791 00792 jack_default_audio_sample_t* buf = 00793 (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize); 00794 00795 const char *portname = port->GetType(); 00796 00797 if (strncmp(portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { 00798 // audio port, decode opus data. 00799 OpusCustomDecoder *decoder = (OpusCustomDecoder*) src_node->data; 00800 if( !packet_payload ) 00801 memset(buf, 0, nframes * sizeof(float)); 00802 else { 00803 unsigned short len; 00804 memcpy(&len, packet_bufX, CDO); 00805 len = ntohs(len); 00806 opus_custom_decode_float( decoder, packet_bufX + CDO, len, buf, nframes ); 00807 } 00808 00809 src_node = jack_slist_next (src_node); 00810 } else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { 00811 // midi port, decode midi events 00812 // convert the data buffer to a standard format (uint32_t based) 00813 unsigned int buffer_size_uint32 = net_period_down / 2; 00814 uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; 00815 if( packet_payload ) 00816 decode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); 00817 } 00818 packet_bufX = (packet_bufX + net_period_down); 00819 node = jack_slist_next (node); 00820 chn++; 00821 } 00822 } 00823 00824 void 00825 JackNetOneDriver::render_jack_ports_to_payload_opus (JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up) 00826 { 00827 int chn = 0; 00828 JSList *node = playback_ports; 00829 JSList *src_node = playback_srcs; 00830 00831 unsigned char *packet_bufX = (unsigned char *)packet_payload; 00832 00833 while (node != NULL) { 00834 jack_port_id_t port_index = (jack_port_id_t) (intptr_t) node->data; 00835 JackPort *port = fGraphManager->GetPort(port_index); 00836 00837 jack_default_audio_sample_t* buf = 00838 (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize); 00839 00840 const char *portname = port->GetType(); 00841 00842 if (strncmp (portname, JACK_DEFAULT_AUDIO_TYPE, jack_port_type_size()) == 0) { 00843 // audio port, encode opus data. 00844 00845 int encoded_bytes; 00846 jack_default_audio_sample_t *floatbuf = (jack_default_audio_sample_t *)alloca (sizeof(jack_default_audio_sample_t) * nframes); 00847 memcpy(floatbuf, buf, nframes * sizeof(jack_default_audio_sample_t)); 00848 OpusCustomEncoder *encoder = (OpusCustomEncoder*) src_node->data; 00849 encoded_bytes = opus_custom_encode_float( encoder, floatbuf, nframes, packet_bufX + CDO, net_period_up - CDO ); 00850 unsigned short len = htons(encoded_bytes); 00851 memcpy(packet_bufX, &len, CDO); 00852 src_node = jack_slist_next( src_node ); 00853 } else if (strncmp(portname, JACK_DEFAULT_MIDI_TYPE, jack_port_type_size()) == 0) { 00854 // encode midi events from port to packet 00855 // convert the data buffer to a standard format (uint32_t based) 00856 unsigned int buffer_size_uint32 = net_period_up / 2; 00857 uint32_t * buffer_uint32 = (uint32_t*) packet_bufX; 00858 encode_midi_buffer (buffer_uint32, buffer_size_uint32, buf); 00859 } 00860 packet_bufX = (packet_bufX + net_period_up); 00861 node = jack_slist_next (node); 00862 chn++; 00863 } 00864 } 00865 #endif 00866 00867 /* Wrapper functions with bitdepth argument... */ 00868 void 00869 JackNetOneDriver::render_payload_to_jack_ports (int bitdepth, void *packet_payload, jack_nframes_t net_period_down, JSList *capture_ports, JSList *capture_srcs, jack_nframes_t nframes, int dont_htonl_floats) 00870 { 00871 #if HAVE_CELT 00872 if (bitdepth == CELT_MODE) 00873 render_payload_to_jack_ports_celt (packet_payload, net_period_down, capture_ports, capture_srcs, nframes); 00874 else 00875 #endif 00876 #if HAVE_OPUS 00877 if (bitdepth == OPUS_MODE) 00878 render_payload_to_jack_ports_opus (packet_payload, net_period_down, capture_ports, capture_srcs, nframes); 00879 else 00880 #endif 00881 render_payload_to_jack_ports_float (packet_payload, net_period_down, capture_ports, capture_srcs, nframes, dont_htonl_floats); 00882 } 00883 00884 void 00885 JackNetOneDriver::render_jack_ports_to_payload (int bitdepth, JSList *playback_ports, JSList *playback_srcs, jack_nframes_t nframes, void *packet_payload, jack_nframes_t net_period_up, int dont_htonl_floats) 00886 { 00887 #if HAVE_CELT 00888 if (bitdepth == CELT_MODE) 00889 render_jack_ports_to_payload_celt (playback_ports, playback_srcs, nframes, packet_payload, net_period_up); 00890 else 00891 #endif 00892 #if HAVE_OPUS 00893 if (bitdepth == OPUS_MODE) 00894 render_jack_ports_to_payload_opus (playback_ports, playback_srcs, nframes, packet_payload, net_period_up); 00895 else 00896 #endif 00897 render_jack_ports_to_payload_float (playback_ports, playback_srcs, nframes, packet_payload, net_period_up, dont_htonl_floats); 00898 } 00899 00900 //driver loader----------------------------------------------------------------------- 00901 00902 #ifdef __cplusplus 00903 extern "C" 00904 { 00905 #endif 00906 00907 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor () 00908 { 00909 jack_driver_desc_t * desc; 00910 jack_driver_desc_filler_t filler; 00911 jack_driver_param_value_t value; 00912 00913 desc = jack_driver_descriptor_construct("netone", JackDriverMaster, "netjack one slave backend component", &filler); 00914 00915 value.ui = 2U; 00916 jack_driver_descriptor_add_parameter(desc, &filler, "audio-ins", 'i', JackDriverParamUInt, &value, NULL, "Number of capture channels (defaults to 2)", NULL); 00917 jack_driver_descriptor_add_parameter(desc, &filler, "audio-outs", 'o', JackDriverParamUInt, &value, NULL, "Number of playback channels (defaults to 2)", NULL); 00918 00919 value.ui = 1U; 00920 jack_driver_descriptor_add_parameter(desc, &filler, "midi-ins", 'I', JackDriverParamUInt, &value, NULL, "Number of midi capture channels (defaults to 1)", NULL); 00921 jack_driver_descriptor_add_parameter(desc, &filler, "midi-outs", 'O', JackDriverParamUInt, &value, NULL, "Number of midi playback channels (defaults to 1)", NULL); 00922 00923 value.ui = 48000U; 00924 jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL); 00925 00926 value.ui = 1024U; 00927 jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL); 00928 00929 value.ui = 5U; 00930 jack_driver_descriptor_add_parameter(desc, &filler, "num-periods", 'n', JackDriverParamUInt, &value, NULL, "Network latency setting in no. of periods", NULL); 00931 00932 value.ui = 3000U; 00933 jack_driver_descriptor_add_parameter(desc, &filler, "listen-port", 'l', JackDriverParamUInt, &value, NULL, "The socket port we are listening on for sync packets", NULL); 00934 00935 value.ui = 1U; 00936 jack_driver_descriptor_add_parameter(desc, &filler, "factor", 'f', JackDriverParamUInt, &value, NULL, "Factor for sample rate reduction", NULL); 00937 00938 value.ui = 0U; 00939 jack_driver_descriptor_add_parameter(desc, &filler, "upstream-factor", 'u', JackDriverParamUInt, &value, NULL, "Factor for sample rate reduction on the upstream", NULL); 00940 00941 #if HAVE_CELT 00942 value.ui = 0U; 00943 jack_driver_descriptor_add_parameter(desc, &filler, "celt", 'c', JackDriverParamUInt, &value, NULL, "Set CELT encoding and number of kbits per channel", NULL); 00944 #endif 00945 #if HAVE_OPUS 00946 value.ui = 0U; 00947 jack_driver_descriptor_add_parameter(desc, &filler, "opus", 'P', JackDriverParamUInt, &value, NULL, "Set Opus encoding and number of kbits per channel", NULL); 00948 #endif 00949 value.ui = 0U; 00950 jack_driver_descriptor_add_parameter(desc, &filler, "bit-depth", 'b', JackDriverParamUInt, &value, NULL, "Sample bit-depth (0 for float, 8 for 8bit and 16 for 16bit)", NULL); 00951 00952 value.i = true; 00953 jack_driver_descriptor_add_parameter(desc, &filler, "transport-sync", 't', JackDriverParamBool, &value, NULL, "Whether to slave the transport to the master transport", NULL); 00954 00955 value.ui = true; 00956 jack_driver_descriptor_add_parameter(desc, &filler, "autoconf", 'a', JackDriverParamBool, &value, NULL, "Whether to use Autoconfig, or just start", NULL); 00957 00958 value.ui = 1U; 00959 jack_driver_descriptor_add_parameter(desc, &filler, "redundancy", 'R', JackDriverParamUInt, &value, NULL, "Send packets N times", NULL); 00960 00961 value.ui = false; 00962 jack_driver_descriptor_add_parameter(desc, &filler, "native-endian", 'e', JackDriverParamBool, &value, NULL, "Dont convert samples to network byte order", NULL); 00963 00964 value.i = 0; 00965 jack_driver_descriptor_add_parameter(desc, &filler, "jitterval", 'J', JackDriverParamInt, &value, NULL, "Attempted jitterbuffer microseconds on master", NULL); 00966 00967 value.i = false; 00968 jack_driver_descriptor_add_parameter(desc, &filler, "always-deadline", 'D', JackDriverParamBool, &value, NULL, "Always use deadline", NULL); 00969 00970 return desc; 00971 } 00972 00973 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) 00974 { 00975 jack_nframes_t sample_rate = 48000; 00976 jack_nframes_t resample_factor = 1; 00977 jack_nframes_t period_size = 1024; 00978 unsigned int capture_ports = 2; 00979 unsigned int playback_ports = 2; 00980 unsigned int capture_ports_midi = 1; 00981 unsigned int playback_ports_midi = 1; 00982 unsigned int listen_port = 3000; 00983 unsigned int bitdepth = 0; 00984 unsigned int handle_transport_sync = 1; 00985 unsigned int use_autoconfig = 1; 00986 unsigned int latency = 5; 00987 unsigned int redundancy = 1; 00988 unsigned int mtu = 1400; 00989 #if HAVE_SAMPLERATE 00990 unsigned int resample_factor_up = 1; 00991 #endif 00992 int dont_htonl_floats = 0; 00993 int always_deadline = 0; 00994 int jitter_val = 0; 00995 const JSList * node; 00996 const jack_driver_param_t * param; 00997 00998 for (node = params; node; node = jack_slist_next(node)) { 00999 param = (const jack_driver_param_t*) node->data; 01000 switch (param->character) { 01001 case 'i': 01002 capture_ports = param->value.ui; 01003 break; 01004 01005 case 'o': 01006 playback_ports = param->value.ui; 01007 break; 01008 01009 case 'I': 01010 capture_ports_midi = param->value.ui; 01011 break; 01012 01013 case 'O': 01014 playback_ports_midi = param->value.ui; 01015 break; 01016 01017 case 'r': 01018 sample_rate = param->value.ui; 01019 break; 01020 01021 case 'p': 01022 period_size = param->value.ui; 01023 break; 01024 01025 case 'l': 01026 listen_port = param->value.ui; 01027 break; 01028 01029 case 'f': 01030 #if HAVE_SAMPLERATE 01031 resample_factor = param->value.ui; 01032 #else 01033 jack_error("not built with libsamplerate support"); 01034 return NULL; 01035 #endif 01036 break; 01037 01038 case 'u': 01039 #if HAVE_SAMPLERATE 01040 resample_factor_up = param->value.ui; 01041 #else 01042 jack_error("not built with libsamplerate support"); 01043 return NULL; 01044 #endif 01045 break; 01046 01047 case 'b': 01048 bitdepth = param->value.ui; 01049 break; 01050 01051 case 'c': 01052 #if HAVE_CELT 01053 bitdepth = CELT_MODE; 01054 resample_factor = param->value.ui; 01055 #else 01056 jack_error("not built with celt support"); 01057 return NULL; 01058 #endif 01059 break; 01060 01061 case 'P': 01062 #if HAVE_OPUS 01063 bitdepth = OPUS_MODE; 01064 resample_factor = param->value.ui; 01065 jack_error("OPUS: %d\n", resample_factor); 01066 #else 01067 jack_error("not built with Opus support"); 01068 return NULL; 01069 #endif 01070 break; 01071 01072 case 't': 01073 handle_transport_sync = param->value.ui; 01074 break; 01075 01076 case 'a': 01077 use_autoconfig = param->value.ui; 01078 break; 01079 01080 case 'n': 01081 latency = param->value.ui; 01082 break; 01083 01084 case 'R': 01085 redundancy = param->value.ui; 01086 break; 01087 01088 case 'H': 01089 dont_htonl_floats = param->value.ui; 01090 break; 01091 01092 case 'J': 01093 jitter_val = param->value.i; 01094 break; 01095 01096 case 'D': 01097 always_deadline = param->value.ui; 01098 break; 01099 } 01100 } 01101 01102 try { 01103 Jack::JackDriverClientInterface* driver = new Jack::JackWaitThreadedDriver ( 01104 new Jack::JackNetOneDriver("system", "net_pcm", engine, table, listen_port, mtu, 01105 capture_ports_midi, playback_ports_midi, capture_ports, playback_ports, 01106 sample_rate, period_size, resample_factor, 01107 "net_pcm", handle_transport_sync, bitdepth, use_autoconfig, latency, redundancy, 01108 dont_htonl_floats, always_deadline, jitter_val)); 01109 01110 if (driver->Open(period_size, sample_rate, 1, 1, capture_ports, playback_ports, 01111 0, "from_master", "to_master", 0, 0) == 0) { 01112 return driver; 01113 } else { 01114 delete driver; 01115 return NULL; 01116 } 01117 01118 } catch (...) { 01119 return NULL; 01120 } 01121 } 01122 01123 #ifdef __cplusplus 01124 } 01125 #endif 01126 }