This version of this document is no longer maintained. For the latest documentation, see http://www.qnx.com/developers/docs. |
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; }