const char *next_sopt(const char *p, unsigned *i) { unsigned int len = 1; for (p = next_opt(p, i, &len); p; p = next_opt(p, i, &len)) { if (p[0] != '-') break; } return p; }
const char *next_lopt(const char *p, unsigned *i, unsigned *len) { for (p = next_opt(p, i, len); p; p = next_opt(p, i, len)) { if (p[0] == '-') { /* Skip leading "-" */ (*len)--; p++; break; } } return p; }
bool param_check (const char *const param, const char *const name, const char **val, int *val_len) { if (val) *val = NULL; if (val_len) *val_len = 0; if (param == NULL || name == NULL) { return FALSE; } const char *p = param; int len; while (*p != '\0') { const char *cur_name; int cur_name_len; const char *cur_val; int cur_val_len; len = next_opt(p, &cur_name, &cur_name_len, &cur_val, &cur_val_len); p += len; if ((cur_name_len > 0) && (strncmp(cur_name, name, cur_name_len) == 0)) { if ((cur_val == NULL) != (val == NULL)) { return FALSE; } if (val && val_len) { *val = cur_val; *val_len = cur_val_len; return TRUE; } else if (!val && !val_len) { return TRUE; } return FALSE; } } return FALSE; }
// Searches 'param' for option 'name'. // If this option is found, 'found' is set to TRUE, otherwise it is set to FALSE. // If given 'val' or 'val_len' is NULL, any option value is ignored. // If the option has a value, it is returned in 'val', its length in 'val_len', otherwise NULL/0 is returned. void param_getopt(const char *const param, const char *const name, bool * found, const char ** val, int * val_len) { if (val) *val = NULL; if (val_len) *val_len = 0; *found = FALSE; if (param == NULL || name == NULL) { *found = FALSE; return; } const char *p = param; int len; while (p[0]!=0) { const char * cur_name; int cur_name_len; const char * cur_val; int cur_val_len; len = next_opt(p, &cur_name, &cur_name_len, &cur_val, &cur_val_len); p+=len; if ((cur_name_len>0) && (strncmp(cur_name, name, cur_name_len)==0)) { *found = TRUE; if (cur_val_len>0 && val && val_len) { *val = cur_val; *val_len = cur_val_len; } return; } } }
/** * Process all the options from our current position onward. (This allows * interspersed options and arguments for the few non-standard programs that * require it.) Thus, do not rewind option indexes because some programs * choose to re-invoke after a non-option. * * @param pOpts program options descriptor * @returns SUCCESS or FAILURE */ LOCAL tSuccess regular_opts(tOptions * pOpts) { /* assert: pOpts->fOptSet & OPTPROC_IMMEDIATE == 0 */ for (;;) { tOptState opt_st = OPTSTATE_INITIALIZER(DEFINED); switch (next_opt(pOpts, &opt_st)) { case FAILURE: goto failed_option; case PROBLEM: return SUCCESS; /* no more args */ case SUCCESS: break; } /* * IF this is an immediate action option, * THEN skip it (unless we are supposed to do it a second time). */ if (! DO_NORMALLY(opt_st.flags)) { if (! DO_SECOND_TIME(opt_st.flags)) continue; opt_st.pOD->optOccCt--; /* don't count this repetition */ } if (! SUCCESSFUL(handle_opt(pOpts, &opt_st))) break; } failed_option:; if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); return FAILURE; }
/** * scan the command line for immediate action options. * This is only called the first time through. */ LOCAL tSuccess doImmediateOpts(tOptions* pOpts) { pOpts->curOptIdx = 1; /* start by skipping program name */ pOpts->pzCurOpt = NULL; /* * Examine all the options from the start. We process any options that * are marked for immediate processing. */ for (;;) { tOptState optState = OPTSTATE_INITIALIZER(PRESET); switch (next_opt(pOpts, &optState)) { case FAILURE: goto failed_option; case PROBLEM: return SUCCESS; /* no more args */ case SUCCESS: break; } /* * IF this is an immediate-attribute option, then do it. */ if (! DO_IMMEDIATELY(optState.flags)) continue; if (! SUCCESSFUL(handle_opt(pOpts, &optState))) break; } failed_option:; if ((pOpts->fOptSet & OPTPROC_ERRSTOP) != 0) (*pOpts->pUsageProc)(pOpts, EXIT_FAILURE); return FAILURE; }
const char *first_sopt(unsigned *i) { const char *p; unsigned int len = 0 /* GCC bogus warning */; for (p = first_opt(i, &len); p; p = next_opt(p, i, &len)) { if (p[0] != '-') break; } return p; }
/** * scan the command line for immediate action options. * This is only called the first time through. * While this procedure is active, the OPTPROC_IMMEDIATE is true. * * @param pOpts program options descriptor * @returns SUCCESS or FAILURE */ LOCAL tSuccess immediate_opts(tOptions * opts) { tSuccess res; opts->fOptSet |= OPTPROC_IMMEDIATE; opts->curOptIdx = 1; /* start by skipping program name */ opts->pzCurOpt = NULL; /* * Examine all the options from the start. We process any options that * are marked for immediate processing. */ for (;;) { tOptState opt_st = OPTSTATE_INITIALIZER(PRESET); res = next_opt(opts, &opt_st); switch (res) { case FAILURE: goto failed_option; case PROBLEM: res = SUCCESS; goto leave; case SUCCESS: break; } /* * IF this is an immediate-attribute option, then do it. */ if (! DO_IMMEDIATELY(opt_st.flags)) continue; if (! SUCCESSFUL(handle_opt(opts, &opt_st))) break; } failed_option:; if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0) (*opts->pUsageProc)(opts, EXIT_FAILURE); leave: opts->fOptSet &= ~OPTPROC_IMMEDIATE; return res; }
/* Initialize the audio path */ int mxuvc_audio_init(const char *backend, const char *options) { RECORD("\"%s\", \"%s\"", backend, options); struct libusb_device *dev = NULL; int ret=0, i, config; uint16_t vendor_id=0xdead, product_id=0xbeef; char *str=NULL, *opt, *value; int audio_sampling_rate; TRACE("Initializing the audio\n"); /* Check that the correct video backend was requested*/ if(strncmp(backend, "libusb-uac", 10)) { ERROR(-1, "The audio backend requested (%s) does not match " "the implemented one (libusb-uac)", backend); } /* Set init parameters to their default values */ packets_per_transfer = PACKETS_PER_TRANSFER_DEFAULT; num_transfers = NUM_TRANSFERS_DEFAULT; audio_duration_ms = AUDIO_DURATION_MS_DEFAULT; audio_sampling_rate = AUDIO_SAMPLING_RATE_DEFAULT; /* Copy the options string to a new buffer since next_opt() needs * non const strings and options could be a const string */ if(options != NULL) { str = (char*)malloc(strlen(options)+1); strncpy(str, options, strlen(options)); *(str + strlen(options)) = '\0'; } /* Get backend option from the option string */ ret = next_opt(str, &opt, &value); while(ret == 0) { if(strncmp(opt, "vid", 3) == 0) { vendor_id = (uint16_t) strtoul(value, NULL, 16); } else if(strncmp(opt, "pid", 3) == 0) { product_id = (uint16_t) strtoul(value, NULL, 16); } else if(strncmp(opt, "packets_per_transfer", 19) == 0) { packets_per_transfer = (unsigned int) strtoul(value, NULL, 10); } else if(strncmp(opt, "num_transfers", 12) == 0) { num_transfers = (unsigned int) strtoul(value, NULL, 10); } else if(strncmp(opt, "audio_duration_ms", 17) == 0) { audio_duration_ms = (unsigned int) strtoul(value, NULL, 10); } else if (strncmp (opt, "audio_sampling_rate", 19) == 0) { audio_sampling_rate = (unsigned int) strtoul (value, NULL, 10); } else { WARNING("Unrecognized option: '%s'", opt); } ret = next_opt(NULL, &opt, &value); } /* Display the values we are going to use */ TRACE("Using vid = 0x%x\n", vendor_id); TRACE("Using pid = 0x%x\n", product_id); TRACE("Using packets_per_transfer = %i\n", packets_per_transfer); TRACE("Using num_transfers = %i\n", num_transfers); TRACE("Using audio_duration_ms = %i\n", audio_duration_ms); TRACE("Using audio_sampling_rate = %i\n", audio_sampling_rate); /* Free the memory allocated to parse 'options' */ if(str) free(str); /* Initialize the backend */ aud_started = 0; audio_disconnected = 0; ret = init_libusb(&audio_ctx); if(ret < 0) return -1; audio_hdl = libusb_open_device_with_vid_pid(audio_ctx, vendor_id, product_id); CHECK_ERROR(audio_hdl == NULL, -1, "Could not open USB device " "%x:%x", vendor_id, product_id); dev = libusb_get_device(audio_hdl); if(dev == NULL) { printf("Unexpected error: libusb_get_device returned a NULL " "pointer."); mxuvc_audio_deinit(); return -1; } /* Get active USB configuration */ libusb_get_configuration(audio_hdl, &config); /* Parse USB decriptors from active USB configuration * to get all the UVC/UAC info needed */ ret = aparse_usb_config(dev, config); if(ret < 0){ mxuvc_audio_deinit(); return -1; } /* Initialize audio */ /* Claim audio control interface */ /* Check if a kernel driver is active on the audio control interface */ ret = libusb_kernel_driver_active(audio_hdl, aud_cfg.ctrlif); if(ret < 0) printf("Error: libusb_kernel_driver_active failed %d\n", ret); if(ret == 1) { TRACE("Detach the kernel driver...\n"); /* If kernel driver is active, detach it so that we can claim * the interface */ ret = libusb_detach_kernel_driver(audio_hdl, aud_cfg.ctrlif); if(ret < 0) printf("Error: libusb_detach_kernel_driver failed " "%d\n", ret); } /* Claim audio control interface */ ret = libusb_claim_interface(audio_hdl, aud_cfg.ctrlif); if(ret < 0) { printf("Error: libusb_claim_interface failed %d\n", ret); } /* Claim audio streaming interface */ /* Check if a kernel driver is active on the audio interface */ ret = libusb_kernel_driver_active(audio_hdl, aud_cfg.interface); if(ret < 0) printf("Error: libusb_kernel_driver_active failed %d\n", ret); if(ret == 1) { TRACE("Detach the kernel driver...\n"); /* If kernel driver is active, detach it so that we can claim * the interface */ ret = libusb_detach_kernel_driver(audio_hdl, aud_cfg.interface); if(ret < 0) printf("Error: libusb_detach_kernel_driver failed " "%d\n",ret); } /* Claim audio streaming interface */ ret = libusb_claim_interface(audio_hdl, aud_cfg.interface); if(ret < 0) { printf("Error: libusb_claim_interface failed %d\n",ret); } /* Select sampling rate */ for(i=0;i<MAX_AUD_FMTS;i++) { if(aud_cfg.format[i].samFr == audio_sampling_rate){ aud_cfg.fmt_idx = i; break; } CHECK_ERROR(i == MAX_AUD_FMTS-1, -1, "Unable to set the sampling rate to %i", audio_sampling_rate); } /* Map default UAC format to Audio format */ cur_aud_format = AUD_FORMAT_PCM_RAW; /* Get min, max and real unit id for ctrl */ AUDIO_CTRL *ctrl = uac_controls; int16_t min = 0, max = 0; uint16_t res = 0; while(ctrl->id != CTRL_NONE) { switch(ctrl->unit) { TRACE(">>>>>id:%d unit:%d\n", ctrl->id,ctrl->unit); case FEATURE: ctrl->unit = aud_cfg.ctrl_feature; break; default: ERROR(-1, "Unsupported control unit (%i) for " "audio control %i", ctrl->unit, ctrl->id); } if (ctrl->id == CTRL_MUTE) { ctrl++; continue; } ret = get_ctrl(ctrl->id, GET_MIN, (void*) &min); CHECK_ERROR(ret < 0, -1, "Unable to get min (GET_MIN) for audio " "control: id=%i, cs=%i, cn=%i.", ctrl->id, ctrl->cs, ctrl->cn); ctrl->min = min; ret = get_ctrl(ctrl->id, GET_MAX, (void*) &max); CHECK_ERROR(ret < 0, -1, "Unable to get max (GET_MAX) for audio " "control: id=%i, cs=%i, cn=%i.", ctrl->id, ctrl->cs, ctrl->cn); ctrl->max = max; ret = get_ctrl(ctrl->id, GET_RES, (void*) &res); CHECK_ERROR(ret < 0, -1, "Unable to get res (GET_RES) for audio " "control: id=%i, cs=%i, cn=%i.", ctrl->id, ctrl->cs, ctrl->cn); ctrl->res = res; ctrl++; } /* Register removal USB event*/ register_libusb_removal_cb((libusb_pollfd_removed_cb) audio_removed, audio_hdl); /* Start event thread/loop */ ret = start_libusb_events(); if(ret < 0) return -1; audio_initialized = 1; return 0; }