1 #include "nSoundStreamer.h"
2 #include "nSoundSystem.h"
3 #include "nSoundSource.h"
5 #include "nSoundStream.h"
6 #include "nSoundStreamerPlaylist.h"
10 const int nSS_BUFFER_SIZE = 4096;
12 nSoundStreamer::nSoundStreamer(QString name, nSoundSource * source, nSoundStreamerPlaylist * playlist, nSoundSystem * parent) :
16 m_playlist = playlist;
18 if(!playlist->itemCount()) {
19 qWarning("nSoundStreamer has no items in playlist");
23 // make sure we can stream to source
26 alGetSourcei(source->openalHandle(), AL_SOURCE_TYPE, &sourceType);
27 if(sourceType == AL_STATIC)
28 throw QString("nSoundStreamer::nSoundStreamer(...): Tried to create stream \"")+name+("\" to an AL_STATIC source.");
31 // create OpenAL buffers
33 unsigned int buffers[3];
34 alGenBuffers(3, buffers);
35 m_buffer0 = buffers[0];
36 m_buffer1 = buffers[1];
37 m_buffer2 = buffers[2];
38 if(alGetError()!=AL_NO_ERROR)
39 throw QString("nSoundStreamer::nSoundStreamer(...): Failed to create streaming buffers for \"")+name+QString("\".");
42 //reserve buffer memory
44 nSoundStream * stream = m_playlist->m_items[m_currentStream].m_soundStream;
45 m_bag = new nSoundBag(stream->format(),
46 (stream->frames() < nSS_BUFFER_SIZE? stream->frames() : nSS_BUFFER_SIZE),
47 stream->frequency(), this);
49 //fill in initial data and queue buffers
50 m_keepStreaming = fillAndQueueBuffer(m_buffer0);
51 if(m_keepStreaming) m_keepStreaming = fillAndQueueBuffer(m_buffer1);
52 if(m_keepStreaming) m_keepStreaming = fillAndQueueBuffer(m_buffer2);
54 // start threaded updater
55 QThread * updaterThread = new QThread(0);
56 updaterThread->setObjectName(objectName() + "_THREAD");
57 m_updater = new nSoundStreamerUpdater(this);
58 m_updater->moveToThread(updaterThread);
59 updaterThread->start();
60 updaterThread->setPriority(QThread::LowPriority);
65 nSoundStreamer::~nSoundStreamer()
67 if(!m_playlist->itemCount()) {
71 QMutexLocker lock(&_mutex);
73 m_updater->_keepGoing = false;
79 alGetSourcei(m_source->openalHandle(), AL_BUFFERS_QUEUED, &queuedBuffers);
80 while(queuedBuffers--)
83 alSourceUnqueueBuffers(m_source->openalHandle(), 1, &buffer);
84 if(alGetError()!=AL_NO_ERROR)
86 qWarning("nSoundStreamer::~nSoundStreamer(): Failed to unqueue buffer");
90 unsigned int buffers[3];
91 buffers[0] = m_buffer0;
92 buffers[1] = m_buffer1;
93 buffers[2] = m_buffer2;
94 alDeleteBuffers(3, buffers);
96 if(alGetError()!=AL_NO_ERROR)
97 qWarning("nSoundStreamer::~nSoundStreamer(): Failed to destroy buffers.");
102 void nSoundStreamer::update(float frameTime)
105 if(!m_playlist->itemCount()) {
109 QMutexLocker lock(&_mutex);
113 unsigned int sourceHandle = m_source->openalHandle();
116 int processedBuffers;
117 alGetSourcei(sourceHandle, AL_BUFFERS_PROCESSED, &processedBuffers);
119 while(processedBuffers--)
122 alSourceUnqueueBuffers(sourceHandle, 1, &buffer);
123 if(alGetError()!=AL_NO_ERROR)
124 throw QString("nSoundStreamer::update(...): Failed to unqueue buffer.");
126 if(m_keepStreaming) m_keepStreaming = fillAndQueueBuffer(buffer);
133 void nSoundStreamer::rewind()
135 if(!m_playlist->itemCount()) {
139 bool playing = m_source->state() == nSoundSource::SSS_PLAYING;
141 m_playlist->m_items[m_currentStream].m_soundStream->rewind();
145 if(playing) m_source->play();
149 bool nSoundStreamer::fillAndQueueBuffer(unsigned int buffer)
153 nSoundBag * bag = m_bag;
154 quint64 frames = bag->m_frames;
155 quint64 readFrames = 0;
156 int byteFactor = nSoundFormat_getFramesize(bag->m_format);
160 nSoundStream * stream = m_playlist->m_items[m_currentStream].m_soundStream;
162 readFrames += stream->read(m_bag->m_data+(readFrames*byteFactor), m_bag->m_frames - readFrames);
164 if(readFrames!=frames)
167 if( ! m_playlist->item(m_currentStream).m_loop)
170 if(m_currentStream==m_playlist->m_items.size())
171 if(m_playlist->loopPlaylist())m_currentStream = 0;
175 }while ( keep && (readFrames < frames));
178 alBufferData(buffer, openalFormat(m_bag->m_format), m_bag->m_data, readFrames*byteFactor, m_bag->m_frequency);
179 if(alGetError()!=AL_NO_ERROR)
180 throw QString("nSoundStreamer::fillAndQueueBuffer(...): Failed to refill buffer.");
182 alSourceQueueBuffers(m_source->openalHandle(), 1, &buffer);
183 if(alGetError()!=AL_NO_ERROR)
184 throw QString("nSoundStreamer::fillAndQueueBuffer(...): Failed to queue buffer.");
189 int nSoundStreamer::openalFormat(nSoundFormat format)
194 return AL_FORMAT_MONO8;
197 return AL_FORMAT_STEREO8;
200 return AL_FORMAT_MONO16;
202 case SF_16BIT_STEREO:
203 return AL_FORMAT_STEREO16;
210 nSoundStreamerUpdater::nSoundStreamerUpdater(nSoundStreamer *parent) : QObject(0),
214 startTimer(static_cast<int>(nSS_BUFFER_SIZE / 44100.0 * 1000));
217 nSoundStreamerUpdater::~nSoundStreamerUpdater()
222 void nSoundStreamerUpdater::setup()
226 void nSoundStreamerUpdater::timerEvent(QTimerEvent * evt)
229 _streamer->update(0);
232 QThread::currentThread()->deleteLater();
233 QThread::currentThread()->exit(0);