[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 playsound_noph.c Example

Here's an example of how to write your own sound player application:

// playsound_noph.c - sound player application
// 
// Compile and link as follows:
// 
//      qcc -l media playsound_noph.c
// 
// 
// Usage:
// 
//      playsound_noph [-i -v] url
//
//      Options:
//            -i  interactive mode
//            -v  be verbose
//            
//      url
//           "file://..." or "http://...  (... = full path to a soundfile )
//      
//      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:
//      
//         playsound_noph -i file:///media/waves/revenge.wav
//               will play revenge.wav and wait for user input when done
//                 
//         playsound_noph http://slonet.org/~rloomis/mail6a.wav
//               will play mail6a.wav 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;
   } // end switch
  } // end if

  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 );
} //end mpcallback

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 playsound_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( "soundfile_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 )
   {
    delay(100); // give time to clean up
    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]