📄 qmmpg123player.cpp
字号:
parseStatus( read_buffer ); break; case 'I': parseInformation( read_buffer ); break; case 'P': parsePlayStatus( read_buffer ); break; case 'E': parseError( read_buffer ); break; case 'B': sscanf(&read_buffer[3], "%d", &m_BufferPid); break; case 'R': if (strncmp("@R MPG123\n", read_buffer, 10) != 0) m_NeedNewline = true;// cout << "Version: " << read_buffer << endl; /* For mpg123 0.59r, the output is: @R MPG123 For mpg123 0.59s, the output is: @R MPG123 0.59s-mh4 */ break; default: m_Message = ""; QTextOStream ostr(&m_Message); ostr << "Unknown code: " << read_buffer << "\n"; emit playerMessage(m_Message); break; }}/*! Status message during playing (frame info) @F <a> <b> <c> <d> a = framecount (int) b = frames left this song (int) c = seconds (float) d = seconds left (float) Examples: @F 1249 9960 32.63 260.18 @F 1250 9959 32.65 260.15 @F 1251 9958 32.68 260.13 @F 1252 9957 32.71 260.10 The above is for mpg123 0.59r. However, mpg123 0.59s changed and outputs one extra field: @F 20 3725 0.52 97.31 128000 @F 21 3724 0.55 97.28 128000 @F 22 3722 0.57 97.23 128000 @F 23 3721 0.60 97.20 128000*/voidQmMpg123Player::parseFrameInfo( char *read_buffer ){ int framecount, framesleft; int bitrate; float seconds, secondsleft;// sscanf(&read_buffer[3], "%d %d %f %f", &framecount,// &framesleft, &seconds, &secondsleft); sscanf(&read_buffer[3], "%d %d %f %f %d", &framecount, &framesleft, &seconds, &secondsleft, &bitrate); bool release = false; if(m_GotNewSong) { m_Playing = true; m_NewSong = false; m_GotNewSong = false; m_TotalFrames = framesleft + framecount; emit frameCount( m_TotalFrames ); emit secondsCount((int)( seconds + secondsleft )); m_TotalSeconds = (int)(seconds + secondsleft); release = true; } if(framesleft == 0) m_Playing = false; m_FrameCount = framecount; m_Seconds = (int)seconds; // release is true if this is the first time, if so we need to send // the information immediately if ( release ) releaseTimingInformation();}/*! Emits the number of frames left and the number of seconds currently played.*/void QmMpg123Player::releaseTimingInformation(){ // Only emit while we are playing if ( m_Playing ) { emit framesLeft(m_FrameCount); emit secondsPlaying(m_Seconds); }}/*! @S <a> <b> <c> <d> <e> <f> <g> <h> <i> <j> <k> <l> Status message after loading a song (stream info) a = mpeg type (string) b = layer (int) c = sampling frequency (int) d = mode (string) e = mode extension (int) f = framesize (int) g = stereo (int) h = copyright (int) i = error protection (int) j = emphasis (int) k = bitrate (int) l = extension (int)*/voidQmMpg123Player::parseStatus( char *read_buffer ){ char mpegType[32], mode[32]; int layer, samplingFreq, modeExtension, frameSize, stereo, copyright, errorProtection; int emphasis, _bitrate, extension; int scanned = sscanf(read_buffer, "@S %31s %d %d %31s %d %d %d %d %d %d %d %d", mpegType, &layer, &samplingFreq, mode, &modeExtension, &frameSize, &stereo, ©right, &errorProtection, &emphasis, &_bitrate, &extension); if (scanned == 12) emit bitrate(_bitrate); else { m_Message = ""; QTextOStream ostr(&m_Message); ostr << "Failed to parse status from mpg123. Failed on: " << read_buffer << "\n"; emit playerMessage(m_Message); }}/*! @I ID3:<a><b><c><d><e><f> Status message after loading a song (ID3 song info) a = title (exactly 30 chars) b = artist (exactly 30 chars) c = album (exactly 30 chars) d = year (exactly 4 chars) e = comment (exactly 30 chars) f = genre (string) @I <a> Status message after loading a song (no ID3 song info) a = filename without path and extension*/voidQmMpg123Player::parseInformation( char *read_buffer){ m_NewSong = true; m_GotNewSong = true; if ( read_buffer[3] == 'I' && read_buffer[4] == 'D' && read_buffer[5] == '3' && read_buffer[6] == ':' ) { char *info = &read_buffer[7]; char title[31], artist[31], album[31], year[5], comment[31]; char *genre; title[30] = artist[30] = album[30] = year[4] = comment[30] = 0; strncpy( title, info, 30 ); info += 30; strncpy( artist, info, 30 ); info += 30; strncpy( album, info, 30 ); info += 30; strncpy( year, info, 4 ); info += 4; strncpy( comment, info, 30 ); info += 30; genre = info; m_Title = QString( title ).stripWhiteSpace(); m_Artist = QString( artist ).stripWhiteSpace(); m_Album = QString( album ).stripWhiteSpace(); m_Year = QString( year ).stripWhiteSpace(); m_Comment = QString( comment ).stripWhiteSpace(); m_Genre = QString( genre ).stripWhiteSpace(); QString song_title = resolveTags(); emit songTitle( song_title ); } else { char *info = &read_buffer[3]; emit songTitle( info ); }}/*! Creates a string useable for showing the title of the current song. The string is created by replacing % tags in the m_ID3Format with song information.*/QStringQmMpg123Player::resolveTags(){ QString song_title; int old_pos = 0; while ( old_pos < (int)m_ID3Format.length() && old_pos >= 0 ) { int pos = m_ID3Format.find( '%', old_pos ); if ( pos != -1 ) { if ( pos != (int)m_ID3Format.length() -1 ) { song_title += m_ID3Format.mid( old_pos, pos - old_pos ); QChar c = m_ID3Format[pos + 1]; switch(c) { case '1': // Artist song_title += m_Artist; break; case '2': // Title song_title += m_Title; break; case '3': // Album song_title += m_Album; break; case '4': // Year song_title += m_Year; break; case '5': // Comment song_title += m_Comment; break; case '6': // Genre song_title += m_Genre; break; case '7': // File name song_title += m_Filename; break; case '8': // File path song_title += m_FilePath; break; case '9': // File extension song_title += m_FileExtension; break; default: song_title += QString( "%" ) + c; } old_pos = pos + 2; } else { song_title += m_ID3Format.mid( old_pos ); old_pos = -1; } } else { song_title += m_ID3Format.mid( old_pos ); old_pos = pos; } } return song_title;}/*! @P <a> Playing status a = 0: playing stopped a = 1: playing paused a = 2: playing unpaused*/voidQmMpg123Player::parsePlayStatus( char *read_buffer ){ int status; sscanf(&read_buffer[3], "%d", &status); switch(status) { case 0: emit playingStopped(); break; case 1: // cout << "paused" << endl; break; case 2: // cout << "unpaused" << endl; break; default: m_Message = ""; QTextOStream ostr(&m_Message); ostr << "Unknown play status: " << read_buffer << "\n"; emit playerMessage(m_Message); break; }}/*! @E <a> An error occured Errors may be also reported by mpg123 through stderr (without @E) a = error message (string)*/voidQmMpg123Player::parseError( char *read_buffer ){ m_Message = ""; QTextOStream ostr(&m_Message); ostr << "Error: " << read_buffer << "\n"; emit playerMessage(m_Message);}/*! \return True if playing, false otherwise. */boolQmMpg123Player::isPlaying() const{ return m_Playing;}/*! \return True if paused, false otherwise. */boolQmMpg123Player::isPaused() const{ return m_Paused;}/*! Sends the string \a write_buffer to the mpg123 process. If the command was not sent successfully, a dialogbox will be shown. This kind of failure will typically happen when the mpg123 process crashed, and the pipe is broken. \return True if successful, false otherwise.*/boolQmMpg123Player::sendCommand( char *write_buffer ){ int len = strlen(write_buffer); if (m_NeedNewline) write_buffer[len] = '\n'; int rc = write(m_SendFd, write_buffer, len+1); if(rc > -1) return true; else { rc = QMessageBox::warning( 0, QObject::tr("Apollo Error"), QObject::tr("Apollo failed to send the command to<br>" "the MP3 player. This typically means<br>" "that the MP3 player process is no longer<br>" "working correctly and needs to be restarted.<br>" "It might just have been a temporary problem<br>" "and you can try again."), QObject::tr("&Restart player"), QObject::tr("&Do nothing")); if(rc == 0) { init(); return sendCommand(write_buffer); } } return false;}/*! Signal handler for mpg123 process.*//* According to the C++ FAQ [1], it is not a good idea to pass a pointer to a member function to a C function such as signal() for function callbacks. Instead, we will have to rely on a static member function (which acts just as a regular C function). [1] See 30.2 at http://www.cs.uu.nl/wais/html/na-dir/C++-faq/part9.html*/voidQmMpg123Player::childHandler( int sig){ // Catch signal of exiting player.// signal(SIGCHLD, 0);// cout << "QmMpg123Player::childHandler(): Signal from mpg123" << endl; if( ! s_OurTermSignal) { QMessageBox::critical( 0, QObject::tr("Apollo Error"), QObject::tr("Apollo has detected that the MP3 player<br>" "process failed (signal %1). Apollo cannot function<br>" "without it. You can try to restart the<br>" "player from the Options menu.<br>" "If the particular song you were trying to<br>" "play keeps continuing to fail the player<br>" "you can mark it as 'bad' from the Playlist menu.").arg(sig)); } /* int status; if(waitpid(-1, &status, WNOHANG) == m_PlayerPid) { cout << "mpg123 process exited with code " << WEXITSTATUS(status) << endl; m_PlayerPid = 0; } */}/*! Signal handler for mpg123 process.*/voidQmMpg123Player::failHandler( int /*sig*/){// signal(SIGUSR1, 0); QMessageBox::critical( 0, QObject::tr("Apollo Error"), QObject::tr("Apollo has detected that the MP3 player<br>" "is not running. Apollo cannot function<br>" "without it. You can try to restart the<br>" "player from the Options menu."));}/*! Sets the fail flag to \a b. Scenario: Apollo starts -> forks -> apollo(1), apollo(2) -> execute mpg123 over apollo(1) -> apollo(2) tries to communicate with mpg123 (apollo(1)) -> mpg123 fails to execute -> process writes to cerr -> apollo(2) reads from cerr; thinks it's mpg123 -> problem! By settings the (static) fail flag to true, the input will be ignored.*/voidQmMpg123Player::setFailFlag( bool b){ s_FailFlag = b;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -