Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5506)
+++ ChangeLog	(revision 5511)
@@ -4,4 +4,5 @@
 	* Added simple UUID interface (Closes: #230)
 	* Improved random number generator.
+	* Added a way to register plugin parts with a universal API (Closes: #245)
 
 v. 1.0beta1 - Sat May 12 2012 11:49 CEST
Index: include/libroar/roardl.h
===================================================================
--- include/libroar/roardl.h	(revision 5501)
+++ include/libroar/roardl.h	(revision 5511)
@@ -48,19 +48,23 @@
 #define ROAR_DL_HANDLE_DEFAULT          ((struct roar_dl_lhandle*)(void*)0)
 #define ROAR_DL_HANDLE_NEXT             ((struct roar_dl_lhandle*)(void*)1)
-
-#define ROAR_DL_FN_DSTR                 0
-#define ROAR_DL_FN_CDRIVER              1
-#define ROAR_DL_FN_TRANSCODER           2
-#define ROAR_DL_FN_DRIVER               3
-#define ROAR_DL_FN_SOURCE               4
-#define ROAR_DL_FN_FILTER               5
-#define ROAR_DL_FN_FF                   6 /* file format */
-#define ROAR_DL_FN_AUTH                 7
-#define ROAR_DL_FN_BRIDGE               8
-#define ROAR_DL_FN_ROARDSCHED           9
-#define ROAR_DL_FN_APPSCHED            10
-#define ROAR_DL_FN_PROTO               11
-#define ROAR_DL_FN_NOTIFY              12
+#define ROAR_DL_HANDLE_LIBROAR          ((struct roar_dl_lhandle*)(void*)2)
+#define ROAR_DL_HANDLE_APPLICATION      ((struct roar_dl_lhandle*)(void*)3)
+
+#define ROAR_DL_FN_DSTR                 0 /* VIO and DSTR drivers */
+#define ROAR_DL_FN_CDRIVER              1 /* Client drivers, libroareio */
+#define ROAR_DL_FN_TRANSCODER           2 /* Transcoder, libroardsp */
+#define ROAR_DL_FN_DRIVER               3 /* Driver, roard? */
+#define ROAR_DL_FN_SOURCE               4 /* Sources, roard? */
+#define ROAR_DL_FN_FILTER               5 /* Filter, libroardsp */
+#define ROAR_DL_FN_FF                   6 /* file format??? */
+#define ROAR_DL_FN_AUTH                 7 /* Auth */
+#define ROAR_DL_FN_BRIDGE               8 /* Bridges, roard? */
+#define ROAR_DL_FN_ROARDSCHED           9 /* Like appsched, but roard specific, old */
+#define ROAR_DL_FN_APPSCHED            10 /* AppSched, old interface */
+#define ROAR_DL_FN_PROTO               11 /* Protocols, roard? */
+#define ROAR_DL_FN_NOTIFY              12 /* ??? */
 #define ROAR_DL_FN_INIT                13 /* global plugin instance init. should be avoided */
+#define ROAR_DL_FN_REGFN               14 /* FN Registrations */
+#define ROAR_DL_FN_APPLICATION         15 /* Application specific stuff */
 //#define ROAR_DL_FN_               9
 #define ROAR_DL_FN_MAX                 24
@@ -296,4 +300,53 @@
 int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger);
 
+// FN Registration:
+
+// Actions objects can emit:
+enum roar_dl_fnreg_action {
+ ROAR_DL_FNREG   = 1, // The object is been registered
+ ROAR_DL_FNUNREG = 2  // The object is been unregistered
+};
+
+// Callback for registering/unregistering objects:
+struct roar_dl_fnreg {
+ int fn;          // Filter: The FN of the registering object or -1 for any.
+ int subtype;     // Filter: The subtype of the registering object or -1 for any.
+ int version;     // Filter: The version of the registering object or -1 for any.
+ int (*callback)( // Callback to call on register/unregister.
+   enum roar_dl_fnreg_action action, // The action happening
+   int fn,                           // The FN of the object
+   int subtype,                      // The subtype of the object
+   const void * object,              // Pointer to the object
+   size_t objectlen,                 // Length of the object
+   int version,                      // Version of the object
+   int options,                      // Object Options.
+   void * userdata,                  // User data for the callback.
+   struct roar_dl_lhandle * lhandle  // The registering handle.
+                                     // This is valid until the object is unregistered.
+                                     // Only roar_dl_context_restore() and roar_dl_context_store()
+                                     // may be used on this object. Result of all other functions
+                                     // is undefined.
+ );
+ void * userdata; // The user data pointer passed to the callback.
+};
+
+// Parameters for FNREG registration:
+#define ROAR_DL_FNREG_SUBTYPE  0
+#define ROAR_DL_FNREG_VERSION  0
+#define ROAR_DL_FNREG_SIZE     sizeof(struct roar_dl_fnreg)
+
+
+// Reg FN:
+
+// Options:
+#define ROAR_DL_FNREG_OPT_NONE 0   /* no options */
+
+// Register an FN.
+int                      roar_dl_register_fn(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options);
+
+// Unregister FN for the given plugin.
+// This should not be called directly and is called internally when needed.
+int                      roar_dl_unregister_fn(struct roar_dl_lhandle * lhandle);
+
 #endif
 
Index: libroar/roardl.c
===================================================================
--- libroar/roardl.c	(revision 5503)
+++ libroar/roardl.c	(revision 5511)
@@ -68,4 +68,6 @@
 };
 
+// TODO: this should be removed on next SONAME change.
+static struct roar_dl_lhandle * __currently_inited = NULL;
 
 struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
@@ -193,12 +195,17 @@
  ROAR_DBG("_roardl2ldl(lhandle=%p) = ?", lhandle);
 
- if ( lhandle == ROAR_DL_HANDLE_DEFAULT ) {
-  ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_DEFAULT);
-  return RTLD_DEFAULT;
- }
-
- if ( lhandle == ROAR_DL_HANDLE_NEXT ) {
-  ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_NEXT);
-  return RTLD_NEXT;
+ if ( (void*)lhandle < (void*)128 ) {
+  switch ((int)(void*)lhandle) {
+   case (int)(void*)ROAR_DL_HANDLE_DEFAULT:
+   case (int)(void*)ROAR_DL_HANDLE_LIBROAR:
+   case (int)(void*)ROAR_DL_HANDLE_APPLICATION:
+     ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_DEFAULT);
+     return RTLD_DEFAULT;
+    break;
+   case (int)(void*)ROAR_DL_HANDLE_NEXT:
+     ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_NEXT);
+     return RTLD_NEXT;
+    break;
+  }
  }
 
@@ -464,4 +471,6 @@
  }
 
+ roar_dl_unregister_fn(lhandle);
+
  if ( lhandle->lib != NULL && lhandle->lib->unload != NULL ) {
   roar_dl_context_restore(lhandle);
@@ -528,4 +537,5 @@
                                          const char * prefix,
                                          struct roar_dl_librarypara * para) {
+ struct roar_dl_lhandle * old_init;
 #define _SUFFIX "_roaraudio_library_init"
  char name[80] = _SUFFIX;
@@ -626,8 +636,12 @@
  }
 
+ old_init = __currently_inited;
+ __currently_inited = lhandle;
  for (i = 0; i < ROAR_DL_FN_MAX; i++) {
   if ( lib->func[i] != NULL )
    lib->func[i](para, lib);
  }
+ __currently_inited = old_init;
+
 
  if ( lib->global_data_pointer != NULL ) {
@@ -838,3 +852,145 @@
 }
 
+
+#define __MAX_FNREGS 24
+static struct __fnregs {
+ struct roar_dl_lhandle * lhandle;
+ int subtype;
+ const void * object;
+ size_t objectlen;
+ int version;
+ int options;
+} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
+
+static int  __fnreg_check_trigger(const struct __fnregs * handle) {
+ if ( handle->subtype != ROAR_DL_FNREG_SUBTYPE )
+  return -1;
+ if ( handle->version != ROAR_DL_FNREG_VERSION )
+  return -1;
+ if ( handle->objectlen != ROAR_DL_FNREG_SIZE )
+  return -1;
+
+ return 0;
+}
+
+static void __fnreg_trigger_if_match(const struct roar_dl_fnreg * callback,
+                                     const struct __fnregs * reg,
+                                     int fn,
+                                     enum roar_dl_fnreg_action action) {
+ if ( callback->fn != -1 && callback->fn != fn )
+  return;
+ if ( callback->subtype != -1 && callback->subtype != reg->subtype )
+  return;
+ if ( callback->version != -1 && callback->version != reg->version )
+  return;
+
+ if ( callback->callback == NULL )
+  return;
+
+ callback->callback(action, fn, reg->subtype, reg->object, reg->objectlen, reg->version, reg->options, callback->userdata, reg->lhandle);
+}
+
+static void __fnreg_trigger_by_reg(const struct __fnregs * reg, enum roar_dl_fnreg_action action, int fn) {
+ size_t j;
+
+ for (j = 0; j < __MAX_FNREGS; j++) {
+  if ( __fnrefs[ROAR_DL_FN_REGFN][j].lhandle != NULL ) {
+   if ( __fnreg_check_trigger(&(__fnrefs[ROAR_DL_FN_REGFN][j])) == -1 )
+    continue;
+   __fnreg_trigger_if_match(__fnrefs[ROAR_DL_FN_REGFN][j].object, reg, fn, action);
+  }
+ }
+}
+
+static void __fnreg_trigger_by_handler(const struct __fnregs * handle, enum roar_dl_fnreg_action action) {
+ size_t i, j;
+
+ if ( __fnreg_check_trigger(handle) == -1 )
+  return;
+
+ for (i = 0; i < ROAR_DL_FN_MAX; i++) {
+  for (j = 0; j < __MAX_FNREGS; j++) {
+   if ( __fnrefs[i][j].lhandle != NULL ) {
+    __fnreg_trigger_if_match(handle->object, &(__fnrefs[i][j]), i, action);
+   }
+  }
+ }
+}
+
+int roar_dl_register_fn(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options) {
+ struct __fnregs * c = NULL;
+ size_t i;
+
+ if ( lhandle == NULL )
+  lhandle = __currently_inited;
+
+ if ( lhandle == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ if ( fn < 0 || fn >= ROAR_DL_FN_MAX ) {
+  roar_err_set(ROAR_ERROR_RANGE);
+  return -1;
+ }
+
+ if ( object == NULL || objectlen == 0 ) {
+  roar_err_set(ROAR_ERROR_INVAL);
+  return -1;
+ }
+
+ for (i = 0; i < __MAX_FNREGS; i++) {
+  if ( __fnrefs[fn][i].lhandle != NULL )
+   continue;
+  c = &(__fnrefs[fn][i]);
+  break;
+ }
+
+ if ( c == NULL ) {
+  roar_err_set(ROAR_ERROR_NOSPC);
+  return -1;
+ }
+
+ c->lhandle   = lhandle;
+ c->subtype   = subtype;
+ c->object    = object;
+ c->objectlen = objectlen;
+ c->version   = version;
+
+ if ( fn == ROAR_DL_FN_REGFN ) {
+  __fnreg_trigger_by_handler(c, ROAR_DL_FNREG);
+ } else {
+  __fnreg_trigger_by_reg(c, ROAR_DL_FNREG, fn);
+ }
+
+ return 0;
+}
+
+int roar_dl_unregister_fn(struct roar_dl_lhandle * lhandle) {
+ size_t i, j;
+
+//} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
+
+ if ( lhandle == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ for (i = 0; i < ROAR_DL_FN_MAX; i++) {
+  for (j = 0; j < __MAX_FNREGS; j++) {
+   if ( __fnrefs[i][j].lhandle == lhandle ) {
+    if ( i == ROAR_DL_FN_REGFN ) {
+     __fnreg_trigger_by_handler(&(__fnrefs[i][j]), ROAR_DL_FNUNREG);
+    } else {
+     __fnreg_trigger_by_reg(&(__fnrefs[i][j]), ROAR_DL_FNUNREG, i);
+    }
+    memset(&(__fnrefs[i][j]), 0, sizeof(__fnrefs[i][j]));
+    __fnrefs[i][j].lhandle = NULL;
+   }
+  }
+ }
+
+ return 0;
+}
+
 //ll
