aboutsummaryrefslogtreecommitdiffhomepage
path: root/backends/rtpmidi.c
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2019-12-08 15:43:05 +0100
committercbdev <cb@cbcdn.com>2019-12-08 15:43:05 +0100
commitaa092469e21674bb99275dda08a695f0d426f6de (patch)
treee50add552af0c3ac12627d0290ec8f53557b06cb /backends/rtpmidi.c
parentac4aa9935bfb6406c71ea5ed14a68bd41617b701 (diff)
downloadmidimonster-aa092469e21674bb99275dda08a695f0d426f6de.tar.gz
midimonster-aa092469e21674bb99275dda08a695f0d426f6de.tar.bz2
midimonster-aa092469e21674bb99275dda08a695f0d426f6de.zip
rtpmidi channel spec parsing
Diffstat (limited to 'backends/rtpmidi.c')
-rw-r--r--backends/rtpmidi.c199
1 files changed, 179 insertions, 20 deletions
diff --git a/backends/rtpmidi.c b/backends/rtpmidi.c
index ea97565..4fb0ce0 100644
--- a/backends/rtpmidi.c
+++ b/backends/rtpmidi.c
@@ -35,6 +35,11 @@ int init(){
.shutdown = rtpmidi_shutdown
};
+ if(sizeof(rtpmidi_channel_ident) != sizeof(uint64_t)){
+ fprintf(stderr, "rtpmidi channel identification union out of bounds\n");
+ return 1;
+ }
+
if(mm_backend_register(rtpmidi)){
fprintf(stderr, "Failed to register rtpmidi backend\n");
return 1;
@@ -45,7 +50,6 @@ int init(){
static int rtpmidi_configure(char* option, char* value){
char* host = NULL, *port = NULL;
- char next_port[10];
if(!strcmp(option, "mdns-name")){
if(cfg.mdns_name){
@@ -93,17 +97,170 @@ static int rtpmidi_configure(char* option, char* value){
}
static int rtpmidi_configure_instance(instance* inst, char* option, char* value){
- //TODO
+ rtpmidi_instance_data* data = (rtpmidi_instance_data*) inst->impl;
+
+ if(!strcmp(option, "mode")){
+ if(!strcmp(value, "direct")){
+ data->mode = direct;
+ return 0;
+ }
+ else if(!strcmp(value, "apple")){
+ data->mode = apple;
+ return 0;
+ }
+ fprintf(stderr, "Unknown rtpmidi instance mode %s for instance %s\n", value, inst->name);
+ return 1;
+ }
+ else if(!strcmp(option, "ssrc")){
+ data->ssrc = strtoul(value, NULL, 0);
+ if(!data->ssrc){
+ fprintf(stderr, "Random SSRC will be generated for rtpmidi instance %s\n", inst->name);
+ }
+ return 0;
+ }
+ else if(!strcmp(option, "bind")){
+ //TODO set the bind host
+ }
+ else if(!strcmp(option, "learn")){
+ if(data->mode != direct){
+ fprintf(stderr, "The rtpmidi 'learn' option is only valid for direct mode instances\n");
+ return 1;
+ }
+ data->learn_peers = 0;
+ if(!strcmp(value, "true")){
+ data->learn_peers = 1;
+ }
+ return 0;
+ }
+ else if(!strcmp(option, "peer")){
+ if(data->mode != direct){
+ fprintf(stderr, "The rtpmidi 'peer' option is only valid for direct mode instances\n");
+ return 1;
+ }
+
+ //TODO add peer
+ return 0;
+ }
+ else if(!strcmp(option, "session")){
+ if(data->mode != apple){
+ fprintf(stderr, "The rtpmidi 'session' option is only valid for apple mode instances\n");
+ return 1;
+ }
+ free(data->session_name);
+ data->session_name = strdup(value);
+ if(!data->session_name){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+ return 0;
+ }
+ else if(!strcmp(option, "invite")){
+ if(data->mode != apple){
+ fprintf(stderr, "The rtpmidi 'invite' option is only valid for apple mode instances\n");
+ return 1;
+ }
+ free(data->invite_peers);
+ data->invite_peers = strdup(value);
+ if(!data->invite_peers){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+ return 0;
+ }
+ else if(!strcmp(option, "join")){
+ if(data->mode != apple){
+ fprintf(stderr, "The rtpmidi 'join' option is only valid for apple mode instances\n");
+ return 1;
+ }
+ free(data->invite_accept);
+ data->invite_accept = strdup(value);
+ if(!data->invite_accept){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return 1;
+ }
+ return 0;
+ }
+
+ fprintf(stderr, "Unknown rtpmidi instance option %s\n", option);
return 1;
}
static instance* rtpmidi_instance(){
- //TODO
- return NULL;
+ rtpmidi_instance_data* data = NULL;
+ instance* inst = mm_instance();
+
+ if(!inst){
+ return NULL;
+ }
+
+ data = calloc(1, sizeof(rtpmidi_instance_data));
+ if(!data){
+ fprintf(stderr, "Failed to allocate memory\n");
+ return NULL;
+ }
+
+ inst->impl = data;
+ return inst;
}
static channel* rtpmidi_channel(instance* inst, char* spec, uint8_t flags){
- //TODO
+ char* next_token = spec;
+ rtpmidi_channel_ident ident = {
+ .label = 0
+ };
+
+ if(!strncmp(spec, "ch", 2)){
+ next_token += 2;
+ if(!strncmp(spec, "channel", 7)){
+ next_token = spec + 7;
+ }
+ }
+ else{
+ fprintf(stderr, "Invalid rtpmidi channel specification %s\n", spec);
+ return NULL;
+ }
+
+ ident.fields.channel = strtoul(next_token, &next_token, 10);
+ if(ident.fields.channel > 15){
+ fprintf(stderr, "rtpmidi channel out of range in channel spec %s\n", spec);
+ return NULL;
+ }
+
+ if(*next_token != '.'){
+ fprintf(stderr, "rtpmidi channel specification %s does not conform to channel<X>.<control><Y>\n", spec);
+ return NULL;
+ }
+
+ next_token++;
+
+ if(!strncmp(next_token, "cc", 2)){
+ ident.fields.type = cc;
+ next_token += 2;
+ }
+ else if(!strncmp(next_token, "note", 4)){
+ ident.fields.type = note;
+ next_token += 4;
+ }
+ else if(!strncmp(next_token, "pressure", 8)){
+ ident.fields.type = pressure;
+ next_token += 8;
+ }
+ else if(!strncmp(next_token, "pitch", 5)){
+ ident.fields.type = pitchbend;
+ }
+ else if(!strncmp(next_token, "aftertouch", 10)){
+ ident.fields.type = aftertouch;
+ }
+ else{
+ fprintf(stderr, "Unknown rtpmidi channel control type in spec %s\n", spec);
+ return NULL;
+ }
+
+ ident.fields.control = strtoul(next_token, NULL, 10);
+
+ if(ident.label){
+ return mm_channel(inst, ident.label, 1);
+ }
return NULL;
}
@@ -124,35 +281,37 @@ static int rtpmidi_handle(size_t num, managed_fd* fds){
}
static int rtpmidi_start(){
- size_t n, u, p;
+ size_t n, u;
int rv = 1;
instance** inst = NULL;
rtpmidi_instance_data* data = NULL;
//TODO if mdns name defined and no socket, bind default values
+ if(cfg.mdns_fd < 0){
+ fprintf(stderr, "No mDNS discovery interface bound, AppleMIDI session support disabled\n");
+ }
+
//fetch all defined instances
if(mm_backend_instances(BACKEND_NAME, &n, &inst)){
fprintf(stderr, "Failed to fetch instance list\n");
return 1;
}
- if(!n){
- free(inst);
- return 0;
- }
-
- if(!cfg.nfds){
- fprintf(stderr, "Failed to start rtpMIDI backend: no descriptors bound\n");
- goto bail;
- }
+ for(u = 0; u < n; u++){
+ data = (rtpmidi_instance_data*) inst[u]->impl;
+ //check whether instances are explicitly configured to a mode
+ if(data->mode == unconfigured){
+ fprintf(stderr, "rtpmidi instance %s is missing a mode configuration\n", inst[u]->name);
+ goto bail;
+ }
- if(cfg.mdns_fd < 0){
- fprintf(stderr, "No mDNS discovery interface bound, APPLEMIDI session support disabled\n");
+ //generate random ssrc's
+ if(!data->ssrc){
+ data->ssrc = rand() << 16 | rand();
+ }
}
- //TODO initialize all instances
-
rv = 0;
bail:
free(inst);
@@ -160,7 +319,7 @@ bail:
}
static int rtpmidi_shutdown(){
- size_t u;
+ //TODO cleanup instance data
free(cfg.mdns_name);
if(cfg.mdns_fd >= 0){