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"