Blob Blame History Raw
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi  CDATA  #FIXED 'http://www.w3.org/2003/XInclude'">
]>

<section id="writing-apps">

  <para>
    This section intends to be a starting point for developers interested
    in getting started with Grilo, and as such it does not try to be
    a comprehensive tutorial covering all topics and features of Grilo,
    instead, this is intends to focus on typical use case scenarios
    and code examples to put the developer on the right track.
  </para>

  <section id="programming-with-grilo-concepts">
    <title>Basic concepts</title>

    <section id="programming-with-grilo-concepts-understanding">
      <title>Understanding Grilo</title>
      <para>
        Grilo provides a high-level API that application developers
        can use to interact with heterogeneous media providers using 
        an homogeneous language, reducing remarkably the effort required
        to integrate media content from multiple sources.
      </para>
      
      <para>
        This high-level, provider-independent API is then implemented
        for all the providers supported by Grilo by means of plugins.
        These plugins encapsulate all the provider-specific details,
        effectively hiding all the technical tidbits and particularities
        of specific media providers from application developers.
      </para>
      
      <para>
        There are two kinds of plugins in Grilo:
        <itemizedlist>
          <listitem>Media Sources, which provide access to media content
            that can be browsed or searched.</listitem>
          <listitem>Metadata Sources, which provide additional metadata
            about media content obtained through media sources.</listitem>
        </itemizedlist>
      </para>
      
      <para>
        Management of available plugins is done through the 
        <link linkend="GrlRegistry">Plugin Registry</link>.
        This object exposes API to load plugins and retrieve
        available media source and metadata source objects.
      </para>
      
      <para>
        Some plugins may require certain configuration information
        in order to work properly. Examples of configuration information
        that may be needed include API keys, service credentials,
        etc. Please check the section 
        <link linkend="programming-with-grilo-configuring-plugins">
          Configuring you plugins
        </link>
        for more details on this subject.
      </para>
      
      <para>
        You can instruct Grilo to load all available plugins via
        <link linkend="grl-registry-load-all-plugins">grl_registry_load_all_plugins()</link>.
        This will look into the default
        installation directory for the plugins and also the paths
        included via the environment variable GRL_PLUGIN_PATH.
        Please check section 
        <link linkend="running-grilo-programs-detailed">
          Running Grilo based programs
        </link>
        for more details on this subject.
      </para>
      
      <para>
        Users can also load plugins using their plugin
        identifiers. These plugin identifier strings
        can be obtained by running the tool 'grl-inspect'.
      </para>
      
      <para>
        Users have two options to gain access to the media source and
        metadata source objects loaded by the plugin registry:
      </para>
      
      <itemizedlist>
        <listitem>
          Call
          <link linkend="grl-registry-get-sources">
            grl_registry_get_sources*
          </link> or
          <link linkend="grl-registry-lookup-source">
            grl_registry_lookup_source
          </link>. These should be used
          when plugins have already been loaded.
        </listitem>
        <listitem>
          By connecting to the
          <link linkend="GrlRegistry-source-added">source-added</link>
          signal, that is emitted whenever a new media source or metadata
          source object is found.
        </listitem>
      </itemizedlist>
      
      <para>
        For more information on how to use the plugin registry, please
        check <link linkend="GrlRegistry">its API reference</link>
        or any of the code examples below.
      </para>
      
      <para>
        Media source and metadata source objects are the objects 
        application developers will be interacting with for most
        of their Grilo work. These objects provide developers
        with a well known interface (API) to interact with
        media content that is provider-independent. Typically,
        each media source object provides access to content
        delivered by one particular media provider.
      </para>
      
    </section>

    <section id="programming-with-grilo-media-sources">
      
      <title>Media Sources</title>
      
      <para>
        Media Source objects provide access to media content. Application
        developers would usually interact  with these objects issuing
        Browse, Search or Query operations on them. The purpose of
        these operations is explained below:
      </para>
      
      <itemizedlist>
        <listitem>
          <emphasis>Search.</emphasis>
          Instructs the media source to look for media matching
          specific keywords. Example: YouTube search.
        </listitem>
        <listitem>
          <emphasis>Browse:.</emphasis>
          Navigates through a hierarchy of content exposed by the
          media provider. Example: Filesystem browsing.
        </listitem>
        <listitem>
          <emphasis>Query:</emphasis>
          An advanced search mode that uses service-specific
          commands to exploit features specific to a particular
          media provider.
        </listitem>
        <listitem>
          <emphasis>Metadata</emphasis>
          Obtain (more) metadata information for a particular media resource.
        </listitem>
        <listitem>
          <emphasis>Store and Remove</emphasis>
          Push and remove content from the media provider.
        </listitem>
      </itemizedlist>
    </section>
    
    <section id="programming-with-grilo-metadata-sources">
      
      <title>Metadata Sources</title>

      <para>
        Metadata Source objects provide means to acquire additional
        metadata that was not provided by the original media source
        that delivered the media. Application developers would usually
        interact with metadata sources via Resolve or SetMetadata
        operations, which are described below:
      </para>

      <itemizedlist>
        <listitem>
          <emphasis>Resolve:</emphasis>
          Acquire additional metadata for a particular media resource.
        </listitem>
        <listitem>
          <emphasis>SetMetadata:</emphasis>
          Update metadata information available for a particular media resource.
        </listitem>
      </itemizedlist>

    </section>

    <section id="programming-with-grilo-async-apis">
      
      <title>Asynchronous APIs</title>

      <para>
        Most of the APIs exposed by Media Source and Metadata Source
        objects are asynchronous. The reason for this is that 
        these operations usually involve I/O  which
        would block the user interface if executed synchronously,
        specially for the more heavy operations like Browse or
        Search, leading to unresponsive GUIs and bad user
        experience.
      </para>

      <para>
        For this reason, most of the APIs in Grilo accept a 
        user callback and user data parameters that are used
        to hand over the result of the operation to the
        client asynchronously.
      </para>

      <para>
        In cases where asynchrony is not needed, for example
        for programs that do not have a graphical user
        interface and are designed to run in the background,
        Grilo also provides synchronous versions of some of
        the APIs, but for situations other than this, use of
        the asynchronous APIs is <emphasis>strongly</emphasis>
        encouraged.
      </para>

      <para>
        For operations that can produce multiple results,
        like Browse, Search or Query, callbacks are
        invoked once per matching result. For operations
        that are expected to produce a single result, like
        Metadata or Resolve, callbacks are invoked just
        once.
      </para>

      <para>
        In any case, clients should always expect the result
        callback to be invoked at least once after an
        asynchronous operation has been issued, even if the
        operation fails or is cancelled (in which case the 
        error parameter of the callback will be set to a
        non-NULL value).
      </para>

    </section>

    <section id="programming-with-grilo-operation-identifiers">

      <title>Operation identifiers</title>

      <para>
        Some Media Source and Metadata Source operations will return
        an operation identifier that serves various purposes:
      </para>

      <itemizedlist>
        <listitem>Identify the operation within the framework.</listitem>
        <listitem>Match asynchronously results with the issuing operations.</listitem>
        <listitem>Provide an operation identifier that can be used to cancel the operation.</listitem>
      </itemizedlist>

      <para>
        For example, issuing an asynchronous Search operation on a Media
        Source object would synchronously return an operation identifier.
        The developer can store this identifier and use it to cancel.
      </para>

      <para>
        Also, if the operation was not cancelled, the results callback
        will be invoked at least once (actually, for the case
        of a Browse operation is will be invoked once per matching
        result) handing the results of the operation to the application.
        Each time the results callback is invoked, the operation identifier
        will be provided so that the callback can identify the operation
        that triggered the result (there can be multiple operations
        ongoing simultaneously).
      </para>

    </section>

    <section id="programmaing-with-grilo-media-objects">

      <title>Media objects</title>

      <para>
        As discussed before, Media Source objects provide means
        to access  media content exposed by  media providers through
        operations like Search, Browse or Query. Media content is
        represented in Grilo via
        <link linkend="GrlMedia">GrlMedia</link>
        objects that contain metadata information related with
        a particular media resource.
      </para>

      <para>
        There are various subclasses of GrlMedia, which provide
        specific APIs to get and set metadata associated with
        specific media types, like video, audio or image
        resources.
      </para>

      <para>
        Typically, these GrlMedia objects will be obtained by
        issuing Search, Browse or Query operations on Media
        Source objects, which produce these objects
        as results. Upon reception, clients would
        usually use the API exposed by these objects to
        collect the information of interest.
      </para>
      
      <para>
        Grilo also supports the concept of media container, represented by a
        container-type GrlMedia class. These objects represent categories or
        folders that contain other media objects (including maybe more container
        objects), allowing tree-like hierarchies of content, like the ones would
        usually traverse during Browse operations.
      </para>

      <para>
        Please, check the <link linkend="GrlMedia">GrlMedia</link>
        API reference for more information on this subject.
      </para>

    </section>

    <section>

      <title>Metadata keys</title>

      <para>
        Metadata keys identify pieces of information (metadata).
        They are often an input parameter for many operations
        in Grilo, with the purpose of specifying what pieces of
        information are relevant for a particular operations.
      </para>

      <para>
        Grilo has a list of predefined supported keys. For each
        of these keys, Grilo provides definitions
        (identifiers) that clients can use to refer to
        specific pieces of information. Some
        examples are GRL_METADATA_KEY_TITLE or
        GRL_METADATA_KEY_ARTIST.
      </para>

      <para>
        For a complete list of all System Keys, please check
        <link linkend="grilo-grl-metadata-key">grl-metadata-key.h</link>.
      </para>

      <para>
        Some plugins can also introduce additional metadata
        keys known as User Keys. The difference with the System
        Keys is that these do not have definitions available, and
        hence clients must query the plugin registry to know
        their identifiers first using
        <link linkend="grl-registry-lookup-metadata-key">
          grl_registry_lookup_metadata_key
        </link>.
      </para>

    </section>
  </section>

  <section id="programming-with-grilo-use-cases-explained">

    <title>Typical use cases explained</title>

    <para>
      The following sections will guide the reader through some
      of the typical use cases of Grilo, using code examples
      to make the ideas even more clear.
    </para>

    <section id="programming-with-grilo-configuring-plugins">

      <title>Configuring your plugins</title>

      <para>For some plugins to work properly, it is required that the user (or
        application developer) provides certain configuration. For example,
        some plugins may require a username and a password, others may
        require an API token to gain access to the underlying media provider.
      </para>
      <para>
        These configuration options could be mandatory (without them
        the plugin cannot operate and will fail to load), or
        optional, in which case they are intended to allow users to tweak
        certain aspects of how a particular plugin should work.
      </para>
      <para>
        An example of a mandatory configuration is in the Youtube plugin: in order
        for it to work a valid API key must be provided. It is the responsibility
        of the user (or the application developer) to get that key (usually
        registering in Youtube and applying for an application key) and provide
        it to the plugin.
      </para>
      <para>
        In order to know what configuration options are available for a certain
        plugin, users/developers must check the plugin documentation.
      </para>
      <para>
        Here is a small program illustrating how to configure a plugin form your
        application:
      </para>
      <programlisting role="C">
        <xi:include  href="configuring-plugins.c"
                     parse="text"
                     xmlns:xi="http://www.w3.org/2001/XInclude"/>
      </programlisting>

      <para>
        For more information on how to configure plugins
        please check the
        <link linkend="GrlConfig">GrlConfig</link>
        API reference.
      </para>
    </section>

    <section id="programming-with-grilo-browsing">

      <title>Browsing media content</title>

      <para>Here is a small program illustrating how you can browse
        content from a particular media source (a similar approach
        can be used for searching content instead of browsing):</para>
      <programlisting role="C">
        <xi:include  href="browsing.c"
                     parse="text"
                     xmlns:xi="http://www.w3.org/2001/XInclude"/>
      </programlisting>

      <para>
        Please notice:
        <itemizedlist>
          <listitem>
            Finalization of the Browse operation is always
            indicated by setting the 'remaining' parameter to 0.
          </listitem>
          <listitem>
            The user callback used to receive the results is
            guaranteed to be invoked at least once (with remaining
            set to 0), even if the operation fails or is cancelled
            (in these cases the error parameter will be set to a
            non-NULL value).
          </listitem>
          <listitem>
            Received GrlMedia objects are owned by the application
            and must be freed when no longer needed.
          </listitem>
          <listitem>
            If an error occurs, the GError parameter is set in the
            callback, but this error parameter is owned by Grilo
            and will be freed immediately after the callback.
            If you want to keep the error beyond the scope of
            the callback you must add a reference to it in the
            callback code.
          </listitem>
          <listitem>
            When the media source cannot estimate the number
            of remaining items, remaining is set to 
            GRL_SOURCE_REMAINING_UNKNOWN.
          </listitem>
        </itemizedlist>
      </para>

      <para>
        For more information on how to operate media sources
        please check the
        <link linkend="GrlMediaSource">GrlMediaSource</link>
        API reference.
      </para>
    </section>

    <section id="programming-with-grilo-searching">

      <title>Searching media content</title>

      <para>Here is a small program illustrating how you can search
        content by text from a particular media source (Jamendo
        in this example):</para>
      <programlisting role="C">
        <xi:include  href="searching.c"
                     parse="text"
                     xmlns:xi="http://www.w3.org/2001/XInclude"/>
      </programlisting>

      <para>
        Please notice that all the considerations remarked for the
        Browse operations above  apply also to Search operations.
      </para>

      <para>
        For more information on how to operate media sources
        please check the
        <link linkend="GrlMediaSource">GrlMediaSource</link>
        API reference.
      </para>
    </section>

    <section id="programming-with-grilo-multivalued-data">

      <title>Handling multi-valued metadata</title>

      <para>When working with multimedia content, it can happen that certain
        attributes of a particular media resource are multi-valued. For example,
        a particular video resource may have multiple URIs associated, considering
        different resolutions, streaming protocols and/or formats.
      </para>
      <para>
        Grilo provides plugin and application developers with means
        to handle multi-valued properties.
      </para>
      <para>
        One issue concerning multi-valued properties are their relations with
        other properties. Following the example of the video resource with
        multiple URIs, each of these URIs should have its own mime-type associated,
        as well as its own width and height values. When dealing with multi-valued
        properties it is necessary to make this relations among keys more explicit.
      </para>
      <para>
        Grilo provides application and plugin developers with a high-level APIs to
        handle certain relations among keys consistently. Continuing with the example
        of the video resource with multiple URIs, there is
        <link linkend="grl-media-add-url-data">
          grl_media_add_url_data
        </link> and
        <link linkend="grl-media-add-url-data-nth">
          grl_media_get_url_data_nth
        </link> to add and retrieve all the metadata
        associated with a particular instance of the video resource (URI, mime-type,
        framerate, width and height, etc) in one go.
      </para>
      <para>
        Grilo allows plugin developers to define their own metadata keys.
        In this case, the plugin developer must also provide information
        on the relations that these keys hold with others. In this scenario
        plugin developers must use GrlRelatedKeys objects to group related keys
        together.
      </para>
      <para>
        Here is a small program illustrating how get all available URLs from
        a video resource, as well the corresponding MIME value for each one.
        We use GrlRelatedKeys instead of the high-level API from GrlMedia
        to illustrate how to use it:
      </para>
      <programlisting role="C">
        <xi:include  href="multivalues.c"
                     parse="text"
                     xmlns:xi="http://www.w3.org/2001/XInclude"/>
      </programlisting>

      <para>
        For more information on how to operate with media objects
        please check the
        <link linkend="GrlData">GrlData</link> hierarchy
        API reference.
      </para>
    </section>

    <section id="programming-with-grilo-efficient-metadata-resolution">

      <title>Efficient metadata resolution</title>

      <para>When executing operations that return lists of media items (like
        Browse or Search) it is convenient to ensure that we do not
        request metadata that could slow down the operation unless it
        is really necessary.
      </para>
      <para>
        A clear example of this situation is the way Youtube video
        URLs are resolved: a browse operation on Youtube can usually
        be resolved in a single HTTP query, however, if one wants to
        obtain the URLs of the videos then for each video in the result
        set another HTTP request is needed. This would slow down
        the browse operation remarkably and would spam Youtube
        with requests to obtain URLs that may not be ever needed.
        Indeed, a normal player would browse a list of videos and show
        information useful for the user to select the one he/she is
        interested in (title, duration, artist, etc), the URL is not
        interesting at this stage, it is only interesting when the user
        selected a video to play, and we would be interested only
        in that single URL and not in all the URLs of the videos
        we are displaying.
      </para>
      <para>
        Grilo provides methods to application developers to query
        the keys (if any) that may have an impact on the performance
        for a particular source (like the URL in the case of Youtube),
        but it is usually easier to just use the GRL_RESOLVE_FAST_ONLY
        flag when issuing Search, Browse or Query operations.
      </para>
      <para>
        By using this flag, Grilo will resolve only the keys
        that do not have an impact on performance. If you browse
        Youtube with this flag Grilo won't request the URL key
        to the Youtube source. However, if the source could resolve
        the URL without performance penalties, it would do so
        normally.
      </para>
      <para>
        Usually, for operations like Browse or Search that operate
        with large result sets it is recommended to use
        GRL_RESOLVE_FAST_ONLY. If you really need to get the metadata
        you requested for a specific item (for example if you want to
        play a video from Youtube you really need the URL), then
        you can safely use the Metadata operation without the
        GRL_RESOLVE_FAST_ONLY flag, which would only operate on this
        particular item, reducing the performance penalty and providing
        a more efficient solution.
      </para>
      <para>
        The program below demonstrates how this works, it accepts as
        argument the id of the source we want to operate with, when the
        source is registered it will issue a search operation requesting
        only fast keys. When the search callback is invoked we will print
        both the title information and the URL of the first media
        that matched the search text.
      </para>
      <para>
        If we run the program using grl-jamendo as target source, we will
        see that it retrieves both the title and the URL of the media
        immediately, however, if we use grl-youtube, it won't and in order
        to obtain the URL we issue a new Metadata operation, this time
        without the GRL_RESOLVE_FAST_ONLY flag.
      </para>
      <para>
        Of course this is a very simple example, in a real application the way
        this would work is that we would request the URL in a
        Browse/Search that could return hundreds of results
        and we may or may not get the URLs depending on the source
        we are operating with, but in any case we will ensure the operation
        will run as fast as possible: the user will see the results
        of the search fast. Then, when the user selects
        a media item to be played from that result set we would check if
        we have the URL already (and we will have the URL ready if the source
        could resolve it fast) in which case we can play the media right away (no
        time penalty at all from the user point of view). If the URL could not
        be resolved because it was slow for the source (like in the case of Youtube)
        then we just have to issue a Metadata operation requesting the URL,
        but that won't be too bad because we are requesting it only
        for the item that the user selected, so from the user's perspective
        the playback will take slightly more to start but would still
        be an acceptable delay.
      </para>
      <programlisting role="C">
        <xi:include  href="efficient-metadata-resolution.c"
                     parse="text"
                     xmlns:xi="http://www.w3.org/2001/XInclude"/>
      </programlisting>
    </section>

  </section>
</section>