playback_window.cc
上传用户:psq1974
上传日期:2007-01-06
资源大小:1195k
文件大小:15k
- /* Copyright (C) 1998, 1999 State University of New York at Stony Brook
- Author: Andrew V. Shuvalov ( andrew@ecsl.cs.sunysb.edu )
- Software license is located in file "COPYING"
- */
- #include <gtk--.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <arpa/inet.h>
- #include "session.h"
- #include "playback_window.h"
- #include "play_commands.h"
- #include "../../pusher/src/timeval.h"
- PlaybackWindow::PlaybackWindow( const char *argv0, Session &ses )
- : session( ses ),
- playerState( STATE_STOPPED ), playerStateMustBe( STATE_STOPPED ),
- currentMovieId( -1 ), playerIsReady( FALSE ), operatingMode( playback ),
- sih_handler_id( 0 ), command_requested_status( nothing ),
- cleanup_flag( false )
- {
- // -1 means that player does not exists
- Player.pid = -1;
- init_player( argv0 );
- // create output socket ( to the push server, should be UDP
- serverSocketOut = socket( PF_INET, SOCK_DGRAM, 0 );
- if( -1 == serverSocketOut )
- throw PlayerException( __LINE__, "create socket: %s", sys_errlist[errno] );
- }
- void PlaybackWindow::prepare_to_die()
- {
- cleanup_flag = true;
- stop();
- wait_player_msg_sec( 1 );
- if( sih_handler_id )
- g2a_send_int( &Player, COM_SIH_FREE, 0, sih_handler_id );
- wait_player_msg_sec( 1 );
- sih_handler_id = 0;
- }
- PlaybackWindow::~PlaybackWindow()
- {
- cerr << "PlaybackWindow destructor" << endl;
- cleanup_flag = true;
- if (Player.pid > 0)
- {
- try
- {
- // first: stop the player
- // g2a_send_int( &Player, COM_STATE, 0, STATE_STOPPED );
- // wait_player_msg_sec( 2 );
- if( sih_handler_id )
- g2a_send_int( &Player, COM_SIH_FREE, 0, sih_handler_id );
- g2a_send_void( &Player, COM_QUIT, 0 );
- // we should wait while player emits A2G_COM_QUIT message...
- for( int i = 0; i < 5 && Player.pid != -1; i++ )
- wait_player_msg_sec( 1 );
-
- g2a_cleanup(&Player);
- // kill it...
- cout << "Player pid " << Player.pid << endl;
- if (Player.pid > 0)
- {
- signal(SIGCHLD, SIG_IGN);
- kill(Player.pid, SIGKILL );
- }
- FILE *_pipe = popen( "ps a|grep mtvp", "r" );
- if( _pipe )
- {
- char buf[200];
- while( true )
- {
- if( NULL == fgets( buf, sizeof( buf ), _pipe ))
- break;
- int pid = atoi( buf );
- string s( buf );
- // should not contains "grep"
- if( s.find( "grep" ) == s.npos )
- kill( pid, SIGKILL );
- }
- fclose( _pipe );
- }
- else
- perror( "popen" );
- } catch ( PlayerException e ) {
- cout << "Exeption: " << e.getText() << endl;
- }
- }
- }
- void PlaybackWindow::init_player( const char *argv0 )
- {
- // name, up to 5 arguments and NULL
- const char *mtvp_argv[7];
- mtvp_argv[0] = session.mtvPlayerName.c_str();
- mtvp_argv[1] = NULL;
- string arguments;
- arguments = session.mtvPlayerArguments.str();
- if( arguments.length() > 0 )
- {
- // some arguments exists, up to 5 possible
- // split to different strings
- int pos = 0;
- const string spaces = " tn";
- for( int i = 1; i < 6; i++ )
- {
- pos = arguments.find_first_not_of( spaces, pos );
- if( pos == arguments.npos )
- break;
- mtvp_argv[i] = arguments.c_str() + pos;
- mtvp_argv[ i+1 ] = NULL;
- // pos points to first character of argument
- int pos_end = arguments.find_first_of( spaces, pos );
- if( pos_end == arguments.npos )
- break;
- // put zero at the end of argument
- *(char*)(arguments.c_str() + pos_end) = 0;
- pos = pos_end + 1;
- }
- }
- if( -1 == g2a_init(&Player, mtvp_argv, argv0 ))
- throw PlayerException( __LINE__, "init: %s", sys_errlist[errno]);
- // clean-up messages stream
- for( int i = 0; i < 10 && playerIsReady == false; i++ )
- wait_player_msg_sec( 2 );
- if( playerIsReady == false )
- throw PlayerException( __LINE__, "Can't get player ready" );
- // add SIH plugin
- session.put_message( 2, "add SIH plugin %s", session.sihPlugin.c_str() );
- g2a_send_string( &Player, COM_SIH_LINK, PMP_FLAG_RETURN_STATUS,
- session.sihPlugin.c_str() );
- // tell which command ask for status:
- command_requested_status = plugin_link;
- // clean-up messages stream
- wait_player_msg_sec( 2 );
- // Next step is skipped:
- // we don't need to open plb and brcst sockets immediately
- g2a_send_int( &Player, COM_AUTO_EXIT, 0, false );
- g2a_send_int( &Player, COM_AUTO_PLAY, 0, false );
- g2a_send_int( &Player, COM_STATE, 0, STATE_STOPPED );
- playerStateMustBe = STATE_STOPPED;
- wait_player_msg_sec( 2 );
- operatingMode = playback;
- }
- void PlaybackWindow::playback_mode( const MovieFilesT &movieFiles,
- struct tm t, int movid )
- {
- if( movieFiles.size() == 0 )
- return; // nothing to do
- // if plays something at that time - stop it,,
- for( int i = 0; playerState != STATE_STOPPED && i < 5; i++ )
- stop();
- session.put_message( 3, (string)"playback mode" );
- // fetch push server addr from the list:
- string pushserv_addr = movieFiles[0].ipaddress;
- // that's control address to send various commands
- pushServControlAddr.construct( movieFiles[0].ipaddress,
- movieFiles[0].control_port );
- // construct URL
- string url = plugin_url_prefix;
- // server name
- if( pushserv_addr.length() > 0 )
- {
- url += pushserv_addr.c_str();
- url.c_str();
- // looks like a bug: string cannot attach just char*
- url += ":";
- }
- // port number
- {
- char tmp_buf[10];
- snprintf( tmp_buf, sizeof( tmp_buf ), "%d",
- (int)session.inputPushSock );
- url += tmp_buf;
- }
- check_player_msgs();
- g2a_send_string( &Player, COM_OPEN_STREAM_URL, 0, url.c_str() );
-
- // after that we must post the "play" command and the list of files to server
- if( session.verbose > 1 )
- for( int i = 0; i < movieFiles.size(); i++ )
- session.put_message( 2, (string)"play " + movieFiles[i].filename );
- // send command to server
- string cmd = string( _play_cmd_ ) + "n";
- // next arg is local socket number to receive data
- char buf[100];
- snprintf( buf, sizeof( buf ), "%dn", (int)session.inputPushSock );
- cmd += buf;
- TIMETOSTR( buf, t );
- cmd += buf;
- cmd += "n";
- for(int i = 0; i < movieFiles.size(); i++ )
- {
- const MovieFile &mf = movieFiles[i];
- cmd += mf.filename + "n";
- TIMETOSTR( buf, mf.start );
- cmd += buf;
- cmd += "n";
- TIMETOSTR( buf, mf.stop );
- cmd += buf;
- cmd += "n";
- }
- if( -1 == sendto( serverSocketOut, (void*) cmd.c_str(),
- cmd.length(), 0, (const sockaddr *)
- &pushServControlAddr.addr,
- sizeof( pushServControlAddr.addr )))
- throw PlayerException( __LINE__, "send: %s", sys_errlist[ errno ] );
- g2a_send_int( &Player, COM_STATE, 0, STATE_PAUSED );
- // currentMovieId is assigned only here
- currentMovieId = movid;
-
- session.put_message( 1, "Play: %s", url.c_str() );
- // clean-up messages stream
- wait_player_msg_sec( 2 );
- g2a_send_int( &Player, COM_STATE, 0, STATE_PLAYING );
- // set-up modes
- operatingMode = playback;
- playerStateMustBe = STATE_PLAYING;
- }
- void PlaybackWindow::broadcast_mode( const string &url )
- {
- // if plays something at that time - stop it,,
- for( int i = 0; playerState != STATE_STOPPED && i < 5; i++ )
- stop();
- g2a_send_string( &Player, COM_OPEN_STREAM_URL, 0, url.c_str() );
- session.put_message( 1, "Play broadcast: %s", url.c_str() );
- // clean-up messages stream
- wait_player_msg_sec( 2 );
- operatingMode = broadcast;
- g2a_send_int( &Player, COM_STATE, 0, STATE_PLAYING );
- playerStateMustBe = STATE_PLAYING;
- }
- void PlaybackWindow::stop()
- {
- session.put_message( 3, (string)"playback stop" );
- // send stop to player: in fact, close the channel
- g2a_send_int( &Player, COM_STATE, 0, STATE_STOPPED );
- g2a_send_void( &Player, COM_CLOSE_STREAM, 0 );
- wait_player_msg_sec( 1 );
- // only when strem is closed, we may send the stop command to push server
- if( operatingMode == playback )
- {
- // send command to server
- string cmd = string( _stop_cmd_ ) + "n";
- if( -1 == sendto( serverSocketOut, (void*) cmd.c_str(),
- cmd.length(), 0, (const sockaddr *)
- &pushServControlAddr.addr,
- sizeof( pushServControlAddr.addr ) ))
- throw PlayerException( __LINE__, "send: %s", sys_errlist[ errno ] );
- }
- playerStateMustBe = STATE_STOPPED;
- }
- void PlaybackWindow::timeout()
- {
- check_player_msgs();
- }
- void PlaybackWindow::check_player_msgs()
- {
- while( a2g_check_msg( &Player ) )
- {
- PMP_HEADER msg; /* to hold message header from Player */
- PMP_DATA_A2G data; /* to hold message data from Player */
-
- if (a2g_read_msg(&Player, &msg, &data) == -1 )
- {
- if( cleanup_flag == false )
- throw PlayerException( __LINE__, "error reading msg from player" );
- else
- return;
- }
-
- switch ((A2G_COM)msg.type)
- {
- case A2G_COM_STATE:
- playerState = data.data_generic.data_int;
- switch( playerState )
- {
- case STATE_STOPPED:
- session.put_message( 1, "Player: stopped" );
- break;
- case STATE_PAUSED:
- session.put_message( 1, "Player: paused" );
- if( playerStateMustBe == STATE_PLAYING )
- g2a_send_int( &Player, COM_STATE, 0, STATE_PLAYING );
- break;
- case STATE_PLAYING:
- session.put_message( 1, "Player: playing" );
- break;
- default:
- session.put_message( 1, "Player: unknown player state" );
- playerState = STATE_STOPPED;
- break;
- }
- break; // state
- case A2G_COM_SIH_FEEDBACK:
- process_feedback( &data, msg.size );
- break;
- case A2G_COM_QUIT:
- g2a_cleanup(&Player);
- Player.pid = -1;
- if( cleanup_flag == false )
- throw PlayerException( __LINE__, "player quits" );
- break;
- case A2G_COM_READY:
- session.put_message( 1, "Player is ready" );
- playerIsReady = true;
- break;
- case A2G_COM_RETURN_SUCCESS:
- session.put_message( 1, "got success to previous command" );
- // who actually requested it?
- switch( command_requested_status )
- {
- case plugin_link:
- sih_handler_id = data.data_return_success.value;
- session.put_message( 1, "got sih plugin ID: %d", sih_handler_id);
- break;
- case nothing:
- break;
- }
- command_requested_status = nothing;
- if( a2g_check_msg( &Player ) )
- {
- PMP_HEADER original_msg;
- PMP_DATA_G2A original_data;
- if (a2g_read_msg(&Player, &original_msg, (PMP_DATA_A2G *)
- &original_data) == -1)
- throw PlayerException( __LINE__,
- "a2g_read_msg: error reading msg");
- char buf[PMP_PRINT_MSG_BUF_SIZE];
- session.put_message
- ( 1, "received msg: %s", pmp_print_msg
- (&original_msg, (const char *)&original_data, buf));
- }
- break;
- case A2G_COM_RETURN_FAILURE:
- session.put_message( 1, "got failure to previous command" );
- break;
- case A2G_COM_NUMBER_OF_FRAMES_PLAYED:
- session.put_message( 1, "%d frames played",
- data.data_generic.data_int );
- break;
- case A2G_COM_ERROR_IN_STREAM:
- session.put_message( 0, "found serious error in stream that "
- "triggered concealment, %d",
- data.data_generic.data_int );
- break;
-
- case A2G_COM_AUDIO_ENABLED:
- session.put_message( 1, "audio enabled" );
- break;
- case A2G_COM_AUDIO_VOLUME:
- session.put_message( 4, "got audio volume" );
- break;
- case A2G_COM_AUDIO_BALANCE:
- session.put_message( 2, "got audio balance" );
- break;
- case A2G_COM_AUDIO_PORTS_AVAILABLE:
- session.put_message( 2, "available audio output ports %d",
- data.data_generic.data_int );
- break;
- case A2G_COM_AUDIO_PORTS_SELECTED:
- session.put_message( 2, "selected audio output ports %d",
- data.data_generic.data_int );
- break;
- case A2G_COM_INPUT_FILE_SIZE:
- session.put_message( 1, "file size %d",
- data.data_generic.data_int );
- break;
- case A2G_COM_INPUT_FD:
- session.put_message( 1, "file descriptor read %d",
- data.data_generic.data_int );
- break;
- case A2G_COM_DISPLAY_READY:
- session.put_message( 2, "display ready (e.g. after seek, etc)" );
- break;
- case A2G_COM_PACK_INFOS:
- session.put_message( 2, "(PMP_DATA_PACK_INFOS) new mux bitrate"
- "in bit/sec or 0 if VBR" );
- break;
- case A2G_COM_FRAME_INFOS:
- session.put_message( 2, "frame infos for new frame displayed. "
- "This message is received only when state "
- "!= STATE_PLAYING." );
- break;
- case A2G_COM_VIDEO_DITHER_TYPE:
- session.put_message( 2, "got dither type" );
- break;
- case A2G_COM_VIDEO_DITHER_ENABLE:
- session.put_message( 2, "dither enabled" );
- break;
- case A2G_COM_AUDIO_INFOS:
- session.put_message( 2, "got new audio infos" );
- break;
- case A2G_COM_VIDEO_INFOS:
- session.put_message( 2, "got new video infos" );
- break;
- case A2G_COM_GOP_INFOS:
- session.put_message( 2, "gop infos" );
- break;
- case A2G_COM_AUDIO_PID:
- session.put_message( 2, "got audio pid" );
- break;
- case A2G_COM_AUDIO_NO_CONTROLS_SELECT:
- session.put_message( 2, "audio mixer not available" );
- break;
- case A2G_COM_CHALLENGE:
- session.put_message( 2, "authentification request" );
- break;
- case A2G_COM_X_EVENT:
- session.put_message( 2, "get X event" );
- break;
- case A2G_COM_SYSTEMS_END_CODE:
- session.put_message( 1, "found a systems-end-code" );
- break;
- case A2G_COM_STREAM_END:
- session.put_message( 1, "video decoder reached end of stream" );
- break;
- default:
- session.put_message( 1, "unknown message %d from player",
- (A2G_COM)msg.type );
- break;
- }
- }
- }
- void PlaybackWindow::process_feedback( const PMP_DATA_A2G *data, int size )
- {
- mtv_msg *msg = (mtv_msg *)( (char *)data + sizeof(SIH_HANDLER_ID) );
- int handler_id = data->data_sih_handler_id;
- switch( msg->type )
- {
- case mtv_msg::debug:
- {
- session.put_message( msg->int_param, (const char *)&msg->data );
- }
- break;
- case mtv_msg::timestamp:
- {
- // scroll the widow to reflect current text position
- session.select_text_line_by_time( currentMovieId,
- (( struct timeval * )msg->data)
- ->tv_sec );
- }
- break;
- default:
- session.put_message( 1, "received A2G_COM_SIH_FEEDBACK, "
- "SIH id %d, size = %u, type %d, data = "%s"n",
- handler_id, size, msg->type, data);
- }
- }
- void PlaybackWindow::wait_player_msg_sec( int sec )
- {
- fd_set set;
- FD_ZERO( &set );
- if( Player.receive_channel.msg_pipe[PMP_FD_READ] != -1 )
- FD_SET( Player.receive_channel.msg_pipe[PMP_FD_READ], &set );
- else
- throw PlayerException( __LINE__, "player pipe is -1" );
-
- Timeval diff( sec, 0 );
- int ret = select( FD_SETSIZE, &set, NULL, NULL, &diff.val() );
- if( ret == -1 )
- throw PlayerException( __LINE__, "select: %s", sys_errlist[ errno ] );
- if( !ret ) // timeval expires
- {
- session.put_message( 1, "time expired, no messages" );
- return;
- }
- // we got it
- check_player_msgs();
- }
- // --------------------------------------------------------------------------
- PlayerException::PlayerException( int line, const char *format, ... )
- {
- va_list ap;
- va_start( ap, format );
- init( format, ap );
- // report this problem...
- fprintf( stderr, "Throws PlayerException, line %d:", line );
- vfprintf( stderr, format, ap );
- fprintf( stderr, "n" );
- va_end( ap );
- }