[gmpi] Querying a plugin's structure (params, IOs, etc)

  • From: thockin@xxxxxxxxxx
  • To: GMPI list <gmpi@xxxxxxxxxxxxx>
  • Date: Mon, 12 Dec 2005 23:15:19 -0800

On Fri, Dec 02, 2005 at 02:43:54PM -0800, thockin@xxxxxxxxxx wrote:
> Anyone have opinions?  This is one of those fundamental design choices
> that can set precedent for other aspects of the API...

How about soemthing like this? (pseudo-code) (discussion below)

 /*
  * A plugin is essentially a tree of elements.  You can inspect the tree,
  * one group at a time.
  */

 enum GMPI_ElementType {
        GMPI_ELEM_AUDIO,
        GMPI_ELEM_CONTROL,
        GMPI_ELEM_GROUP
 }

 /* an element is a single piece of a plugin */
 GMPI_Element {
        GMPI_ElementType type;
        uint32_t key;
        char* name;
 }

 GMPI_Plugin {
        ...
        Inspect(uint32_t group, int index, GMPI_Element* element);
        GetAudioIO(uint32_t key, GMPI_Unknown* unknown);
        GetControlIO(uint32_t key, GMPI_Unknown* unknown);
        ...
 }

 GMPI_AudioIO {
        ...
        GetDirection(void);
        GetChannels(void);
        GetEncoding(void);
        ...
 }

 GMPI_ControlIO {
        ...
        GetType(void);
        GetDirection(void);
        ...
 }

 GMPI_FloatControl {
        ...
        GetType(void);
        GetDirection(void);
        GetMin(void);
        GetMax(void);
        GetDefault(void);
        ...
 }

 GMPI_IntControl {
        ...
        GetType(void);
        GetDirection(void);
        GetMin(void);
        GetMax(void);
        GetDefault(void);
        ...
 }

 host internals:
 --------

 main loop {
        ...
        Find and load a plugin
        InspectGroup(plugin, GMPI_GROUP_ROOT);
        ...
 }

 InspectGroup(GMPI_Plugin* plugin, uint32_t group) {
        GMPI_Element element;
        int index = 0;

        while (plugin->Inspect(group, index, &element) == GMPI_SUCCESS) {
                if (element.type == GMPI_ELEM_GROUP) {
                        /* recurse into a sub-group */
                        InspectGroup(plugin, element.key);
                }

                /*
                 * we found an element - save it's object
                 */

                if (element.type == GMPI_ELEM_AUDIO) {
                        /*
                         * An audio IO
                         */
                        GMPI_Unknown* unknown;
                        GMPI_AudioIO* audio;
                        plugin->GetAudioIO(key, &unknown);
                        unknown->QueryInterface(IID_AUDIO_IO, &audio);
                        SaveAudio(plugin, audio, element);
                } else if (element.type == GMPI_ELEM_CONTROL) {
                        /*
                         * Some sort of control - but what kind?
                         */
                        GMPI_Unknown* unknown;
                        GMPI_Control* control;
                        plugin->GetControlIO(key, &unknown);
                        unknown->QueryInterface(IID_CONTROL_IO, &control);

                        switch (control->Type()) {
                        case GMPI_CONTROL_FLOAT: {
                                /*
                                 * a float control
                                 */
                                GMPI_FloatControl* floatControl;
                                control->QueryInterface(IID_FLOAT_CONTROL,
                                                &floatControl);
                                SaveControl(plugin, floatControl, element);
                                break;
                        }
                        case GMPI_CONTROL_INT: {
                                /*
                                 * an int control
                                 */
                                GMPI_IntControl* intControl;
                                control->QueryInterface(IID_INT_CONTROL,
                                                &intControl);
                                SaveControl(plugin, intControl, element);
                                break;
                        }
                        }
                }
                index++;
        }
 }


Essentially, the host walks the plugin's tree of elements, figuring out
what they are along the way, and getting handles to them.  For controls,
it can specialize down to a type-specific interface.

This results in a unique interface class for each type of control.  Each
interface has a number of small data-query methods.  Because we agreed
that *all* methods return GMPI_Result and take pointers to out parameters,
these are not quite as simple as I have illustrated.  I'd like to argue
that sometimes it is ok to just return a value.  For example, if
QueryInterface returned a void*, then catcher could implicitly convert
types instead of needing reinterpret_cast<>.

This is just one model.  It makes sense to me, but it is pretty highly
normalized.  I'm open to ideas.

> On Tue, Nov 29, 2005 at 04:28:34PM -0800, thockin@xxxxxxxxxx wrote:
> > We've got very basic plugins that can be found and loaded.
> > 
> > Now how do we find out what they do?  The host has to figure out all the
> > control inputs, control outputs, audio inputs, audio outputs, etc.  There
> > are a lot of potential models, I'd like to hear some reasons to go with
> > one or the other or something totally different.
> > 
> > Remember that we need to be able to extract a lot of data:
> >     * control ports
> >       - name
> >       - data type
> >       - range
> >       - flags
> >     * audio ports
> >       - name
> >       - format
> >       - channels
> >     * nested sub-groups of the above
> >     * channels
> >     * ..and more
> > 
> > Some ideas I've already heard:
> > 
> > 1) Host loops from 0 to n, asking the plugin for metadata about "thing x".
> > The metadata explains what each thing is.
> > 
> > 2) Host asks for structure and gets back an XML blob that represents
> > everything.
> > 
> > What else?  What makes the most sense?  What will be easy to program and
> > easy to expand?
> > 
> > Tim
> > 
> > ----------------------------------------------------------------------
> > Generalized Music Plugin Interface (GMPI) public discussion list
> > Participation in this list is contingent upon your abiding by the
> > following rules:  Please stay on topic.  You are responsible for your own
> > words.  Please respect your fellow subscribers.  Please do not
> > redistribute anyone else's words without their permission.
> > 
> > Archive: //www.freelists.org/archives/gmpi
> > Email gmpi-request@xxxxxxxxxxxxx w/ subject "unsubscribe" to unsubscribe
> > 
> 
> -- 
> Tim Hockin
> thockin@xxxxxxxxxx
> Soon anyone who's not on the World Wide Web will qualify for a government 
> subsidy for the home-pageless.
> 
> ----------------------------------------------------------------------
> Generalized Music Plugin Interface (GMPI) public discussion list
> Participation in this list is contingent upon your abiding by the
> following rules:  Please stay on topic.  You are responsible for your own
> words.  Please respect your fellow subscribers.  Please do not
> redistribute anyone else's words without their permission.
> 
> Archive: //www.freelists.org/archives/gmpi
> Email gmpi-request@xxxxxxxxxxxxx w/ subject "unsubscribe" to unsubscribe
> 

-- 
Tim Hockin
thockin@xxxxxxxxxx
Soon anyone who's not on the World Wide Web will qualify for a government 
subsidy for the home-pageless.

----------------------------------------------------------------------
Generalized Music Plugin Interface (GMPI) public discussion list
Participation in this list is contingent upon your abiding by the
following rules:  Please stay on topic.  You are responsible for your own
words.  Please respect your fellow subscribers.  Please do not
redistribute anyone else's words without their permission.

Archive: //www.freelists.org/archives/gmpi
Email gmpi-request@xxxxxxxxxxxxx w/ subject "unsubscribe" to unsubscribe

Other related posts: