int main(int argc, char *argv[]) { int autoconnect = 0; jack_options_t jack_opt = JackNullOption; char *client_name = DEFAULT_CLIENT_NAME; char *connect_left = NULL; char *connect_right = NULL; const char *format_name = NULL; int bitrate = DEFAULT_BITRATE; int sync_period = DEFAULT_SYNC_PERIOD; float sleep_time = 0; time_t next_sync = 0; int i,opt; // Make STDOUT unbuffered setbuf(stdout, NULL); // Parse Switches while ((opt = getopt(argc, argv, "al:r:n:N:O:p:jf:b:Q:d:c:R:L:s:uvqh")) != -1) { switch (opt) { case 'a': autoconnect = 1; break; case 'l': connect_left = optarg; break; case 'r': connect_right = optarg; break; case 'n': client_name = optarg; break; case 'N': archive_name = optarg; break; case 'O': originator = strdup(optarg); break; case 'p': archive_period_seconds = atol(optarg); break; case 'j': jack_opt |= JackNoStartServer; break; case 'f': format_name = rotter_str_tolower(optarg); break; case 'b': bitrate = atoi(optarg); break; case 'Q': vbr_quality = atof(optarg); break; case 'd': delete_hours = atoi(optarg); break; case 'c': channels = atoi(optarg); break; case 'R': rb_duration = atof(optarg); break; case 'L': file_layout = optarg; break; case 's': sync_period = atoi(optarg); break; case 'u': utc = 1; break; case 'v': verbose = 1; break; case 'q': quiet = 1; break; default: usage(); break; } } // Validate parameters if (quiet && verbose) { rotter_error("Can't be quiet and verbose at the same time."); usage(); } // Check the number of channels if (channels!=1 && channels!=2) { rotter_error("Number of channels should be either 1 or 2."); usage(); } // Check remaining arguments argc -= optind; argv += optind; if (argc!=1) { rotter_error("%s requires a root directory argument.", PACKAGE_NAME); usage(); } else { root_directory = argv[0]; if (root_directory[strlen(root_directory)-1] == '/') root_directory[strlen(root_directory)-1] = 0; if (rotter_directory_exists(root_directory)) { rotter_debug("Root directory: %s", root_directory); } else { rotter_fatal("Root directory does not exist: %s", root_directory); goto cleanup; } } // Search for the selected output format if (format_name) { for(i=0; format_list[i].name; i++) { if (strcmp( format_list[i].name, format_name ) == 0) { // Found desired format output_format = &format_list[i]; rotter_debug("User selected [%s] '%s'.", output_format->name, output_format->desc); break; } } if (output_format==NULL) { rotter_fatal("Failed to find format [%s], please check the supported format list.", format_name); goto cleanup; } } else { output_format = &format_list[0]; } // No originator defined? if (!originator) { originator = rotter_get_hostname(); } // Initialise JACK if (init_jack( client_name, jack_opt )) { rotter_debug("Failed to initialise Jack client."); goto cleanup; } // Create ring buffers if (init_ringbuffers()) { rotter_debug("Failed to initialise ring buffers."); goto cleanup; } // Create temporary buffer for reading samples into if (init_tmpbuffers(output_format->samples_per_frame)) { rotter_debug("Failed to initialise temporary buffers."); goto cleanup; } // Initialise encoder encoder = output_format->initfunc(output_format, channels, bitrate); if (encoder==NULL) { rotter_debug("Failed to initialise encoder."); goto cleanup; } // Activate JACK if (jack_activate(client)) { rotter_fatal("Cannot activate JACK client."); goto cleanup; } // Setup signal handlers signal(SIGTERM, rotter_termination_handler); signal(SIGINT, rotter_termination_handler); signal(SIGHUP, rotter_termination_handler); // Auto-connect our input ports ? if (autoconnect) autoconnect_jack_ports( client ); if (connect_left) connect_jack_port( connect_left, inport[0] ); if (connect_right && channels == 2) connect_jack_port( connect_right, inport[1] ); // Calculate period to wait when there is no audio to process sleep_time = (2.0f * output_format->samples_per_frame / jack_get_sample_rate( client )); rotter_debug("Sleep period is %dms.", (int)(sleep_time * 1000)); while( rotter_run_state == ROTTER_STATE_RUNNING ) { time_t now = time(NULL); int samples_processed = rotter_process_audio(); if (samples_processed <= 0) { usleep(sleep_time * 1000000); } // Is it time to sync the encoded audio to disk? if (next_sync < now) { rotter_sync_to_disk(); next_sync = now + sync_period; } deletefiles_cleanup_child(); } cleanup: // Clean up JACK deinit_jack(); // Free buffers and close files deinit_tmpbuffers(); deinit_ringbuffers(); // Shut down encoder if (encoder) encoder->deinit(); // Free the originator string if (originator) free(originator); // Did something go wrong? if (rotter_run_state == ROTTER_STATE_QUITING) { return EXIT_SUCCESS; } else { return EXIT_FAILURE; } }
// Initialise Jack related stuff static jack_client_t* init_jack( MastSendTool* tool ) { const char* client_name = tool->get_tool_name(); jack_client_t* client = NULL; jack_status_t status; size_t ringbuffer_size = 0; int port_count = tool->get_input_channels(); int i = 0; pthread_mutex_init(&g_ringbuffer_cond_mutex, NULL); pthread_cond_init(&g_ringbuffer_cond, NULL); // Register with Jack if ((client = jack_client_open(client_name, g_client_opt, &status)) == 0) { MAST_ERROR("Failed to start jack client: 0x%x", status); return NULL; } else { MAST_INFO( "JACK client registered as '%s'", jack_get_client_name( client ) ); } // Create our input port(s) if (port_count==1) { if (!(g_jackport[0] = jack_port_register(client, "mono", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) { MAST_ERROR("Cannot register mono input port"); return NULL; } } else { if (!(g_jackport[0] = jack_port_register(client, "left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) { MAST_ERROR("Cannot register left input port"); return NULL; } if (!(g_jackport[1] = jack_port_register(client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0))) { MAST_ERROR( "Cannot register left input port"); return NULL; } } // Create ring buffer ringbuffer_size = jack_get_sample_rate( client ) * g_rb_duration * port_count * sizeof(int16_t) / 1000; MAST_INFO("Duration of the ring buffer is %d ms (%d bytes)", g_rb_duration, (int)ringbuffer_size ); if (!(g_ringbuffer = jack_ringbuffer_create( ringbuffer_size ))) { MAST_ERROR("Cannot create ringbuffer %d", i); return NULL; } // Register callbacks jack_on_shutdown(client, shutdown_callback, tool ); jack_set_buffer_size_callback( client, buffersize_callback, tool); jack_set_process_callback(client, process_callback, tool); // Create conversion buffer buffersize_callback( jack_get_buffer_size(client), tool ); // Activate JACK if (jack_activate(client)) MAST_FATAL("Cannot activate JACK client"); /* Auto connect ports ? */ if (g_do_autoconnect) autoconnect_jack_ports( client, tool->get_input_channels() ); return client; }
static int connect_jack_ports(out123_handle *ao , jack_handle_t* handle) { debug1("connect_jack_ports with dev=%s", ao->device ? ao->device : "<nil>"); if(ao->device==NULL || strcmp(ao->device, "auto")==0) return autoconnect_jack_ports(ao, handle); else { /* Parse device for a set of ports, comma separated. */ const char** wishlist; /* Channels and end marker. */ int wish_channels = 1; /* Numper of entries in wishlist. */ char *devcopy, *chr; int ret; int c; size_t len; len = strlen(ao->device); /* We connect as many JACK ports as desired, possibly duplicating. */ for(chr=ao->device; *chr; ++chr) if(*chr == ',') ++wish_channels; debug1("wish_channels: %i", wish_channels); wishlist = malloc(sizeof(char*)*(wish_channels+1)); devcopy = compat_strdup(ao->device); if(devcopy == NULL || wishlist == NULL) { if(devcopy) free(devcopy); if(wishlist) free(wishlist); if(!AOQUIET) error("OOM"); return 0; } for(c=0;c<=wish_channels;++c) wishlist[c] = NULL; if(len && strcmp(devcopy, "none")) { size_t i=0; wishlist[0] = devcopy; for(c=0;c<wish_channels;++c) { while(devcopy[i] != 0 && devcopy[i] != ',') ++i; debug2("devcopy[%"SIZE_P"]=%i", i, devcopy[i]); if(devcopy[i] == ',') { /* Terminate previous port name, assign next one. */ devcopy[i++] = 0; debug2("terminaled wish %i: %s", c, wishlist[c]); if(c+1 < wish_channels) wishlist[c+1] = devcopy+i; } else break; } } if(wishlist[0] == NULL && !AOQUIET) warning("Not connecting up jack ports as requested."); ret = real_connect_jack_ports(ao, handle, wishlist); free(devcopy); free(wishlist); return ret; } return 1; }