// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { af_channels_t* s = af->setup; switch(cmd){ case AF_CONTROL_REINIT: // Set default channel assignment if(!s->router){ int i; // Make sure this filter isn't redundant if(af->data->nch == ((af_data_t*)arg)->nch) return AF_DETACH; // If mono: fake stereo if(((af_data_t*)arg)->nch == 1){ s->nr = min(af->data->nch,2); for(i=0;i<s->nr;i++){ s->route[i][FR] = 0; s->route[i][TO] = i; } } else{ s->nr = min(af->data->nch, ((af_data_t*)arg)->nch); for(i=0;i<s->nr;i++){ s->route[i][FR] = i; s->route[i][TO] = i; } } } af->data->rate = ((af_data_t*)arg)->rate; af->data->format = ((af_data_t*)arg)->format; af->data->bps = ((af_data_t*)arg)->bps; af->mul.n = af->data->nch; af->mul.d = ((af_data_t*)arg)->nch; af_frac_cancel(&af->mul); return check_routes(s,((af_data_t*)arg)->nch,af->data->nch); case AF_CONTROL_COMMAND_LINE:{ int nch = 0; int n = 0; // Check number of channels and number of routing pairs sscanf(arg, "%i:%i%n", &nch, &s->nr, &n); // If router scan commandline for routing pairs if(s->nr){ char* cp = &((char*)arg)[n]; int ch = 0; // Sanity check if((s->nr < 1) || (s->nr > AF_NCH)){ af_msg(AF_MSG_ERROR,"[channels] The number of routing pairs must be" " between 1 and %i. Current value is %i\n",AF_NCH,s->nr); } s->router = 1; // Scan for pairs on commandline while((*cp == ':') && (ch < s->nr)){ sscanf(cp, ":%i:%i%n" ,&s->route[ch][FR], &s->route[ch][TO], &n); af_msg(AF_MSG_VERBOSE,"[channels] Routing from channel %i to" " channel %i\n",s->route[ch][FR],s->route[ch][TO]); cp = &cp[n]; ch++; } } if(AF_OK != af->control(af,AF_CONTROL_CHANNELS | AF_CONTROL_SET ,&nch)) return AF_ERROR; return AF_OK; } case AF_CONTROL_CHANNELS | AF_CONTROL_SET: // Reinit must be called after this function has been called // Sanity check if(((int*)arg)[0] <= 0 || ((int*)arg)[0] > AF_NCH){ af_msg(AF_MSG_ERROR,"[channels] The number of output channels must be" " between 1 and %i. Current value is %i\n",AF_NCH,((int*)arg)[0]); return AF_ERROR; } af->data->nch=((int*)arg)[0]; if(!s->router) af_msg(AF_MSG_VERBOSE,"[channels] Changing number of channels" " to %i\n",af->data->nch); return AF_OK; case AF_CONTROL_CHANNELS | AF_CONTROL_GET: *(int*)arg = af->data->nch; return AF_OK; case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_SET:{ int ch = ((af_control_ext_t*)arg)->ch; int* route = ((af_control_ext_t*)arg)->arg; s->route[ch][FR] = route[FR]; s->route[ch][TO] = route[TO]; return AF_OK; } case AF_CONTROL_CHANNELS_ROUTING | AF_CONTROL_GET:{ int ch = ((af_control_ext_t*)arg)->ch; int* route = ((af_control_ext_t*)arg)->arg; route[FR] = s->route[ch][FR]; route[TO] = s->route[ch][TO]; return AF_OK; } case AF_CONTROL_CHANNELS_NR | AF_CONTROL_SET: s->nr = *(int*)arg; return AF_OK; case AF_CONTROL_CHANNELS_NR | AF_CONTROL_GET: *(int*)arg = s->nr; return AF_OK; case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_SET: s->router = *(int*)arg; return AF_OK; case AF_CONTROL_CHANNELS_ROUTER | AF_CONTROL_GET: *(int*)arg = s->router; return AF_OK; } return AF_UNKNOWN; }
// Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { switch(cmd){ case AF_CONTROL_REINIT:{ char buf1[256]; char buf2[256]; af_data_t *data = arg; // Make sure this filter isn't redundant if(af->data->format == data->format && af->data->bps == data->bps) return AF_DETACH; // Check for errors in configuraton if((AF_OK != check_bps(data->bps)) || (AF_OK != check_format(data->format)) || (AF_OK != check_bps(af->data->bps)) || (AF_OK != check_format(af->data->format))) return AF_ERROR; af_msg(AF_MSG_VERBOSE,"[format] Changing sample format from %s to %s\n", af_fmt2str(data->format,buf1,256), af_fmt2str(af->data->format,buf2,256)); af->data->rate = data->rate; af->data->nch = data->nch; af->mul.n = af->data->bps; af->mul.d = data->bps; af_frac_cancel(&af->mul); af->play = play; // set default // look whether only endianess differences are there if ((af->data->format & ~AF_FORMAT_END_MASK) == (data->format & ~AF_FORMAT_END_MASK)) { af_msg(AF_MSG_VERBOSE,"[format] Accelerated endianess conversion only\n"); af->play = play_swapendian; } if ((data->format == AF_FORMAT_FLOAT_NE) && (af->data->format == AF_FORMAT_S16_NE)) { af_msg(AF_MSG_VERBOSE,"[format] Accelerated %s to %s conversion\n", af_fmt2str(data->format,buf1,256), af_fmt2str(af->data->format,buf2,256)); af->play = play_float_s16; } if ((data->format == AF_FORMAT_S16_NE) && (af->data->format == AF_FORMAT_FLOAT_NE)) { af_msg(AF_MSG_VERBOSE,"[format] Accelerated %s to %s conversion\n", af_fmt2str(data->format,buf1,256), af_fmt2str(af->data->format,buf2,256)); af->play = play_s16_float; } return AF_OK; } case AF_CONTROL_COMMAND_LINE:{ int format = af_str2fmt_short(arg); if (format == -1) { af_msg(AF_MSG_ERROR, "[format] %s is not a valid format\n", (char *)arg); return AF_ERROR; } if(AF_OK != af->control(af,AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET,&format)) return AF_ERROR; return AF_OK; } case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET:{ // Check for errors in configuraton if(AF_OK != check_format(*(int*)arg)) return AF_ERROR; af->data->format = *(int*)arg; af->data->bps = af_fmt2bits(af->data->format)/8; return AF_OK; } } return AF_UNKNOWN; }