00001 #ifdef _MSC_VER
00002 #pragma warning(disable : 4786)
00003 #endif
00004
00005
00006 #include <algorithm>
00007 #include <functional>
00008 #include "device_null.h"
00009 #include "timer.h"
00010 #include "threads.h"
00011 #include "utility.h"
00012
00013 namespace audiere {
00014
00015 NullAudioDevice*
00016 NullAudioDevice::create(const ParameterList& ) {
00017 return new NullAudioDevice;
00018 }
00019
00020
00021 NullAudioDevice::NullAudioDevice() {
00022 }
00023
00024
00025 NullAudioDevice::~NullAudioDevice() {
00026 ADR_GUARD("~NullAudioDevice");
00027
00028 ADR_ASSERT(m_streams.size() == 0,
00029 "Null output context should not die with open streams");
00030 }
00031
00032
00033 void
00034 NullAudioDevice::update() {
00035 ADR_GUARD("NullAudioDevice::update");
00036 SYNCHRONIZED(this);
00037
00038 StreamList::iterator i = m_streams.begin();
00039 for (; i != m_streams.end(); ++i) {
00040 (*i)->update();
00041 }
00042
00043 AI_Sleep(50);
00044 }
00045
00046
00047 OutputStream*
00048 NullAudioDevice::openStream(SampleSource* source) {
00049 ADR_GUARD("NullAudioDevice::openStream");
00050
00051 if (!source) {
00052 return 0;
00053 }
00054
00055 SYNCHRONIZED(this);
00056
00057 NullOutputStream* stream = new NullOutputStream(this, source);
00058 m_streams.push_back(stream);
00059 return stream;
00060 }
00061
00062
00063 OutputStream*
00064 NullAudioDevice::openBuffer(
00065 void* samples, int frame_count,
00066 int channel_count, int sample_rate, SampleFormat sample_format)
00067 {
00068 ADR_GUARD("NullAudioDevice::openBuffer");
00069
00070 RefPtr<SampleSource> source(OpenBufferStream(
00071 samples, frame_count,
00072 channel_count, sample_rate, sample_format));
00073 return openStream(source.get());
00074 }
00075
00076
00077 const char*
00078 NullAudioDevice::getName() {
00079 return "null";
00080 }
00081
00082
00083 void
00084 NullAudioDevice::removeStream(NullOutputStream* stream) {
00085 SYNCHRONIZED(this);
00086 m_streams.remove(stream);
00087 }
00088
00089
00090 NullOutputStream::NullOutputStream(
00091 NullAudioDevice* device,
00092 SampleSource* source)
00093 : m_device(device)
00094 , m_source(source)
00095 , m_is_playing(false)
00096 , m_volume(1)
00097 , m_pan(0)
00098 , m_shift(1)
00099 , m_last_update(0)
00100 {
00101 ADR_GUARD("NullOutputStream::NullOutputStream");
00102 m_source->getFormat(m_channel_count, m_sample_rate, m_sample_format);
00103 }
00104
00105
00106 NullOutputStream::~NullOutputStream() {
00107 m_device->removeStream(this);
00108 }
00109
00110
00111 void
00112 NullOutputStream::play() {
00113 ADR_GUARD("NullOutputStream::play");
00114 m_is_playing = true;
00115 resetTimer();
00116 }
00117
00118
00119 void
00120 NullOutputStream::stop() {
00121 doStop(false);
00122 }
00123
00124
00125 void
00126 NullOutputStream::reset() {
00127 SYNCHRONIZED(m_device.get());
00128 resetTimer();
00129 m_source->reset();
00130 }
00131
00132
00133 bool
00134 NullOutputStream::isPlaying() {
00135 return m_is_playing;
00136 }
00137
00138
00139 void
00140 NullOutputStream::setRepeat(bool repeat) {
00141 SYNCHRONIZED(m_device.get());
00142 m_source->setRepeat(repeat);
00143 }
00144
00145
00146 bool
00147 NullOutputStream::getRepeat() {
00148 SYNCHRONIZED(m_device.get());
00149 return m_source->getRepeat();
00150 }
00151
00152
00153 void
00154 NullOutputStream::setVolume(float volume) {
00155 m_volume = volume;
00156 }
00157
00158
00159 float
00160 NullOutputStream::getVolume() {
00161 return m_volume;
00162 }
00163
00164
00165 void
00166 NullOutputStream::setPan(float pan) {
00167 m_pan = pan;
00168 }
00169
00170
00171 float
00172 NullOutputStream::getPan() {
00173 return m_pan;
00174 }
00175
00176
00177 void
00178 NullOutputStream::setPitchShift(float shift) {
00179 m_shift = shift;
00180 }
00181
00182
00183 float
00184 NullOutputStream::getPitchShift() {
00185 return m_shift;
00186 }
00187
00188
00189 bool
00190 NullOutputStream::isSeekable() {
00191 return m_source->isSeekable();
00192 }
00193
00194
00195 int
00196 NullOutputStream::getLength() {
00197 return m_source->getLength();
00198 }
00199
00200
00201 void
00202 NullOutputStream::setPosition(int position) {
00203 SYNCHRONIZED(m_device.get());
00204 m_source->setPosition(position);
00205 reset();
00206 }
00207
00208
00209 int
00210 NullOutputStream::getPosition() {
00211 return m_source->getPosition();
00212 }
00213
00214
00215 void
00216 NullOutputStream::doStop(bool internal) {
00217 if (m_is_playing) {
00218 m_is_playing = false;
00219 if (!internal) {
00220
00221 m_device->fireStopEvent(this, StopEvent::STOP_CALLED);
00222 }
00223 } else {
00224 m_is_playing = false;
00225 }
00226 }
00227
00228
00229 void
00230 NullOutputStream::resetTimer() {
00231 m_last_update = GetNow();
00232 }
00233
00234
00235 void
00236 NullOutputStream::update() {
00237 ADR_GUARD("NullOutputStream::update");
00238
00239 if (m_is_playing) {
00240 ADR_LOG("Null output stream is playing");
00241
00242
00243
00244 u64 now = GetNow();
00245 u64 elapsed = now - m_last_update;
00246
00247 double shifted_time = m_shift * s64(elapsed) / 1000000.0;
00248 int samples_to_read = int(m_sample_rate * shifted_time);
00249
00250 ADR_IF_DEBUG {
00251 char str[100];
00252 sprintf(str, "Samples to read: %d", samples_to_read);
00253 ADR_LOG(str);
00254 }
00255
00256 int samples_read = dummyRead(samples_to_read);
00257
00258 if (samples_read != samples_to_read) {
00259 ADR_LOG("Stopping null output stream");
00260 m_source->reset();
00261 doStop(true);
00262 m_device->fireStopEvent(this, StopEvent::STREAM_ENDED);
00263 }
00264
00265 m_last_update = now;
00266 }
00267 }
00268
00269
00270 int
00271 NullOutputStream::dummyRead(int samples_to_read) {
00272 int total = 0;
00273
00274 const int bytes_per_sample = GetSampleSize(m_sample_format);
00275
00276
00277 u8* dummy = new u8[1024 * m_channel_count * bytes_per_sample];
00278 while (samples_to_read > 0) {
00279 int read = std::min(1024, samples_to_read);
00280 int actual_read = m_source->read(read, dummy);
00281 total += actual_read;
00282 samples_to_read -= actual_read;
00283 if (actual_read < read) {
00284 break;
00285 }
00286 }
00287
00288 delete[] dummy;
00289 return total;
00290 }
00291
00292 }