Appendix: Using Addon Resources

This appendix contains information about using resources in your addon. A resource is any piece of data that you want to have access to. For example, in a multimedia interface, you may want to specify "volume" as a resource. You can then write functions to get and set the volume, using GetResource() and SetResource() as defined in the AOResourceAccess interface.

An Example

Here's an example of working with a resource in an addon. Lets start with creating resources in your addon. One approach is to create a const structure containing your resources definitions, and then use that as a template to create a resources structure for each context, if your addon uses contexts. You would use contexts if you needed more than one instance of the same addon. Lets create a context structure first:

 typedef struct my_context
 {
  int32_t volume;       // volume, 0-100
  int64_t position;     // position, in microseconds
  AOResource_t *resources;
 };

We'll need typing info for our volume and position resources, such as minimum, maximum, and increment values. In an AOResource_t there is pre-defined typing info in the type element flags. When the type flag for an AOResource_t is AOR_TYPE_LONG, then value is an int32_t and the resource info is a pointer to int32_t min, max, and step values:

 // volume range from 0 to 100, in increments of one
 static const int32_t volumerange[] = {0,100,1};

When type is AOR_TYPE_LONGLONG, the resource value is an int64_t and info is a pointer to int64_t min, max, and step values:

 // position range from 0 to 86400000000 (86400 seconds, or 24 hours.)
 static const int64_t posrange[] = {0,86400000000,1};

The AOResource_t structure is defined as:

typedef struct
{
        char *name;
        char *description;
        void *value;
        void *info;
        int32_t type;
} AOResource_t;

For more information about the AOResource_t structure, see AOResource_t.

Now we can define our const AOResource_t resources structure:

static const AOResource_t resources[] =
{
 { "Volume","Current Volume",(void*)offsetof(my_context,volume),
   &volumerange,AOR_TYPE_LONG|AOR_TYPE_READABLE|AOR_TYPE_WRITABLE },
 { "Position","Current Position",(void*)offsetof(my_context,position),
   &posrange,AOR_TYPE_LONGLONG|AOR_TYPE_READABLE|AOR_TYPE_WRITABLE },
 { 0 }
};

As you can see, the pointer to the current value of the resource is not valid; its an offset into the context. When we create a new context, we'll have to adjust this pointer accordingly. Assuming we use the AODeConstructor interface, our create function might look like:

 static void *Create(const AOICtrl_t *interfaces)
 {
  my_context *ctx=(my_context*)calloc(1,sizeof(my_context);
  int32_t n;
  AOResource_t *res;

  // allocate new resource structure, and copy const version
  // into it:
  ctx->res=(AOResource_t*)malloc(sizeof(resources));
  memcpy(ctx->res,&resources,sizeof(resources));

  for (res=ctx->res;res->name;res++)
  {
        char *p=(char *)ctx;

        // Add the address of the context to the offset, making
        // the value pointer now point to the correct location
        // in our context:
        res->value=(void*)(&p[(int32_t)res->value]);
  }

  // initialize our context elements, if necessary
  ctx->volume=50;

  return ctx;
 }

 static void Destroy(void *p)
 {
  my_context *ctx=(my_context*)p;

  free(ctx->res);
  free(ctx);
 }

 static AODeConstructor media_filter =
 {
  Create,
  Destroy
 };

If we want the outside world to be able to access our resources, we'll need to implement the AOResourceAccess interface. This is quite easy as well:

 static const AOResource_t *GetResources(void *handle)
 {
  my_context *ctx=(my_context*)handle;

  return handle->resources;
 }

 static int32_t SetResource(void *handle,const char *res,
                            const void *data)
 {
  my_context *ctx=(my_context*)handle;

  // first resource is volume
  if (strcmp(res,ctx->resources[0].name)==0)
  {
   ctx->volume=*((int32_t*)data);

   // do any other volume control stuff here

   // return success
   return 0;
  }
  else

  // second resource is position
  if (strcmp(res,ctx->resources[1].name)==0)
  {
   ctx->position=*((int64_t*)data);

   // do any other positioning stuff here

   // return success
   return 0;
  }

  // no matching resource, return error
  return -1;
 }

 static AOResourceAccess resource_access =
 {
  GetResources,
  SetResource,
 };

At the end of our addon, we put them all together in our interfaces list:

 #ifdef VARIANT_dll
 AOInterface_t interfaces[] =
 #else
 AOInterface_t my_addon_interfaces[] =
 #endif
 {
  { "Name",1,"my_addon" },
  { "AODeConstructor",AODECONSTRUCTOR_VERSION,&media_filter },
  { "AOResourceAccess",AORESOURCEACCESS_VERSION,&resource_access },
  { 0,0,0 },
 };

We use the #ifdef in order to build a shared (DLL) and static (library) version of our addon with the same source code. This way we can link directly with the static version if we want our application to be completely self contained, and use the DLL if not.

Using addon resources in your application

To use the our addon's resources in an application, we simply get the addon's AOResourceAccess interface using the AOGetInterface() function, call its GetResources() function, and iterate through the resources until we find one we want to look at. If we want to change one of the resources, and its AOR_TYPE_WRITABLE type flag is set, we call the interfaces SetResource() function. Here are examples for getting and setting the volume:

int32_t GetVolume(AOICtrl_t *ctrl,void *ctx)
{
 AOResource_t *res;
 AOInterface_t *i;

 // does it have resource access?
 if (i=AOGetInterface(ctrl,"AOResourceAccess",AORESOURCEACCESS_VERSION,0))
 {
  // does it have resources?
  if (res=i->GetResources(ctx))
  {
   // iterate through the resources
   for (;res->name;res++)
   {
    // is the current resource the volume?
    if (strcmp(res->name,"Volume")==0) return *((int32_t*)res->value);
   }
  }
 }
 return -1;
}

int32_t SetVolume(AOICtrl_t *ctrl,void *ctx,int32_t volume)
{
 AOInterface_t *i;

 // does it have resource access?
 if (i=AOGetInterface(ctrl,"AOResourceAccess",AORESOURCEACCESS_VERSION,0))
 {
  // try to set its Volume resource.
  return i->SetResource(ctx,"Volume",&volume);
 }
 return -1;
}