⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qmmpg123player.cpp

📁 可以播放MP3,wma等文件格式的播放器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* qmmpg123player.cpp * * $Id: qmmpg123player.cpp,v 1.56.2.2 2002/10/11 06:39:03 kyllingstad Exp $ * * Apollo sound player: http://www.apolloplayer.org * Copyright(C) 2000-2002 Apollo Team.  See CREDITS file. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. * * The GNU General Public License is also available online at: * * http://www.gnu.org/copyleft/gpl.html */#include <errno.h>#include <iostream>#include <signal.h>#include <stdio.h>#include <string.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/wait.h>#include <unistd.h>#include <qfile.h>#include <qfileinfo.h>#include <qmessagebox.h>#include <qsocketnotifier.h>#include <qtextstream.h>#include <qtimer.h>#include "qmmpg123player.h"#include "qmconfig.h"bool 	QmMpg123Player::s_OurTermSignal = false;bool 	QmMpg123Player::s_FailFlag 		= false;/** * @file qmmpg123player.cpp * @brief Interface to mpg123*//*!  \class QmMpg123Player qmmpg123player.h  \brief Provides functionality for communicating with mpg123.  This class is used to communicate with <a href="http://www.mpg123.com">mpg123</a>  to play MP3 files.  The communication is done through pipes.  Apollo sends a set  of commands to mpg123, and mpg123 provides Apollo with playing info.  Some of the code in this class was taken from Andreas Neuhaus' IRMP3.    \warning The current mpg123 version does not handle all MP3 files very well.  With  some MP3 files, mpg123 will provide faulty playing info but play the song correctly.  The user interface will try to detect this, but may still act a little weird.  \warning mpg123 is very buggy with a buffer enabled.  Stop is not immediate (Pause  seems to be, though), jump forward is not immediate (but jump backward seems to be)  and not even quit is immediate.*//*!  Initializes the player with some variables.  The player is not started.  Call  init() for that.*/QmMpg123Player::QmMpg123Player()	: QmPlayer(0, 0),	  m_ID3Format( "%1 - %2" ),	  m_Playing( false ),	  m_Paused( false ),	  m_NewSong( false ),	  m_GotNewSong( false ),	  m_BufferLeftovers( 0 ),	  m_SendFd( 0 ),	  m_RecvFd( 0 ),	  m_PlayerPid( 0 ),      m_BufferPid( 0 ),	  m_FrameCount( 0 ),	  m_Seconds( 0 ){	s_OurTermSignal = false;	s_FailFlag 		= false;    m_pTimer 		= new QTimer( this );    connect( m_pTimer, SIGNAL( timeout() ),             this, SLOT( releaseTimingInformation() ) );}/*!  Sends a termination signal to the mpg123 process.  \sa terminate()*/QmMpg123Player::~QmMpg123Player(){	terminate();}/*!  Terminates the player.  \sa init() */voidQmMpg123Player::terminate(){	s_OurTermSignal = true;	strcpy(m_WriteBuffer, "QUIT");	sendCommand( m_WriteBuffer );//kill(m_PlayerPid, SIGQUIT);//kill(m_PlayerPid, SIGTERM);#ifdef ENABLE_MPG123_BUFFER	kill(m_PlayerPid, SIGKILL);#endif	delete m_pReadNotifier;	close(m_SendFd);	close(m_RecvFd);}/*!  Starts mpg123.  If a mpg123 process is already running, it will  be terminated and another one restarted.  \return -1 if failure, 0 otherwise.  \sa terminate()*/intQmMpg123Player::init(){	// check if player is already running	if(m_PlayerPid != 0)		terminate();	// make socketpair to communicate with player	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd_send) < 0)		return -1;	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd_recv) < 0)		return -1;	// handle signals	signal(SIGPIPE, SIG_IGN);	signal(SIGUSR1, QmMpg123Player::failHandler);	struct sigaction *tmp = new struct sigaction; 	tmp->sa_handler = QmMpg123Player::childHandler; 	tmp->sa_flags = SA_NOCLDSTOP; 	sigaction(SIGCHLD, tmp, 0);	QmConfig *conf = QmConfig::instance();	QString mpgpath = conf->getString( "mpg123", "path" );	QFileInfo mpg123player(mpgpath); 	if( ! (mpg123player.exists() && mpg123player.isExecutable())) 	{		QMessageBox::critical(			0,			QObject::tr("Apollo Error"),			QObject::tr("Apollo tried to start the mpg123 player as:<br>"						"<center>\"%1\"</center><br>"						"but failed."						"<p>"						"Does the file exists and is it executable?"						"<p>"						"You can specify the mpg123 path in the configuration dialog.").arg(mpgpath));		return -1;	}		m_PlayerPid = fork();		if (m_PlayerPid == 0)	{		// pipe in/output through socket to parent		dup2(fd_send[0], STDIN_FILENO);		close(fd_send[0]);		close(fd_send[1]);		dup2(fd_recv[0], STDOUT_FILENO);		dup2(fd_recv[0], STDERR_FILENO);		close(fd_recv[0]);		close(fd_recv[1]);        QString buffer = conf->getString( "mpg123", "buffer" );        int buffer_size = buffer.toInt()*1024; // Multiply to get Kb        buffer.sprintf( "%d", buffer_size );		int rc = 0;        QString channels = conf->getString( "mpg123", "channels" );        int downsample = conf->getInt( "mpg123", "downsample" );        if ( downsample < 0 || downsample > 2 )            downsample = 0;		// Spawn player.  -R for starting mpg123 in remote mode (i.e. we're using		// mpg123 through commands via pipe).  The last argument, '-', is necessary		// otherwise mpg123 will quit immediately (dash is an alternative to an		// URL or file name).        const char *args[10];        int i = 0;		QString artsdsp = conf->getString("mpg123", "artsdsp");		QFileInfo artsdspi(artsdsp);		// debug: exists || warn user; executable || warn user		if ( artsdspi.isExecutable() )		{			args[i++] = artsdsp.latin1(); 			args[i++] = "-m";			args[i++] = mpgpath.latin1();		}		else			args[i++] = mpgpath.latin1();        if ( buffer != "0" )        {            args[i++] = "-b";            args[i++] = buffer.ascii();        }        if ( channels == "mono" )            args[i++] = "-m";        if ( downsample != 0 )            args[i++] = downsample == 1 ? "-2" : "-4";        args[i++] = "-R";        args[i++] = "-";        args[i++] = 0;        rc = execvp(args[0], (char *const *)args);		// Note that all std ouput is now piped to the parent.//         const char *args[8];//         int i = 0;//         args[i++] = mpgpath.ascii();//         if ( buffer != "0" )//         {//             args[i++] = "-b";//             args[i++] = buffer.ascii();//         }//         if ( channels == "mono" )//             args[i++] = "-m";//         if ( downsample != 0 )//             args[i++] = downsample == 1 ? "-2" : "-4";//         args[i++] = "-R";//         args[i++] = "-";//         args[i++] = 0;//         rc = execvp(mpgpath.ascii(), (char *const *)args);		// never reached if exec was ok		_exit(-1);	}	// parent (Apollo) continues here	close(fd_send[0]);	m_SendFd = fd_send[1];	close(fd_recv[0]);	m_RecvFd = fd_recv[1];		m_pReadNotifier = new QSocketNotifier(m_RecvFd, QSocketNotifier::Read);	QObject::connect(m_pReadNotifier, SIGNAL(activated(int)), this, SLOT(dataReceived()));		FD_SET(m_RecvFd, &mpg123_fdset);	s_OurTermSignal = false;	// Check whether we have a child (player) process or not.    int status;		sleep(1);	if(waitpid(-1, &status, WNOHANG) == m_PlayerPid)	{		m_Message = "";		QTextOStream ostr(&m_Message);		ostr << "mpg123 process exited with status " << WIFEXITED(status) << ".\n";		emit playerMessage(m_Message);		m_PlayerPid = 0;		return -1;	}		return 0;}/*!  Plays the song \a filename.*/voidQmMpg123Player::play(    const QString &filename){    m_FrameCount	= -1;    m_Seconds		= -1;    m_TotalSeconds	= -1;    m_NewSong  		= true;    m_GotNewSong    = false;    m_Filename 		= filename;    QFileInfo		fi( m_Filename );    m_FilePath 		= fi.absFilePath();    m_FileExtension = fi.extension();    sprintf(m_WriteBuffer, "LOAD %s", m_Filename.latin1());	sendCommand( m_WriteBuffer );    startTimer();}/*!  Plays the current song from the beginning.  \sa stop()*/voidQmMpg123Player::play(){    m_FrameCount	= -1;    m_TotalSeconds	= m_Seconds = -1;    m_NewSong		= true;    m_GotNewSong	= false;	restart();    startTimer();}/*!  Starts the timer used for emitting time values to clients.*/voidQmMpg123Player::startTimer(){    m_pTimer->start( 500, false );}/*!  Stops the player.  \sa play()*/voidQmMpg123Player::stop(){    m_FrameCount	= -1;    m_Seconds		= m_TotalSeconds = -1;	strcpy(m_WriteBuffer, "STOP");	sendCommand( m_WriteBuffer );	m_Playing		= false;    m_pTimer->stop();}/*!  Pauses the player.*/voidQmMpg123Player::pause(){	strcpy(m_WriteBuffer, "PAUSE");	sendCommand( m_WriteBuffer );}/*!  Restarts the song.  \sa jump(int)*/voidQmMpg123Player::restart(){	jump(0);}/*!  Jumps to a specific position in the song.  @param pos seconds into song  \sa restart()*/voidQmMpg123Player::jump(	int pos ){	sprintf(m_WriteBuffer, "JUMP %d", pos * m_TotalFrames / m_TotalSeconds);	sendCommand( m_WriteBuffer );}/*!  Reads the response from mpg123.*/voidQmMpg123Player::dataReceived(){//	memset(m_ReadBuffer, 0, READ_BUF_SIZE);	if(s_FailFlag)		return;	    int bytes_read;    	do 	{        bytes_read = read(m_RecvFd,                          m_ReadBuffer + m_BufferLeftovers,                          READ_BUF_SIZE - m_BufferLeftovers );        		m_ReadBuffer[bytes_read + m_BufferLeftovers] = '\0';//          cout << "$$ " << m_ReadBuffer << " $$";        char *buffer_pointers[50];        char **buffer_ptr = buffer_pointers;        // Split lines into separate strings and store their pointers        char *tmp = m_ReadBuffer;        char *last_tmp = tmp;		        while ( *tmp != 0 )        {            if ( *tmp == '\n' )            {                *tmp = 0;                *buffer_ptr = last_tmp;                ++buffer_ptr;                last_tmp = tmp + 1;            }            ++tmp;        }        *buffer_ptr			= 0;				// This ends the pointer list        buffer_ptr			= buffer_pointers;	// Start from the top        char *line_ptr		= m_ReadBuffer;        int line_counter	= 1;        while ( *buffer_ptr != 0 )		{            line_ptr = *buffer_ptr;						if( line_ptr[0] == '@')				parseCodes( line_ptr );			else			{				m_Message = "";				QTextOStream ostr(&m_Message);				ostr << "dataReceived(): Received " << bytes_read					 << " bytes, skipping line " << line_counter << ":\n"					 << line_ptr << " - Filename: " << m_Filename << "\n";				emit playerMessage(m_Message);			}            // Jump to next string, if any            ++line_counter;            ++buffer_ptr;		}        // There's some text without an endline        if ( tmp <= last_tmp )            m_BufferLeftovers = 0;        else        {            // Read all available data but line still not terminated:            if ( bytes_read != READ_BUF_SIZE - m_BufferLeftovers)            {				m_Message = "";				QTextOStream ostr(&m_Message);                ostr << m_BufferLeftovers << " bytes left over:\n"                     << '#' << last_tmp << "#\n";				emit playerMessage(m_Message);            }            int leftovers = tmp - last_tmp;            m_BufferLeftovers = leftovers;                        // Copy it to the beginning of the buffer            char *dst = m_ReadBuffer;            for ( ; leftovers > 0; --leftovers )            {                *dst++ = *last_tmp++;            }        }            } while( bytes_read == READ_BUF_SIZE - m_BufferLeftovers ); }/*!  Parses the response \a read_buffer from mpg123.*/voidQmMpg123Player::parseCodes(	char *read_buffer ){    char code = read_buffer[1];	    switch(code)    {        case 'F':            parseFrameInfo( read_buffer );            break;        case 'S':

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -