1 /* This file is part of the KDE project
2 Copyright (C) 2006 Alexander Kern <alex.kern@gmx.de>
3
4 based on example for Phonon Architecture, Matthias Kretz <kretz@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License version 2 as published by the Free Software Foundation.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21 #include "audio_phonon.h"
22 #include "audio.h"
23
24 #include <QByteArray>
25 #include <QDataStream>
26 #include <QTimer>
27 #include <QWaitCondition>
28 #include <QMutex>
29
30 #include <phonon/audiooutput.h>
31 #include <phonon/audiopath.h>
32 #include <phonon/mediaobject.h>
33
LibWMPcmPlayer()34 LibWMPcmPlayer::LibWMPcmPlayer() : AbstractMediaStream(NULL),
35 m_media(NULL),
36 m_cmd(WM_CDM_UNKNOWN),
37 m_blk(NULL)
38 {
39 Phonon::AudioOutput* m_output = new Phonon::AudioOutput(Phonon::MusicCategory, this);
40 Phonon::AudioPath* m_path = new Phonon::AudioPath(this);
41 m_path->addOutput(m_output);
42 m_media = new Phonon::MediaObject(this);
43 m_media->addAudioPath(m_path);
44 m_media->setCurrentSource(this);
45 setStreamSeekable(false);
46 setStreamSize(0xffffffff);
47
48 connect(this, SIGNAL(cmdChanged(int)), this, SLOT(executeCmd(int)));
49 connect(this, SIGNAL(nextBuffer(cdda_block*)), this, SLOT(playBuffer(cdda_block*)));
50 connect(m_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
51 this, SLOT(stateChanged(Phonon::State,Phonon::State)));
52
53 DEBUGLOG("writeHeader\n");
54 writeData( wavHeader() );
55 DEBUGLOG("writeHeader end\n");
56 }
57
~LibWMPcmPlayer()58 LibWMPcmPlayer::~LibWMPcmPlayer()
59 {
60 stop();
61 }
62
wavHeader() const63 QByteArray LibWMPcmPlayer::wavHeader() const
64 {
65 QByteArray data;
66 QDataStream stream( &data, QIODevice::WriteOnly );
67 stream.setByteOrder( QDataStream::LittleEndian );
68 stream
69 << 0x46464952 //"RIFF"
70 << static_cast<quint32>( 0x7FFFFFFF )
71 << 0x45564157 //"WAVE"
72 << 0x20746D66 //"fmt " //Subchunk1ID
73 << static_cast<quint32>( 16 ) //Subchunk1Size
74 << static_cast<quint16>( 1 ) //AudioFormat
75 << static_cast<quint16>( 2 ) //NumChannels
76 << static_cast<quint32>( 44100 ) //SampleRate
77 << static_cast<quint32>( 2*2*44100 )//ByteRate
78 << static_cast<quint16>( 2*2 ) //BlockAlign
79 << static_cast<quint16>( 16 ) //BitsPerSample
80 << 0x61746164 //"data" //Subchunk2ID
81 << static_cast<quint32>( 0x7FFFFFFF-36 )//Subchunk2Size
82 ;
83
84 return data;
85 }
86
reset()87 void LibWMPcmPlayer::reset()
88 {
89 setStreamSeekable(false);
90 setStreamSize(0xffffffff);
91 DEBUGLOG("writeHeader\n");
92 writeData( wavHeader() );
93 DEBUGLOG("writeHeader end\n");
94 }
95
needData()96 void LibWMPcmPlayer::needData()
97 {
98 DEBUGLOG("needData\n");
99 m_mutex.lock();
100 m_readyToPlay.wakeAll();
101 m_mutex.unlock();
102
103 }
104
setNextBuffer(struct cdda_block * blk)105 void LibWMPcmPlayer::setNextBuffer(struct cdda_block *blk)
106 {
107 Q_EMIT nextBuffer(blk);
108 m_mutex.lock();
109 m_readyToPlay.wait(&m_mutex);
110 m_mutex.unlock();
111 }
112
playBuffer(struct cdda_block * blk)113 void LibWMPcmPlayer::playBuffer(struct cdda_block *blk)
114 {
115 if(m_cmd != WM_CDM_PLAYING) {
116 Q_EMIT cmdChanged(WM_CDM_PLAYING);
117 m_cmd = WM_CDM_PLAYING;
118 }
119 writeData(QByteArray(blk->buf, blk->buflen));
120
121 }
122
pause(void)123 void LibWMPcmPlayer::pause(void)
124 {
125 if(m_cmd != WM_CDM_PAUSED) {
126 Q_EMIT cmdChanged(WM_CDM_PAUSED);
127 m_cmd = WM_CDM_PAUSED;
128
129 m_readyToPlay.wakeAll();
130 }
131 }
132
stop(void)133 void LibWMPcmPlayer::stop(void)
134 {
135 if(m_cmd != WM_CDM_STOPPED) {
136 Q_EMIT cmdChanged(WM_CDM_STOPPED);
137 m_cmd = WM_CDM_STOPPED;
138
139 m_readyToPlay.wakeAll();
140 }
141 }
142
executeCmd(int cmd)143 void LibWMPcmPlayer::executeCmd(int cmd)
144 {
145 switch(cmd) {
146 case WM_CDM_PLAYING:
147 DEBUGLOG("set play\n");
148 m_media->play();
149 break;
150 case WM_CDM_PAUSED:
151 DEBUGLOG("set pause\n");
152 m_media->pause();
153 break;
154 case WM_CDM_STOPPED:
155 DEBUGLOG("set stop\n");
156 m_media->stop();
157 break;
158 default:
159 cmd = WM_CDM_STOPPED;
160 break;
161 }
162 }
163
stateChanged(Phonon::State newstate,Phonon::State oldstate)164 void LibWMPcmPlayer::stateChanged( Phonon::State newstate, Phonon::State oldstate )
165 {
166 DEBUGLOG("stateChanged from %i to %i\n", oldstate, newstate);
167 }
168
169 static LibWMPcmPlayer *PhononObject = NULL;
170
phonon_open(void)171 int phonon_open(void)
172 {
173 DEBUGLOG("phonon_open\n");
174
175 if(PhononObject) {
176 ERRORLOG("Already initialized!\n");
177 return -1;
178 }
179
180 PhononObject = new LibWMPcmPlayer();
181
182 return 0;
183 }
184
phonon_close(void)185 int phonon_close(void)
186 {
187 DEBUGLOG("phonon_close\n");
188
189 if(!PhononObject) {
190 ERRORLOG("Unable to close\n");
191 return -1;
192 }
193
194 delete PhononObject;
195
196 PhononObject = NULL;
197
198 return 0;
199 }
200
201 /*
202 * Play some audio and pass a status message upstream, if applicable.
203 * Returns 0 on success.
204 */
205 int
phonon_play(struct cdda_block * blk)206 phonon_play(struct cdda_block *blk)
207 {
208 DEBUGLOG("phonon_play %ld samples, frame %i\n",
209 blk->buflen / (2 * 2), blk->frame);
210
211 if(!PhononObject) {
212 ERRORLOG("Unable to play\n");
213 blk->status = WM_CDM_CDDAERROR;
214 return -1;
215 }
216
217 PhononObject->setNextBuffer(blk);
218
219 return 0;
220 }
221
222 /*
223 * Pause the audio immediately.
224 */
225 int
phonon_pause(void)226 phonon_pause(void)
227 {
228 DEBUGLOG("phonon_pause\n");
229
230 if(!PhononObject) {
231 ERRORLOG("Unable to pause\n");
232 return -1;
233 }
234
235 PhononObject->pause();
236
237 return 0;
238 }
239
240 /*
241 * Stop the audio immediately.
242 */
243 int
phonon_stop(void)244 phonon_stop(void)
245 {
246 DEBUGLOG("phonon_stop\n");
247
248 if(!PhononObject) {
249 ERRORLOG("Unable to stop\n");
250 return -1;
251 }
252
253 PhononObject->stop();
254
255 return 0;
256 }
257
258 /*
259 * Get the current audio state.
260 */
261 int
phonon_state(struct cdda_block * blk)262 phonon_state(struct cdda_block *blk)
263 {
264 DEBUGLOG("phonon_state\n");
265
266 return -1; /* not implemented yet for PHONON */
267 }
268
269 static struct audio_oops phonon_oops = {
270 phonon_open,
271 phonon_close,
272 phonon_play,
273 phonon_pause,
274 phonon_stop,
275 phonon_state,
276 NULL,
277 NULL
278 };
279
280 extern "C" struct audio_oops*
setup_phonon(const char * dev,const char * ctl)281 setup_phonon(const char *dev, const char *ctl)
282 {
283 DEBUGLOG("setup_phonon\n");
284
285 phonon_open();
286
287 return &phonon_oops;
288 }
289
290 #include "audio_phonon.moc"
291