[Previous] [Contents] [Next]

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

Appendix: A plaympegaudio_noph.c Example

Here's an example of how to write your own mpeg audio player:

// plaympegaudio_noph.c  -- mpeg audio player application
//
//   Compile as follows:
//
//       qcc -lmedia -lasound plaympegaudio_noph.c
//
// Usage:
//
//     plaympegaudio_noph [-q -v] url
//
//     Options:
//
//         -i  interactive mode
//         -v  be verbose
//
//     url
//
//        "file://..." or "http://...  (... = full path to a mpegaudio file )
//
//     Commands available in interactive mode:
//
//          p   play/pause selection
//          s   stop selection
//          q   exit the application
//
//     Note:
//          you must press the "Enter" key after each interactive command
//
//     Usage Examples:
//
//          plaympegaudio_noph -i file:///media/mpegaudio/believe.mp2
//          will play believe.mp2 and wait for user input when done
//
//          plaympegaudio_noph http://www2.qnx.com/mp3/Slayers-Get_Along.MP3
//          will play Slayers-Get_Along.MP3 and quit when done playing


#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <curses.h>
#include <pthread.h>
#include <dlfcn.h>
#include <photon/Mv.h>
#include <photon/MvReg.h>
#include <sys/asoundlib.h>
#include <sys/ioctl.h>
#include <errno.h>


typedef struct tag
{
   pthread_mutex_t  mutex;
   pthread_cond_t   cond;
   int              wakeUp;
   pthread_t        userInputThread_id;
   MvPluginState_t  lastState;
   int              endOfStream;
   char             *userInput;
} player_t;

player_t player;

int bInteractive = FALSE;  // quit when done playing if TRUE
int bVerbose = FALSE;      // be verbose


// This function is called if we have been launched from the background.
// This will terminate the user input thread since we don't have stdin.
void SIGTTIN_Handler( int sig_number )
{
  signal( SIGTTIN, SIG_IGN );
  //attempted background tty read
   bInteractive = FALSE;
   bVerbose = FALSE;
}

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;
      if( bVerbose )
      {
       fprintf( stderr,"Loaded DLL %p '%s'\n", dll, name );
      }
      pctrl->APIversion = MV_API_VERSION;
      pctrl->name = path;
      if( ( init = dlsym( dll, "MvInit" ) ) != NULL )
      {
       if(!MvGetMpSetting( &pctrl->setup) )
       {
        MvGetMpDefaultSetting( &pctrl->setup);
       }

       if( init( pctrl ) == 0 ) // calling plugin init function
       {
        if( bVerbose )
        {
         fprintf(stderr, "MvInit() succeeded\n" );
        }
        pctrl->dll_handle = dll;
        return 0;
       }
       else if( bVerbose )
       {
        fprintf( stderr, "LoadDll(): MvInit() in \"%s\" failed\n", name );
       }
      }
      else
      {
        fprintf( stderr, "LoadDll(): MvInit not found in \"%s\" (%s)\n", name, dlerror() );
      }
      pctrl->name = NULL;
      dlclose( dll );
    }
    else
    {
      fprintf( stderr, " LoadDll(): dlopen(\"%s\") failed (%s)\n", name, dlerror() );
    }
    free( path );
  }
  else
  {
    fprintf( stderr, "LoadDll(): no memory\n" );
  }
  return -1;
}

// This thread gets user input from the keyboard
// and wakes up main().
static void* UserInputThread( void *arg )
{
  char buffer[4];
  pthread_detach( pthread_self() );
  //while( (c = getchar()) != EOF )
  while( bInteractive && fgets( buffer, 4, stdin ) != NULL )
  {
   if( bVerbose )
   {
    fprintf(stderr,"In %s UserInputThread() You pressed %s\n",__FILE__,buffer);
   }
   pthread_mutex_lock( &player.mutex );
   player.userInput = buffer;
   player.wakeUp = TRUE;
   //wake up main thread
   pthread_cond_signal( &player.cond );
   pthread_mutex_unlock( &player.mutex );
  }
  //fprintf(stderr,"In %s UserInputThread() returning\n",__FILE__);
  return arg;
}

// This function is called when the plugin has info
// to send back to the application.
// This function is executing from within the dll thread.
static void mpcallback( MvPluginCtrl_t *pctrl, MvEventFlags_t change, MvPluginStatus_t const *status )
{
  static int hasPlayed = FALSE;
  pthread_mutex_lock( &player.mutex );
  if( change & MVS_PLUGIN_STATE )
  {
   player.lastState = status->state;
   switch( status->state )
   {
    case MV_DEAD:
    if( bVerbose )
    {
     fprintf(stderr,"mpcallback() STATE = MV_DEAD\n");
    }
    player.endOfStream = TRUE;
    break;

    case MV_CLOSED:
    if( bVerbose )
    {
     fprintf(stderr,"mpcallback() STATE = MV_CLOSED\n");
    }
    player.endOfStream = TRUE;
    break;

    case MV_OPENING:
    if( bVerbose )
    {
     fprintf(stderr,"mpcallback() STATE = MV_OPENING\n");
    }
    break;

    case MV_STOPPED:
    if( bVerbose )
    {
     fprintf(stderr,"mpcallback() STATE = MV_STOPPED\n");
    }
    if( !bInteractive && hasPlayed )
    {
     pctrl->calls->terminate( pctrl );
     break;
    }
    else if( hasPlayed )
    {
     // rewind to the beginning of the file
     MvCommandData_t cmdData           = {0};
     MvPlaybackParams_t playback_parms = {0};
     cmdData.pluginCtrl                = pctrl;
     cmdData.cmdType                   = CMD_PLUGIN_SEEK_TO;
     cmdData.which                     = MVP_DELTA | MVP_POSITION;
     cmdData.param                     = &playback_parms;
     playback_parms.delta              = 0;
     playback_parms.position           = 0;
     pctrl->calls->command( &cmdData );
    }
    hasPlayed = FALSE;
    break;

    case MV_PAUSED:
    if( bVerbose )
    {
     fprintf(stderr,"mpcallback() STATE = MV_PAUSED\n");
    }
    break;

    case MV_PREFETCHING:
    if( bVerbose )
    {
     fprintf(stderr,"mpcallback() STATE = MV_PREFETCHING\n");
    }
    break;

    case MV_PLAYING:
    if( bVerbose )
    {
      fprintf(stderr," mpcallback() STATE = MV_PLAYING\n");
    }
    hasPlayed = TRUE;
    break;

    default:
    break;
   }
  }

  if( change & MVS_ERRORMSG )
  {
   fprintf(stderr,"%s\n", status->errormsg);
   player.endOfStream = TRUE;
  }

  if( player.endOfStream )
  {
   // wake up main thread
   player.wakeUp = TRUE;
   pthread_cond_signal( &player.cond );
  }
  pthread_mutex_unlock( &player.mutex );
}

MvPluginCtrl_t* load_plugin( const char *name )
{
  MvPluginCtrl_t *pc;
  if( ( pc = malloc(sizeof(MvPluginCtrl_t)) ) != NULL )
  {
   memset( pc, 0, sizeof(MvPluginCtrl_t) );
   pc->prio = getprio( 0 );
   pc->cb   = mpcallback;
   if( LoadDll( name, pc ) == 0 )
   {
     // InitAudio( &audio);
   }
   else
   {
    free( pc );
    pc = NULL;
   }
  }
  return pc;
}

// This function is called from main() and
// sends the user input translated command to the plugin dll.
void SendCommand( MvPluginCtrl_t *pctrl, char *input )
{
  MvCommandData_t cmdData = {0};
  cmdData.pluginCtrl      = pctrl;

  if( !input || !pctrl )
  { return; }

  switch( input[0] )
  {
   case 'p':
   case 'P':
   // pause/play command
   if( player.lastState == MV_PAUSED ||  player.lastState == MV_STOPPED )
   {
    cmdData.cmdType = CMD_PLUGIN_START;
    cmdData.which = MVP_NONE;
    pctrl->calls->command( &cmdData );
   }
   else
   {
    cmdData.cmdType = CMD_PLUGIN_PAUSE;
    cmdData.which = MVP_NONE;
    pctrl->calls->command( &cmdData );
   }
   break;

   case 'q':
   case 'Q':
   // quit command
   pctrl->calls->terminate( pctrl );
   break;

   case 's':
   case 'S':
   // stop command
   cmdData.cmdType = CMD_PLUGIN_STOP;
   cmdData.which = MVP_NONE;
   pctrl->calls->command( &cmdData );
   break;

   default:
   break;
  }
}


int main( int argc, char *argv[] )
{

  MvPluginCtrl_t *pctrl;
  char* file;
  int c = 0;

  signal( SIGTTIN, SIGTTIN_Handler ); // set signal handler
  while( ( c = getopt( argc, argv, "iv" ) ) != -1 )
  {
   switch( c )
   {
    case 'i':
    // printf( "in getopt seeing q\n" );
    bInteractive = TRUE;
    break;

    case 'v':
    // printf( "in getopt seeing v\n" );
    bVerbose = TRUE;
    break;

    default:
    break;
   }
  }

  if( optind >= argc )
  {
   fprintf(stderr,"\nInvalid argument: type 'use plaympegaudio_noph' for usage options\n");
   exit(1);
  }
  else
  {
   file = argv[optind];
   if( bVerbose )
   {
    fprintf(stderr,"file = %s\n",file);
   }
   if( !strstr( file, "file://" ) && !strstr( file, "http://" ))
   {
    // append "file://" to string
    file = alloca( strlen( file) + 8 );
    sprintf( file,"%s%s","file://",argv[argc -1] );
   }
  }
  pthread_cond_init( &player.cond, NULL);
  pthread_mutex_init( &player.mutex, NULL );

  pctrl = load_plugin( "mpegaudio_noph.so");
  if( pctrl )
  {
   // success
   // send open_url command to plugin
   MvCommandData_t    cmdData        = {0};
   MvPlaybackParams_t playback_parms = {0};

   cmdData.pluginCtrl           = pctrl;
   cmdData.cmdType              = CMD_PLUGIN_OPEN_URLS;
   cmdData.which                = MVP_DELTA;
   cmdData.nodeString           = getenv("HOSTNAME");
   cmdData.displayString        = getenv("PHOTON");
   cmdData.urls                 = (char**) &file;
   cmdData.param                = &playback_parms;
   playback_parms.delta         = 1;
   pctrl->calls->command( &cmdData );

   sleep(1);
   // send start command to plugin
   cmdData.cmdType              = CMD_PLUGIN_START;
   cmdData.which                = MVP_NONE;
   pctrl->calls->command( &cmdData );
  }

  // create the user input thread
  if( bInteractive )
  {
   pthread_create( &player.userInputThread_id, NULL, UserInputThread, NULL ) ;
  }

  // main loop
  while( !player.wakeUp )
  {
   pthread_mutex_lock( &player.mutex );
   pthread_cond_wait( &player.cond, &player.mutex );
   if( player.endOfStream )
   {
     break;
   }

   if( player.userInput )
   {
    // fprintf(stderr,"In %s main You pressed %c (%d)\n",__FILE__,player.userInput,player.userInput);
    player.wakeUp = 0;
    pthread_mutex_unlock( &player.mutex );
    SendCommand( pctrl, player.userInput );
    pthread_mutex_lock( &player.mutex );
    player.userInput = 0;
   }
   pthread_mutex_unlock( &player.mutex );
  }

  dlclose( pctrl->dll_handle );
  pthread_mutex_destroy( &player.mutex );
  pthread_cond_destroy( &player.cond );
  return 0;
}

[Previous] [Contents] [Next]