![]() |
![]() |
![]() |
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ncurses.h> #include <pthread.h> #include <dlfcn.h> #include <photon/Mv.h> #include <sys/asoundlib.h> #include <sys/ioctl.h> #include <errno.h> typedef struct Item { char* url; char* title; int selectionIndex; } Item_t; typedef struct Playlist { Item_t *items; // array of play items unsigned short itemCount; // number of items in the playlist unsigned short selectionCount; // number of selected items in the playlist unsigned short activeItem; // active playing track } Playlist_t; typedef struct tag { pthread_mutex_t mutex; pthread_cond_t cond; int wakeUp; pthread_t userInputThread_id; Playlist_t playlist; MvPluginState_t lastState; enum MvMediaFlags mediaType; // AUDIO,VIDEO,SEEKABLE,SPEEDABLE,REMOVABLE,PLAYLIST,MULTITRACT MvTime_t duration; int endOfStream; char *userInput; } player_t; player_t player; int OpenUrl( MvPluginCtrl_t *pctrl, int index ) { if( index >= 0 && index < player.playlist.itemCount ) { // open the url MvCommandData_t cmdData = {0}; MvPlaybackParams_t playback_parms = {0}; cmdData.pluginCtrl = pctrl; cmdData.cmdType = CMD_PLUGIN_OPEN_URLS; cmdData.which = MVP_DELTA; cmdData.urls = (char**)& player.playlist.items[index].url; cmdData.nodeString = getenv("HOSTNAME"); cmdData.displayString = getenv("PHOTON"); cmdData.param = &playback_parms; playback_parms.delta = 1; pctrl->calls->command( &cmdData ); player.playlist.activeItem = index; fprintf(stderr,"Playing %s\n",player.playlist.items[index].title); return TRUE; } return FALSE; } int GetPluginList( MvPluginCtrl_t *pctrl ) { MvMediaInfo_t const *item = NULL; int index = 0; int count = player.playlist.itemCount; Item_t *mem = malloc( count * sizeof( Item_t ) ); if( pctrl && mem ) { player.playlist.items = mem; fprintf(stderr,"PLUGIN PLAYLIST:\n"); for( index = 0; index < count; index++ ) { item = pctrl->calls->get_item( pctrl, MV_MEDIA_INFO, index ); if( item ) { // make sure this plugin item is a url and not general playlist info if( (item->type & MV_MEDIA_PLAYLIST) == 0 ) { player.playlist.items[index].url = strdup( item->url ); player.playlist.items[index].title = strdup( item->title ); player.playlist.items[index].selectionIndex = ++player.playlist.selectionCount; fprintf(stderr,"%2d URL = %20s TITLE = %s\n",index + 1,item->url,item->title); } } } return TRUE; } return FALSE; } void DeletePluginList() { int index; for( index = 0; index < player.playlist.itemCount; index++ ) { free( player.playlist.items[index].url ); free( player.playlist.items[index].title ); } free( player.playlist.items ); player.playlist.items = NULL; player.playlist.itemCount = 0; player.playlist.selectionCount = 0; player.playlist.activeItem = 0; } 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; printf( "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); } pctrl->setup.audio.mixerDevice = 1; // using CD_IN audiocard input if( init( pctrl ) == 0 ) // calling plugin init function { printf( "MvInit() succeeded\n" ); pctrl->dll_handle = dll; return 0; } else { 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]; //while( (c = getchar()) != EOF ) while( fgets( buffer, 4, stdin ) != NULL ) { 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 = 0; pthread_mutex_lock( &player.mutex ); if( change & MVS_PLUGIN_STATE ) { player.lastState = status->state; switch( status->state ) { case MV_DEAD: fprintf(stderr,"mpcallback() STATE = MV_DEAD\n"); player.endOfStream = TRUE; break; case MV_CLOSED: fprintf(stderr,"mpcallback() STATE = MV_CLOSED\n"); player.endOfStream = TRUE; break; case MV_OPENING: fprintf(stderr,"mpcallback() STATE = MV_OPENING\n"); break; case MV_STOPPED: fprintf(stderr,"mpcallback() STATE = MV_STOPPED\n"); if( hasPlayed && player.playlist.activeItem == player.playlist.itemCount ) { // end of playlist detected // issue a stop command to the audiocd plugin MvCommandData_t cmdData = {0}; cmdData.pluginCtrl = pctrl; cmdData.cmdType = CMD_PLUGIN_START; cmdData.which = MVP_NONE; pctrl->calls->command( &cmdData ); } hasPlayed = FALSE; break; case MV_PAUSED: fprintf(stderr,"mpcallback() STATE = MV_PAUSED\n"); break; case MV_PREFETCHING: fprintf(stderr,"mpcallback() STATE = MV_PREFETCHING\n"); break; case MV_PLAYING: fprintf(stderr,"mpcallback() STATE = MV_PLAYING\n"); hasPlayed = TRUE; break; default: break; } } if( change & MVS_MEDIA ) // media_info is valid and points to new media { if( player.lastState >= MV_STOPPED ) { // last state was MV_STOPPED or MV_PAUSED or MV_PREFETCHING or MV_PLAYING const char* title = status->media_info->title; player.mediaType = status->media_info->type; player.duration = status->media_info->duration; if( status->media_info->type & MV_MEDIA_PLAYLIST ) { // the plugin new media info is a playlist player.playlist.itemCount = status->media_info->plcount; GetPluginList( pctrl ); OpenUrl( pctrl, 0 ); } } else { // last state was MV_DEAD or MV_CLOSED or MV_OPENING } } if( change & MVS_ERRORMSG ) { fprintf(stderr,"%s\n", status->errormsg); player.endOfStream = TRUE; } if( change & MVS_POSITION ) { // position is valid //fprintf(stderr,"position = %d\n",status->position); } 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; } int ChangeTrack( MvPluginCtrl_t *pctrl, int delta ) { int track = delta - 1; // first track start at zero in playlist if( track >= 0 && track < player.playlist.itemCount ) { MvCommandData_t cmdData = {0}; MvPlaybackParams_t playback_parms = {0}; player.playlist.activeItem = track; if( pctrl && player.mediaType & MV_MEDIA_MULTITRACK ) { cmdData.pluginCtrl = pctrl; cmdData.cmdType = CMD_PLUGIN_SEEK_RELATIVE; cmdData.which = MVP_SEEK_UNIT | MVP_DELTA; cmdData.param = &playback_parms; playback_parms.seekUnit = MVS_TRACK; playback_parms.delta = track; pctrl->calls->command( &cmdData ); } else { // close plugin cmdData.cmdType = CMD_PLUGIN_CLOSE; cmdData.which = MVP_NONE; pctrl->calls->command( &cmdData ); // open the url cmdData.pluginCtrl = pctrl; cmdData.cmdType = CMD_PLUGIN_OPEN_URLS; cmdData.which = MVP_DELTA; cmdData.urls = (char**)&player.playlist.items[track].url; cmdData.nodeString = getenv("HOSTNAME"); cmdData.displayString = getenv("PHOTON"); cmdData.param = &playback_parms; playback_parms.delta = 1; pctrl->calls->command( &cmdData ); } // restart the plugin cmdData.cmdType = CMD_PLUGIN_START; cmdData.which = MVP_NONE; pctrl->calls->command( &cmdData ); fprintf(stderr,"Playing %s\n",player.playlist.items[track].title); return TRUE; } else { fprintf(stderr,"Unable to go to track %d ( range = 1 to %d )\n", track + 1, player.playlist.itemCount ); } return FALSE; } // This function is called from the 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 ) { 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 cmdData.cmdType = CMD_PLUGIN_CLOSE; cmdData.which = MVP_NONE; pctrl->calls->command( &cmdData ); 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; case 'b': case 'B': // go back command ChangeTrack( pctrl, player.playlist.activeItem ); break; case 'n': case 'N': // go next command ChangeTrack( pctrl, player.playlist.activeItem + 2 ); break; default: if( isdigit( input[0] ) ) { int track; input[1] = ( isdigit(input[1]) ) ? input[1]: 0; input[2] = 0; track = atoi( input ); ChangeTrack( pctrl, track ); } break; } } int main( int argc, char *argv[] ) { MvPluginCtrl_t *pctrl; char* file; pthread_cond_init( &player.cond, NULL); pthread_mutex_init( &player.mutex, NULL ); if(argc < 2) { printf("Usage: playAudioCd /fs/cdXX\n"); exit(1); } else { file = argv[argc -1]; fprintf(stderr,"file = %s\n",file); if( !strstr( file, "file://" )) { // append "file://" to string file = alloca( strlen( file) + 8 ); sprintf( file,"%s%s","file://",argv[argc -1] ); } } pctrl = load_plugin( "audiocd_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 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 ) { player.wakeUp = 0; SendCommand( pctrl, player.userInput ); player.userInput = 0; } pthread_mutex_unlock( &player.mutex ); } dlclose( pctrl->dll_handle ); pthread_mutex_destroy( &player.mutex ); pthread_cond_destroy( &player.cond ); DeletePluginList(); return 0; }
![]() |
![]() |
![]() |