00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <stdio.h>
00019 #include <stdlib.h>
00020 #include <unistd.h>
00021 #include <fcntl.h>
00022 #include <sys/types.h>
00023 #include <signal.h>
00024 #include <pthread.h>
00025 #include <errno.h>
00026 #include <iostream>
00027 #include <iomanip>
00028 #include <zlib.h>
00029 #include <limits.h>
00030
00031 using namespace std;
00032
00033 #include <qsettings.h>
00034 #include <qevent.h>
00035 #include <qapplication.h>
00036
00037 #include "RioInterfaceTypes.h"
00038 #include "RioInterface.h"
00039 #include "RioMMObject.h"
00040 #include "RioFile.h"
00041 #include "RioMMVideo.h"
00042 #include "BufferStream.h"
00043 #include "CommMulticastStream.h"
00044 #include "RioError.h"
00045 #include "RioMMTgif.h"
00046
00047 #include <netdb.h>
00048 #include <sys/socket.h>
00049
00050 #include <qtextstream.h>
00051 #include <qfile.h>
00052
00053 static unsigned int avgBlockTime = 0;
00054 static unsigned int n_blocks_played = 0;
00055 RioBlock last_played = 0;
00056
00057 #ifdef RIO_EMUL
00058 unsigned int totalBytesPlayed = 0;
00059 int requestedBlocks = 0;
00060 int completeBlocks = 0;
00061 int partialBlocks = 0;
00062 int lostBlocks = 0;
00063 #endif
00064
00065 CRioMMVideo::CRioMMVideo( char *videoname, unsigned int blocksize,
00066 RioBlock numBuffers, struct timeval average_RTT,
00067 RioMMInterface *rio, int block,
00068 ConfigData *config, RioMMExplorer *rioMMExplorer )
00069 :CRioMMObject( videoname, blocksize, numBuffers, average_RTT )
00070 {
00071 this->ReadFrom = READFROM_SERVER;
00072 this->connectPI = config->getRioMMConnectPI();
00073 this->piHost = config->getRioMMPIHost();
00074 this->useCache = config->getRioMMUseCache();
00075 this->User = config->getRioMMUser();
00076 this->rioMMExplorer = rioMMExplorer;
00077
00078 #ifdef RIO_EMUL
00079 this->logPath = config->getRioMMLogPath();
00080 #endif
00081
00082 this->riomminterface = rio;
00083 pthread_mutex_init( &log_mutex , NULL );
00084 pthread_mutex_init( &multicastMutex , NULL );
00085 pthread_mutex_init( &PlayPauseMutex , NULL );
00086 pthread_mutex_init( &PrefetchMutex , NULL );
00087 pthread_cond_init( &multicastCondition, NULL );
00088
00089 syncOn = config->getRioMMSync();
00090 Paused = false;
00091
00092 #ifndef RIO_EMUL
00093 HasSubTitle = false;
00094 subTitle = NULL;
00095 #endif
00096
00097 PlayBuffer = 0;
00098 PlayThreadID = 0;
00099 NextRequestBlock = block;
00100 target = INT_MAX;
00101 WaitingPrefetch = false;
00102 group_block = -1;
00103 req_block = 0;
00104 patching = false;
00105 my_address = 0;
00106 my_port = 0;
00107 playerPID = 0;
00108 playerCmdLine = NULL;
00109 PID = 0;
00110 first = false;
00111 wId = 0;
00112 CommMultiStream = NULL;
00113 player = "";
00114
00115
00116
00117
00118
00119
00120
00121 waitingMSGCODE_IP = false;
00122
00123 #ifdef RIO_EMUL
00124 gettimeofday( &final_block_time, 0 );
00125 gettimeofday( &timer_before , 0 );
00126 gettimeofday( &timer_after , 0 );
00127 gettimeofday( &diff_timer , 0 );
00128 gettimeofday( &initial_time , 0 );
00129 gettimeofday( &final_time , 0 );
00130 Stopped = false;
00131 makeLog = false;
00132 multicast = -1;
00133 delayed_blocks = 0;
00134 lost_blocks = 0;
00135 m_log.open( "/dev/null" );
00136 calculeted_time = 0;
00137 play_time = 0;
00138 timers = new print_log[ nBuffers ];
00139
00140
00141 cout.flags(ios::fixed);
00142 cerr.flags(ios::fixed);
00143 m_log.flags(ios::fixed);
00144 #endif
00145
00146 for( unsigned int i = 0; i < nBuffers; i++ )
00147 {
00148 Request[i].CallBackFunction = CRioMMVideo::CallBack;
00149 Request[i].User = (void *)i;
00150 Request[i].Result = S_OK;
00151 Request[i].Status = RIO_REQUEST_FREE;
00152 Request[i].reqid = 0;
00153 #ifdef RIO_EMUL
00154 timers[ i ].block = 0;
00155 gettimeofday( &timers[i].arrival_time, NULL );
00156 gettimeofday( &timers[i].call_time , NULL );
00157 #endif
00158 }
00159
00160 bufferStream = NULL;
00161
00162 for( unsigned int i = 0; i < 2; i++ )
00163 pipe_player[ i ] = 0;
00164
00165 for( int i = 0; i < MaxPipeDataSize; i++ )
00166 pipe_buffer[ i ] = ' ';
00167
00168 PTEventStack.setAutoDelete( true );
00169 PTEventStack.clear();
00170
00171
00172
00173
00174 ReadBlockStatus = true;
00175
00176 }
00177
00178
00179 CRioMMVideo::~CRioMMVideo()
00180 {
00181 #ifdef RIO_DEBUG2
00182 RioErr << "[RioMMVideo] Entrei no destrutor " << endl;
00183 #endif
00184
00185 #ifdef RIO_EMUL
00186 requestedBlocks = lostBlocks + completeBlocks;
00187 completeBlocks -= partialBlocks;
00188
00189 m_log << "Blocos requisitados: " << requestedBlocks << endl
00190 << "Blocos completamente recebidos: " << completeBlocks << endl
00191 << "Blocos parcialmente recebidos: " << partialBlocks << endl
00192 << "Blocos perdidos: " << lostBlocks << endl
00193 << "Bytes exibidos: " << totalBytesPlayed << endl;
00194 if( requestedBlocks > 0 )
00195 m_log << "Goodness: " << ( (float)totalBytesPlayed /
00196 (float)( requestedBlocks * 128 * 1024 ) ) * 100 << endl;
00197 #endif
00198
00199 if( PlayThreadID != 0 )
00200 {
00201 if( pthread_cancel( PlayThreadID ) != 0 )
00202 {
00203 #ifdef RIO_DEBUG2
00204 RioErr << "Destrutor - failed to cancel thread " << endl;
00205 #endif
00206 }
00207 else
00208 {
00209 #ifdef RIO_DEBUG2
00210 RioErr << "Destrutor - cancel thread OK " << endl;
00211 #endif
00212 }
00213 pthread_join( PlayThreadID, NULL );
00214 }
00215
00216 #ifndef RIO_EMUL
00217 if( HasSubTitle )
00218 {
00219 subTitle->Delete();
00220 HasSubTitle = false;
00221 }
00222
00223 if( subTitle != NULL )
00224 delete subTitle;
00225 #endif
00226
00227 if( bufferStream )
00228 {
00229 delete bufferStream;
00230 }
00231
00232 #ifdef RIO_EMUL
00233
00234
00235 delete[] timers;
00236
00237 m_log.close();
00238 #endif
00239
00240 inputLog( QUIT );
00241 }
00242
00243 #ifdef RIO_DEBUG2
00244 ClientMode CRioMMVideo::getMode()
00245 {
00246 ClientMode mode = INACTIVE;
00247
00248 if( connectPI )
00249 mode = CommMultiStream->getTable()->searchPidForMode( PID );
00250
00251 return mode;
00252 }
00253 #endif
00254
00255 bool CRioMMVideo::isFirst()
00256 {
00257 ClientMode status = PASSIVE;
00258
00259 if( connectPI )
00260 status = CommMultiStream->getTable()->searchPidForMode( PID );
00261
00262 return ( ( status == LEADER ) ||
00263 ( status == SUBLEADER )
00264 );
00265 }
00266
00267 bool CRioMMVideo::WaitPrefetch()
00268 {
00269 #ifdef RIO_DEBUG2
00270 RioErr << "[RioMMVideo] Entrei na WaitPrefetch " << endl;
00271 #endif
00272
00273 struct timespec timer;
00274 struct timespec timeout;
00275 int rc = 0;
00276 int nBlocks = 0;
00277 bool status = true;
00278 bool wait_again = true;
00279 unsigned int i;
00280 struct timeval now;
00281 CRioStream Stream;
00282
00283 if( riomminterface )
00284 {
00285
00286 QCustomEvent *event = new QCustomEvent( QEvent::User + 10 );
00287 QApplication::postEvent( (QObject*)riomminterface, event );
00288 }
00289
00290 RTT_average = 0;
00291
00292
00293 RTT_window = 2 * INITIAL_RTT * nBuffers;
00294
00295 gettimeofday( &now, 0 );
00296
00297 if( ( now.tv_usec + RTT_window ) > 1000000 )
00298 {
00299 timer.tv_sec = now.tv_sec + (int)( RTT_window / 1000000 );
00300 timer.tv_nsec = ( now.tv_usec + ( RTT_window % 1000000 ) ) * 1000;
00301 }
00302 else
00303 {
00304 timer.tv_sec = now.tv_sec;
00305 timer.tv_nsec = ( now.tv_usec + RTT_window ) * 1000;
00306 }
00307
00308 #ifdef RIO_DEBUG2
00309 RioErr << "WaitPrefetch - valor inicial de RTT_window: "
00310 << RTT_window << endl;
00311
00312 RioErr << "Primeiro timer calculado: " << timer.tv_sec
00313 << " sec " << timer.tv_nsec << " nanosec " << endl;
00314 #endif
00315
00316 do
00317 {
00318 WaitingPrefetch = false;
00319
00320 for( i = 0; i < nBuffers; i++ )
00321 {
00322 if( BufferStatus[i] == BUFFEREMPTY )
00323 WaitingPrefetch = true;
00324 else
00325 nBlocks++;
00326 }
00327
00328 #ifdef RIO_DEBUG2
00329 RioErr << "[WaitPrefetch] WaitingPrefetch = " << WaitingPrefetch
00330 << endl;
00331 #endif
00332
00333 if( WaitingPrefetch )
00334 {
00335 rc = 0;
00336
00337 #ifdef RIO_DEBUG2
00338 RioErr << "[WaitPrefetch] Esperando timeout ... "
00339 << timer.tv_sec - now.tv_sec << "s "
00340 << timer.tv_nsec-(now.tv_usec*1000) << "ns" << endl;
00341 #endif
00342
00343
00344
00345 rc = PlayThreadWaitCondition( &timer, "wapr1" );
00346 PlayThreadMutexUnlock( "wapr1" );
00347
00348 if( rc == ETIMEDOUT )
00349 {
00350 #ifdef RIO_DEBUG2
00351 RioErr << "[WaitPrefetch] Tempo expirou " << endl;
00352 #endif
00353
00354
00355 if( wait_again )
00356 {
00357
00358 gettimeofday( &now, 0 );
00359
00360 if( ( now.tv_usec + RTT_window ) > 1000000 )
00361 {
00362 timer.tv_sec = now.tv_sec +
00363 (int)( RTT_window/1000000 );
00364 timer.tv_nsec = ( now.tv_usec +
00365 ( RTT_window % 1000000 ) ) * 1000;
00366 }
00367 else
00368 {
00369 timer.tv_sec = now.tv_sec;
00370 timer.tv_nsec = ( now.tv_usec + RTT_window ) * 1000;
00371 }
00372
00373 #ifdef RIO_DEBUG2
00374 RioErr << "WaitPrefetch - atualizando timer: "
00375 << timer.tv_sec << " sec " << timer.tv_nsec
00376 << " nano " << endl;
00377 #endif
00378
00379 wait_again = false;
00380 }
00381 else
00382 {
00383 #ifdef RIO_DEBUG2
00384 RioErr << "RioMMVideo - Verificando se ja recebeu algum "
00385 << "fragmento " << endl;
00386 #endif
00387
00388 for( i = 0; i < nBuffers; i ++ )
00389 {
00390 if( BufferStatus[i] == BUFFEREMPTY )
00391 {
00392 rc = FreeBlock( i );
00393 if( rc != 0 )
00394 {
00395 nBlocks++;
00396
00397 #ifdef RIO_DEBUG2
00398 RioErr << "WaitPrefetch - freeblock OK. "
00399 << "Esperando timeout. Bloco "
00400 << Request[ i ].Block << " Valor "
00401 << "retornado do bloco: " << rc
00402 << endl;
00403 #endif
00404
00405 gettimeofday( &now, NULL );
00406 timeout.tv_sec = now.tv_sec + 1;
00407 timeout.tv_nsec = now.tv_usec * 1000;
00408
00409
00410
00411
00412 PlayThreadWaitCondition( &timeout,
00413 "wapr2" );
00414 PlayThreadMutexUnlock( "wapr2" );
00415
00416 if( BufferStatus[i] != BUFFEREMPTY &&
00417 useCache )
00418 {
00419 Request[ i ].Size = rc;
00420
00421 #ifdef RIO_DEBUG2
00422 RioErr << "Tamanho do bloco recuperado: "
00423 << Request[ i ].Size << ", pos "
00424 << i << endl;
00425 #endif
00426
00427 bufferStream->readBlock(
00428 Request[i].Block,
00429 (unsigned char *) Request[ i ].Buffer
00430 );
00431 }
00432 }
00433 #ifdef RIO_DEBUG2
00434 else
00435 {
00436 RioErr << "WaitPrefetch - Bloco "
00437 << Request[ i ].Block
00438 << " nao encontrado " << endl;
00439 }
00440 #endif
00441 }
00442 else
00443 {
00444 #ifdef RIO_DEBUG2
00445 RioErr << "Bloco " << Request[ i ].Block
00446 << " já chegou." << endl;
00447 #endif
00448
00449 nBlocks++;
00450 }
00451 }
00452
00453 if( nBlocks == 0 )
00454 {
00455 #ifdef RIO_DEBUG_EMUL
00456 RioErr << "Finalizando cliente por timeout " << endl;
00457 #endif
00458
00459 #ifdef RIO_EMUL
00460 m_log << "Finalizando cliente por timeout "
00461 << endl;
00462 #endif
00463
00464 status = false;
00465 }
00466
00467 #ifdef RIO_DEBUG2
00468 RioErr << "WaitingPrefetch = false " << endl;
00469 #endif
00470
00471 WaitingPrefetch = false;
00472
00473 }
00474 }
00475 #ifdef RIO_DEBUG2
00476 else if( rc != 0 )
00477 {
00478 RioErr << "Erro no pthread_cond_timedwait: "
00479 << strerror( errno ) << endl;
00480 RioErr << "Timer values: " << timer.tv_sec << ":"
00481 << timer.tv_nsec << endl;
00482 }
00483 #endif
00484 }
00485 }while( WaitingPrefetch );
00486
00487 PlayThreadMutexUnlock( "wapr3" );
00488
00489 #ifdef RIO_DEBUG2
00490 RioErr << "[RioMMVideo] Saindo da WaitPrefetch" << endl;
00491 #endif
00492
00493 if( riomminterface )
00494 {
00495
00496 QCustomEvent *event = new QCustomEvent( QEvent::User + 11 );
00497 QApplication::postEvent( (QObject*)riomminterface, event );
00498 }
00499
00500 #ifndef RIO_EMUL
00501 for( unsigned int i = 0; i < nMedias; i++ )
00502 Media[i]->WaitPrefetch();
00503 #endif
00504
00505 return( status );
00506 }
00507
00508 void CRioMMVideo::Prefetch()
00509 {
00510 unsigned int limit = NextRequestBlock + nBuffers;
00511 unsigned int index = NextRequestBlock % nBuffers;
00512
00513 #ifdef RIO_DEBUG2
00514 RioErr << "[Prefetch] Entrei na Prefetch..." << endl;
00515 #endif
00516
00517 ClearBuffer();
00518
00519 if( connectPI )
00520 {
00521
00522 if( bufferStream->exist( NextRequestBlock ) )
00523 {
00524 #ifdef RIO_DEBUG2
00525 RioErr << "Prefetch - Cliente iniciou execução mas já tem blocos "
00526 << "na cache. A PL não será notificada." << endl;
00527 #endif
00528
00529 ReadFrom = READFROM_BUFFER;
00530 }
00531 else
00532 {
00533 #ifdef RIO_DEBUG2
00534 RioErr << "Prefetch - cliente avisando acao ACTION_PLAY e sendo "
00535 << "alocado em grupo." << endl;
00536 #endif
00537
00538 MulticastMutexLock( "prefe1" );
00539 CommMultiStream->sendMoveMsg( PID, ACTION_PLAY, NextRequestBlock );
00540 MulticastWaitCondition( "prefe1" );
00541 MulticastMutexUnlock( "prefe1" );
00542
00543 ReadFrom = READFROM_SERVER;
00544 }
00545
00546 first = isFirst();
00547 }
00548
00549 while( NextRequestBlock < limit )
00550 {
00551 #ifdef RIO_DEBUG2
00552 RioErr << "[Prefetch] Request Block " << NextRequestBlock << endl;
00553 #endif
00554
00555 gettimeofday( &calculete_RTT[ index ].initial_time, 0 );
00556 calculete_RTT[ index ].block = 0;
00557 if( ReadNextBlock( index ) == false )
00558 {
00559 #ifdef RIO_DEBUG2
00560 RioErr << "[RioMMVideo Prefetch] ReadNextBlock retornou false!! "
00561 << "Chamando Stop()" << endl;
00562 #endif
00563
00564 Stop();
00565 }
00566
00567 index = NextRequestBlock % nBuffers;
00568 }
00569
00570 #ifndef RIO_EMUL
00571 for( unsigned int i = 0; i < nMedias; i++ )
00572 Media[i]->Prefetch();
00573 #endif
00574
00575 #ifdef RIO_DEBUG2
00576 RioErr << "[Prefetch] Saindo da prefetch " << endl;
00577 #endif
00578 }
00579
00580 bool CRioMMVideo::Move_Prefetch()
00581 {
00582 #ifdef RIO_DEBUG2
00583 RioErr << "[RioMMVideo] Entrei na Move_Prefetch..." << endl;
00584 #endif
00585
00586 unsigned int index = NextRequestBlock % nBuffers;
00587
00588 if( WaitingPrefetch )
00589 {
00590 #ifdef RIO_DEBUG2
00591 RioErr << "[Move_Prefetch] Cliente estava aguardando na WaitPrefetch "
00592 << "enquanto interagiu. Espera dos pedidos anteriores sendo "
00593 << "cancelada, novos pedidos sendo feitos." << endl;
00594 #endif
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 PlayThreadMutexLock( "mvprefetch" );
00605 PlayThreadReleaseCondition( "mvprefetch" );
00606 PlayThreadMutexUnlock( "mvprefetch" );
00607 WaitingPrefetch = false;
00608 }
00609
00610 ClearBuffer();
00611 PlayBuffer = index;
00612
00613 for(unsigned int i = 0; i < nBuffers; i++ )
00614 {
00615 index = NextRequestBlock % nBuffers;
00616
00617 #ifdef RIO_DEBUG2
00618 RioErr << "[RioMMVideo] Move_Prefetch... pedindo bloco "
00619 << NextRequestBlock << "(index " << index << ")" << endl;
00620 #endif
00621
00622 gettimeofday( &calculete_RTT[ index ].initial_time, 0);
00623 calculete_RTT[ index ].block = 0;
00624
00625
00626 if( ReadNextBlock( index ) == false )
00627 {
00628 #ifdef RIO_DEBUG2
00629 RioErr << "[RioMMVideo] Move_Prefetch: Erro na ReadNextBlock."
00630 << endl;
00631 #endif
00632 return( false );
00633 }
00634 }
00635
00636 #ifdef RIO_DEBUG2
00637 RioErr << "[RioMMVideo] Saindo da Move_Prefetch..." << endl;
00638 #endif
00639
00640 return( true );
00641 }
00642
00643 int CRioMMVideo::init()
00644 {
00645 if( !readSettings() )
00646 writeDefaultSettings();
00647
00648 if( useCache )
00649 this->bufferStream = new BufferStream( MMObjectName,
00650 ( unsigned int ) TotalBlocks,
00651 ( unsigned int ) BlockSize
00652 );
00653
00654 if( connectPI )
00655 {
00656 char ip[ 16 ];
00657
00658 callback_transport.block = 0;
00659 callback_transport.object = (void *)this;
00660 callback_transport.main_callback = MulticastCallBack;
00661 callback_transport.callback = MulticastCallBack;
00662
00663 CommMultiStream = new CommunicationStream( &Object, 0,
00664 (void *) &callback_transport, this->bufferStream, this );
00665
00666 struct hostent *host2ip;
00667 host2ip = gethostbyname( piHost );
00668 if( host2ip->h_addr )
00669 strcpy( ip,
00670 inet_ntoa(*(reinterpret_cast<in_addr*>(host2ip->h_addr)))
00671 );
00672
00673 AddressIP *address = new AddressIP( ip, COMMPORT );
00674
00675 #ifdef RIO_DEBUG2
00676 RioErr << "[RioMMVideo] PI HOSTNAME: " << piHost.ascii() << " "
00677 << my_address << endl;
00678 #endif
00679
00680 int sd = CommMultiStream->createSocket( address );
00681 if( sd == -1 )
00682 {
00683 RioErr << "Error creating socket " << endl;
00684 return( 1 );
00685 }
00686
00687 delete address;
00688
00689 CommunicationStreamThreadParam *p;
00690 p = new CommunicationStreamThreadParam();
00691 p->port = COMMPORT;
00692 p->stream = CommMultiStream;
00693
00694 pthread_t rThread;
00695
00696 if( pthread_create( &rThread, NULL,
00697 CommunicationStream::startReceiveThread, p ) != 0 )
00698 {
00699 delete p;
00700 RioErr << "Could not create communication thread" << endl;
00701 return( 1 );
00702 }
00703
00704 int FlagRequests = 1;
00705 int rc = 0;
00706
00707 rc = GetObject()->GetMulticastInfo( &FlagRequests, &PID );
00708
00709 if( FAILED( rc ) )
00710 {
00711 RioErr << " não conseguiu pegar informacoes multicast. " << endl;
00712 exit( 0 );
00713 }
00714
00715 #ifdef RIO_DEBUG2
00716 RioErr << "[RioMMVideo] PID: " << PID << endl;
00717 #endif
00718
00719 this->PID = PID;
00720
00721 FD_SET( sd, CommMultiStream->readfds );
00722
00723 CommMultiStream->getTable()->insert( new CommunicationItem( PID, sd ) );
00724
00725 MulticastMutexLock( "init1" );
00726 CommMultiStream->sendPIDMsg( PID );
00727 MulticastWaitCondition( "init1" );
00728 MulticastMutexUnlock( "init1" );
00729 }
00730
00731 #ifdef RIO_EMUL
00732
00733 int *blocks_size;
00734 char video_name[ 256 ];
00735 char line[ 256 ];
00736 int i = 0;
00737 FILE *block_time;
00738
00739 blocks_size = (int *)malloc( TotalBlocks * sizeof( int ) );
00740
00741
00742
00743
00744
00745
00746 if( getenv( "CACTIMESPATH" ) )
00747 {
00748 strcpy( video_name, getenv( "CACTIMESPATH" ) );
00749 strcat( video_name, MMObjectName );
00750 }
00751 else
00752 strcpy( video_name, MMObjectName );
00753
00754
00755 char *pext;
00756
00757 pext = strstr( video_name, ".mpg" );
00758 if( pext == NULL )
00759 pext = strstr( video_name, ".mpeg" );
00760
00761
00762 if( pext != NULL )
00763 *pext = 0;
00764
00765 strcat( video_name, ".cactimes" );
00766
00767 if( ( block_time = fopen( video_name, "r" ) ) == NULL )
00768 {
00769 RioErr << "Cannot open cactimes file " << video_name << endl
00770 << "Você deve setar corretamente a variável de ambiente "
00771 << "\"CACTIMESPATH\" e lembrar-se de exportá-la ou deve "
00772 << "colocar o arquivo cactimes no mesmo diretório que roda"
00773 << "o cliente riommclient." << endl;
00774 if( getenv( "CACTIMESPATH" ) )
00775 RioErr << "Valor atual de CACTIMESPATH = \""
00776 << getenv( "CACTIMESPATH" ) << "\"" << endl;
00777 else
00778 RioErr << "variavel de ambiente CACTIMESPATH nao foi definida"
00779 << endl;
00780 if ( kill( getpid(), SIGKILL ) == -1 )
00781 RioErr << "CRioMMVideo::init erro " << errno << " ("
00782 << strerror( errno ) << ") ao tentar matar o processo "
00783 << endl;
00784 else
00785 while ( 1 ) ;
00786 }
00787
00788 i = 0;
00789
00790 while( fgets( line, 99, block_time ) != NULL )
00791 {
00792 if( sscanf( line, "%d\n", &blocks_size[ i ] ) != 1 )
00793 {
00794 RioErr << "[RioMMClient]: Wrong input format." << endl;
00795 if ( kill( getpid(), SIGKILL ) == -1 )
00796 RioErr << "CRioMMVideo::init erro " << errno << " ("
00797 << strerror( errno ) << ") ao tentar matar o processo "
00798 << endl;
00799 else
00800 while ( 1 ) ;
00801 }
00802 i++;
00803 }
00804
00805
00806
00807
00808
00809
00810
00811 if( (unsigned int) i != TotalBlocks )
00812 {
00813 RioErr << "O formato do arquivo cactimes " << video_name << " esta "
00814 << "incorreto: possui " << i << " linhas e deveria ter "
00815 << TotalBlocks << " linhas." << endl;
00816 if ( kill( getpid(), SIGKILL ) == -1 )
00817 RioErr << "CRioMMVideo::init erro " << errno << " ("
00818 << strerror( errno ) << ") ao tentar matar o processo "
00819 << endl;
00820 else
00821 while ( 1 ) ;
00822 }
00823
00824 SetBlocksDuration( blocks_size );
00825 #endif
00826
00827 first = isFirst();
00828
00829 #ifdef RIO_DEBUG2
00830 RioErr << "[RioMMVideo]: Valor de first: " << first << "." << endl;
00831 #endif
00832
00833 Getmyaddr( &my_address, &my_port );
00834
00835 #ifdef RIO_EMUL
00836 QString outputLogPath;
00837 outputLogPath = logPath;
00838
00839 #ifdef RIO_DEBUG2
00840 RioErr << "[RioMMVideo - init] Arquivo de log de saída sendo criado. Nome: "
00841 << outputLogPath.ascii() << endl;
00842 #endif
00843
00844 m_log.close();
00845 sprintf( LOGARRIVAL, "%s", outputLogPath.latin1() );
00846 m_log.open( LOGARRIVAL );
00847 #endif
00848
00849 return 0;
00850 }
00851
00852
00853 int CRioMMVideo::GetSubTitles( RioAccess access, CRioStream *stream )
00854 {
00855 int rc;
00856 char subTitleFilename[ 80 ];
00857
00858 sprintf( subTitleFilename, "%s.subtitle", MMObjectName );
00859
00860 #ifdef RIO_DEBUG2
00861 RioErr << "Try to open subtitles" << subTitleFilename << endl;
00862 #endif
00863
00864 subTitle = new RioFile( subTitleFilename, BlockSize );
00865
00866 rc = subTitle->Open( access, stream );
00867 if( rc < 0 )
00868 {
00869 #ifdef RIO_DEBUG2
00870 RioErr << "Could not find subtitles" << endl;
00871 #endif
00872
00873 return rc;
00874 }
00875
00876 subTitle->Download();
00877 HasSubTitle = true;
00878
00879 #ifdef RIO_DEBUG2
00880 RioErr << "Using subtitles" << endl;
00881 #endif
00882
00883 return 0;
00884 }
00885
00886 void CRioMMVideo::PlayBlock( int buf, int size )
00887 {
00888 int sent = 0;
00889 int n;
00890 int nwrite;
00891 char *buffer = (char *)Request[ buf ].Buffer;
00892
00893 #ifdef RIO_DEBUG2
00894 RioErr << "[RioMMVideo] Entrei na PlayBlock() (size = "
00895 << size << ")" << endl;
00896 #endif
00897
00898 timer.Reset();
00899 timer.Start();
00900
00901 PlayPauseMutexLock( "plblk1" );
00902 while( sent < size )
00903 {
00904 n = size - sent;
00905 if( n > MaxPipeDataSize )
00906 n = MaxPipeDataSize;
00907
00908 nwrite = write( pipe_player[ 1 ], (void*)buffer, n );
00909
00910 if( nwrite < 0 )
00911 Rioperror( "write: pipe mpeg player" );
00912 #ifdef RIO_DEBUG2
00913 else if( nwrite != MaxPipeDataSize )
00914 {
00915 RioErr << "[PlayBlock] Escrito apenas " << nwrite
00916 << " de " << n << " bytes no pipe_player." << endl;
00917 }
00918 #endif
00919
00920 sent += nwrite;
00921 buffer += nwrite;
00922 }
00923 PlayPauseMutexUnlock( "plblk1" );
00924
00925 timer.Stop();
00926 avgBlockTime = ((avgBlockTime * n_blocks_played) +
00927 timer.Get())/(n_blocks_played+1);
00928 n_blocks_played++;
00929
00930 #ifdef RIO_DEBUG2
00931 RioErr << avgBlockTime/1000.0f << endl;
00932 #endif
00933
00934
00935 inputLog( PLAYING, Request[ PlayBuffer ].Block, ( unsigned int )size );
00936
00937
00938
00939
00940 last_played = Request[buf].Block;
00941
00942
00943
00944
00945 #ifdef RIO_DEBUG2
00946 RioErr << "Update interface?" << endl;
00947 #endif
00948 if( PTEventStack.isEmpty() &&
00949 ( (unsigned) labs( NextRequestBlock - last_played ) <= nBuffers )
00950 )
00951 {
00952 #ifdef RIO_DEBUG2
00953 RioErr << "Update interface!" << endl;
00954 #endif
00955 if( riomminterface )
00956 {
00957 #ifdef RIO_DEBUG2
00958 RioErr << "Played block: sending event to interface" << endl;
00959 #endif
00960
00961
00962 QCustomEvent *event = new QCustomEvent( QEvent::User,
00963 &last_played );
00964 QApplication::postEvent( (QObject*)riomminterface, event );
00965 }
00966 }
00967
00968
00969 if( riomminterface && ( Request[ buf ].Block == (TotalBlocks - 1) ) )
00970 {
00971 QCustomEvent *event = new QCustomEvent( QEvent::User, &TotalBlocks );
00972 QApplication::postEvent( (QObject*)riomminterface, event );
00973 }
00974
00975 #ifdef RIO_DEBUG2
00976 RioErr << "[RioMMVideo] Saindo da PlayBlock()" << endl;
00977 #endif
00978 }
00979
00980
00981 void CRioMMVideo::FastForward(){}
00982 void CRioMMVideo::FastRewind(){}
00983
00984 bool CRioMMVideo::WaitFullBuffer()
00985 {
00986 #ifdef RIO_DEBUG2
00987 RioErr << "[RioMMVideo] Entrei na WaitFullBuffer..." << endl;
00988 #endif
00989
00990 PlayThreadMutexUnlock( "wtfubf1" );
00991 if( Move_Prefetch() == false )
00992 {
00993 #ifdef RIO_DEBUG2
00994 RioErr << "[RioMMVideo] Erro na Move_Prefetch. Saindo com erro da "
00995 << "WaitFullBuffer..." << endl;
00996 #endif
00997
00998 return( false );
00999 }
01000
01001
01002 if( WaitPrefetch() == false )
01003 {
01004 #ifdef RIO_DEBUG2
01005 RioErr << "[RioMMVideo] Erro na WaitPrefetch. Saindo com erro da "
01006 << "WaitFullBuffer..." << endl;
01007 #endif
01008
01009 return( false );
01010 }
01011
01012 #ifdef RIO_DEBUG2
01013 RioErr << "[RioMMVideo] Saindo da WaitFullBuffer..." << endl;
01014 #endif
01015
01016 return( true );
01017 }
01018
01019 void CRioMMVideo::GoTo( RioBlock block )
01020 {
01021 if( PlayThreadID == 0 )
01022 {
01023 NextRequestBlock = (RioBlock) block;
01024 Play();
01025 }
01026 else
01027 {
01028
01029 PlayThreadEvent *thisEvent = new PlayThreadEvent();
01030 thisEvent->event = EVENT_GOTO;
01031 thisEvent->source = NextRequestBlock;
01032 thisEvent->target = block;
01033 PTEventStack.push( thisEvent );
01034 }
01035 }
01036
01037 void CRioMMVideo::Stop()
01038 {
01039 bool inPause = Paused;
01040
01041 #ifdef RIO_EMUL
01042 Stopped = true;
01043 #endif
01044
01045 #ifdef RIO_DEBUG2
01046 RioErr << "[RioMMVideo] Entrei na stop..." << endl;
01047 #endif
01048
01049 if( PlayThreadID != 0 )
01050 {
01051 if( pthread_cancel( PlayThreadID ) != 0 )
01052 {
01053 #ifdef RIO_DEBUG2
01054 RioErr << "Stop - failed to cancel thread " << endl;
01055 #endif
01056 }
01057 else
01058 {
01059 #ifdef RIO_DEBUG2
01060 RioErr << "Stop - cancel thread OK " << endl;
01061 #endif
01062 }
01063
01064 if( Paused )
01065 {
01066 Paused = false;
01067 PlayPauseMutexUnlock( "Stop1" );
01068 }
01069 }
01070
01071 if( connectPI )
01072 {
01073 if( group_block != -1 )
01074 group_block = -1;
01075
01076
01077
01078
01079 if( !inPause )
01080 {
01081 MulticastMutexLock( "Stop2" );
01082
01083 #ifdef RIO_DEBUG2
01084 RioErr << "Enviando ACTION_STOP pra PL." << endl;
01085 #endif
01086
01087 CommMultiStream->sendMoveMsg( PID, ACTION_STOP );
01088
01089 #ifdef RIO_DEBUG2
01090 RioErr << "[RioMMVideo] Stop: Waiting Condition" << endl;
01091 #endif
01092
01093 MulticastWaitCondition( "Stop2" );
01094 MulticastMutexUnlock( "Stop2" );
01095 }
01096 }
01097
01098 fullBuffers = 0;
01099 NextRequestBlock = 0;
01100 PlayBuffer = 0;
01101 PlayThreadID = 0;
01102 Paused = false;
01103 target = INT_MAX;
01104 PrefetchMutexUnlock( "Stop3" );
01105
01106
01107
01108
01109
01110
01111 #ifdef RIO_DEBUG2
01112 int freedPendentsSize = FreePendentBlocks( useCache, nBuffers );
01113 RioErr << "[RioMMVideo] Stop - FreePendentBlocks liberou "
01114 << freedPendentsSize << " bytes de blocos pendentes." << endl;
01115 #else
01116 FreePendentBlocks( useCache, nBuffers );
01117 #endif
01118
01119 CRioMMObject::Stop();
01120 }
01121
01122 #ifdef RIO_EMUL
01123 void CRioMMVideo::Quit()
01124 {
01125 #ifdef RIO_DEBUG2
01126 RioErr << "[RioMMVideo] Entrei no Quit..." << endl;
01127 #endif
01128
01129 if( !Stopped )
01130 Stop();
01131
01132 finalize_emul = true;
01133 }
01134 #endif
01135
01136 void CRioMMVideo::Pause()
01137 {
01138 if( PlayThreadID != 0 )
01139 {
01140
01141 PlayThreadEvent *thisEvent = new PlayThreadEvent();
01142 thisEvent->event = EVENT_PAUSE;
01143 thisEvent->source = NextRequestBlock;
01144 thisEvent->target = NextRequestBlock;
01145 PTEventStack.push( thisEvent );
01146 }
01147 }
01148
01149 void CRioMMVideo::Play()
01150 {
01151 PlayBuffer = NextRequestBlock % nBuffers;
01152
01153 #ifdef RIO_EMUL
01154 m_log << "Play " << NextRequestBlock << endl;
01155 Stopped = false;
01156 #endif
01157
01158 #ifdef RIO_DEBUG2
01159 RioErr << "[RioMMVideo] Play - NextRequestBlock = " << NextRequestBlock
01160 << endl;
01161 #endif
01162
01163 if( PlayThreadID == 0 )
01164 {
01165 #ifdef RIO_DEBUG2
01166 RioErr << "[RioMMVideo] Play - Criando PlayThread."
01167 << endl;
01168 #endif
01169
01170 if( pthread_create( &PlayThreadID, NULL, &PlayThread, this ) )
01171 {
01172 RioErr << "Could not create play thread" << endl;
01173 return;
01174 }
01175 }
01176 else
01177 {
01178 if( connectPI )
01179 {
01180 if( bufferStream->exist( NextRequestBlock ) )
01181 {
01182 #ifdef RIO_DEBUG2
01183 RioErr << "[PLAY] Buffer Exist: Cliente vai ler do buffer e "
01184 << "não precisa avisar isto à PL." << endl;
01185 #endif
01186
01187 ReadFrom = READFROM_BUFFER;
01188 }
01189 else
01190 {
01191 #ifdef RIO_DEBUG2
01192 RioErr << "[PLAY] Buffer Doesn't Exist " << NextRequestBlock
01193 << endl;
01194 #endif
01195
01196 MulticastMutexLock( "Play1" );
01197 CommMultiStream->sendMoveMsg( PID, ACTION_PLAY,
01198 NextRequestBlock );
01199 MulticastWaitCondition( "Play1" );
01200 MulticastMutexUnlock( "Play1" );
01201
01202 ReadFrom = READFROM_SERVER;
01203 }
01204
01205 first = isFirst();
01206 }
01207
01208 if( Paused )
01209 {
01210
01211
01212 PlayPauseMutexUnlock( "Play2" );
01213 Paused = false;
01214
01215 #ifdef RIO_DEBUG2
01216 RioErr << "[RioMMVideo] Liberou mutex playpause " << endl;
01217 #endif
01218
01219
01220 if( wId && ( player == RIOXINE_PLAYER ) )
01221 kill( playerPID, SIGUSR1 );
01222 }
01223 }
01224 }
01225
01226 void CRioMMVideo::WaitEndOfVideo()
01227 {
01228 pthread_join( PlayThreadID, NULL );
01229 PlayThreadID = 0;
01230 }
01231
01232 RioBlock CRioMMVideo::GetCurrentPosition()
01233 {
01234 return( CurrentBlock );
01235 }
01236
01237 RioBlock CRioMMVideo::GetNextRequestBlock()
01238 {
01239 return( NextRequestBlock );
01240 }
01241
01242 RioBlock CRioMMVideo::GetTotalPositions()
01243 {
01244 return( TotalBlocks );
01245 }
01246
01247 void *CRioMMVideo::PlayThread( void *videoObject )
01248 {
01249 CRioMMVideo *Video;
01250 int curBlockSize;
01251 unsigned int ind;
01252 struct timeval now;
01253 struct timespec timeout;
01254 bool free_status = true;
01255 int maxbuf0 = 0;
01256
01257 pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
01258 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
01259 pthread_cleanup_push( CRioMMVideo::PlayThreadCleanup, videoObject );
01260
01261 Video = (CRioMMVideo *)videoObject;
01262
01263 #ifdef RIO_EMUL
01264
01265 int *duration;
01266 int indice;
01267 duration = Video->GetBlocksDuration();
01268 #else
01269 #ifdef RIO_DEBUG2
01270 RioErr << "" << endl;
01271 RioErr << "CVS tag version: " VERSION << endl;
01272 RioErr << "**********************Start Player***********************"
01273 << endl;
01274 RioErr << "" << endl;
01275 #endif
01276
01277
01278 Video->StartPlayer();
01279 #endif
01280
01281
01282
01283
01284
01285
01286
01287 Video->PlayThreadMutexLock( "plthr1" );
01288 Video->Prefetch();
01289
01290 if( Video->WaitPrefetch() == false )
01291 {
01292 RioErr << "***|------------------------------------------|***" << endl;
01293 RioErr << "***|[Playthread] Blocos iniciais não chegaram.|***" << endl;
01294 RioErr << "***|------------------------------------------|***" << endl;
01295
01296 pthread_exit( NULL );
01297 }
01298
01299 if( !Video->CanStart() )
01300 {
01301 RioErr << "[Playthread] Cant't start video " << endl;
01302 pthread_exit( NULL );
01303
01304
01305 }
01306
01307 while( 1 )
01308 {
01309 #ifdef RIO_DEBUG2
01310 switch( Video->getMode() )
01311 {
01312 case LEADER:
01313 RioErr << "\033[01;40;36m";
01314 RioErr << "Sou líder!!!" << endl;
01315 break;
01316 case SUBLEADER:
01317 RioErr << "\033[01;40;31m";
01318 RioErr << "Sou sublíder!!!" << endl;
01319 break;
01320 case PASSIVE:
01321 RioErr << "\033[01;40;33m";
01322 RioErr << "Sou passivo!!!" << endl;
01323 break;
01324 default:
01325 RioErr << "\033[0m";
01326 if( Video->connectPI )
01327 RioErr << "Sou inativo ou indisponível!!!" << endl;
01328 else
01329 RioErr << "Sou cliente unicast." << endl;
01330 }
01331 RioErr << "GetFullBuffers = " << Video->GetFullBuffers() << endl;
01332 #endif
01333
01334 while( Video->GetFullBuffers() > 0 )
01335 {
01336 if( Video->DealPendentEvents() == false )
01337 {
01338 #ifdef RIO_DEBUG2
01339 RioErr << "[RioMMVideo] Evento inválido. Saindo da PlayThread"
01340 << endl;
01341 #endif
01342
01343 pthread_exit( NULL );
01344 }
01345
01346 #ifdef RIO_DEBUG2
01347 switch( Video->getMode() )
01348 {
01349 case LEADER:
01350 RioErr << "\033[01;40;36m";
01351 RioErr << "Sou líder!!!" << endl;
01352 break;
01353 case SUBLEADER:
01354 RioErr << "\033[01;40;31m";
01355 RioErr << "Sou sublíder!!!" << endl;
01356 break;
01357 case PASSIVE:
01358 RioErr << "\033[01;40;33m";
01359 RioErr << "Sou passivo!!!" << endl;
01360 break;
01361 default:
01362 RioErr << "\033[0m";
01363 if( Video->connectPI )
01364 RioErr << "Sou inativo ou indisponível!!!" << endl;
01365 else
01366 RioErr << "Sou cliente unicast." << endl;
01367 }
01368 #endif
01369
01370 Video->PlayThreadMutexUnlock( "plthr1" );
01371
01372 usleep( 1000 );
01373
01374 Video->PrefetchMutexLock( "plthr2" );
01375
01376 if( Video->Request[ Video->PlayBuffer ].Block <
01377 Video->TotalBlocks-1
01378 )
01379 {
01380 curBlockSize = Video->Request[ Video->PlayBuffer ].Size;
01381 }
01382 else
01383 {
01384 if( Video->Request[ Video->PlayBuffer ].Block ==
01385 ( Video->TotalBlocks - 1 )
01386 )
01387 curBlockSize = Video->ObjSize - ( Video->BlockSize *
01388 (Video->TotalBlocks-1) );
01389 else
01390 {
01391 RioErr << "[PlayThread] Unbounded streams are not supported "
01392 << "yet!" << endl;
01393 pthread_exit( NULL );
01394 }
01395 }
01396
01397
01398
01399 if( Video->GetBufferStatus( Video->PlayBuffer ) != BUFFERFULL )
01400 {
01401 #ifdef RIO_DEBUG2
01402 RioErr << "[Playthread] buffer empty " << Video->PlayBuffer
01403 << endl;
01404 #endif
01405
01406 if( Video->useCache &&
01407 ( Video->bufferStream->readBlock(
01408 Video->Request[ Video->PlayBuffer ].Block,
01409 (unsigned char *)Video->Request[Video->PlayBuffer].Buffer
01410 ) == 0
01411 )
01412 )
01413 {
01414 #ifdef RIO_DEBUG2
01415 RioErr << "[PlayThread] Copiando bloco "
01416 << Video->Request[ Video->PlayBuffer ].Block
01417 << " para playbuffer " << Video->PlayBuffer
01418 << endl;
01419 #endif
01420
01421 #ifdef RIO_EMUL
01422 timeval tv;
01423 gettimeofday( &tv, 0 );
01424 Video->m_log << tv.tv_sec << "."
01425 << ( (double) tv.tv_usec / 1000000 );
01426 Video->m_log << " Cache : "
01427 << Video->Request[
01428 Video->PlayBuffer ].Block << endl;
01429 #endif
01430 }
01431 else
01432 {
01433 #ifdef RIO_DEBUG2
01434 RioErr << "[Playthread] Esperando chegada de bloco "
01435 << Video->Request[ Video->PlayBuffer ].Block
01436 << endl;
01437 #endif
01438
01439 gettimeofday( &now, NULL );
01440 timeout.tv_sec = now.tv_sec + 1;
01441 timeout.tv_nsec = now.tv_usec * 1000;
01442
01443
01444
01445 Video->PlayThreadMutexLock( "plthr3" );
01446 Video->PlayThreadWaitCondition( &timeout, "plthr3" );
01447 Video->PlayThreadMutexUnlock( "plthr3" );
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467 if( Video->GetBufferStatus( Video->PlayBuffer ) !=
01468 BUFFERFULL )
01469 {
01470 if( Video->CallFreeBlock( Video->PlayBuffer ) )
01471 {
01472 #ifdef RIO_EMUL
01473 Video->m_log << "Recuperado : "
01474 << Video->Request[ Video->PlayBuffer ].Block
01475 << " tamanho: " << curBlockSize << " Bytes"
01476 << endl;
01477 partialBlocks++;
01478 #endif
01479
01480 free_status = true;
01481 curBlockSize = Video->Request[
01482 Video->PlayBuffer].Size;
01483
01484 }
01485 else
01486 {
01487 #ifdef RIO_EMUL
01488 Video->m_log << "Perdido: "
01489 << Video->Request[
01490 Video->PlayBuffer ].Block << endl;
01491 lostBlocks++;
01492 #endif
01493
01494 #ifdef RIO_DEBUG2
01495 RioErr << "Playthread - nao existe referencia do "
01496 << "bloco: " << Video->Request[
01497 Video->PlayBuffer].Block
01498 << endl;
01499 #endif
01500
01501 free_status = false;
01502 Video->Object.CancelExpect( Video->Request[
01503 Video->PlayBuffer].reqid );
01504 }
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518 #ifdef RIO_DEBUG2
01519 int freedPendentsSize = Video->FreePendentBlocks(
01520 Video->useCache, Video->nBuffers );
01521 RioErr << "[RioMMVideo] PlayThread - FreePendentBlocks "
01522 << "liberou " << freedPendentsSize
01523 << " bytes de blocos pendentes." << endl;
01524 #else
01525 Video->FreePendentBlocks( Video->useCache,
01526 Video->nBuffers );
01527 #endif
01528 }
01529 }
01530 }
01531
01532 if( free_status )
01533 #ifdef RIO_EMUL
01534
01535 {
01536 Video->PlayPauseMutexLock( "plthr4" );
01537 indice = Video->Request[ Video->PlayBuffer ].Block;
01538
01539 #ifdef RIO_DEBUG2
01540 RioErr << "Playthread --------------> Tocando bloco "
01541 << Video->Request[ Video->PlayBuffer ].Block
01542 << " posicao buffer: " << Video->PlayBuffer
01543 << " duração " << duration[ indice ] << endl;
01544 string message;
01545 message = "meu pid é ";
01546 message += int2string( (int) Video->PID );
01547 message += "\n";
01548 Video->printDebug( 1, message );
01549 #endif
01550
01551
01552 timeval tv;
01553 gettimeofday( &tv, 0 );
01554 Video->m_log
01555 << (double)(tv.tv_sec + ( (double)tv.tv_usec / 1000000 ))
01556 << " Execução: " << indice << endl;
01557
01558
01559
01560
01561 completeBlocks++;
01562
01563 totalBytesPlayed = totalBytesPlayed +
01564 Video->Request[ Video->PlayBuffer ].Size;
01565
01566 usleep( duration[ indice ] );
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579 #if 0
01580 {
01581 Video->bufferStream->dropBlock(
01582 Video->Request[ Video->PlayBuffer ].Block );
01583
01584 #ifdef RIO_DEBUG2
01585 RioErr << "Simulando liberacao do bloco"
01586 << Video->Request[ Video->PlayBuffer ].Block
01587 << " da cache." << endl;
01588 #endif
01589 }
01590 #endif
01591
01592 gettimeofday( &Video->timer_after, 0 );
01593 Video->diff_timer.tv_sec = Video->timer_after.tv_sec -
01594 Video->timer_before.tv_sec;
01595
01596 Video->diff_timer.tv_usec = Video->timer_after.tv_usec -
01597 Video->timer_before.tv_usec;
01598
01599 if( Video->diff_timer.tv_usec < 0 )
01600 {
01601 Video->diff_timer.tv_sec -= 1;
01602 Video->diff_timer.tv_usec += 1000000;
01603 }
01604
01605 Video->play_time = (unsigned int)( Video->diff_timer.tv_sec *
01606 1000000.0 +
01607 Video->diff_timer.tv_usec);
01608
01609 Video->PlayPauseMutexUnlock( "plthr4" );
01610 }
01611 #else // else do ifdef RIO_EMUL
01612 {
01613 #ifdef RIO_DEBUG2
01614 RioErr << "Playthread --------------> Tocando bloco "
01615 << Video->Request[ Video->PlayBuffer ].Block
01616 << " posicao buffer: " << Video->PlayBuffer << endl;
01617 string message;
01618 message = "meu pid é ";
01619 message += int2string( (int) Video->PID );
01620 message += "\n";
01621 Video->printDebug( 1, message );
01622 #endif
01623
01624 Video->PlayBlock( Video->PlayBuffer, curBlockSize );
01625 }
01626 #ifdef RIO_DEBUG2
01627 else
01628 {
01629 RioErr << "Playthread - free_status = "
01630 << (free_status? "true":"false")
01631 << ": Bloco não será tocado." << endl;
01632 }
01633 #endif // endif do ifdef RIO_DEBUG2
01634 #endif // endif do ifdef RIO_EMUL
01635
01636 if( free_status )
01637 {
01638 #ifdef RIO_DEBUG2
01639 RioErr << "Liberando espaco: " << Video->PlayBuffer
01640 << " no playbuffer " << endl;
01641 #endif
01642
01643 Video->SetBufferStatus( Video->PlayBuffer, BUFFEREMPTY );
01644 }
01645 else
01646 free_status = true;
01647
01648 #ifndef RIO_EMUL
01649 Video->SyncMedia( (void *)Video->Request[
01650 Video->PlayBuffer ].Block );
01651 #endif
01652
01653
01654 Video->PlayThreadMutexLock( "plthr5" );
01655
01656
01657 ind = Video->PlayBuffer;
01658
01659
01660 Video->PlayBuffer++;
01661 if( Video->PlayBuffer >= Video->nBuffers )
01662 Video->PlayBuffer = 0;
01663
01664 #ifdef RIO_DEBUG2
01665 RioErr << "[PlayThread] PlayBuffer atualizado para "
01666 << Video->PlayBuffer << endl;
01667 #endif
01668
01669
01670
01671 if( Video->NextRequestBlock < Video->TotalBlocks )
01672 {
01673 #ifdef RIO_DEBUG2
01674 RioErr << "Playthread - Precisando do bloco "
01675 << Video->NextRequestBlock << endl;
01676 #endif
01677
01678 if( Video->ReadNextBlock( ind ) == false )
01679 {
01680 #ifdef RIO_DEBUG2
01681 RioErr << "Finalizando playthread. Erro na "
01682 << "ReadNextBlock( " << ind << " )." << endl;
01683 #endif
01684
01685 pthread_exit( NULL );
01686 }
01687 }
01688 else
01689 {
01690 #ifdef RIO_DEBUG2
01691 RioErr << "PlayThread - Bloco " << Video->NextRequestBlock
01692 << " náo será solicitado pois NextRequestBlock > "
01693 << "TotalBlocks" << endl;
01694 #endif
01695
01696
01697 if( Video->Request[ind].Block == ( Video->TotalBlocks - 1 ) )
01698 {
01699 #ifdef RIO_DEBUG2
01700 RioErr << "[RioMMVideo] Ultimo bloco do filme: "
01701 << Video->Request[ind].Block << endl;
01702 #endif
01703
01704
01705 usleep( 2000000 );
01706
01707 pthread_exit( NULL );
01708 }
01709
01710 if( Video->NextRequestBlock > Video->TotalBlocks )
01711 pthread_exit( NULL );
01712 }
01713
01714 Video->PrefetchMutexUnlock( "plthr6" );
01715
01716 #ifdef RIO_DEBUG2
01717 RioErr << "GetFullBuffers = " << Video->GetFullBuffers() << endl;
01718 #endif
01719 }
01720
01721 if( Video->DealPendentEvents() == false )
01722 {
01723 #ifdef RIO_DEBUG2
01724 RioErr << "[RioMMVideo] Evento inválido. Saindo da PlayThread" << endl;
01725 #endif
01726
01727 pthread_exit( NULL );
01728 }
01729
01730 #ifdef RIO_DEBUG2
01731 RioErr << "[RioMMVideo] PlayThread: Chamando WaitBlocks" << endl;
01732 #endif
01733
01734 if( Video->WaitBlocks() == false )
01735 {
01736 #ifdef RIO_DEBUG2
01737 RioErr << "[RioMMVideo] Saindo da PlayThread" << endl;
01738 #endif
01739 pthread_exit( NULL );
01740 }
01741
01742
01743
01744
01745 if( Video->GetFullBuffers() == 0 )
01746 {
01747 maxbuf0++;
01748 if( maxbuf0 >= 20 )
01749 {
01750 #ifdef RIO_DEBUG_EMUL
01751 RioErr << "[RioMMVideo] Saindo da PlayThread. Cliente "
01752 << "finalizando por inanicao." << endl;
01753 #endif
01754
01755 pthread_exit( NULL );
01756 }
01757 }
01758 else
01759 {
01760 maxbuf0=0;
01761 }
01762 }
01763
01764 pthread_cleanup_pop( 1 );
01765 pthread_exit( NULL );
01766 }
01767
01768 bool CRioMMVideo::DealPendentEvents()
01769 {
01770
01771 if( !PTEventStack.isEmpty() )
01772 {
01773 PlayThreadEvent *event = NULL;
01774
01775 waitingMSGCODE_IP = true;
01776
01777
01778
01779
01780 #ifdef RIO_DEBUG2
01781 RioErr << "Pilha de eventos tem " << PTEventStack.count()
01782 << " eventos. Processando-os." << endl;
01783 #endif
01784
01785 bool jumped = false;
01786
01787
01788
01789 while( !PTEventStack.isEmpty() )
01790 {
01791 PlayThreadEvent *thisevent;
01792 thisevent = PTEventStack.pop();
01793
01794 if( thisevent->event == EVENT_PAUSE )
01795 {
01796 #ifdef RIO_DEBUG2
01797 RioErr << "Encontrado um PAUSE na pilha de eventos... "
01798 << "Ignorando os demais e limpando a pilha." << endl;
01799 #endif
01800
01801
01802
01803
01804 if( event != NULL ) delete event;
01805 event=thisevent;
01806 PTEventStack.clear();
01807 break;
01808 }
01809 else if( thisevent->event == EVENT_GOTO )
01810 {
01811
01812
01813
01814 if( jumped == false )
01815 {
01816 #ifdef RIO_DEBUG2
01817 RioErr << "Encontrado um GOTO " << thisevent->target
01818 << " na pilha de eventos... Ignorando os demais "
01819 << "pulos." << endl;
01820 #endif
01821
01822 jumped = true;
01823 event=thisevent;
01824 continue;
01825 }
01826 else
01827 {
01828 #ifdef RIO_DEBUG2
01829 RioErr << "Encontrado outro GOTO(para " << thisevent->target
01830 << ") na pilha de eventos... Este será ignorado."
01831 << endl;
01832 #endif
01833
01834 delete thisevent;
01835 continue;
01836 }
01837 }
01838 else
01839 {
01840 #ifdef RIO_DEBUG2
01841 RioErr << "[RioMMVideo] DealPendentEvents: Evento "
01842 << thisevent->event << " inválido!" << endl;
01843 #endif
01844
01845 delete thisevent;
01846
01847
01848 return false;
01849 }
01850 }
01851
01852 switch( event->event )
01853 {
01854 case EVENT_PAUSE:
01855 {
01856 #ifdef RIO_DEBUG2
01857 RioErr << "Evento PAUSE - Source: " << event->source
01858 << ", Target: " << event->target << endl;
01859 #endif
01860
01861 delete event;
01862
01863
01864
01865 if( Paused )
01866 return true;
01867
01868 #ifdef RIO_EMUL
01869 m_log << "Pause" << endl;
01870 #endif
01871
01872 PrefetchMutexLock( "Pause1" );
01873 PlayPauseMutexLock( "Pause2" );
01874
01875 Paused = true;
01876
01877 if( connectPI )
01878 {
01879 MulticastMutexLock( "Pause3" );
01880
01881 #ifdef RIO_DEBUG2
01882 RioErr << "[Pause] - Enviando msg ACTION_PAUSE pra PL."
01883 << endl;
01884 #endif
01885
01886 CommMultiStream->sendMoveMsg( PID, ACTION_PAUSE );
01887 MulticastWaitCondition( "Pause3" );
01888 MulticastMutexUnlock( "Pause3" );
01889
01890 first = isFirst();
01891
01892 if( group_block != -1 )
01893 group_block = -1;
01894 }
01895
01896 PrefetchMutexUnlock( "Pause1" );
01897
01898
01899 if( wId && ( player == RIOXINE_PLAYER ) )
01900 kill( playerPID, SIGUSR1 );
01901
01902
01903
01904 target = INT_MAX;
01905
01906
01907
01908
01909
01910
01911 #ifdef RIO_DEBUG2
01912 int freedPendentsSize = FreePendentBlocks( useCache, nBuffers );
01913
01914 RioErr << "[RioMMVideo] Pause - FreePendentBlocks liberou "
01915 << freedPendentsSize << " bytes de blocos pendentes." << endl;
01916 #else
01917 FreePendentBlocks( useCache, nBuffers );
01918 #endif
01919
01920 #ifdef RIO_DEBUG2
01921 RioErr << "Saindo da Pause " << endl;
01922 #endif
01923
01924 break;
01925 }
01926
01927 case EVENT_GOTO:
01928 {
01929 #ifdef RIO_DEBUG2
01930 RioErr << "Evento GOTO - Source: " << event->source
01931 << ", Target: " << event->target << endl;
01932 #endif
01933
01934 RioBlock block = event->target;
01935 delete event;
01936
01937 #ifdef RIO_DEBUG2
01938 RioErr << "[GoTo] pulando do bloco " << NextRequestBlock
01939 << " para o bloco "
01940 << block << endl;
01941 #endif
01942
01943 if( Paused )
01944 {
01945 Paused = false;
01946 PlayPauseMutexUnlock( "GoTo1" );
01947 }
01948
01949 if( connectPI && ( group_block != -1 ) )
01950 group_block = -1;
01951
01952 if( PlayThreadID == 0 )
01953 {
01954 NextRequestBlock = block;
01955 Play();
01956 }
01957 else
01958 {
01959 MoveAction action;
01960
01961 if( NextRequestBlock < block )
01962 action = ACTION_FORWARD;
01963 else
01964 action = ACTION_REWIND;
01965
01966
01967
01968
01969
01970
01971
01972 #if 0
01973 {
01974 for( int i = 0; i < block; i++ )
01975 {
01976 bufferStream->dropBlock(i);
01977
01978 #ifdef RIO_DEBUG2
01979 RioErr << "Simulando liberacao do bloco "
01980 << i << " da cache na GoTo." << endl;
01981 #endif
01982 }
01983 }
01984 #endif
01985
01986 NextRequestBlock = block;
01987
01988 if( NextRequestBlock >= TotalBlocks )
01989 NextRequestBlock = TotalBlocks-1;
01990
01991 if( connectPI )
01992 {
01993 MulticastMutexLock( "GoTo2" );
01994
01995 #ifdef RIO_DEBUG2
01996 RioErr << "[GoTo] Se bloco " << NextRequestBlock
01997 << " não existir, chamarei CallFreeBlock pro "
01998 << "bloco " << Request[PlayBuffer].Block << "."
01999 << endl;
02000 #endif
02001
02002 if( bufferStream->exist( NextRequestBlock ) ||
02003 thereAreFragments( NextRequestBlock )
02004 )
02005 {
02006
02007
02008
02009
02010 #ifdef RIO_DEBUG2
02011 RioErr << "[GoTo] Jump pra área de blocos que já tem na cache."
02012 << " PID: " << PID << ", action: " << action
02013 << " block: -1.\n";
02014 RioErr << "Cliente será removido para lista de inativos." << endl;
02015 #endif
02016
02017 CommMultiStream->sendMoveMsg( PID, action, -1 );
02018 ReadFrom = READFROM_BUFFER;
02019 }
02020 else
02021 {
02022 #ifdef RIO_DEBUG2
02023 RioErr << "[GoTo] Sending MoveMsg " << " PID: "
02024 << PID << ", action: "
02025 << CommMultiStream->MoveAction2String( action )
02026 << ", block: " << NextRequestBlock << endl;
02027 #endif
02028
02029 CommMultiStream->sendMoveMsg( PID, action,
02030 NextRequestBlock );
02031 ReadFrom = READFROM_SERVER;
02032 }
02033
02034 MulticastWaitCondition( "GoTo2" );
02035 MulticastMutexUnlock( "GoTo2" );
02036
02037 first = isFirst();
02038 }
02039
02040 Paused = false;
02041 PlayPauseMutexUnlock( "GoTo3" );
02042 if( WaitFullBuffer() == false )
02043 {
02044 #ifdef RIO_DEBUG2
02045 RioErr << "[RioMMVideo] WaitFullBuffer == false. Chamando Stop() "
02046 << endl;
02047 #endif
02048
02049 Stop();
02050 }
02051 }
02052 break;
02053 }
02054 }
02055 }
02056 #ifdef RIO_DEBUG2
02057 else
02058 {
02059 RioErr << "Pilha de eventos vazia. Retornando." << endl;
02060 }
02061 #endif
02062
02063 return true;
02064 }
02065
02066 bool CRioMMVideo::WaitBlocks()
02067 {
02068 struct timeval now;
02069 struct timespec timeout;
02070
02071 PrefetchMutexLock( "wtblk1" );
02072
02073
02074
02075 if( connectPI )
02076 {
02077 if( first )
02078 {
02079 if( (signed) NextRequestBlock == group_block )
02080 req_block = NextRequestBlock - ( nBuffers - 1 );
02081 else
02082 req_block = NextRequestBlock - nBuffers;
02083
02084 PlayBuffer = ( req_block % nBuffers );
02085 Request[ PlayBuffer ].Block = req_block;
02086
02087 #ifdef RIO_DEBUG2
02088 RioErr << "[WaitBlocks] PlayBuffer atualizado para "
02089 << PlayBuffer << endl;
02090 #endif
02091
02092 gettimeofday( &now, NULL );
02093 timeout.tv_sec = now.tv_sec + 1;
02094 timeout.tv_nsec = now.tv_usec * 1000;
02095
02096 PlayThreadWaitCondition( &timeout, "wtblk2" );
02097 PlayThreadMutexUnlock( "wtblk2" );
02098
02099 #ifdef RIO_DEBUG2
02100 RioErr << "WaitBlocks - verificando chegada de bloco: "
02101 << req_block
02102 << endl;
02103 #endif
02104
02105 if( !bufferStream->exist( req_block ) )
02106 {
02107 #ifdef RIO_DEBUG2
02108 RioErr << "WaitBlocks - playbuffer: " << PlayBuffer
02109 << " vazio. Chamando Leader_WaitMulticastBlocks"
02110 << endl;
02111 #endif
02112
02113
02114
02115
02116 if( Leader_WaitMulticastBlocks() == false )
02117 {
02118 PrefetchMutexUnlock( "wtblk3" );
02119 return( false );
02120 }
02121 }
02122 else
02123 {
02124 if( bufferStream->readBlock(
02125 Request[ PlayBuffer ].Block,
02126 (unsigned char *) Request[ PlayBuffer ].Buffer )
02127 == 0
02128 )
02129 {
02130 #ifdef RIO_DEBUG2
02131 RioErr << "WaitBlocks (1) req_block " << req_block
02132 << " disponível. Gravando no PlayOutBuffer "
02133 << PlayBuffer << endl;
02134 #endif
02135 SetBufferStatus( PlayBuffer, BUFFERFULL );
02136 }
02137 }
02138 }
02139 else
02140 {
02141
02142 if( patching )
02143 {
02144 gettimeofday( &now, NULL );
02145 timeout.tv_sec = now.tv_sec + 1;
02146 timeout.tv_nsec = now.tv_usec * 1000;
02147
02148 PlayThreadWaitCondition( &timeout, "wtblk4" );
02149 PlayThreadMutexUnlock( "wtblk4" );
02150
02151
02152
02153
02154 if( bufferStream->readBlock( Request[PlayBuffer].Block,
02155 (unsigned char *) Request[PlayBuffer].Buffer ) != 0
02156 )
02157 {
02158 if( CallFreeBlock( PlayBuffer ) == false )
02159 {
02160 #ifdef RIO_DEBUG2
02161 RioErr << "[WaitBlocks] 1 - Bloco esperado ("
02162 << Request[PlayBuffer].Block
02163 << ") nao recuperado " << endl;
02164 #endif
02165 }
02166 }
02167 else
02168 {
02169 #ifdef RIO_DEBUG2
02170 RioErr << "[WaitBlocks] Bloco "
02171 << Request[PlayBuffer].Block
02172 << " existe na cache e foi gravado no "
02173 << "PlayOutBuffer " << PlayBuffer
02174 << endl;
02175 #endif
02176
02177 SetBufferStatus( PlayBuffer, BUFFERFULL );
02178 }
02179 }
02180 else if( WaitMulticastBlocks() == false )
02181 {
02182
02183 PrefetchMutexUnlock( "wtblk5" );
02184 return( false );
02185 }
02186 }
02187 }
02188 else
02189 {
02190 #ifdef RIO_DEBUG2
02191 RioErr << "WaitBlocks - esperando sinal " << endl;
02192 #endif
02193 gettimeofday( &now, NULL );
02194
02195 if( WaitingPrefetch )
02196 {
02197 #ifdef RIO_DEBUG2
02198 RioErr << "[WaitBlocks] - WaitingPrefetch true.." << endl;
02199 #endif
02200
02201 if( ( now.tv_usec + RTT_window ) > 1000000 )
02202 {
02203 timeout.tv_sec = now.tv_sec + (int)( RTT_window / 1000000 );
02204 timeout.tv_nsec = ( now.tv_usec + ( RTT_window % 1000000 ) ) * 1000;
02205 }
02206 else
02207 {
02208 timeout.tv_sec = now.tv_sec;
02209 timeout.tv_nsec = ( now.tv_usec + RTT_window ) * 1000;
02210 }
02211 }
02212 else
02213 {
02214 #ifdef RIO_DEBUG2
02215 RioErr << "[WaitBlocks] - WaitingPrefetch false.." << endl;
02216 #endif
02217
02218 timeout.tv_sec = now.tv_sec + 1;
02219 timeout.tv_nsec = now.tv_usec * 1000;
02220 }
02221
02222 PlayThreadWaitCondition( &timeout, "wtblk6" );
02223 PlayThreadMutexUnlock( "wtblk6" );
02224
02225 #ifdef RIO_DEBUG2
02226 RioErr << "WaitBlocks - playbuffer: " << PlayBuffer << endl;
02227 #endif
02228
02229 for( unsigned int index = 0; index < nBuffers; index++ )
02230 {
02231 if( useCache && ( GetBufferStatus( index ) == BUFFEREMPTY ) )
02232 {
02233 if( bufferStream->readBlock( Request[ index ].Block,
02234 (unsigned char *) Request[ index ].Buffer ) == 0
02235 )
02236 {
02237 #ifdef RIO_DEBUG2
02238 RioErr << "WaitBlocks: Gravando bloco "
02239 << Request[ index ].Block
02240 << " no PlayOutBuffer " << index << endl;
02241 #endif
02242
02243 SetBufferStatus( index, BUFFERFULL );
02244 }
02245 else if( CallFreeBlock( index ) == false )
02246 {
02247 #ifdef RIO_DEBUG2
02248 RioErr << "[WaitBlocks] 3 - Bloco esperado ("
02249 << Request[index].Block
02250 << ") nao recuperado " << endl;
02251 #endif
02252 }
02253 }
02254 else if( ( GetBufferStatus( index ) == BUFFEREMPTY ) &&
02255 ( CallFreeBlock( index ) == false )
02256 )
02257 {
02258 #ifdef RIO_DEBUG2
02259 RioErr << "[WaitBlocks] 4 - Bloco esperado ("
02260 << Request[index].Block
02261 << ") nao recuperado " << endl;
02262 #endif
02263 }
02264 }
02265 }
02266
02267 PrefetchMutexUnlock( "wtblk1" );
02268
02269 return( true );
02270 }
02271
02272 bool CRioMMVideo::CallFreeBlock( int PlayBuffer )
02273 {
02274 int freedSize;
02275 struct timeval now;
02276 struct timespec timeout;
02277
02278 #ifdef RIO_DEBUG2
02279 RioErr << "[RioMMVideo] CallFreeBlock - bloco/reqid = "
02280 << Request[ PlayBuffer ].Block << "/" << Request[ PlayBuffer ].reqid
02281 << endl;
02282 #endif
02283
02284 #ifdef RIO_DEBUG2
02285 RioErr << "[RioMMVideo] CallFreeBlock - Chamando FreeBlock para bloco "
02286 << Request[ PlayBuffer ].Block << ". PlayBuffer = " << PlayBuffer
02287 << endl;
02288 #endif
02289
02290 freedSize = FreeBlock( PlayBuffer );
02291
02292 if( freedSize != 0 )
02293 {
02294 Request[ PlayBuffer ].Size = freedSize;
02295
02296 #ifdef RIO_DEBUG2
02297 RioErr << "CallFreeBlock - FreeBlock liberou bloco "
02298 << Request[ PlayBuffer ].Block << "(size " << freedSize << ")"
02299 << endl;
02300 #endif
02301
02302
02303
02304
02305
02306
02307
02308 while( ( GetBufferStatus( PlayBuffer ) == BUFFEREMPTY ) &&
02309 ( useCache &&
02310 ( bufferStream->readBlock( Request[ PlayBuffer ].Block,
02311 (unsigned char *) Request[ PlayBuffer ].Buffer ) != 0
02312 )
02313 )
02314 )
02315 {
02316 #ifdef RIO_DEBUG2
02317 RioErr << "CallFreeBlock2 - Esperando 1 segundo pela sinalizacao "
02318 << "de chegada do bloco " << Request[ PlayBuffer ].Block
02319 << " (PlayOutBuffer posição " << PlayBuffer << ")." << endl;
02320 #endif
02321
02322 gettimeofday( &now, NULL );
02323 timeout.tv_sec = now.tv_sec + 1;
02324 timeout.tv_nsec = now.tv_usec * 1000;
02325
02326
02327
02328
02329
02330
02331 PlayThreadWaitCondition( &timeout, "cafrbl2" );
02332 PlayThreadMutexUnlock( "cafrbl2" );
02333 }
02334
02335 #ifdef RIO_DEBUG2
02336 RioErr << "CallFreeBlock -Saindo... Tamanho do bloco recuperado: "
02337 << Request[ PlayBuffer ].Size << endl;
02338 #endif
02339
02340 SetBufferStatus( PlayBuffer, BUFFERFULL );
02341 return true;
02342 }
02343 else
02344 {
02345
02346 if( useCache &&
02347 ( bufferStream->readBlock( Request[ PlayBuffer ].Block,
02348 (unsigned char *) Request[ PlayBuffer ].Buffer ) == 0
02349 )
02350 )
02351 {
02352 #ifdef RIO_DEBUG2
02353 RioErr << "CallFreeBlock -Saindo... FreeBlock falhou mas eu tinha"
02354 << " o bloco " << Request[ PlayBuffer ].Block
02355 << " na cache e o recuperei." << endl;
02356 #endif
02357
02358 SetBufferStatus( PlayBuffer, BUFFERFULL );
02359 return true;
02360 }
02361 else
02362 {
02363 #ifdef RIO_DEBUG2
02364 RioErr << "[CallFreeBlock] Retornando false: bloco não recuperado."
02365 << endl;
02366 #endif
02367
02368 return false;
02369 }
02370 }
02371 }
02372
02373 void CRioMMVideo::MulticastMutexLock( string msg )
02374 {
02375 #ifdef RIO_DEBUG2
02376 if( msg.length() )
02377 RioErr << "[MulticastMutexLock] " << msg << "... " << endl;
02378 #endif
02379
02380 pthread_mutex_lock( &multicastMutex );
02381
02382 #ifdef RIO_DEBUG2
02383 if( msg.length() )
02384 RioErr << "..." << msg << " OK!" << endl;
02385 #endif
02386 }
02387
02388 void CRioMMVideo::MulticastMutexUnlock( string msg )
02389 {
02390 #ifdef RIO_DEBUG2
02391 if( msg.length() )
02392 RioErr << "[MulticastMutexUnlock] " << msg << endl;
02393 #endif
02394
02395 pthread_mutex_unlock( &multicastMutex );
02396 }
02397
02398 void CRioMMVideo::MulticastWaitCondition( string msg )
02399 {
02400 #ifdef RIO_DEBUG2
02401 if( msg.length() )
02402 RioErr << "[MulticastWaitCondition] " << msg << "... " << endl;
02403 #endif
02404
02405 pthread_cond_wait( &multicastCondition, &multicastMutex );
02406
02407 #ifdef RIO_DEBUG2
02408 if( msg.length() )
02409 RioErr << "..." << msg << " OK!" << endl;
02410 #endif
02411 }
02412
02413 void CRioMMVideo::MulticastReleaseCondition( string msg )
02414 {
02415 #ifdef RIO_DEBUG2
02416 if( msg.length() )
02417 RioErr << "[MulticastReleaseCondition] " << msg << endl;
02418 #endif
02419
02420 pthread_cond_broadcast( &multicastCondition );
02421 waitingMSGCODE_IP = false;
02422 }
02423
02424 void CRioMMVideo::PlayPauseMutexLock( string msg )
02425 {
02426 #ifdef RIO_DEBUG2
02427 if( msg.length() )
02428 RioErr << "[PlayPauseMutexLock] " << msg << "... " << endl;
02429 #endif
02430
02431 pthread_mutex_lock( &PlayPauseMutex );
02432
02433 #ifdef RIO_DEBUG2
02434 if( msg.length() )
02435 RioErr << "..." << msg << " OK!" << endl;
02436 #endif
02437 }
02438
02439 void CRioMMVideo::PlayPauseMutexUnlock( string msg )
02440 {
02441 #ifdef RIO_DEBUG2
02442 if( msg.length() )
02443 RioErr << "[PlayPauseMutexUnlock] " << msg << endl;
02444 #endif
02445
02446 pthread_mutex_unlock( &PlayPauseMutex );
02447 }
02448
02449 void CRioMMVideo::PrefetchMutexLock( string msg )
02450 {
02451 #ifdef RIO_DEBUG2
02452 if( msg.length() )
02453 RioErr << "[PrefetchMutexLock] " << msg << "... " << endl;
02454 #endif
02455
02456 pthread_mutex_lock( &PrefetchMutex );
02457
02458 #ifdef RIO_DEBUG2
02459 if( msg.length() )
02460 RioErr << "..." << msg << " OK!" << endl;
02461 #endif
02462 }
02463
02464 void CRioMMVideo::PrefetchMutexUnlock( string msg )
02465 {
02466 #ifdef RIO_DEBUG2
02467 if( msg.length() )
02468 RioErr << "[PrefetchMutexUnlock] " << msg << endl;
02469 #endif
02470
02471 pthread_mutex_unlock( &PrefetchMutex );
02472 }
02473
02474
02475 void CRioMMVideo::PlayThreadCleanup( void *videoObject )
02476 {
02477 CRioMMVideo *Video;
02478
02479 #ifdef RIO_DEBUG2
02480 RioErr << "[RioMMVideo]: Entrei na PlayThreadCleanup" << endl;
02481 #endif
02482
02483 Video = (CRioMMVideo *)videoObject;
02484
02485 Video->PlayThreadID = 0;
02486
02487 #ifndef RIO_EMUL
02488 kill( Video->playerPID, SIGKILL );
02489 #else
02490 Video->finalize_emul = true;
02491 #endif
02492
02493 Video->PlayPauseMutexUnlock( "plthcl1" );
02494 Video->PlayThreadMutexUnlock( "plthcl2" );
02495 Video->PrefetchMutexUnlock( "plthcl3");
02496
02497 #ifdef RIO_EMUL
02498 if( !Video->Stopped )
02499 {
02500 Video->Stop();
02501 Video->Close();
02502 }
02503 #endif
02504
02505 #ifdef RIO_DEBUG2
02506 RioErr << "[RioMMVideo]: Saindo da PlayThreadCleanup" << endl;
02507 #endif
02508
02509
02510
02511
02512 if( !Video->ReadBlockStatus )
02513 {
02514
02515
02516
02517
02518
02519
02520
02521
02522 if( Video->GetNMedias() > 0 )
02523 {
02524 CRioMMTgif *Tgif;
02525 Tgif = (CRioMMTgif * ) Video->GetMedia( 0 );
02526
02527 kill( Tgif->GetTgifpid(), SIGKILL );
02528 }
02529
02530 #ifdef RIO_EMUL
02531 Video->m_log << "Erro ao ler o ultimo bloco: server is down?" << endl;
02532 raise( SIGTERM );
02533 #else
02534
02535 QCustomEvent *event;
02536 event = new QCustomEvent( ( QEvent::Type )( QEvent::User + 9 ),
02537 NULL );
02538 QApplication::postEvent( (QObject*) Video->riomminterface, event );
02539 #endif
02540 }
02541 }
02542
02543 bool CRioMMVideo::Leader_WaitMulticastBlocks()
02544 {
02545 bool empty_buffer = true;
02546 struct timeval now;
02547 struct timespec timeout;
02548 unsigned int i;
02549 unsigned int full = 0;
02550 unsigned int steps = 0;
02551 unsigned int index;
02552 static unsigned int exit = 0;
02553
02554 #ifdef RIO_DEBUG2
02555 RioErr << "[RioMMVideo]: Leader_WaitMulticastBlocks..." << endl;
02556 #endif
02557
02558 while( empty_buffer )
02559 {
02560 if( full > 0 )
02561 full = 0;
02562
02563 for( i = 0; i < nBuffers; i++ )
02564 {
02565 index = (req_block + i) % nBuffers;
02566 if( useCache && bufferStream->exist( req_block + i ) )
02567 {
02568 #ifdef RIO_DEBUG2
02569 RioErr << "Leader_WaitMulticastBlocks() - Bloco "
02570 << req_block + i << " ja existe. "
02571 << "Gravando no PlayOutBuffer " << index << endl;
02572 #endif
02573
02574 Request[ index ].Block = req_block + i;
02575 Request[ index ].Result = S_OK;
02576 Request[ index ].Status = RIO_REQUEST_COMPLETED;
02577 Request[ index ].Who = this;
02578
02579 bufferStream->readBlock( Request[ index ].Block,
02580 (unsigned char *)Request[index].Buffer);
02581
02582 PlayThreadMutexUnlock( "lewtmtbl1" );
02583 SetBufferStatus( index, BUFFERFULL );
02584 full++;
02585 steps++;
02586 }
02587 else
02588 {
02589 Request[ index ].Block = req_block + i;
02590 Request[ index ].Result = S_OK;
02591 Request[ index ].Status = RIO_REQUEST_COMPLETED;
02592 Request[ index ].Who = this;
02593
02594 #ifdef RIO_DEBUG2
02595 RioErr << "[RioMMVideo] Leader_WaitMulticastBlocks chamando "
02596 << "CallFreeBlock pra ver se há fragmentos do bloco "
02597 << req_block + i << endl;
02598 #endif
02599
02600 if( CallFreeBlock( index ) )
02601 {
02602 PlayThreadMutexUnlock( "lewtmtbl2" );
02603 SetBufferStatus( index, BUFFERFULL );
02604 full++;
02605 steps++;
02606 }
02607 else if( steps < nBuffers )
02608 {
02609 if( !ReadBlock( index, req_block + i, UNICASTTRAFFIC,
02610 0, 0 ) )
02611 {
02612 #ifdef RIO_DEBUG2
02613 RioErr << "[Leader_WaitMulticastBlocks] - Saindo... "
02614 << "Erro no pedido do bloco " << req_block
02615 << endl;
02616 #endif
02617
02618 return( false );
02619 }
02620
02621 steps++;
02622 }
02623 }
02624 }
02625
02626 if( full > 0 && steps >= nBuffers )
02627 {
02628 #ifdef RIO_DEBUG2
02629 RioErr << "[Leader_WaitMulticastBlocks] Ja chegou algum bloco "
02630 << endl;
02631 #endif
02632
02633 empty_buffer = false;
02634 }
02635 else
02636 {
02637 #ifdef RIO_DEBUG2
02638 RioErr << "[Leader_WaitMulticastBlocks] Nenhum bloco chegou... "
02639 << "Esperando mais." << endl;
02640 #endif
02641
02642 if( Paused )
02643 {
02644 PlayPauseMutexLock( "lewtmtbl4" );
02645 empty_buffer = false;
02646 }
02647 else
02648 {
02649 gettimeofday( &now, NULL );
02650 timeout.tv_sec = now.tv_sec + 1;
02651 timeout.tv_nsec = now.tv_usec * 1000;
02652
02653 PlayThreadWaitCondition( &timeout, "lewtmtbl6" );
02654 PlayThreadMutexUnlock( "lewtmtbl6" );
02655
02656 for( i = 0; i < nBuffers; i++ )
02657 {
02658 PlayBuffer = (req_block + i) % nBuffers;
02659
02660 if( CallFreeBlock( PlayBuffer ) == false )
02661 {
02662 #ifdef RIO_DEBUG2
02663 RioErr << "[WaitBlocks] 4 - Bloco esperado ("
02664 << Request[PlayBuffer].Block
02665 << ") nao recuperado " << endl;
02666 #endif
02667 }
02668 }
02669
02670
02671 PlayBuffer = req_block % nBuffers;
02672 exit++;
02673 }
02674
02675 if( exit == ( 3 * nBuffers ) )
02676 {
02677 #ifdef RIO_DEBUG2
02678 RioErr << "Leader_WaitMulticastBlocks - Saindo "
02679 << "e retornando erro. Exit: " << exit << endl;
02680 #endif
02681
02682 return( false );
02683 }
02684 }
02685 }
02686
02687 #ifdef RIO_DEBUG2
02688 RioErr << "[RioMMVideo] Saindo da Leader_WaitMulticastBlocks..." << endl;
02689 #endif
02690
02691 return( true );
02692 }
02693
02694 bool CRioMMVideo::WaitMulticastBlocks()
02695 {
02696 bool empty_buffer = true;
02697 struct timeval now;
02698 struct timespec timeout;
02699 unsigned int i;
02700 unsigned int full = 0;
02701 unsigned int steps = 0;
02702 int expected_block;
02703 int wait_block;
02704
02705 wait_block = Request[PlayBuffer].Block;
02706 expected_block = wait_block;
02707
02708 while( empty_buffer )
02709 {
02710 gettimeofday( &now, NULL );
02711 timeout.tv_sec = now.tv_sec + 5;
02712 timeout.tv_nsec = now.tv_usec * 1000;
02713
02714 #ifdef RIO_DEBUG2
02715 RioErr << "WaitMulticastBlocks - wait_block " << expected_block << endl;
02716 #endif
02717
02718 for( i = 0; i < nBuffers; i++ )
02719 {
02720 if( useCache && bufferStream->exist( i ) )
02721 {
02722 #ifdef RIO_DEBUG2
02723 RioErr << "Bloco " << Request[ i ].Block << " ja existe na cache." << endl;
02724 #endif
02725
02726 full++;
02727 steps++;
02728 }
02729 }
02730
02731
02732
02733 if( ( steps >= nBuffers ) || first )
02734 {
02735 for( i = 0; i < nBuffers; i++ )
02736 {
02737 if( useCache && bufferStream->exist( i ) )
02738 {
02739 Request[ i ].Result = S_OK;
02740 Request[ i ].Status = RIO_REQUEST_COMPLETED;
02741 Request[ i ].Who = this;
02742
02743 #ifdef RIO_DEBUG2
02744 RioErr << "[WaitMulticastBlocks] Gravando bloco "
02745 << Request[ i ].Block << " no PlayOutBuffer "
02746 << i << endl;
02747 #endif
02748
02749 bufferStream->readBlock( Request[ i ].Block,
02750 (unsigned char *) Request[ i ].Buffer );
02751
02752 PlayThreadMutexUnlock( "wtmtbl1" );
02753 SetBufferStatus( i, BUFFERFULL );
02754 }
02755 }
02756
02757 empty_buffer = false;
02758
02759
02760
02761
02762
02763
02764
02765
02766
02767
02768
02769
02770
02771 }
02772 else
02773 {
02774 if( Paused )
02775 {
02776 empty_buffer = false;
02777 PlayPauseMutexLock( "wtmtbl4" );
02778 }
02779 else
02780 {
02781 PlayThreadWaitCondition( &timeout, "wtmtbl5" );
02782 PlayThreadMutexUnlock( "wtmtbl5" );
02783
02784 for( i = 0; i < nBuffers; i++ )
02785 {
02786
02787
02788
02789 if( BufferStatus[i] == BUFFEREMPTY )
02790 {
02791 if( CallFreeBlock( i ) == false )
02792 {
02793 #ifdef RIO_DEBUG2
02794 RioErr << "[WaitBlocks] 5 - Bloco esperado ("
02795 << Request[i].Block
02796 << ") nao recuperado." << endl;
02797 #endif
02798 }
02799 }
02800
02801 steps++;
02802 }
02803
02804 if( ( full == 0 ) &&
02805 ( steps >= ( nBuffers * nBuffers ) )
02806 )
02807 return( false );
02808 }
02809 }
02810 }
02811
02812 return( true );
02813 }
02814
02815
02816
02817
02818
02819
02820 bool CRioMMVideo::ReadBlock( int index, RioBlock block, RioStreamType traffic,
02821 int ip, int port )
02822 {
02823 bool status = true;
02824
02825 #ifdef RIO_EMUL
02826
02827 timeval tv;
02828 gettimeofday( &tv, 0 );
02829 m_log << (double)(tv.tv_sec + ( (double)tv.tv_usec / 1000000 )) ;
02830 m_log << " Pedido: " << block << endl;
02831 requestedBlocks++;
02832 #endif
02833
02834 #ifdef RIO_DEBUG2
02835 struct in_addr printIP;
02836 printIP.s_addr = (unsigned int) ip;
02837 if( traffic == MULTICASTTRAFFIC )
02838 RioErr << "[ReadBlock] Requisitando Multicast. block: " << block
02839 << " ip: " << inet_ntoa( printIP ) << " porta: " << ntohs( port )
02840 << endl;
02841 else
02842 RioErr << "[ReadBlock] Requisitando Patching or Unicast. block: "
02843 << block << " ip: " << inet_ntoa( printIP ) << " porta: "
02844 << ntohs( port ) << endl;
02845 #endif
02846
02847 if( !Read( index, block, traffic, ip, ntohs(my_port) ) )
02848 {
02849 #ifndef RIO_EMUL
02850
02851 sendMsg( QString( "RioMMVideo" ),
02852 QString( "Error receiving data: Server is down?" ),
02853 riomminterface );
02854 #ifdef RIO_DEBUG2
02855 RioErr << "[ReadBlock] Erro no pedido do bloco " << block << endl;
02856 #endif
02857 #endif
02858
02859 status = false;
02860 }
02861
02862 inputLog( REQSERV, block );
02863
02864
02865
02866
02867 ReadBlockStatus = status;
02868
02869 return( status );
02870 }
02871
02872 bool CRioMMVideo::ReadNextBlock( unsigned int index )
02873 {
02874 bool status = true;
02875 bool disableMulticastRequest = false;
02876
02877 #ifdef RIO_DEBUG2
02878 RioErr << "[ReadNextBlock] index = " << index
02879 << ", group_block = " << group_block
02880 << ", NextRequestBlock = " << NextRequestBlock
02881 << ", TotalBlocks = " << TotalBlocks
02882 << ", target = " << target
02883 #ifdef RIO_EMUL
02884 << ", Stopped = " << Stopped
02885 #endif
02886 << ", connectPI = " << connectPI << endl;
02887 #endif
02888
02889
02890
02891
02892
02893
02894
02895 if( group_block != -1 && first )
02896 {
02897
02898
02899
02900
02901
02902
02903
02904
02905
02906 if( (unsigned int) group_block == TotalBlocks )
02907 {
02908 #ifdef RIO_DEBUG2
02909 RioErr << "O bloco relativo a este grupo já alcançou o fim do "
02910 << "vídeo. Como sou líder, deixarei a liderança e não "
02911 << "farei mais pedidos. Enviando ACTION_READBUFFER "
02912 << "para PL." << endl;
02913 #endif
02914
02915
02916
02917
02918
02919
02920
02921
02922
02923
02924 MulticastMutexLock( "renxbl1a" );
02925 CommMultiStream->sendMoveMsg( PID, ACTION_READBUFFER, group_block );
02926 MulticastWaitCondition( "renxbl1a" );
02927 MulticastMutexUnlock( "renxbl1a" );
02928 }
02929 else if( group_block >= target )
02930 {
02931 #ifdef RIO_DEBUG2
02932 RioErr << "O bloco relativo a este grupo é o meu target. "
02933 << "Enviando ACTION_REACHLEADER à PL."
02934 << endl;
02935 #endif
02936
02937
02938
02939
02940
02941
02942 CommMultiStream->sendMoveMsg( PID, ACTION_REACHLEADER,
02943 group_block );
02944 target = INT_MAX;
02945 group_block = -1;
02946
02947 if( patching )
02948 Stream_Control( "renxbl1" );
02949 }
02950 else if( useCache &&
02951 bufferStream->exist( ( unsigned int ) group_block + 1 ) &&
02952 ( ( group_block + 1 ) < target )
02953 )
02954 {
02955 #ifdef RIO_DEBUG2
02956 RioErr << "O bloco relativo a este grupo já está em meu cache."
02957 << " Como sou líder, deixarei a liderança e não farei mais"
02958 << " pedidos. Enviando ACTION_READBUFFER para PL."
02959 << endl;
02960 #endif
02961
02962 MulticastMutexLock( "renxbl1b" );
02963 CommMultiStream->sendMoveMsg( PID, ACTION_READBUFFER,
02964 group_block + 1 );
02965 MulticastWaitCondition( "renxbl1b" );
02966 MulticastMutexUnlock( "renxbl1b" );
02967 }
02968 else
02969 {
02970 #ifdef RIO_DEBUG2
02971 RioErr << "Pedido para grupo. Bloco " << group_block << "."
02972 << endl;
02973 #endif
02974
02975
02976 if( !MulticastRead( group_block, MULTICASTTRAFFIC ) )
02977 {
02978 #ifdef RIO_DEBUG2
02979 RioErr << "[ReadNextBlock] Erro no pedido de bloco multicast "
02980 << group_block << ". É possível que os outros clientes "
02981 << "parem de funcionar caso eu entre aqui!" << endl;
02982 #endif
02983
02984 status = false;
02985 }
02986 else
02987 {
02988
02989
02990 group_block++;
02991 disableMulticastRequest = true;
02992 }
02993 }
02994 }
02995
02996 if( connectPI )
02997 {
02998 if( ( NextRequestBlock < TotalBlocks ) && status )
02999 {
03000 if( bufferStream->exist( NextRequestBlock ) )
03001 {
03002
03003
03004 if( ReadFrom == READFROM_SERVER )
03005 {
03006 if( !disableMulticastRequest )
03007 {
03008
03009
03010
03011
03012
03013
03014
03015 if( first )
03016 {
03017 if( ( group_block == -1 ) &&
03018 ( NextRequestBlock < (RioBlock)target )
03019 )
03020 {
03021
03022
03023
03024
03025
03026 #ifdef RIO_DEBUG2
03027 RioErr << "Cliente vai ler dados do buffer e,"
03028 << " por ser (sub)lider natural, vai "
03029 << "enviar ACTION_READBUFFER pra PL "
03030 << "que saberá o que ele deve fazer."
03031 << endl;
03032 #endif
03033
03034
03035
03036
03037
03038
03039 MulticastMutexLock( "renxbl2" );
03040 CommMultiStream->sendMoveMsg( PID,
03041 ACTION_READBUFFER,
03042 NextRequestBlock );
03043 MulticastWaitCondition( "renxbl2" );
03044 MulticastMutexUnlock( "renxbl2" );
03045 }
03046 #ifdef RIO_DEBUG2
03047 else if( group_block != -1 )
03048 {
03049 RioErr << "Cliente vai ler dados do buffer"
03050 << " mas por ser lider forçado, não "
03051 << "vai enviar ACTION_READBUFFER pra"
03052 << " PL pois está pedindo à frente."
03053 << endl;
03054 }
03055 #endif
03056 }
03057 else
03058 {
03059 if( patching && ( target != INT_MAX ) )
03060 {
03061
03062
03063
03064
03065
03066
03067 #ifdef RIO_DEBUG2
03068 RioErr << "[ReadNextBlock] Cliente tem dados "
03069 << "na cache mas ainda não alcançou "
03070 << "seu target. Verificando se pode "
03071 << "sair do patching." << endl;
03072 #endif
03073
03074 bool keepOnPathcing = true;
03075 for( int i = NextRequestBlock + 1;
03076 ( i <= target ) && keepOnPathcing;
03077 i++
03078 )
03079 {
03080 keepOnPathcing = bufferStream->exist(i);
03081 }
03082
03083
03084
03085 if( !keepOnPathcing )
03086 {
03087 #ifdef RIO_DEBUG2
03088 RioErr << "[ReadNextBlock] Cliente "
03089 << "alcançou o líder antes "
03090 << "do target ser alcançado."
03091 << "Saindo do patching."
03092 << endl;
03093 #endif
03094
03095
03096 CommMultiStream->sendMoveMsg( PID,
03097 ACTION_REACHLEADER,
03098 NextRequestBlock );
03099 target = INT_MAX;
03100 Stream_Control( "renxbl1" );
03101 }
03102 }
03103 }
03104 }
03105 #ifdef RIO_DEBUG2
03106 else if( patching )
03107 RioErr << " NÃO PODERIA ENTRAR AQUI! Como posso ser "
03108 << "líder forçado e estar em patching?!?!?!"
03109 << endl;
03110 #endif
03111
03112 ReadFrom = READFROM_BUFFER;
03113 }
03114 }
03115 else
03116 {
03117
03118
03119 if( !first )
03120 {
03121 if( ReadFrom == READFROM_BUFFER )
03122 {
03123 if( !thereAreFragments( NextRequestBlock ) )
03124 {
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149 #ifdef RIO_DEBUG2
03150 RioErr << "[ReadNextBlock] BLOCO "
03151 << NextRequestBlock
03152 << " NÃO EXISTE - Enviando mensagem "
03153 << "ACTION_PLAY para bloco "
03154 << NextRequestBlock << endl;
03155 #endif
03156
03157 MulticastMutexLock( "renxbl3" );
03158 CommMultiStream->sendMoveMsg( PID, ACTION_PLAY,
03159 NextRequestBlock );
03160 MulticastWaitCondition( "renxbl3" );
03161 MulticastMutexUnlock( "renxbl3" );
03162
03163 ReadFrom = READFROM_SERVER;
03164 }
03165 #ifdef RIO_DEBUG2
03166 else
03167 {
03168 RioErr << "[ReadNextBlock] BLOCO "
03169 << NextRequestBlock
03170 << " NÃO EXISTE mas eu tenho seus "
03171 << "fragmentos e os recuperarei."
03172 << endl;
03173 }
03174 #endif
03175 }
03176 #ifdef RIO_DEBUG2
03177 else
03178 {
03179 RioErr << "[ReadNextBlock] ReadFrom == READFROM_SERVE"
03180 << "R para bloco " << NextRequestBlock << endl;
03181 }
03182 #endif
03183 }
03184 }
03185
03186 if( NextRequestBlock >= (RioBlock)target )
03187 {
03188 #ifdef RIO_DEBUG2
03189 RioErr << "Alcançado o líder... " << NextRequestBlock
03190 << " >= " << (RioBlock)target << endl;
03191
03192 if( useCache && bufferStream->exist( NextRequestBlock ) )
03193 {
03194 RioErr << "Cliente alcançou o líder. Vai ler "
03195 << "dados do buffer e continua "
03196 << "escutando fluxo multicast."
03197 << endl;
03198 }
03199 else
03200 {
03201 RioErr << "Cliente alcançou o líder mas não "
03202 << "tem os dados no buffer. Avisando à "
03203 << "PL." << endl;
03204 }
03205 #endif
03206
03207
03208
03209
03210
03211
03212 CommMultiStream->sendMoveMsg( PID,
03213 ACTION_REACHLEADER,
03214 NextRequestBlock );
03215
03216
03217
03218
03219
03220 target = INT_MAX;
03221
03222 if( patching )
03223 Stream_Control( "reachingLeader" );
03224 }
03225 #ifdef RIO_DEBUG2
03226 else
03227 {
03228 if( target != INT_MAX )
03229 RioErr << "[ReadNextBlock] Patching size = "
03230 << (RioBlock)target - NextRequestBlock
03231 << endl;
03232 else
03233 RioErr << "[ReadNextBlock] No target to reach!"
03234 << endl;
03235 }
03236 #endif
03237 }
03238 else
03239 {
03240 status = false;
03241 }
03242 }
03243
03244 if( ( NextRequestBlock < TotalBlocks ) && status )
03245 {
03246 if( useCache )
03247 {
03248 Request[ index ].Block = NextRequestBlock;
03249 if( bufferStream->readBlock( Request[ index].Block,
03250 ( unsigned char * ) Request[ index ].Buffer ) != 0 )
03251 {
03252
03253 if( connectPI )
03254 {
03255
03256
03257
03258 if( !( first && ( group_block == -1 ) ) )
03259 {
03260 #ifdef RIO_DEBUG2
03261 RioErr << "[ReadNextBlock] bloco "
03262 << NextRequestBlock << " não está na cache"
03263 << ". Verificando se há fragmentos do mesmo"
03264 << endl;
03265 #endif
03266
03267
03268
03269
03270 if( !thereAreFragments( NextRequestBlock ) )
03271 {
03272 #ifdef RIO_DEBUG2
03273 RioErr << "[ReadNextBlock] Não há fragmentos do "
03274 << "bloco " << NextRequestBlock
03275 << ". Solicitando ao servidor." << endl;
03276 #endif
03277
03278
03279
03280
03281 status = ReadBlock( index, NextRequestBlock,
03282 UNICASTTRAFFIC,
03283 my_address, my_port );
03284 }
03285 else
03286 {
03287 if( CallFreeBlock( index ) == false )
03288 {
03289 #ifdef RIO_DEBUG2
03290 RioErr << "[ReadNextBlock] Bloco "
03291 << Request[PlayBuffer].Block
03292 << " nao recuperado." << endl;
03293 #endif
03294 }
03295 #ifdef RIO_DEBUG2
03296 else
03297 {
03298 RioErr << "[ReadNextBlock] Bloco "
03299 << NextRequestBlock << " tem fragmentos "
03300 << "recebidos via multicast e estes "
03301 << "foram recuperados." << endl;
03302 }
03303 #endif
03304
03305
03306
03307
03308
03309 #ifdef RIO_DEBUG2
03310 int freedPendentsSize = FreePendentBlocks( useCache,
03311 nBuffers );
03312
03313 RioErr << "[RioMMVideo] ReadNextBlock - "
03314 << "FreePendentBlocks liberou "
03315 << freedPendentsSize << " bytes de blocos "
03316 << "pendentes." << endl;
03317 #else
03318 FreePendentBlocks( useCache, nBuffers );
03319 #endif
03320 }
03321
03322 }
03323 else
03324 {
03325
03326 #ifdef RIO_DEBUG2
03327 RioErr << "[ReadNextBlock] Bloco " << NextRequestBlock
03328 << " não está na cache. Sou lider natural e o "
03329 << "pedirei para o grupo." << endl;
03330 #endif
03331 status = ReadBlock( index, NextRequestBlock,
03332 MULTICASTTRAFFIC,
03333 0, 0 );
03334 }
03335 }
03336 else
03337 {
03338 #ifdef RIO_EMUL
03339 gettimeofday( &timers[ index ].call_time, 0);
03340 #endif
03341
03342 #ifdef RIO_DEBUG2
03343 RioErr << "[ReadNextBlock] Sou cliente unicast. "
03344 << "Pedindo bloco " << NextRequestBlock
03345 << "." << endl;
03346 #endif
03347
03348 status = ReadBlock( index, NextRequestBlock,
03349 UNICASTTRAFFIC, my_address,
03350 my_port );
03351 }
03352 }
03353 else
03354 {
03355
03356
03357 #ifdef RIO_EMUL
03358
03359 timeval tv;
03360 gettimeofday( &tv, 0 );
03361 m_log << (double)(tv.tv_sec + ((double)tv.tv_usec / 1000000 ));
03362 m_log << " Recuperado da cache: " << NextRequestBlock << endl;
03363 #endif
03364
03365 #ifdef RIO_DEBUG2
03366 RioErr << "[ReadNextBlock] Bloco " << NextRequestBlock
03367 << " foi encontrado na cache e será gravado no "
03368 << "PlayOutBuffer " << index << endl;
03369 #endif
03370
03371 inputLog( REQCACHE, NextRequestBlock );
03372
03373
03374 int inc;
03375 inc = index;
03376 calculete_RTT[ index ].block = inc++;
03377
03378 Request[ index ].Block = NextRequestBlock;
03379 Request[ index ].Result = S_OK;
03380 Request[ index ].Status = RIO_REQUEST_COMPLETED;
03381 Request[ index ].Who = this;
03382
03383 PlayThreadMutexUnlock( "renxbl4" );
03384 SetBufferStatus( index, BUFFERFULL );
03385 }
03386 }
03387 else
03388 {
03389 #ifdef RIO_DEBUG2
03390 RioErr << "[ReadNextBlock] Não uso cache. "
03391 << "Pedindo bloco " << NextRequestBlock
03392 << " unicast." << endl;
03393 #endif
03394
03395 status = ReadBlock( index, NextRequestBlock, UNICASTTRAFFIC,
03396 my_address, my_port );
03397 }
03398
03399 NextRequestBlock++;
03400 }
03401 else
03402 {
03403 status = false;
03404 }
03405
03406 return( status );
03407 }
03408
03409
03410
03411
03412
03413
03414 void CRioMMVideo::Stream_Control( string msg )
03415 {
03416 #ifdef RIO_DEBUG2
03417 RioErr << "[Stream_Control] " << msg << endl;
03418 #endif
03419
03420 if( patching )
03421 {
03422 patching = false;
03423
03424 #ifdef RIO_EMUL
03425
03426 multicast = -1;
03427 if( connectPI )
03428 CommMultiStream->sendFluxoMsg( PID, -1,
03429 multicast );
03430 #endif
03431
03432 #ifdef RIO_DEBUG2
03433 RioErr << "[RioMMVideo] Cliente " << PID << " saiu do patching "
03434 << endl;
03435 #endif
03436 }
03437 else
03438 {
03439 patching = true;
03440
03441 #ifdef RIO_EMUL
03442
03443 multicast = -1;
03444
03445 if( connectPI )
03446 CommMultiStream->sendFluxoMsg( PID, 1,
03447 multicast );
03448 #endif
03449
03450 #ifdef RIO_DEBUG2
03451 RioErr << "[RioMMVideo] Cliente " << PID << " entrou no patching "
03452 << endl;
03453 #endif
03454 }
03455 }
03456
03457
03458
03459
03460 void CRioMMVideo::StartPlayer()
03461 {
03462 setbuffer( stdin, pipe_buffer, (size_t)MaxPipeDataSize );
03463
03464 if( pipe( pipe_player ) < 0 )
03465 {
03466 Rioperror("pipe(). Failed to create pipe to player.");
03467 return;
03468 }
03469
03470
03471 if( dup2( pipe_player[0], 0 ) == -1 )
03472 {
03473 Rioperror("dup2(). Failed to associate pipe to stdin.");
03474 return;
03475 }
03476 setbuffer( stdin, pipe_buffer, (size_t)MaxPipeDataSize );
03477
03478
03479 if( (playerPID = fork()) != 0 )
03480 {
03481 if( playerPID < 0 )
03482 {
03483 Rioperror("fork(). Failed to fork process.");
03484 return;
03485 }
03486 }
03487 else
03488 {
03489 #ifndef RIO_DEBUG2
03490 int null_file;
03491
03492
03493 null_file = open( "/dev/null", O_WRONLY );
03494 if( null_file != -1 )
03495 {
03496 dup2( null_file, 1 );
03497 dup2( null_file, 2 );
03498 }
03499 #endif
03500
03501 int argc = 0;
03502 char **argv;
03503 QString title(MMObjectName);
03504 QString wId_str;
03505
03506 argv=(char**)malloc(sizeof(char*)*(playerCmdLine->count() + 1));
03507 wId_str.sprintf("%d",wId);
03508 for( QStringList::Iterator it=playerCmdLine->begin();
03509 it != playerCmdLine->end();
03510 it++
03511 )
03512 {
03513 (*it).replace( "%w", wId_str );
03514 (*it).replace( "%s", subTitle->GetLocalFilename() );
03515 (*it).replace( "%t", title.section('/',-1) );
03516 argv[ argc++ ] = strdup( (*it).latin1() );
03517 }
03518
03519
03520
03521
03522
03523 argv[ argc++ ] = NULL;
03524 if( execvp( argv[ 0 ], argv ) < 0 )
03525 {
03526 Rioperror( "execvp(): Failed to execute mpeg player" );
03527 exit( 1 );
03528 }
03529 }
03530 }
03531
03532 void CRioMMVideo::CallBack( struct RioRequest *request )
03533 {
03534 CRioMMVideo *videoPtr;
03535
03536 #ifdef RIO_DEBUG2
03537 RioErr << "[RioMMVideo] Entrei na CallBack" << endl;
03538 #endif
03539
03540
03541
03542
03543 {
03544 #ifdef RANDOM_LOSS
03545 if( rand()<(RAND_MAX/2) )
03546 {
03547 }
03548 else
03549 #endif
03550 {
03551 videoPtr = (CRioMMVideo *)request->Who;
03552
03553 videoPtr->inputLog( ARRIVING, request->Block );
03554
03555 int index = request->Block % videoPtr->nBuffers;
03556
03557 #ifdef RIO_EMUL
03558
03559 gettimeofday( &videoPtr->timers[
03560 (int) (long long int) request->User].arrival_time,
03561 0);
03562
03563 videoPtr->final_time.tv_sec =
03564 videoPtr->timers[
03565 (int) (long long int) request->User].arrival_time.tv_sec -
03566 videoPtr->timers[(int) (long long int) request->User].call_time.tv_sec;
03567 videoPtr->final_time.tv_usec =
03568 videoPtr->timers[
03569 (int) (long long int) request->User].arrival_time.tv_usec -
03570 videoPtr->timers[
03571 (int) (long long int) request->User].call_time.tv_usec;
03572
03573 if( videoPtr->final_time.tv_usec < 0 )
03574 {
03575 videoPtr->final_time.tv_sec -= 1;
03576 videoPtr->final_time.tv_usec += 1000000;
03577 }
03578
03579 videoPtr->calculeted_time = ( unsigned int )
03580 ( videoPtr->final_time.tv_sec * 1000.0 +
03581 videoPtr->final_time.tv_usec/1000.0
03582 );
03583 #endif
03584
03585 if( videoPtr->GetBufferStatus( (int) (long long int) request->User ) == BUFFEREMPTY )
03586 {
03587
03588
03589
03590
03591
03592
03593
03594 if( request->reqid == videoPtr->Request[ index ].reqid )
03595 {
03596
03597
03598 videoPtr->SetBufferStatus( (int) (long long int) request->User, BUFFERFULL );
03599 }
03600 #ifdef RIO_DEBUG2
03601 else
03602 {
03603 RioErr << "[CallBack] request->reqid = " << request->reqid
03604 << " videoPtr->Request[ index ].reqid = "
03605 << videoPtr->Request[ index ].reqid
03606 << endl;
03607 }
03608 #endif
03609
03610 #ifdef RIO_DEBUG2
03611 RioErr << "[RioMMVideo] CallBack VIDEO BLOCK: "
03612 << request->Block << endl;
03613 #endif
03614
03615 #ifdef RIO_EMUL
03616 timeval tv;
03617 gettimeofday( &tv, 0 );
03618 videoPtr->m_log << (double)(tv.tv_sec +
03619 ( (double)tv.tv_usec / 1000000 )) ;
03620 videoPtr->m_log << " Recepção: " << request->Block << endl;
03621 #endif
03622 }
03623 #ifdef RIO_DEBUG2
03624 else
03625 {
03626 RioErr << "[RioMMVideo] CallBack: Buffer já se encontra cheio na"
03627 << " posicao " << request->User << ". Bloco "
03628 << request->Block << " (reqid " << request->reqid
03629 << ") deve ter sido requisitado mais de uma vez."
03630 << endl;
03631 }
03632 #endif
03633
03634
03635 if( videoPtr->useCache )
03636 {
03637 #ifdef RIO_DEBUG2
03638 RioErr << "!videoPtr->bufferStream->"
03639 << "exist( request->Block ) "
03640 << !videoPtr->bufferStream->exist( request->Block )
03641 << " request->reqid " << request->reqid
03642 << " videoPtr->Request[ index ].reqid "
03643 << videoPtr->Request[ index ].reqid
03644 << " videoPtr->useCache " << videoPtr->useCache
03645 << " index " << index << endl;
03646 #endif
03647
03648 if( !videoPtr->bufferStream->exist( request->Block ) )
03649 {
03650 #ifdef RIO_DEBUG2
03651 RioErr << "[CallBack] Gravando bloco "
03652 << request->Block << " (reqid "
03653 << request->reqid << ") na cache."
03654 << endl;
03655 #endif
03656
03657 videoPtr->bufferStream->writeBlock( request->Block,
03658 (unsigned char *) request->Buffer );
03659 }
03660 }
03661 #ifdef RIO_DEBUG2
03662 else
03663 {
03664 RioErr << "[CallBack] Cache desabilitado. Bloco "
03665 << request->Block << " nao sera gravado."
03666 << endl;
03667 }
03668 #endif
03669 }
03670 }
03671
03672 #ifdef RIO_DEBUG2
03673 RioErr << "[RioMMVideo] Saindo da CallBack " << endl;
03674 #endif
03675 }
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685 void CRioMMVideo::MulticastCallBack( void *parm, int result )
03686 {
03687 RioCallBackTransport *callback = (RioCallBackTransport *) parm;
03688 CRioMMVideo *videoPtr = (CRioMMVideo *) callback->object;
03689 bool blockRecorded = false;
03690
03691 #ifdef RIO_DEBUG2
03692 RioErr << "[MulticastCallBack] PID: " << videoPtr->PID
03693 << ", callback->block: " << callback->block
03694 << ", first: " << videoPtr->first
03695 << ", patching = " << videoPtr->patching << endl;
03696 #endif
03697
03698
03699
03700 for( unsigned int index = 0; index < videoPtr->nBuffers; index ++ )
03701 {
03702 if( ( signed ) videoPtr->Request[ index ].Block == callback->block )
03703 {
03704 if( videoPtr->GetBufferStatus( index ) == BUFFEREMPTY )
03705 {
03706 blockRecorded = true;
03707 #ifdef RIO_DEBUG2
03708 RioErr << "MulticastCallBack - copiando bloco "
03709 << callback->block << ", "
03710 << videoPtr->Request[ index ].Size
03711 << " bytes, para PlayOutBuffer " << index << endl;
03712 #endif
03713
03714 videoPtr->Request[ index ].User = (void *) index;
03715 videoPtr->Request[ index ].Block = callback->block;
03716 videoPtr->Request[ index ].Result = S_OK;
03717 videoPtr->Request[ index ].Status = RIO_REQUEST_COMPLETED;
03718 videoPtr->Request[ index ].Who = videoPtr;
03719 memcpy( videoPtr->Request[ index ].Buffer, callback->data,
03720 videoPtr->Request[ index ].Size );
03721
03722 videoPtr->SetBufferStatus( index, BUFFERFULL );
03723 }
03724 #ifdef RIO_DEBUG2
03725 else
03726 {
03727 RioErr << "[MulticastCallBack] BUFFERFULL: Bloco não será gravado "
03728 << "na cache." << endl;
03729 }
03730 #endif
03731 break;
03732 }
03733 }
03734
03735 #ifdef RIO_DEBUG2
03736 if( !blockRecorded )
03737 {
03738 RioErr << "[MulticastCallBack] Bloco recebido("
03739 << callback->block << ") não será gravado no "
03740 << "PlayOutBuffer por não ser um dos blocos esperados" << endl;
03741 }
03742 #endif
03743
03744
03745 #ifdef RIO_DEBUG2
03746 RioErr << "[MulticastCallBack] Gravando bloco " << callback->block
03747 << " na cache." << endl;
03748 #endif
03749
03750 if( videoPtr->useCache )
03751 {
03752 if( !videoPtr->bufferStream->exist( callback->block ) )
03753 {
03754 #ifdef RIO_DEBUG2
03755 RioErr << "[CallBack] Gravando bloco "
03756 << callback->block << " na cache."
03757 << endl;
03758 #endif
03759
03760 videoPtr->bufferStream->writeBlock( callback->block,
03761 (unsigned char *) callback->data );
03762 }
03763 #ifdef RIO_DEBUG2
03764 else
03765 {
03766 RioErr << "[MulticastCallBack] Bloco " << callback->block
03767 << " já existe na cache e será descartado."
03768 << endl;
03769 }
03770 #endif
03771 }
03772 #ifdef RIO_DEBUG2
03773 else
03774 {
03775 RioErr << "[MulticastCallBack] Cache desabilitado. Bloco "
03776 << callback->block << " nao sera gravado."
03777 << endl;
03778 }
03779 #endif
03780
03781
03782
03783 delete[] callback->data;
03784 delete callback;
03785
03786 #ifdef RIO_EMUL
03787 int index = callback->block % videoPtr->nBuffers;
03788
03789 gettimeofday( &videoPtr->timers[ index ].arrival_time, 0);
03790
03791 videoPtr->final_time.tv_sec =
03792 videoPtr->timers[ index ].arrival_time.tv_sec -
03793 videoPtr->initial_time.tv_sec;
03794 videoPtr->final_time.tv_usec =
03795 videoPtr->timers[ index ].arrival_time.tv_usec -
03796 videoPtr->initial_time.tv_usec;
03797
03798 if( videoPtr->final_time.tv_usec < 0 )
03799 {
03800 videoPtr->final_time.tv_sec -= 1;
03801 videoPtr->final_time.tv_usec += 1000000;
03802 }
03803
03804 videoPtr->calculeted_time = ( unsigned int )
03805 ( videoPtr->final_time.tv_sec * 1000.0 +
03806 videoPtr->final_time.tv_usec/1000.0
03807 );
03808 #endif
03809 }
03810
03811 void CRioMMVideo::ClearBuffer()
03812 {
03813 unsigned int i;
03814
03815 #ifdef RIO_DEBUG2
03816 RioErr << "[ClearBuffer] Limpando buffer..." << endl;
03817 RioErr << "\t fullBuffers = " << fullBuffers << endl;
03818 #endif
03819
03820 for( i = 0; i < nBuffers; i++ )
03821 {
03822 #ifdef RIO_DEBUG2
03823 RioErr << "[ClearBuffer] Cancelando espera do bloco "
03824 << Request[i].Block << ", reqid " << Request[i].reqid << endl;
03825 #endif
03826
03827 Object.CancelExpect( Request[i].reqid );
03828
03829 #ifdef RIO_DEBUG2
03830 RioErr << "\t BufferStatus = " << BufferStatus[i] << "==>0" << endl;
03831 RioErr << "\t Result = " << Request[i].Result << "==>0" << endl;
03832 RioErr << "\t Status = " << Request[i].Status << "==>0" << endl;
03833 RioErr << "\t reqid = " << Request[i].reqid << "==>0" << endl;
03834 RioErr << "\t Block = " << Request[i].Block << " ==> não muda." << endl;
03835 RioErr << "\t -----------------------" << endl;
03836 #endif
03837
03838 BufferStatus[i] = BUFFEREMPTY;
03839 Request[i].User = (void *)i;
03840 Request[i].Result = S_OK;
03841 Request[i].Status = RIO_REQUEST_FREE;
03842 Request[i].reqid = 0;
03843 }
03844 fullBuffers = 0;
03845 }
03846
03847 int CRioMMVideo::FreeBlock( int PlayBuffer )
03848 {
03849 RioStreamType traffic;
03850 unsigned int free_block;
03851
03852 if( connectPI && !bufferStream->isUnicast( Request[ PlayBuffer ].Block ) )
03853 {
03854 traffic = MULTICASTTRAFFIC;
03855
03856
03857
03858
03859
03860
03861 free_block = Request[ PlayBuffer ].Block;
03862
03863 #ifdef RIO_DEBUG2
03864 RioErr << "[RioMMVideo] Chamada a FreeBlock pra bloco de id "
03865 << free_block << " modo MULTICAST." << endl;
03866 #endif
03867 }
03868 else
03869 {
03870 traffic = UNICASTTRAFFIC;
03871 free_block = Request[ PlayBuffer ].reqid;
03872
03873 #ifdef RIO_DEBUG2
03874 RioErr << "[RioMMVideo] Chamada a FreeBlock pra bloco de id "
03875 << free_block << " modo UNICAST." << endl;
03876 #endif
03877 }
03878
03879 return( Object.FreeBlock( free_block, traffic ) );
03880 }
03881
03882 int CRioMMVideo::FreePendentBlocks( bool useCache, int nBuffers )
03883 {
03884 return( Object.FreePendentBlocks( useCache, nBuffers ) );
03885 }
03886
03887 bool CRioMMVideo::thereAreFragments( RioBlock block )
03888 {
03889 return( Object.thereAreFragments( block ) );
03890 }
03891
03892 void CRioMMVideo::SetWID( int windowId )
03893 {
03894 wId = windowId;
03895 }
03896
03897
03898
03899
03900
03901
03902
03903 void CRioMMVideo::writeDefaultSettings()
03904 {
03905 ConfigData config;
03906 config.writeDefaultRioMMVideoSettings();
03907 config.readRioMMClientSettings();
03908
03909 player = DEFAULT_PLAYER;
03910 playerCmdLine = new QStringList( config.getRioMMVMPlayerBinary() );
03911 if( wId != 0 )
03912 {
03913 *playerCmdLine += QStringList::split( " ", config.getRioMMVMPlayerEmbeded() );
03914 }
03915 *playerCmdLine += QStringList::split( " ", config.getRioMMVMPlayerArguments() );
03916 }
03917
03918
03919
03920
03921
03922
03923 bool CRioMMVideo::readSettings()
03924 {
03925 ConfigData config;
03926 bool ok1 = false,
03927 ok2 = false;
03928 QString temp, opt_value;
03929 QStringList keys;
03930
03931 config.readRioMMClientSettings();
03932 opt_value = config.getRioMMVVersion();
03933 if( opt_value != QString::null )
03934 {
03935
03936
03937
03938
03939 if( opt_value == RIORC_RIOMMVIDEO_VERSION )
03940 {
03941 ok1 = true;
03942
03943 #ifndef RIO_EMUL
03944 opt_value = config.getRioMMVMakelog();
03945 if( opt_value == "false" )
03946 makeLog = false;
03947 else
03948 makeLog = true;
03949 #else
03950
03951 makeLog = false;
03952 #endif
03953
03954 player = config.getRioMMVPlayer();
03955 if( player != QString::null )
03956 {
03957 ok2 = true;
03958 temp = config.getRioMMVMPlayerBinary();
03959 if( playerCmdLine )
03960 delete playerCmdLine;
03961 playerCmdLine = new QStringList();
03962 playerCmdLine->append( temp );
03963
03964 #ifndef RIO_EMUL
03965 if( HasSubTitle )
03966 *playerCmdLine += QStringList::split( " ",
03967 config.getRioMMVMPlayerSubtitle() );
03968 #endif
03969
03970 if( wId != 0 )
03971 {
03972 *playerCmdLine += QStringList::split( " ",
03973 config.getRioMMVMPlayerEmbeded() );
03974 }
03975
03976 *playerCmdLine += QStringList::split( " ",
03977 config.getRioMMVMPlayerArguments() );
03978 }
03979 }
03980 }
03981
03982 return( ok1 && ok2 );
03983 }
03984
03985 const bool CRioMMVideo::getmakeLog()
03986 {
03987 return makeLog;
03988 }
03989
03990
03991
03992
03993
03994
03995
03996 int CRioMMVideo::ProcessSignal( int sig, void *data )
03997 {
03998 int status = 0;
03999 switch( sig )
04000 {
04001 case SIGHUP:
04002 readSettings();
04003 break;
04004
04005 case SIGCHLD:
04006 if( (int) (long long int) data == playerPID )
04007 status = 2;
04008 break;
04009 }
04010
04011
04012 if( status != 2 )
04013 CRioMMObject::ProcessSignal( sig, data );
04014
04015 return( status );
04016 }
04017
04018 unsigned int CRioMMVideo::getCurrentPlayingBlock()
04019 {
04020 unsigned int currentPlayingBlock;
04021
04022 if( PlayThreadID == 0 )
04023 currentPlayingBlock = 0;
04024 else
04025 currentPlayingBlock = Request[ PlayBuffer ].Block;
04026
04027 return currentPlayingBlock;
04028 }
04029
04030
04031
04032
04033 void CRioMMVideo::appendLog( QString text )
04034 {
04035 if( makeLog == false )
04036 return;
04037
04038 pthread_mutex_lock( &log_mutex );
04039 logAppend += text;
04040 pthread_mutex_unlock( &log_mutex );
04041 }
04042
04043 void CRioMMVideo::inputLog( QString text )
04044 {
04045 if( makeLog == false )
04046 return;
04047
04048 pthread_mutex_lock( &log_mutex );
04049 logData += text;
04050 pthread_mutex_unlock( &log_mutex );
04051 }
04052
04053 void CRioMMVideo::inputLog( int action, unsigned int block, unsigned int size )
04054 {
04055 if( makeLog == false )
04056 return;
04057
04058 struct timeval time;
04059 long long int total_time;
04060
04061 gettimeofday( &time, 0 );
04062 total_time = (1000000 * (long long int) time.tv_sec) +
04063 (long long int)time.tv_usec;
04064
04065 pthread_mutex_lock( &log_mutex );
04066
04067 #ifdef USE_QT_GRID
04068
04069 logAction += QString().sprintf( "%lli\t", total_time );
04070 #else
04071 logAction += QString( "%1\t" ).arg( total_time );
04072 #endif
04073
04074 switch( action )
04075 {
04076 case BPLAY:
04077 logAction += "bplay";
04078 break;
04079 case BPAUSE:
04080 logAction += "bpause";
04081 break;
04082 case BFFORWARD:
04083 logAction += "bffwrd";
04084 break;
04085 case BFREWIND:
04086 logAction += "bfrew";
04087 break;
04088 case STOP:
04089 logAction += "stop";
04090 break;
04091 case PLAYING:
04092 logAction += "plays";
04093 break;
04094 case JUMPBAR:
04095 logAction += "jmpbar";
04096 break;
04097 case JUMPTOPIC:
04098 logAction += "jmptop";
04099 break;
04100 case REQSERV:
04101 logAction += "reqserv";
04102 break;
04103 case REQCACHE:
04104 logAction += "reqcache";
04105 break;
04106 case ARRIVING:
04107 logAction += "arrives";
04108 break;
04109 case QUIT:
04110 logAction += "quit";
04111 }
04112
04113 if( action != QUIT )
04114 logAction += QString( "\t%1" ).arg( block );
04115
04116 if( action == PLAYING )
04117 logAction += QString( "\t%1\n" ).arg( size );
04118 else
04119 logAction += "\n";
04120
04121 pthread_mutex_unlock( &log_mutex );
04122
04123
04124 if( action == QUIT )
04125 {
04126 time_t t;
04127 t = ::time( NULL );
04128
04129 pthread_mutex_lock( &log_mutex );
04130
04131 logData.prepend( QString( "Log date: %1").arg( ctime( &t ) ) );
04132
04133
04134
04135
04136 int ins_pos = logData.find(
04137 "\n------------------Command Options-----------------\n" );
04138 logData.insert( ins_pos, logAppend );
04139
04140
04141 logData.append( logAction );
04142
04143 char logFileName[MAXNAMELEN] = "";
04144 strcpy( logFileName, "/tmp/RIOActionLog.XXXXXX" );
04145
04146 int fd = mkstemp( logFileName );
04147 if( fd )
04148 close( fd );
04149 else
04150 {
04151 RioErr << "Could not create file " << logFileName << endl;
04152 return;
04153 }
04154
04155 QFile logFile( QString( "%1" ).arg( logFileName ) );
04156 QTextStream tslogFile;
04157 if( !logFile.open( IO_WriteOnly ) )
04158 {
04159 RioErr << "Could not open created file " << logFileName << endl;
04160 return;
04161 }
04162
04163 tslogFile.setDevice( &logFile );
04164 tslogFile << logData.latin1();
04165
04166 pthread_mutex_unlock( &log_mutex );
04167
04168
04169 logFile.close();
04170
04171 QString src;
04172 QString dst;
04173 ObjectInfo objectInfo;
04174 gzFile zipfile;
04175 int logfile;
04176 int byread;
04177 char buf[ 1024 ];
04178 bool status = true;
04179
04180
04181 src = QString( "%1.gz" ).arg( logFileName );
04182 zipfile = gzopen( src.ascii(), "w9" );
04183 logfile = open( logFileName, O_RDONLY );
04184
04185 while( ( byread = read( logfile, buf, 1024 ) ) > 0 )
04186 gzwrite( zipfile, buf, byread );
04187
04188 close( logfile );
04189 gzclose( zipfile );
04190
04191
04192 dst = QString( "/var/log/%1" ).arg( src ).remove( "/tmp/" );
04193
04194 status = rioMMExplorer->getObjectInfo( ( char* )src.ascii(), NULL,
04195
04196 &objectInfo );
04197
04198 bool copy_allowed = true;
04199
04200 if( status )
04201 status = rioMMExplorer->cp( NULL, rioMMExplorer->getSession(),
04202 &objectInfo, ( char* )dst.ascii(),
04203 false, false, ©_allowed );
04204 if( !status )
04205 RioErr << "nao consegui fazer o upload do arquivo de log." << endl;
04206
04207
04208
04209 if( rioMMExplorer->rm( &objectInfo, NULL, false ) == false )
04210 {
04211 #ifdef RIO_DEBUG2
04212 RioErr << "Nao consegui remover o arquivo temporario "
04213 << objectInfo.getFullName() << "." << endl;
04214 #endif
04215 }
04216
04217
04218 if( !rioMMExplorer->getObjectInfo( logFileName, NULL, &objectInfo ) ||
04219 !rioMMExplorer->rm( &objectInfo, NULL, false )
04220 )
04221 {
04222 #ifdef RIO_DEBUG2
04223 RioErr << "Nao consegui remover o arquivo temporario "
04224 << objectInfo.getFullName() << "." << endl;
04225 #endif
04226 }
04227 }
04228 }
04229
04230 bool CRioMMVideo::isPatching()
04231 {
04232 return patching;
04233 }
04234
04235 void CRioMMVideo::SetTarget( int target )
04236 {
04237 this->target = target;
04238 }
04239
04240 void CRioMMVideo::SetNextRequestBlock( int block )
04241 {
04242 NextRequestBlock = block;
04243 }