File indexing completed on 2024-04-21 04:54:20
0001 /* This file is part of the KDE project 0002 Copyright (C) 2006 Alexander Kern <alex.kern@gmx.de> 0003 0004 based on example for Phonon Architecture, Matthias Kretz <kretz@kde.org> 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License version 2 as published by the Free Software Foundation. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "audio_phonon.h" 0022 #include "audio.h" 0023 0024 #include <QDataStream> 0025 0026 #include <phonon/audiooutput.h> 0027 #include <phonon/audiopath.h> 0028 #include <phonon/mediaobject.h> 0029 0030 LibWMPcmPlayer::LibWMPcmPlayer() : AbstractMediaStream(NULL), 0031 m_media(NULL), 0032 m_cmd(WM_CDM_UNKNOWN), 0033 m_blk(NULL) 0034 { 0035 Phonon::AudioOutput* m_output = new Phonon::AudioOutput(Phonon::MusicCategory, this); 0036 Phonon::AudioPath* m_path = new Phonon::AudioPath(this); 0037 m_path->addOutput(m_output); 0038 m_media = new Phonon::MediaObject(this); 0039 m_media->addAudioPath(m_path); 0040 m_media->setCurrentSource(this); 0041 setStreamSeekable(false); 0042 setStreamSize(0xffffffff); 0043 0044 connect(this, SIGNAL(cmdChanged(int)), this, SLOT(executeCmd(int))); 0045 connect(this, SIGNAL(nextBuffer(cdda_block*)), this, SLOT(playBuffer(cdda_block*))); 0046 connect(m_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), 0047 this, SLOT(stateChanged(Phonon::State,Phonon::State))); 0048 0049 DEBUGLOG("writeHeader\n"); 0050 writeData( wavHeader() ); 0051 DEBUGLOG("writeHeader end\n"); 0052 } 0053 0054 LibWMPcmPlayer::~LibWMPcmPlayer() 0055 { 0056 stop(); 0057 } 0058 0059 QByteArray LibWMPcmPlayer::wavHeader() const 0060 { 0061 QByteArray data; 0062 QDataStream stream( &data, QIODevice::WriteOnly ); 0063 stream.setByteOrder( QDataStream::LittleEndian ); 0064 stream 0065 << 0x46464952 //"RIFF" 0066 << static_cast<quint32>( 0x7FFFFFFF ) 0067 << 0x45564157 //"WAVE" 0068 << 0x20746D66 //"fmt " //Subchunk1ID 0069 << static_cast<quint32>( 16 ) //Subchunk1Size 0070 << static_cast<quint16>( 1 ) //AudioFormat 0071 << static_cast<quint16>( 2 ) //NumChannels 0072 << static_cast<quint32>( 44100 ) //SampleRate 0073 << static_cast<quint32>( 2*2*44100 )//ByteRate 0074 << static_cast<quint16>( 2*2 ) //BlockAlign 0075 << static_cast<quint16>( 16 ) //BitsPerSample 0076 << 0x61746164 //"data" //Subchunk2ID 0077 << static_cast<quint32>( 0x7FFFFFFF-36 )//Subchunk2Size 0078 ; 0079 0080 return data; 0081 } 0082 0083 void LibWMPcmPlayer::reset() 0084 { 0085 setStreamSeekable(false); 0086 setStreamSize(0xffffffff); 0087 DEBUGLOG("writeHeader\n"); 0088 writeData( wavHeader() ); 0089 DEBUGLOG("writeHeader end\n"); 0090 } 0091 0092 void LibWMPcmPlayer::needData() 0093 { 0094 DEBUGLOG("needData\n"); 0095 m_mutex.lock(); 0096 m_readyToPlay.wakeAll(); 0097 m_mutex.unlock(); 0098 0099 } 0100 0101 void LibWMPcmPlayer::setNextBuffer(struct cdda_block *blk) 0102 { 0103 Q_EMIT nextBuffer(blk); 0104 m_mutex.lock(); 0105 m_readyToPlay.wait(&m_mutex); 0106 m_mutex.unlock(); 0107 } 0108 0109 void LibWMPcmPlayer::playBuffer(struct cdda_block *blk) 0110 { 0111 if(m_cmd != WM_CDM_PLAYING) { 0112 Q_EMIT cmdChanged(WM_CDM_PLAYING); 0113 m_cmd = WM_CDM_PLAYING; 0114 } 0115 writeData(QByteArray(blk->buf, blk->buflen)); 0116 0117 } 0118 0119 void LibWMPcmPlayer::pause(void) 0120 { 0121 if(m_cmd != WM_CDM_PAUSED) { 0122 Q_EMIT cmdChanged(WM_CDM_PAUSED); 0123 m_cmd = WM_CDM_PAUSED; 0124 0125 m_readyToPlay.wakeAll(); 0126 } 0127 } 0128 0129 void LibWMPcmPlayer::stop(void) 0130 { 0131 if(m_cmd != WM_CDM_STOPPED) { 0132 Q_EMIT cmdChanged(WM_CDM_STOPPED); 0133 m_cmd = WM_CDM_STOPPED; 0134 0135 m_readyToPlay.wakeAll(); 0136 } 0137 } 0138 0139 void LibWMPcmPlayer::executeCmd(int cmd) 0140 { 0141 switch(cmd) { 0142 case WM_CDM_PLAYING: 0143 DEBUGLOG("set play\n"); 0144 m_media->play(); 0145 break; 0146 case WM_CDM_PAUSED: 0147 DEBUGLOG("set pause\n"); 0148 m_media->pause(); 0149 break; 0150 case WM_CDM_STOPPED: 0151 DEBUGLOG("set stop\n"); 0152 m_media->stop(); 0153 break; 0154 default: 0155 cmd = WM_CDM_STOPPED; 0156 break; 0157 } 0158 } 0159 0160 void LibWMPcmPlayer::stateChanged( Phonon::State newstate, Phonon::State oldstate ) 0161 { 0162 DEBUGLOG("stateChanged from %i to %i\n", oldstate, newstate); 0163 } 0164 0165 static LibWMPcmPlayer *PhononObject = NULL; 0166 0167 int phonon_open(void) 0168 { 0169 DEBUGLOG("phonon_open\n"); 0170 0171 if(PhononObject) { 0172 ERRORLOG("Already initialized!\n"); 0173 return -1; 0174 } 0175 0176 PhononObject = new LibWMPcmPlayer(); 0177 0178 return 0; 0179 } 0180 0181 int phonon_close(void) 0182 { 0183 DEBUGLOG("phonon_close\n"); 0184 0185 if(!PhononObject) { 0186 ERRORLOG("Unable to close\n"); 0187 return -1; 0188 } 0189 0190 delete PhononObject; 0191 0192 PhononObject = NULL; 0193 0194 return 0; 0195 } 0196 0197 /* 0198 * Play some audio and pass a status message upstream, if applicable. 0199 * Returns 0 on success. 0200 */ 0201 int 0202 phonon_play(struct cdda_block *blk) 0203 { 0204 DEBUGLOG("phonon_play %ld samples, frame %i\n", 0205 blk->buflen / (2 * 2), blk->frame); 0206 0207 if(!PhononObject) { 0208 ERRORLOG("Unable to play\n"); 0209 blk->status = WM_CDM_CDDAERROR; 0210 return -1; 0211 } 0212 0213 PhononObject->setNextBuffer(blk); 0214 0215 return 0; 0216 } 0217 0218 /* 0219 * Pause the audio immediately. 0220 */ 0221 int 0222 phonon_pause(void) 0223 { 0224 DEBUGLOG("phonon_pause\n"); 0225 0226 if(!PhononObject) { 0227 ERRORLOG("Unable to pause\n"); 0228 return -1; 0229 } 0230 0231 PhononObject->pause(); 0232 0233 return 0; 0234 } 0235 0236 /* 0237 * Stop the audio immediately. 0238 */ 0239 int 0240 phonon_stop(void) 0241 { 0242 DEBUGLOG("phonon_stop\n"); 0243 0244 if(!PhononObject) { 0245 ERRORLOG("Unable to stop\n"); 0246 return -1; 0247 } 0248 0249 PhononObject->stop(); 0250 0251 return 0; 0252 } 0253 0254 /* 0255 * Get the current audio state. 0256 */ 0257 int 0258 phonon_state(struct cdda_block *blk) 0259 { 0260 DEBUGLOG("phonon_state\n"); 0261 0262 return -1; /* not implemented yet for PHONON */ 0263 } 0264 0265 static struct audio_oops phonon_oops = { 0266 phonon_open, 0267 phonon_close, 0268 phonon_play, 0269 phonon_pause, 0270 phonon_stop, 0271 phonon_state, 0272 NULL, 0273 NULL 0274 }; 0275 0276 extern "C" struct audio_oops* 0277 setup_phonon(const char *dev, const char *ctl) 0278 { 0279 DEBUGLOG("setup_phonon\n"); 0280 0281 phonon_open(); 0282 0283 return &phonon_oops; 0284 } 0285 0286 #include "audio_phonon.moc" 0287 #include "moc_audio_phonon.cpp"