Otclient  14/8/2020
streamsoundsource.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 #include "streamsoundsource.h"
24 #include "soundbuffer.h"
25 #include "soundfile.h"
26 
28 #include <boost/concept_check.hpp>
29 
31 {
32  for(auto& buffer : m_buffers)
33  buffer = SoundBufferPtr(new SoundBuffer);
34  m_downMix = NoDownMix;
35 }
36 
38 {
39  stop();
40 }
41 
43 {
44  m_soundFile = soundFile;
45  if(m_waitingFile) {
46  m_waitingFile = false;
47  play();
48  }
49 }
50 
52 {
53  m_playing = true;
54 
55  if(!m_soundFile) {
56  m_waitingFile = true;
57  return;
58  }
59 
60  if(m_eof) {
61  m_soundFile->reset();
62  m_eof = false;
63  }
64 
65  queueBuffers();
66 
68 }
69 
71 {
72  m_playing = false;
73 
74  if(m_waitingFile)
75  return;
76 
78  unqueueBuffers();
79 }
80 
81 void StreamSoundSource::queueBuffers()
82 {
83  int queued;
84  alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queued);
85  for(int i = 0; i < STREAM_FRAGMENTS - queued; ++i) {
86  if(!fillBufferAndQueue(m_buffers[i]->getBufferId()))
87  break;
88  }
89 }
90 
91 void StreamSoundSource::unqueueBuffers()
92 {
93  int queued;
94  alGetSourcei(m_sourceId, AL_BUFFERS_QUEUED, &queued);
95  for(int i = 0; i < queued; ++i) {
96  uint buffer;
97  alSourceUnqueueBuffers(m_sourceId, 1, &buffer);
98  }
99 }
100 
102 {
103  if(m_waitingFile)
104  return;
105 
107 
108  int processed = 0;
109  alGetSourcei(m_sourceId, AL_BUFFERS_PROCESSED, &processed);
110  for(int i = 0; i < processed; ++i) {
111  uint buffer;
112  alSourceUnqueueBuffers(m_sourceId, 1, &buffer);
113  //SoundManager::check_al_error("Couldn't unqueue audio buffer: ");
114 
115  if(!fillBufferAndQueue(buffer))
116  break;
117  }
118 
119  if(!isBuffering() && m_playing) {
120  if(!m_looping && m_eof) {
121  stop();
122  } else if(processed == 0) {
123  g_logger.traceError("audio buffer underrun");
124  play();
125  } else if(m_looping) {
126  play();
127  }
128  }
129 }
130 
131 bool StreamSoundSource::fillBufferAndQueue(uint buffer)
132 {
133  if(m_waitingFile)
134  return false;
135 
136  // fill buffer
137  static DataBuffer<char> bufferData(2*STREAM_FRAGMENT_SIZE);
138  ALenum format = m_soundFile->getSampleFormat();
139 
140  int maxRead = STREAM_FRAGMENT_SIZE;
141  if(m_downMix != NoDownMix)
142  maxRead *= 2;
143 
144  int bytesRead = 0;
145  do {
146  bytesRead += m_soundFile->read(&bufferData[bytesRead], maxRead - bytesRead);
147 
148  // end of sound file
149  if(bytesRead < maxRead) {
150  if(m_looping)
151  m_soundFile->reset();
152  else {
153  m_eof = true;
154  break;
155  }
156  }
157  } while(bytesRead < maxRead);
158 
159  if(bytesRead > 0) {
160  if(m_downMix != NoDownMix) {
161  if(format == AL_FORMAT_STEREO16) {
162  assert(bytesRead % 2 == 0);
163  bytesRead /= 2;
164  uint16_t *data = (uint16_t*)bufferData.data();
165  for(int i=0;i<bytesRead/2;i++)
166  data[i] = data[2*i + (m_downMix == DownMixLeft ? 0 : 1)];
167  format = AL_FORMAT_MONO16;
168  }
169  }
170 
171  alBufferData(buffer, format, &bufferData[0], bytesRead, m_soundFile->getRate());
172  ALenum err = alGetError();
173  if(err != AL_NO_ERROR)
174  g_logger.error(stdext::format("unable to refill audio buffer for '%s': %s", m_soundFile->getName(), alGetString(err)));
175 
176  alSourceQueueBuffers(m_sourceId, 1, &buffer);
177  err = alGetError();
178  if(err != AL_NO_ERROR)
179  g_logger.error(stdext::format("unable to queue audio buffer for '%s': %s", m_soundFile->getName(), alGetString(err)));
180  }
181 
182  // return false if there aren't more buffers to fill
183  return (bytesRead >= STREAM_FRAGMENT_SIZE && !m_eof);
184 }
185 
187 {
188  m_downMix = downMix;
189 }
databuffer.h
SoundFile::getName
std::string getName()
Definition: soundfile.h:46
SoundSource::isBuffering
virtual bool isBuffering()
Definition: soundsource.cpp:69
DataBuffer
Definition: databuffer.h:27
Logger::error
void error(const std::string &what)
Definition: logger.h:54
soundbuffer.h
stdext::format
std::string format()
Definition: format.h:82
SoundFile::getSampleFormat
ALenum getSampleFormat()
Definition: soundfile.cpp:57
StreamSoundSource::play
void play()
Definition: streamsoundsource.cpp:51
StreamSoundSource::setSoundFile
void setSoundFile(const SoundFilePtr &soundFile)
Definition: streamsoundsource.cpp:42
StreamSoundSource::stop
void stop()
Definition: streamsoundsource.cpp:70
StreamSoundSource::NoDownMix
@ NoDownMix
Definition: streamsoundsource.h:37
soundfile.h
uint
unsigned int uint
Definition: types.h:31
StreamSoundSource::DownMixLeft
@ DownMixLeft
Definition: streamsoundsource.h:37
StreamSoundSource::update
void update()
Definition: streamsoundsource.cpp:101
StreamSoundSource::DownMix
DownMix
Definition: streamsoundsource.h:37
g_logger
Logger g_logger
Definition: logger.cpp:35
SoundFile::getRate
int getRate()
Definition: soundfile.h:43
SoundFile::reset
virtual void reset()
Definition: soundfile.h:37
StreamSoundSource::downMix
void downMix(DownMix downMix)
Definition: streamsoundsource.cpp:186
SoundSource::stop
virtual void stop()
Definition: soundsource.cpp:58
SoundSource::play
virtual void play()
Definition: soundsource.cpp:52
StreamSoundSource::~StreamSoundSource
virtual ~StreamSoundSource()
Definition: streamsoundsource.cpp:37
SoundSource::m_sourceId
uint m_sourceId
Definition: soundsource.h:69
SoundBuffer
Definition: soundbuffer.h:30
stdext::shared_object_ptr< SoundFile >
SoundSource::update
virtual void update()
Definition: soundsource.cpp:141
streamsoundsource.h
SoundFile::read
virtual int read(void *buffer, int bufferSize)
Definition: soundfile.h:36
SoundBufferPtr
stdext::shared_object_ptr< SoundBuffer > SoundBufferPtr
Definition: declarations.h:44
StreamSoundSource::StreamSoundSource
StreamSoundSource()
Definition: streamsoundsource.cpp:30