Starting Up and Connecting to the MME

The information and instructions in this chapter assume that you have installed the MME, and that you have a target system with the MME configured and running. On this target system you need, as a minimum:

For more information about starting the MME, see the chapter MME Quickstart Guide in Introduction to the MME.


Note: In everyday discussions of electronic media, the terms “file” and “track” are often used interchangeably. In this document, “file” refers to all non-media files (the MME configuration file, for instance) and to media files that are being read or otherwise manipulated for a purpose other than playing them. The term “track” refers to media files that are being played or read and otherwise accessed or manipulated for playing. For example, the MME synchronizes folders and the files inside them, but it reads the tracks from a playlist and places them in a track session.

Connecting to the MME

The MME is designed to make communications with client applications both simple to implement and efficient in its execution. To communicate and work with the MME, a client application needs only to connect to the MME and register for the types of events it requires for that connection.

The figure below illustrates the flow of activities from first connection to the MME to disconnection.


Client application-MME workflow


Client application workflow with MME from connection to disconnection

You may also want to set the preferred language for media output. For more information, see Setting the preferred playback language in the chapter Configuring Internationalization of the MME Configuration Guide.


Note:
  • For information about control contexts and how to define them, see Control Contexts in the chapter Control Contexts, Zones and Output Devices.
  • For information about detecting mediastore states at startup, see Understanding mediastore states at startup in the chapter Working with Mediastores.

The MME connection handle

Each client application connected to the MME has its own unique connection handle. The connection handle information is stored in the opaque structure mme_hdl_t. Valid connection handles are created by mme_connect(). The MME fills in all needed information to create the connection handle; all calls to MME functions require a valid connection handle.

The function mme_disconnect() releases connection handles. Function calls made with a connection handle after it has been released will cause an error.

Safety

All MME functions are thread-safe. The client application can create multiple connections, and the MME handles thread safety for all threads when each thread uses a different connection handle.

However, if you use the same connection handle for more than one thread in your client application, you must use mutexes, semaphores, or some other method to maintain thread safety.

About connections, validation and blocking

The MME allows you to set a timeout period for blocking functions. If you set a timeout period, when the timeout period expires, the function returns, unblocking the client application. To enable the MME's unblocking capabilies, you need to set the <Unblock> configuration element attribute to true. For more information, see Enabling the unblock capability in the the MME Configuration Guide, and mme_set_api_timeout() and mme_get_api_timeout_remaining() in the chapter MME API.

For information about setting the MME's behavior when making a connection (synchronous or asynchronous, and blocking or non-blocking) see mme_connect(). For blocking and validation information for specific functions, see the descriptions of the functions in the MME API Library Reference.

Making the connection

Before it can start using the MME API, your client application must:

For more information about QDB, see the QDB Developer's Guide.

The function mme_connect() requires:

For more information, see mme_connect() in the MME API Reference.

Disconnecting from the MME

When the client application has finished all the work it needs to do on an MME connection, it should disconnect from the MME and the QDB. To disconnect from the MME and the QDB, call the functions mme_disconnect() and qdb_disconnect() with the appropriate connection handles.

The sample below shows how a client application disconnects from the MME and the QDB:

// disconnect from the servers.
mme_disconnect( mme );
qdb_disconnect( qdb );

Note: Disconnecting from the MME doesn't shut down the MME. It simply disconnects the client application from the device path to which it was connected in a control context.

Shutting down the MME

To shut down the MME:

  1. Call mme_shutdown() to prepare the MME for shutdown.
  2. Call mme_disconnect() to disconnect from the MME.
  3. Kill the mme process, or shut down the system.

A call to mme_shutdown():


Note: Because the MME shuts down threads in the background, the client application may receive events from other operations after it receives MME_EVENT_SHUTDOWN and before it receives MME_EVENT_SHUTDOWN_COMPLETED.

After calling mme_shutdown(), you can:

  1. Call mme_disconnect() to disconnect the client application from the MME.
  2. Shut down the system by, for instance, turning off the power.

A call to mme_shutdown() disables the MME. The MME must be killed and restarted before a client application can use it again.

If you want to shut down the MME without turning off the system, after calling mme_shutdown() your client application needs to kill the MME process.


Note: Before calling mme_shutdown(), make sure that your client application completes necessary operations and, if necessary, informs the users that it is shutting down.

Using the MME notification interface

The MME uses events to communicate with client applications. Client applications should be designed to use these events to trigger processes, from responding to end-user input to handling errors.

In order to receive events from the MME, the client application must:

Registering for events

To receive events after connecting to the MME, a client application must use mme_register_for_events() to register for events, specifying the class or classes of events it wants to receive.

The client application must register after each connection. This feature allows the client application to register different connections for different classes of events. For example, a connection used to handle synchronizations can register for synchronization events, but ignore playback events.

Each event class has a different sigevent. When it has registered for an event class, the client application has told the MME which sigevents it wants to receive. When it has a relevant event, the MME will:

For information about , see sigevent in the Neutrino Library Reference.

The client application can then decide from the sigevent if it needs to see the associated event.

The code snippet below provides an example of how to register for events in a Photon environment. It shows the steps required to set up the client application and the MME so that the MME delivers playback events (MME_EVENT_CLASS_PLAY) to the client application. These steps are:

The client application now needs only to call mme_get_event() to retrieve playback events with their data.

#include <mme/mme.h>
#include <qdb/qdb.h>

...

// Set up the MME input handler.
if( 0 == ( pulse = PtAppCreatePulse(NULL, -1)) ) {
    perror( "PtAppCreatePulse()" );
    exit( EXIT_FAILURE );
}

if( NULL == PtAppAddInput( NULL, pulse, my_input_handler, NULL) ) {
    perror( "PtAppAddInput()" );
    exit( EXIT_FAILURE );
}

PtPulseArm(NULL, pulse, &mme_event);

// Let the mme know that we need events for this class.
if( -1 == mme_register_for_events(
    mme, MME_EVENT_CLASS_PLAY, &mme_event ) ) {
    perror( "mme_register_for_events()" );
    exit( EXIT_FAILURE );
}

The code snippet below shows how the MME's command-line tool mmecli registers for events.

// Connect to the mme for the event thread
mme_ev_hdl = mme_connect(controlcontextdevice, O_SYNC);
if (mme_ev_hdl == NULL) {
    fprintf(stderr,
        "Could not connect to %s\n", controlcontextdevice);
    exit(EXIT_FAILURE);
}

// We need a channel to receive the pulse notification on.
chid = ChannelCreate(0);

// And we need a connection to that channel for the pulse
// to be delivered on.
coid = ConnectAttach(0, 0, chid, _NTO_SIDE_CHANNEL, 0);

// fill in the event structure for a pulse
SIGEV_PULSE_INIT(&event, coid,
    SIGEV_PULSE_PRIO_INHERIT, MY_PULSE_CODE, 0);

// Setup the timer; we want first event right away.
timer_create(CLOCK_REALTIME, &event, &timer_id);
itime.it_value.tv_sec = 0;
itime.it_value.tv_nsec = 0;
itime.it_interval.tv_sec = 0;
itime.it_interval.tv_nsec = 0;
itime.it_interval.tv_sec = 0;

// Register for all events from the MME
if (mme_register_for_events(mme_ev_hdl,
        registeredclasses, &event) == -1) {
           fprintf(stderr,
           "Could not register for events of type ALL. errno = %d\n", errno);
    finish(0);
}

MME event classes

The MME event classes are bit masks. You can combine them with an OR operator to register for several events at once. The structure mme_event_classes_t defines the different MME event classes as bit masks. These classes are:

To register for playback and synchronization events call mme_register_for_events() as follows:

mme_register_for_events( hdl,
                         MME_EVENT_CLASS_PLAY | MME_EVENT_CLASS_SYNC,
                         event);

Getting events

To see the events in the MME's event queue, your client application needs to call mme_get_event(). The example below shows part of a routine used by a client application to get events from the MME:




for(;;) {

    if( -1 == mme_get_event( mme, &event ) ) {
        perror( "mme_get_event()" );
        return Pt_CONTINUE;
    }

    if( event.type == MME_EVENT_NONE ) {
        break;        // no more events, exit the loop.
    }
}

For a complete list of events delivered by the MME, see the chapters on events in the MME API Library Reference.

Unregistering for events

To stop receiving a class of events, the client application must unregister for that event class. To unregister for an event class, call mme_register_for_events() with the event_class set to the event class for which you want to stop receiving events, and the argument event set to NULL.

If the client application has registered for several or all event classes, it can unregister for any event class without affecting the registration for the other event classes. The example below shows a registration to receive all event classes, and a registration to stop receiving media copy and ripping events:



mme_register_for_events( hdl, MME_EVENT_CLASS_ALL, &event );

// Do some work here.

mme_register_for_events(hdl, MM_EVENT_CLASS_COPY, NULL);

MME and QDB slog codes

The MME and QDB slog codes have permanent values, as follows: