[Previous] [Contents] [Next]

Caution: This version of this document is no longer maintained. For the latest documentation, see http://www.qnx.com/developers/docs.

Loading and Unloading the Plugins

Loading the Plugins

The following code takes the name of the plugin to load and a pointer to the MvPluginCtrl_t structure and then tries to open the plugin. When the plugin is opened, MvInit() is called to obtain the function pointers to command(), terminate(), and get_item().

int LoadDll( const char *name, MvPluginCtrl_t *pctrl ) 
{
  char *path;
   
  if( ( path = strdup(name) ) != NULL ) 
  {
   void *dll;
   if( ( dll = dlopen( path, RTLD_LOCAL ) ) != NULL ) 
   {
    MvInitF_t *init;
    pctrl->APIversion   = MV_API_VERSION;
    pctrl->MinorVersion = MV_MINOR_API_VERSION;
    pctrl->name         = path;
    if( ( init = dlsym( dll, "MvInit" ) ) != NULL ) 
    {
     if( init( pctrl ) == 0 ) // calling plugin init function
     { 
      // MvInit succeeded
      pctrl->dll_handle = dll;
      // Increment count of loaded plugins
      atomic_add_value( &g_plugin_count, 1 );
      return 0;
     }
     else
     {
      dprintf((1, "LoadDll(): MvInit() in \"%s\" failed\n", name ));
     }
    }
    else
    {				
     dprintf((1, "LoadDll(): MvInit not found in \"%s\" (%s)\n", name, dlerror() ));
    }
    pctrl->name = NULL;
    dlclose( dll );
   }
   else
   {
    dprintf((1, " LoadDll(): dlopen(\"%s\") failed (%s)\n", name, dlerror() ));
   }
   free( path );
  }
  else
  {
   dprintf((1, "LoadDll(): no memory\n" ));
  }
  return -1;
}		

Unloading the Plugins

To unload a plugin, you send the plugin a stop (CMD_PLUGIN_STOP) and a close command (CMD_PLUGIN_CLOSE), followed by a call to the terminate() function pointer. After this, you can safely dlclose() the plugin.

// phplay's plugin termination structure.
typedef struct {
   pthread_mutex_t mutex;  // The mutex to block on before closing the dll
   pthread_attr_t attr;
   plugin_ctrl_t *pctrl;    // plugin control structure
} plugin_terminate_t;


// workproc to invoke phplay's terminate_plugin() function
int invoke_terminate_method( void *data )
{
  plugin_ctrl_t *pc = (plugin_ctrl_t *) data;
  terminate_plugin( pc, (pc == (plugin_ctrl_t *) mplayer.pctrl) ? PLG_F_BASEINIT|PLG_F_BASECLEAN : 0 );
  return Pt_END;
}


// dlclose-thread startup function
void *dlclose_plugin( void *data )
{   
  plugin_terminate_t *pt = (plugin_terminate_t *) data;
  unsigned u;
   
  if ( NULL == data )
    return NULL;
   
  pthread_mutex_lock( &pt->mutex );
  pthread_mutex_unlock( &pt->mutex );
  pthread_mutex_destroy( &pt->mutex );
   
  // Permit the vcb (which caused this thread to be
  // created) to safely return and the plugin to
  // free the plugin control structure.
  sched_yield();
  delay( 50 );
   
  dlclose( pt->pctrl->mv.dll_handle );
   
  u = atomic_sub_value( &g_plugin_count, 1 );
   
  free( (void *) pt->pctrl->mv.name );
  free( (void *) pt->pctrl );  // NB: This frees the plugin_ctrl_t structure allocated by load_plugin()
  free( data );
   
  return NULL;
} 


//   pc    - phplay's plugin control structure (different from MvPluginCtrl_t)
//
//   flags
//         PLG_F_DEAD      - the plugin is known to be in the MV_DEAD state.
//         PLG_F_BASECLEAN - clean up the base window if the plugin still controlls it
//         PLG_F_BASEINIT  - perform more base-window and playlist reinitializations
//
void terminate_plugin( plugin_ctrl_t *pc, int flags ) 
{
  PtArg_t arg;
  plugin_terminate_t *pt = NULL;
  int ri=EINVAL, rl=EINVAL, rc=EINVAL, klozing=0;
   
  if ( NULL == pc )
    return;   

  if ( PLG_F_DEAD & flags )
  {  // The plugin is dead. Unload it.
    if ( !(PLG_F_DEAD & pc->flags) )
    {
     klozing = 1;
     pc->flags |= PLG_F_DEAD|PLG_F_TERMINATE;

     if ( pc->video_wgt )
     { // destroy the video window if necessary
       PtDestroyWidget( pc->video_wgt );
       mplayer.playback_parms.video_wgt = NULL;
       pc->video_wgt = NULL;
     }

     if ( pt = (plugin_terminate_t *) calloc( 1, sizeof( plugin_terminate_t ) ) )
       pt->pctrl = pc;

     if ( pt &&
          EOK == pthread_attr_init( &pt->attr ) &&
          EOK == pthread_attr_setdetachstate( &pt->attr, PTHREAD_CREATE_DETACHED ) &&
          EOK == (ri = pthread_mutex_init( &pt->mutex, NULL )) &&	
          EOK == (rl = pthread_mutex_lock( &pt->mutex ))
        )
       rc = pthread_create( NULL, &pt->attr, dlclose_plugin, (void *) pt ))
    }
  }

  else if ( !(PLG_F_TERMINATE & pc->flags ) )
  { // Terminate the plugin.
      
    MvCommandData_t cmdData;
    memset( &cmdData, 0x0, sizeof( MvCommandData_t ) );
      
    // Send stop command 
    mplayer.playIsSet = FALSE;
    mplayer.played = FALSE;
    cmdData.pluginCtrl           = &pc->mv;
    cmdData.cmdType              = CMD_PLUGIN_STOP;
    cmdData.which                = MVP_NONE;
    pc->mv.calls->command( &cmdData );
      
    // Send close command
    cmdData.pluginCtrl           = &pc->mv;
    cmdData.cmdType              = CMD_PLUGIN_CLOSE;
    cmdData.which                = MVP_NONE;
    pc->mv.calls->command( &cmdData );
      
    // Invoke terminate method
    pc->flags |= PLG_F_TERMINATE;
    pc->mv.calls->terminate( (MvPluginCtrl_t *) pc );
  } // end else if


  //
  // Clean up the base window if the plugin was controlling it.
  // 
  if ( pc == mplayer.pctrl && (flags & PLG_F_BASECLEAN) && !(pc->flags & PLG_F_BASECLEAN))
  {
   pc->flags |= PLG_F_BASECLEAN;
   mplayer.pctrl = NULL;
   mplayer.pluginIsLoaded = FALSE;
   mplayer.playIsSet = (mplayer.bStartupOnPlay) ? FALSE : TRUE;
      
   // change mplayer icon
   mplayer.iconImage = ApGetImageRes(mplayer.dbase,"mediaPane");
   PtSetResource( ABW_icon_pane, Pt_ARG_LABEL_IMAGE, mplayer.iconImage, 0 );
      
   // init ring buffer state info
   PtSetResource( ABW_statusBar, Pt_ARG_TEXT_STRING, "", 0 );
      
   HideClientArea( 0 );
   InitAudio( FALSE );
                  
   // unlock Advance Dialog widgets if dialog box is displayed
   if( mplayer.bAdvanceDlg )
     OnAdvanceDlg(NULL,NULL,NULL);	

   // Reinitialize if necessary
   if ( flags & PLG_F_BASEINIT )
   {
    mplayer.played = FALSE;
    ControllerDeleteAll();
    SetStopEjectButton( FALSE );
    SetPlayPauseButton( TRUE );
    // reset cursor position
    PtSetResource( ABW_curpos, Pt_ARG_GAUGE_VALUE, 0, 0 );
    // reset base Info Label
    PtSetResource( ABW_baseInfo, Pt_ARG_TEXT_STRING, "Photon Media Player", 0 );
	 
    PtSetResource( ABW_playlistEditorDlg, Pt_ARG_WINDOW_TITLE, PL_TXT_TITLE, 0 );
   }
  }
   

  // Handle the case where a dlclose thread may have been created.
  if ( klozing )
  {
   if ( EOK == rl ) // mutex was locked
     pthread_mutex_unlock( &pt->mutex ); // Wake up the dlclose thread.
      
   if ( EOK == rc ) // dlclose thread was created
     return; // The dlclose-thread will destroy the mutex and free the termination structure.
      
   // Failed to create dlclose thread.
   // Clean up as much as possible.
 
   if ( EOK == ri ) // mutex was initialized
     pthread_mutex_destroy( &pt->mutex );
      
   free( (void *) pt->pctrl->mv.name );
   free( (void *) pt->pctrl );  // NB: This frees the plugin_ctrl_t structure allocated by load_plugin()
   free( pt );
  }
}

[Previous] [Contents] [Next]