Back to index

libsfml  1.6+dfsg2
SoundStream.cpp
Go to the documentation of this file.
00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #include <SFML/Audio/SoundStream.hpp>
00029 #include <SFML/Audio/AudioDevice.hpp>
00030 #include <SFML/Audio/OpenAL.hpp>
00031 #include <SFML/System/Sleep.hpp>
00032 
00033 
00034 namespace sf
00035 {
00039 SoundStream::SoundStream() :
00040 myIsStreaming     (false),
00041 myChannelsCount   (0),
00042 mySampleRate      (0),
00043 myFormat          (0),
00044 myLoop            (false),
00045 mySamplesProcessed(0)
00046 {
00047 
00048 }
00049 
00050 
00054 SoundStream::~SoundStream()
00055 {
00056     // Stop the sound if it was playing
00057     Stop();
00058 }
00059 
00060 
00064 void SoundStream::Initialize(unsigned int ChannelsCount, unsigned int SampleRate)
00065 {
00066     myChannelsCount = ChannelsCount;
00067     mySampleRate    = SampleRate;
00068 
00069     // Deduce the format from the number of channels
00070     myFormat = priv::AudioDevice::GetInstance().GetFormatFromChannelsCount(ChannelsCount);
00071 
00072     // Check if the format is valid
00073     if (myFormat == 0)
00074     {
00075         myChannelsCount = 0;
00076         mySampleRate    = 0;
00077         std::cerr << "Unsupported number of channels (" << myChannelsCount << ")" << std::endl;
00078     }
00079 }
00080 
00081 
00085 void SoundStream::Play()
00086 {
00087     // Check if the sound parameters have been set
00088     if (myFormat == 0)
00089     {
00090         std::cerr << "Failed to play audio stream : sound parameters have not been initialized (call Initialize first)" << std::endl;
00091         return;
00092     }
00093 
00094     // If the sound is already playing (probably paused), just resume it
00095     if (myIsStreaming)
00096     {
00097         Sound::Play();
00098         return;
00099     }
00100 
00101     // Notify the derived class
00102     if (OnStart())
00103     {
00104         // Start updating the stream in a separate thread to avoid blocking the application
00105         mySamplesProcessed = 0;
00106         myIsStreaming = true;
00107         Launch();
00108     }
00109 }
00110 
00111 
00115 void SoundStream::Stop()
00116 {
00117     // Wait for the thread to terminate
00118     myIsStreaming = false;
00119     Wait();
00120 }
00121 
00122 
00126 unsigned int SoundStream::GetChannelsCount() const
00127 {
00128     return myChannelsCount;
00129 }
00130 
00131 
00135 unsigned int SoundStream::GetSampleRate() const
00136 {
00137     return mySampleRate;
00138 }
00139 
00140 
00144 Sound::Status SoundStream::GetStatus() const
00145 {
00146     Status Status = Sound::GetStatus();
00147 
00148     // To compensate for the lag between Play() and alSourcePlay()
00149     if ((Status == Stopped) && myIsStreaming)
00150         Status = Playing;
00151 
00152     return Status;
00153 }
00154 
00155 
00162 float SoundStream::GetPlayingOffset() const
00163 {
00164     return Sound::GetPlayingOffset() + static_cast<float>(mySamplesProcessed) / mySampleRate / myChannelsCount;
00165 }
00166 
00167 
00171 void SoundStream::SetLoop(bool Loop)
00172 {
00173     myLoop = Loop;
00174 }
00175 
00176 
00180 bool SoundStream::GetLoop() const
00181 {
00182     return myLoop;
00183 }
00184 
00185 
00189 void SoundStream::Run()
00190 {
00191     // Create the buffers
00192     ALCheck(alGenBuffers(BuffersCount, myBuffers));
00193     for (int i = 0; i < BuffersCount; ++i)
00194         myEndBuffers[i] = false;
00195 
00196     // Fill the queue
00197     bool RequestStop = FillQueue();
00198 
00199     // Play the sound
00200     Sound::Play();
00201 
00202     while (myIsStreaming)
00203     {
00204         // The stream has been interrupted !
00205         if (Sound::GetStatus() == Stopped)
00206         {
00207             if (!RequestStop)
00208             {
00209                 // Just continue
00210                 Sound::Play();
00211             }
00212             else
00213             {
00214                 // End streaming
00215                 myIsStreaming = false;
00216             }
00217         }
00218 
00219         // Get the number of buffers that have been processed (ie. ready for reuse)
00220         ALint NbProcessed;
00221         ALCheck(alGetSourcei(Sound::mySource, AL_BUFFERS_PROCESSED, &NbProcessed));
00222 
00223         while (NbProcessed--)
00224         {
00225             // Pop the first unused buffer from the queue
00226             ALuint Buffer;
00227             ALCheck(alSourceUnqueueBuffers(Sound::mySource, 1, &Buffer));
00228 
00229             // Find its number
00230             unsigned int BufferNum = 0;
00231             for (int i = 0; i < BuffersCount; ++i)
00232                 if (myBuffers[i] == Buffer)
00233                 {
00234                     BufferNum = i;
00235                     break;
00236                 }
00237 
00238             // Retrieve its size and add it to the samples count
00239             if (myEndBuffers[BufferNum])
00240             {
00241                 // This was the last buffer: reset the sample count
00242                 mySamplesProcessed = 0;
00243                 myEndBuffers[BufferNum] = false;
00244             }
00245             else
00246             {
00247                 ALint Size;
00248                 ALCheck(alGetBufferi(Buffer, AL_SIZE, &Size));
00249                 mySamplesProcessed += Size / sizeof(Int16);
00250             }
00251 
00252             // Fill it and push it back into the playing queue
00253             if (!RequestStop)
00254             {
00255                 if (FillAndPushBuffer(BufferNum))
00256                     RequestStop = true;
00257             }
00258         }
00259 
00260         // Leave some time for the other threads if the stream is still playing
00261         if (Sound::GetStatus() != Stopped)
00262             Sleep(0.1f);
00263     }
00264 
00265     // Stop the playback
00266     Sound::Stop();
00267 
00268     // Unqueue any buffer left in the queue
00269     ClearQueue();
00270 
00271     // Delete the buffers
00272     ALCheck(alSourcei(Sound::mySource, AL_BUFFER, 0));
00273     ALCheck(alDeleteBuffers(BuffersCount, myBuffers));
00274 }
00275 
00276 
00281 bool SoundStream::FillAndPushBuffer(unsigned int BufferNum)
00282 {
00283     bool RequestStop = false;
00284 
00285     // Acquire audio data
00286     Chunk Data = {NULL, 0};
00287     if (!OnGetData(Data))
00288     {
00289         // Mark the buffer as the last one (so that we know when to reset the playing position)
00290         myEndBuffers[BufferNum] = true;
00291 
00292         // Check if the stream must loop or stop
00293         if (myLoop && OnStart())
00294         {
00295             // If we succeeded to restart and we previously had no data, try to fill the buffer once again
00296             if (!Data.Samples || (Data.NbSamples == 0))
00297             {
00298                 return FillAndPushBuffer(BufferNum);
00299             }
00300         }
00301         else
00302         {
00303             // Not looping or restart failed: request stop
00304             RequestStop = true;
00305         }
00306     }
00307 
00308     // Fill the buffer if some data was returned
00309     if (Data.Samples && Data.NbSamples)
00310     {
00311         unsigned int Buffer = myBuffers[BufferNum];
00312 
00313         // Fill the buffer
00314         ALsizei Size = static_cast<ALsizei>(Data.NbSamples) * sizeof(Int16);
00315         ALCheck(alBufferData(Buffer, myFormat, Data.Samples, Size, mySampleRate));
00316 
00317         // Push it into the sound queue
00318         ALCheck(alSourceQueueBuffers(Sound::mySource, 1, &Buffer));
00319     }
00320 
00321     return RequestStop;
00322 }
00323 
00324 
00328 bool SoundStream::FillQueue()
00329 {
00330     // Fill and enqueue all the available buffers
00331     bool RequestStop = false;
00332     for (int i = 0; (i < BuffersCount) && !RequestStop; ++i)
00333     {
00334         if (FillAndPushBuffer(i))
00335             RequestStop = true;
00336     }
00337 
00338     return RequestStop;
00339 }
00340 
00341 
00345 void SoundStream::ClearQueue()
00346 {
00347     // Get the number of buffers still in the queue
00348     ALint NbQueued;
00349     ALCheck(alGetSourcei(Sound::mySource, AL_BUFFERS_QUEUED, &NbQueued));
00350 
00351     // Unqueue them all
00352     ALuint Buffer;
00353     for (ALint i = 0; i < NbQueued; ++i)
00354         ALCheck(alSourceUnqueueBuffers(Sound::mySource, 1, &Buffer));
00355 }
00356 
00357 
00361 bool SoundStream::OnStart()
00362 {
00363     // Does nothing by default
00364 
00365     return true;
00366 }
00367 
00368 } // namespace sf