From a0f7a7670c09d333adfe97bb21bb9bb0aced743a Mon Sep 17 00:00:00 2001 From: casey Date: Sat, 30 Apr 2016 14:31:37 -0700 Subject: [PATCH] Fixed WaveOut to actually use both channels, instead of just the left one. Also fixed a few bugs related to closing WaveOut. --- src/contrib/oggdecoder/OGGDecoder.cpp | 233 ------------------ ...urceSupplier.cpp => OggDecoderFactory.cpp} | 36 ++- ...ggSourceSupplier.h => OggDecoderFactory.h} | 6 +- src/contrib/oggdecoder/VorbisDecoder.cpp | 214 ++++++++++++++++ .../{OGGDecoder.h => VorbisDecoder.h} | 29 ++- src/contrib/oggdecoder/oggdecoder.vcxproj | 8 +- src/contrib/oggdecoder/oggdecoder_plugin.cpp | 4 +- src/contrib/waveout/WaveOut.cpp | 40 ++- src/contrib/waveout/WaveOutBuffer.cpp | 11 +- src/core/audio/Player.cpp | 10 +- src/core/audio/Stream.cpp | 154 ++++++------ src/core/filestreams/LocalFileStream.cpp | 17 +- src/core/sdk/IPlugin.h | 15 +- src/core/sdk/IRequestParser.h | 58 +++++ src/core/sdk/IRequestPlugin.h | 61 +++++ src/core/sdk/IResponder.h | 58 +++++ 16 files changed, 542 insertions(+), 412 deletions(-) delete mode 100644 src/contrib/oggdecoder/OGGDecoder.cpp rename src/contrib/oggdecoder/{OggSourceSupplier.cpp => OggDecoderFactory.cpp} (75%) rename src/contrib/oggdecoder/{OggSourceSupplier.h => OggDecoderFactory.h} (93%) create mode 100644 src/contrib/oggdecoder/VorbisDecoder.cpp rename src/contrib/oggdecoder/{OGGDecoder.h => VorbisDecoder.h} (73%) create mode 100644 src/core/sdk/IRequestParser.h create mode 100644 src/core/sdk/IRequestPlugin.h create mode 100644 src/core/sdk/IResponder.h diff --git a/src/contrib/oggdecoder/OGGDecoder.cpp b/src/contrib/oggdecoder/OGGDecoder.cpp deleted file mode 100644 index b8825ccaf..000000000 --- a/src/contrib/oggdecoder/OGGDecoder.cpp +++ /dev/null @@ -1,233 +0,0 @@ -////////////////////////////////////////////////////////////////////////////// -// Copyright © 2007, mC2 team -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// * Neither the name of the author nor the names of other contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -////////////////////////////////////////////////////////////////////////////// -#include "StdAfx.h" -#include "OGGDecoder.h" - -OGGDecoder::OGGDecoder() -{ - // Set the callbacks to handle all file io - this->oggCallbacks.read_func = &OggRead; - this->oggCallbacks.seek_func = &OggSeek; - this->oggCallbacks.tell_func = &OggTell; - this->oggCallbacks.close_func = &OggClose; - - -} - -size_t OGGDecoder::OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource){ - return (size_t)((OGGDecoder*)datasource)->fileStream->Read(buffer,(long)(nofParts*partSize)); -} - -int OGGDecoder::OggSeek(void *datasource, ogg_int64_t offset, int whence){ - switch(whence){ - case SEEK_CUR: - { - long currentPosition = ((OGGDecoder*)datasource)->fileStream->Position(); - if( ((OGGDecoder*)datasource)->fileStream->SetPosition(currentPosition+(long)offset)){ - return 0; - } - } - break; - case SEEK_END: - { - long fileSize = ((OGGDecoder*)datasource)->fileStream->Filesize(); - if( ((OGGDecoder*)datasource)->fileStream->SetPosition(fileSize)){ - return 0; - } - } - break; - default: - { - if( ((OGGDecoder*)datasource)->fileStream->SetPosition((long)offset)){ - return 0; - } - } - } - - // Unsuccessfull - return -1; -} - -long OGGDecoder::OggTell(void *datasource){ - return ((OGGDecoder*)datasource)->fileStream->Position(); -} - -int OGGDecoder::OggClose(void *datasource){ - if( ((OGGDecoder*)datasource)->fileStream->Close() ){ - return 0; - } - return -1; -} - - -OGGDecoder::~OGGDecoder() -{ -} - -bool OGGDecoder::Open(musik::core::filestreams::IFileStream *fileStream) -{ - this->fileStream = fileStream; - - if(ov_open_callbacks(this,&this->oggFile,NULL,0,this->oggCallbacks)!=0){ - return false; - } - - return true; -} - - -void OGGDecoder::Destroy(void){ - - ov_clear(&this->oggFile); - - delete this; -} -/* -bool OGGDecoder::GetFormat(unsigned long * SampleRate, unsigned long * Channels){ - vorbis_info *info = ov_info(&this->oggFile,-1); - if(info){ - *SampleRate = info->rate; - *Channels = info->channels; - return true; - } - return false; -} - -bool OGGDecoder::GetLength(unsigned long * MS){ - double time = ov_time_total(&this->oggFile, 0); - if( time!=OV_EINVAL ){ - *MS = (unsigned long)(time * 1000.0); - return true; - } - return false; -} -*/ -double OGGDecoder::SetPosition(double second,double totalLength){ - - if(ov_seekable(&this->oggFile)){ - if(!ov_time_seek(&this->oggFile, second)){ - return ov_time_tell(&this->oggFile); - } - } - return -1; -} - -bool OGGDecoder::GetBuffer(IBuffer *buffer){ - vorbis_info *info = ov_info(&this->oggFile, -1); - - long nofSamplesMax = 1024*2; - int currentSelection; - - buffer->SetChannels(info->channels); - buffer->SetSampleRate(info->rate); - buffer->SetSamples(nofSamplesMax); - - float ** pcm; - unsigned long samplesRead = ov_read_float(&this->oggFile, &pcm, nofSamplesMax, ¤tSelection); - if(samplesRead == 0) { - return false; - } - - buffer->SetSamples(samplesRead); - -/* MUSIKCUBE EXPECTS -SPEAKER_FRONT_LEFT 0x1 -SPEAKER_FRONT_RIGHT 0x2 -SPEAKER_FRONT_CENTER 0x4 -SPEAKER_LOW_FREQUENCY 0x8 -SPEAKER_BACK_LEFT 0x10 -SPEAKER_BACK_RIGHT 0x20 -*/ - -/* OGG DOES - -One channel: the stream is monophonic -Two channels: the stream is stereo. channel order: left, right. -Three channels: the stream is a 1d-surround encoding. channel order: left, center, right -Four channels: the stream is quadraphonic surround. channel order: front left, front right, rear left, rear right -Five channels: the stream is five-channel surround. channel order: front left, front center, front right, rear left, rear right -Six channels: (used in Dolby Digital/AC3) the stream is 5,1 surround. channel order: front left, front center, front right, rear left, rear right, LFE (the sixth channel is entirely bass). -*/ - -// so we need to REORDER - float *pDataBuffer = buffer->BufferPointer(); - - if(info->channels == 3){ - float *pDataBuffer = buffer->BufferPointer(); - for(unsigned long x=0; xchannels == 5){ - for(unsigned long x=0; xchannels == 6){ - for(unsigned long x=0; xchannels; ++channel){ - *pDataBuffer = pcm[channel][x]; - ++pDataBuffer; - } - } - } - - return true; -} diff --git a/src/contrib/oggdecoder/OggSourceSupplier.cpp b/src/contrib/oggdecoder/OggDecoderFactory.cpp similarity index 75% rename from src/contrib/oggdecoder/OggSourceSupplier.cpp rename to src/contrib/oggdecoder/OggDecoderFactory.cpp index a8513ca60..998a5ed5c 100644 --- a/src/contrib/oggdecoder/OggSourceSupplier.cpp +++ b/src/contrib/oggdecoder/OggDecoderFactory.cpp @@ -32,47 +32,41 @@ ////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" - #include +#include "OggDecoderFactory.h" +#include "VorbisDecoder.h" -#include "OggSourceSupplier.h" - -#include "OggDecoder.h" - -OggSourceSupplier::OggSourceSupplier() -{ +OggDecoderFactory::OggDecoderFactory() { } -OggSourceSupplier::~OggSourceSupplier() -{ +OggDecoderFactory::~OggDecoderFactory() { } -void OggSourceSupplier::Destroy() -{ +void OggDecoderFactory::Destroy() { delete this; } -IDecoder* OggSourceSupplier::CreateDecoder() -{ - return new OGGDecoder(); +IDecoder* OggDecoderFactory::CreateDecoder() { + return new VorbisDecoder(); } -bool OggSourceSupplier::CanHandle(const utfchar* type) const -{ - if(type){ +bool OggDecoderFactory::CanHandle(const utfchar* type) const { + if (type) { utfstring typeString(type); - if(typeString.find(UTF("ogg"))!=utfstring::npos){ + + if (typeString.find(UTF("ogg")) != utfstring::npos) { return true; } - if(typeString.find(UTF("oga"))!=utfstring::npos){ + if (typeString.find(UTF("oga")) != utfstring::npos) { return true; } - if(typeString.find(UTF("audio/ogg"))!=utfstring::npos){ + if (typeString.find(UTF("audio/ogg")) != utfstring::npos) { return true; } - if(typeString.find(UTF("audio/vorbis"))!=utfstring::npos){ + if (typeString.find(UTF("audio/vorbis")) != utfstring::npos) { return true; } } + return false; } diff --git a/src/contrib/oggdecoder/OggSourceSupplier.h b/src/contrib/oggdecoder/OggDecoderFactory.h similarity index 93% rename from src/contrib/oggdecoder/OggSourceSupplier.h rename to src/contrib/oggdecoder/OggDecoderFactory.h index 99bd6cbc7..03117e1f2 100644 --- a/src/contrib/oggdecoder/OggSourceSupplier.h +++ b/src/contrib/oggdecoder/OggDecoderFactory.h @@ -37,10 +37,10 @@ using namespace musik::core::audio; -class OggSourceSupplier : public IDecoderFactory { +class OggDecoderFactory : public IDecoderFactory { public: - OggSourceSupplier(); - ~OggSourceSupplier(); + OggDecoderFactory(); + ~OggDecoderFactory(); IDecoder* CreateDecoder(); void Destroy(); diff --git a/src/contrib/oggdecoder/VorbisDecoder.cpp b/src/contrib/oggdecoder/VorbisDecoder.cpp new file mode 100644 index 000000000..6ae9b1845 --- /dev/null +++ b/src/contrib/oggdecoder/VorbisDecoder.cpp @@ -0,0 +1,214 @@ +////////////////////////////////////////////////////////////////////////////// +// Copyright © 2007, mC2 team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "VorbisDecoder.h" + +VorbisDecoder::VorbisDecoder() { + this->oggCallbacks.read_func = &OggRead; + this->oggCallbacks.seek_func = &OggSeek; + this->oggCallbacks.tell_func = &OggTell; + this->oggCallbacks.close_func = &OggClose; +} + +size_t VorbisDecoder::OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource) { + return (size_t)((VorbisDecoder*)datasource)->fileStream->Read(buffer,(long)(nofParts*partSize)); +} + +int VorbisDecoder::OggSeek(void *datasource, ogg_int64_t offset, int whence) { + switch(whence) { + case SEEK_CUR: + { + long currentPosition = ((VorbisDecoder*)datasource)->fileStream->Position(); + if(((VorbisDecoder*)datasource)->fileStream->SetPosition(currentPosition+(long) offset)) { + return 0; + } + } + break; + case SEEK_END: + { + long fileSize = ((VorbisDecoder*) datasource)->fileStream->Filesize(); + if(((VorbisDecoder*) datasource)->fileStream->SetPosition(fileSize)) { + return 0; + } + } + break; + default: + { + if(((VorbisDecoder*) datasource)->fileStream->SetPosition((long) offset)) { + return 0; + } + } + } + + return -1; +} + +long VorbisDecoder::OggTell(void *datasource) { + return ((VorbisDecoder*)datasource)->fileStream->Position(); +} + +int VorbisDecoder::OggClose(void *datasource) { + if(((VorbisDecoder*)datasource)->fileStream->Close()) { + return 0; + } + return -1; +} + +VorbisDecoder::~VorbisDecoder() { +} + +bool VorbisDecoder::Open(musik::core::filestreams::IFileStream *fileStream) { + this->fileStream = fileStream; + + if (ov_open_callbacks(this, &this->oggFile, NULL, 0, this->oggCallbacks) != 0) { + return false; + } + + return true; +} + +void VorbisDecoder::Destroy() { + ov_clear(&this->oggFile); + delete this; +} + +double VorbisDecoder::SetPosition(double second, double totalLength) { + if (ov_seekable(&this->oggFile)) { + if (!ov_time_seek(&this->oggFile, second)) { + return ov_time_tell(&this->oggFile); + } + } + + return -1; +} + +#define OGG_MAX_SAMPLES 1024 + +bool VorbisDecoder::GetBuffer(IBuffer *buffer) { + int bitstream; + float **pcm; + + unsigned long samplesRead = ov_read_float(&this->oggFile, &pcm, OGG_MAX_SAMPLES, &bitstream); + + if (samplesRead == 0) { + return false; + } + + vorbis_info *info = ov_info(&this->oggFile, -1); + buffer->SetChannels(info->channels); + buffer->SetSampleRate(info->rate); + buffer->SetSamples(samplesRead); + + /* + The musik audio engine expects: + + SPEAKER_FRONT_LEFT 0x1 + SPEAKER_FRONT_RIGHT 0x2 + SPEAKER_FRONT_CENTER 0x4 + SPEAKER_LOW_FREQUENCY 0x8 + SPEAKER_BACK_LEFT 0x10 + SPEAKER_BACK_RIGHT 0x20 + + OGG returns: + + One channel: the stream is monophonic + Two channels: the stream is stereo. channel order: left, right. + Three channels: the stream is a 1d-surround encoding. channel order: left, center, right + Four channels: the stream is quadraphonic surround. channel order: front left, front right, rear left, rear right + Five channels: the stream is five-channel surround. channel order: front left, front center, front right, rear left, rear right + Six channels: (used in Dolby Digital/AC3) the stream is 5,1 surround. channel order: front left, front center, front right, rear left, rear right, LFE (the sixth channel is entirely bass). + + ... so let's re-order when writing to our output buffer ... + */ + + float *pDataBuffer = buffer->BufferPointer(); + + if (info->channels == 2) { + for (unsigned long x = 0; x < samplesRead; ++x) { + pDataBuffer[0] = pcm[0][x]; + pDataBuffer[1] = pcm[1][x]; + pDataBuffer += 2; + } + } + else if (info->channels == 3) { + for (unsigned long x=0; x < samplesRead; ++x) { + *pDataBuffer = pcm[0][x]; + ++pDataBuffer; + *pDataBuffer = pcm[2][x]; + ++pDataBuffer; + *pDataBuffer = pcm[1][x]; + ++pDataBuffer; + } + } + else if (info->channels == 5) { + for (unsigned long x = 0; x < samplesRead; ++x) { + *pDataBuffer = pcm[0][x]; + ++pDataBuffer; + *pDataBuffer = pcm[2][x]; + ++pDataBuffer; + *pDataBuffer = pcm[1][x]; + ++pDataBuffer; + *pDataBuffer = pcm[3][x]; + ++pDataBuffer; + *pDataBuffer = pcm[4][x]; + ++pDataBuffer; + } + } + else if (info->channels == 6) { + for (unsigned long x = 0; x < samplesRead; ++x) { + *pDataBuffer = pcm[0][x]; + ++pDataBuffer; + *pDataBuffer = pcm[2][x]; + ++pDataBuffer; + *pDataBuffer = pcm[1][x]; + ++pDataBuffer; + *pDataBuffer = pcm[5][x]; + ++pDataBuffer; + *pDataBuffer = pcm[3][x]; + ++pDataBuffer; + *pDataBuffer = pcm[4][x]; + ++pDataBuffer; + } + } + else { + for (unsigned long x = 0; x < samplesRead; ++x) { + for (int channel(0); channel < info->channels; ++channel) { + *pDataBuffer = pcm[channel][x]; + ++pDataBuffer; + } + } + } + + return true; +} diff --git a/src/contrib/oggdecoder/OGGDecoder.h b/src/contrib/oggdecoder/VorbisDecoder.h similarity index 73% rename from src/contrib/oggdecoder/OGGDecoder.h rename to src/contrib/oggdecoder/VorbisDecoder.h index 88ca2566c..f6201ffd0 100644 --- a/src/contrib/oggdecoder/OGGDecoder.h +++ b/src/contrib/oggdecoder/VorbisDecoder.h @@ -39,29 +39,28 @@ using namespace musik::core::audio; -class OGGDecoder : public IDecoder +class VorbisDecoder : public IDecoder { public: - OGGDecoder(); - ~OGGDecoder(); + VorbisDecoder(); + ~VorbisDecoder(); public: - virtual void Destroy(); - virtual double SetPosition(double second,double totalLength); - virtual bool GetBuffer(IBuffer *buffer); - virtual bool Open(musik::core::filestreams::IFileStream *fileStream); + virtual void Destroy(); + virtual double SetPosition(double second, double totalLength); + virtual bool GetBuffer(IBuffer *buffer); + virtual bool Open(musik::core::filestreams::IFileStream *fileStream); public: - // OGG callbacks - static size_t OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource); - static int OggSeek(void *datasource, ogg_int64_t offset, int whence); - static long OggTell(void *datasource); - static int OggClose(void *datasource); + /* libvorbis callbacks */ + static size_t OggRead(void *buffer, size_t nofParts, size_t partSize, void *datasource); + static int OggSeek(void *datasource, ogg_int64_t offset, int whence); + static long OggTell(void *datasource); + static int OggClose(void *datasource); protected: musik::core::filestreams::IFileStream *fileStream; - OggVorbis_File oggFile; - ov_callbacks oggCallbacks; - + OggVorbis_File oggFile; + ov_callbacks oggCallbacks; }; diff --git a/src/contrib/oggdecoder/oggdecoder.vcxproj b/src/contrib/oggdecoder/oggdecoder.vcxproj index feb2fb7d7..20dc4801a 100755 --- a/src/contrib/oggdecoder/oggdecoder.vcxproj +++ b/src/contrib/oggdecoder/oggdecoder.vcxproj @@ -93,14 +93,14 @@ - + - + - - + + diff --git a/src/contrib/oggdecoder/oggdecoder_plugin.cpp b/src/contrib/oggdecoder/oggdecoder_plugin.cpp index dedfd80fa..a00ef1848 100644 --- a/src/contrib/oggdecoder/oggdecoder_plugin.cpp +++ b/src/contrib/oggdecoder/oggdecoder_plugin.cpp @@ -38,7 +38,7 @@ #include -#include "OggSourceSupplier.h" +#include "OggDecoderFactory.h" BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return true; @@ -57,5 +57,5 @@ extern "C" __declspec(dllexport) musik::core::IPlugin* GetPlugin() { } extern "C" __declspec(dllexport) IDecoderFactory* GetDecoderFactory() { - return new OggSourceSupplier(); + return new OggDecoderFactory(); } diff --git a/src/contrib/waveout/WaveOut.cpp b/src/contrib/waveout/WaveOut.cpp index 6ccd15c6e..72e631425 100644 --- a/src/contrib/waveout/WaveOut.cpp +++ b/src/contrib/waveout/WaveOut.cpp @@ -33,7 +33,7 @@ #include "WaveOut.h" -#define MAX_VOLUME 65535.0 +#define MAX_VOLUME 0xFFFF WaveOut::WaveOut() : waveHandle(NULL) @@ -51,7 +51,7 @@ WaveOut::~WaveOut(){ } } -void WaveOut::Destroy(){ +void WaveOut::Destroy() { delete this; } @@ -66,7 +66,8 @@ void WaveOut::Resume() { void WaveOut::SetVolume(double volume) { if (this->waveHandle) { DWORD newVolume = (DWORD)(volume * MAX_VOLUME); - waveOutSetVolume(this->waveHandle,newVolume); + DWORD leftAndRight = (newVolume << 16) | newVolume; + waveOutSetVolume(this->waveHandle, leftAndRight); } this->currentVolume = volume; @@ -148,7 +149,7 @@ void WaveOut::SetFormat(IBuffer *buffer) { this->currentSampleRate = buffer->SampleRate(); /* format changed, kill the old output device */ - if(this->waveHandle!=NULL) { + if (this->waveHandle != NULL) { waveOutClose(this->waveHandle); this->waveHandle = NULL; } @@ -156,44 +157,41 @@ void WaveOut::SetFormat(IBuffer *buffer) { /* reset, and configure speaker output */ ZeroMemory(&this->waveFormat, sizeof(this->waveFormat)); - DWORD speakerconfig = 0; + DWORD speakerConfig = 0; switch (buffer->Channels()) { case 1: - speakerconfig = KSAUDIO_SPEAKER_MONO; + speakerConfig = KSAUDIO_SPEAKER_MONO; break; case 2: - speakerconfig = KSAUDIO_SPEAKER_STEREO; + speakerConfig = KSAUDIO_SPEAKER_STEREO; break; case 4: - speakerconfig = KSAUDIO_SPEAKER_QUAD; + speakerConfig = KSAUDIO_SPEAKER_QUAD; break; case 5: - speakerconfig = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT); + speakerConfig = (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT); break; case 6: - speakerconfig = KSAUDIO_SPEAKER_5POINT1; + speakerConfig = KSAUDIO_SPEAKER_5POINT1; break; } - this->waveFormat.Format.cbSize = 22; + this->waveFormat.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); this->waveFormat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; this->waveFormat.Format.nChannels = (WORD) buffer->Channels(); + this->waveFormat.Format.wBitsPerSample = sizeof(float) * 8; this->waveFormat.Format.nSamplesPerSec = (DWORD) buffer->SampleRate(); - this->waveFormat.Format.wBitsPerSample = 32; - this->waveFormat.Format.nBlockAlign = - (this->waveFormat.Format.wBitsPerSample / 8) * this->waveFormat.Format.nChannels; + int bytesPerSample = this->waveFormat.Format.wBitsPerSample / 8; + this->waveFormat.Format.nBlockAlign = bytesPerSample * this->waveFormat.Format.nChannels; this->waveFormat.Format.nAvgBytesPerSec = - ((this->waveFormat.Format.wBitsPerSample/8) * - this->waveFormat.Format.nChannels) * - this->waveFormat.Format.nSamplesPerSec; /* Compute using nBlkAlign * nSamp/Sec */ + this->waveFormat.Format.nBlockAlign * this->waveFormat.Format.nSamplesPerSec; - /* IMPORTANT NOTE: wValidBitsPerSample/wReserved/wSamplesPerBlock are a union, - so don't set wReserved or wSamplesPerBlock to 0 after assigning wValidBitsPerSample. */ - this->waveFormat.Samples.wValidBitsPerSample = 32; - this->waveFormat.dwChannelMask = speakerconfig; + /* NOTE: wValidBitsPerSample/wReserved/wSamplesPerBlock are a union */ + this->waveFormat.Samples.wValidBitsPerSample = this->waveFormat.Format.wBitsPerSample; + this->waveFormat.dwChannelMask = speakerConfig; this->waveFormat.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; /* create the output device */ diff --git a/src/contrib/waveout/WaveOutBuffer.cpp b/src/contrib/waveout/WaveOutBuffer.cpp index d66e5111b..7faaedb73 100644 --- a/src/contrib/waveout/WaveOutBuffer.cpp +++ b/src/contrib/waveout/WaveOutBuffer.cpp @@ -34,6 +34,8 @@ #include "WaveOutBuffer.h" #include "WaveOut.h" +#include + WaveOutBuffer::WaveOutBuffer(WaveOut *waveOut, IBuffer *buffer, IPlayer *player) : waveOut(waveOut) , buffer(buffer) @@ -44,9 +46,9 @@ WaveOutBuffer::WaveOutBuffer(WaveOut *waveOut, IBuffer *buffer, IPlayer *player) } void WaveOutBuffer::Initialize() { - this->header.dwBufferLength = this->buffer->Samples() * this->buffer->Channels()*sizeof(float); - this->header.lpData = (LPSTR)this->buffer->BufferPointer(); - this->header.dwUser = (DWORD_PTR)this; + this->header.dwBufferLength = this->buffer->Samples() * this->buffer->Channels() * sizeof(float); + this->header.lpData = (LPSTR) this->buffer->BufferPointer(); + this->header.dwUser = (DWORD_PTR) this; this->header.dwBytesRecorded = 0; this->header.dwFlags = 0; this->header.dwLoops = 0; @@ -57,14 +59,13 @@ void WaveOutBuffer::Initialize() { if (result != MMSYSERR_NOERROR) { throw; } - - this->header.dwFlags |= WHDR_DONE; } void WaveOutBuffer::Destroy() { if (!this->destroyed) { if (this->waveOut->waveHandle && this->header.dwFlags & WHDR_PREPARED) { waveOutUnprepareHeader(this->waveOut->waveHandle, &this->header, sizeof(WAVEHDR)); + this->header.dwFlags = WHDR_DONE; } this->player->Notify(); diff --git a/src/core/audio/Player.cpp b/src/core/audio/Player.cpp index 0f475ca44..f631e5055 100644 --- a/src/core/audio/Player.cpp +++ b/src/core/audio/Player.cpp @@ -186,7 +186,9 @@ void Player::ThreadLoop() { } } - /* TODO: why do we release buffers from the output here?? */ + /* TODO: why do we release buffers from the output here?? this appears to be + an old hack to fix up some WaveOut issues where pending buffers need to be + released before the device can be closed. we can probably remove this now. */ this->output->ReleaseBuffers(); BufferPtr buffer; @@ -207,6 +209,8 @@ void Player::ThreadLoop() { } } + /* TODO CLEAN UP AND DOCUMENT */ + /* if we have a buffer available, let's try to send it to the output device */ if (buffer) { { @@ -232,7 +236,7 @@ void Player::ThreadLoop() { } } } - else{ + else { // Buffer send to output boost::mutex::scoped_lock lock(this->mutex); if(!this->bufferQueue.empty()) { @@ -246,6 +250,8 @@ void Player::ThreadLoop() { } } + /* END TODO CLEAN UP AND DOCUMENT */ + /* if we're unable to obtain a buffer, it means we're out of data and the player is finished. terminate the thread. */ else { diff --git a/src/core/audio/Stream.cpp b/src/core/audio/Stream.cpp index 30b44a61e..a82354668 100644 --- a/src/core/audio/Stream.cpp +++ b/src/core/audio/Stream.cpp @@ -38,6 +38,7 @@ #include using namespace musik::core::audio; +using musik::core::PluginFactory; Stream::Stream(unsigned int options) :preferedBufferSampleSize(4096) @@ -45,12 +46,9 @@ Stream::Stream(unsigned int options) ,decoderSampleRate(0) ,decoderSamplePosition(0) { - // Get all DSPs - // TODO: fixing PluginFactory - if( (this->options&NoDSP)==0){ - this->dsps = musik::core::PluginFactory::Instance().QueryInterface< - IDSP, - musik::core::PluginFactory::DestroyDeleter >("GetDSP"); + if((this->options&NoDSP) == 0){ + typedef PluginFactory::DestroyDeleter Deleter; + this->dsps = PluginFactory::Instance().QueryInterface("GetDSP"); } } @@ -62,9 +60,7 @@ StreamPtr Stream::Create(unsigned int options){ return StreamPtr(new Stream(options)); } -BufferPtr Stream::NextBuffer(){ - - // Decode a new buffer +BufferPtr Stream::NextBuffer() { return this->GetNextBuffer(); } @@ -82,110 +78,104 @@ double Stream::SetPosition(double seconds){ } return newPosition; } -/* -void Stream::SetMaxCacheLength(double seconds){ -} -void Stream::SetPreferedBufferSampleSize(long samples){ -} -*/ -bool Stream::OpenStream(utfstring uri){ - - // Open the filestream - this->fileStream = musik::core::filestreams::Factory::OpenFile(uri.c_str()); - if(!this->fileStream){ +bool Stream::OpenStream(utfstring uri) { + /* use our file stream abstraction to open the data at the + specified URI */ + this->fileStream = musik::core::filestreams::Factory::OpenFile(uri.c_str()); + if (!this->fileStream) { return false; } - // Look up what DecoderFactory to use + /* find a DecoderFactory we can use for this type of data*/ StreamHelper::DecoderFactoryPtr decoderFactory; - for(StreamHelper::DecoderFactories::iterator decoderFactoryIt=Stream::Helper()->decoderFactories.begin();decoderFactoryIt!=Stream::Helper()->decoderFactories.end() && !decoderFactory;++decoderFactoryIt){ - if( (*decoderFactoryIt)->CanHandle(this->fileStream->Type())){ - decoderFactory = (*decoderFactoryIt); + StreamHelper::DecoderFactories::iterator factories = Stream::Helper()->decoderFactories.begin(); + StreamHelper::DecoderFactories::iterator end = Stream::Helper()->decoderFactories.end(); + + for( ; factories != end && !decoderFactory; ++factories) { + if((*factories)->CanHandle(this->fileStream->Type())){ + decoderFactory = (*factories); } } - if(!decoderFactory){ - // We have failed to get a working decoderFactory + if (!decoderFactory) { + /* nothing can decode this type of file */ return false; } - - // Create the decoder - IDecoder *decoderPtr = decoderFactory->CreateDecoder(); - if(!decoderPtr){ + IDecoder *decoder = decoderFactory->CreateDecoder(); + if (!decoder) { + /* shouldn't ever happen, the factory said it can handle this file */ return false; } + typedef PluginFactory::DestroyDeleter Deleter; - // Open the decoder - typedef musik::core::PluginFactory::DestroyDeleter IDecoderDeleter; - this->decoder.reset(decoderPtr,IDecoderDeleter()); - if( !this->decoder->Open(this->fileStream.get()) ){ + /* ask the decoder to open the data stream. if it returns true we're + good to start pulling data out of it! */ + this->decoder.reset(decoder, Deleter()); + if (!this->decoder->Open(this->fileStream.get())) { return false; } + return true; - } -BufferPtr Stream::GetNextDecoderBuffer(){ - // First get a buffer +BufferPtr Stream::GetNextDecoderBuffer() { + /* get a spare buffer, then ask the decoder for some data */ BufferPtr buffer = this->NewBuffer(); - - // Get the buffer from the decoder - if(!this->decoder->GetBuffer(buffer.get())){ - // Nothing to decode left, return a empty buffer + if(!this->decoder->GetBuffer(buffer.get())) { return BufferPtr(); } - // We need to save the decoders samplerate to be able to calculate the current time-position + /* remember the samplerate so we can calculate the current time-position */ if(!this->decoderSampleRate){ this->decoderSampleRate = buffer->SampleRate(); } - // Calculate the current sample position + /* calculate the current offset, in samples */ this->decoderSamplePosition += buffer->Samples(); - // Save the position (seconds) in the buffer - buffer->position = ((double)this->decoderSamplePosition)/((double)this->decoderSampleRate); + /* calculate the position (seconds) in the buffer */ + buffer->position = ((double)this->decoderSamplePosition) / ((double)this->decoderSampleRate); return buffer; - } -BufferPtr Stream::GetNextBuffer(){ - // First get the next decoded buffer +BufferPtr Stream::GetNextBuffer() { + /* ask the decoder for the next buffer */ BufferPtr currentBuffer = this->GetNextDecoderBuffer(); - if(currentBuffer){ - ///////////////////////////////////////////// - // Lets check if the buffer is too small - bool moreBuffers(true); - while(currentBuffer->Samples()preferedBufferSampleSize && moreBuffers){ - BufferPtr appendBuffer = this->GetNextDecoderBuffer(); - if(appendBuffer){ - currentBuffer->Append(appendBuffer); - this->DeleteBuffer(appendBuffer); - }else{ + if(currentBuffer) { + /* try to fill the buffer to its optimal size; if the decoder didn't return + a full buffer, ask it for some more data. */ + bool moreBuffers = true; + while (currentBuffer->Samples() < this->preferedBufferSampleSize && moreBuffers) { + BufferPtr bufferToAppend = this->GetNextDecoderBuffer(); + if (bufferToAppend) { + currentBuffer->Append(bufferToAppend); + this->DeleteBuffer(bufferToAppend); + } + else { moreBuffers = false; } } - ///////////////////////////////////////////// - BufferPtr oldBuffer = this->NewBuffer(); + /* let DSP plugins process the buffer */ + if (this->dsps.size() > 0) { + BufferPtr oldBuffer = this->NewBuffer(); - // Now lets loop through all DSP plugins - for(Dsps::iterator dsp=this->dsps.begin();dsp!=this->dsps.end();++dsp){ - oldBuffer->CopyFormat(currentBuffer); - oldBuffer->position = currentBuffer->position; + for (Dsps::iterator dsp = this->dsps.begin(); dsp != this->dsps.end(); ++dsp) { + oldBuffer->CopyFormat(currentBuffer); + oldBuffer->position = currentBuffer->position; - if( (*dsp)->ProcessBuffers(currentBuffer.get(),oldBuffer.get()) ){ - // Success in processing DSP, swap the buffers - currentBuffer.swap(oldBuffer); + if ((*dsp)->ProcessBuffers(currentBuffer.get(), oldBuffer.get())) { + currentBuffer.swap(oldBuffer); + } } - } - this->DeleteBuffer(oldBuffer); + this->DeleteBuffer(oldBuffer); + } } @@ -203,7 +193,7 @@ BufferPtr Stream::NewBuffer(){ return buffer; } -void Stream::DeleteBuffer(BufferPtr oldBuffer){ +void Stream::DeleteBuffer(BufferPtr oldBuffer) { this->availableBuffers.push_back(oldBuffer); } @@ -215,20 +205,22 @@ Stream::StreamHelperPtr Stream::Helper(){ return helper; } -Stream::StreamHelper::StreamHelper(){ - // Look up all DecoderFactories - this->decoderFactories = musik::core::PluginFactory::Instance().QueryInterface< - IDecoderFactory, - musik::core::PluginFactory::DestroyDeleter >("GetDecoderFactory"); +Stream::StreamHelper::StreamHelper() { + PluginFactory::DestroyDeleter typedef Deleter; + + this->decoderFactories = PluginFactory::Instance() + .QueryInterface("GetDecoderFactory"); } -double Stream::DecoderProgress(){ - if(this->fileStream){ - long fileSize = this->fileStream->Filesize(); - long filePosition = this->fileStream->Position(); - if(fileSize && filePosition){ - return ((double)filePosition)/((double)fileSize); +double Stream::DecoderProgress() { + if (this->fileStream) { + long fileSize = this->fileStream->Filesize(); + long filePosition = this->fileStream->Position(); + + if (fileSize && filePosition) { + return ((double) filePosition) / ((double) fileSize); } } + return 0; } diff --git a/src/core/filestreams/LocalFileStream.cpp b/src/core/filestreams/LocalFileStream.cpp index 8080094d0..9994dcc8f 100644 --- a/src/core/filestreams/LocalFileStream.cpp +++ b/src/core/filestreams/LocalFileStream.cpp @@ -41,8 +41,6 @@ #include #include -////////////////////////////////////////////////////////////////////////////// - #ifdef UTF_WIDECHAR #define UTFFopen _wfopen typedef fpos_t stdioPositionType; @@ -51,11 +49,8 @@ typedef fpos_t stdioPositionType; typedef fpos_t stdioPositionType; #endif -////////////////////////////////////////////////////////////////////////////// - using namespace musik::core::filestreams; -////////////////////////////////////////////////////////////////////////////// LocalFileStream::LocalFileStream() : file(NULL) , filesize(-1) @@ -82,10 +77,10 @@ bool LocalFileStream::Open(const utfchar *filename,unsigned int options){ std::cerr << "File not a regular file" << std::endl; } - this->filesize = (long)boost::filesystem::file_size(file); + this->filesize = (long)boost::filesystem::file_size(file); this->extension = file.extension().wstring(); this->file = UTFFopen(filename,UTF("rb")); - this->fd = new boost::iostreams::file_descriptor(file); + this->fd = new boost::iostreams::file_descriptor(file); this->fileStream = new boost::iostreams::stream(*this->fd); this->fileStream->exceptions(std::ios_base::eofbit | std::ios_base::failbit | std::ios_base::badbit); @@ -128,8 +123,6 @@ PositionType LocalFileStream::Read(void* buffer,PositionType readBytes) { } bool LocalFileStream::SetPosition(PositionType position) { - /*stdioPositionType newPosition = (stdioPositionType)position; - return fsetpos(this->file,&newPosition)==0;*/ try { this->fileStream->clear(); this->fileStream->seekg(position); @@ -142,16 +135,10 @@ bool LocalFileStream::SetPosition(PositionType position) { } PositionType LocalFileStream::Position() { - /*stdioPositionType currentPosition(0); - if(fgetpos(this->file,¤tPosition)==0){ - return (PositionType)currentPosition; - } - return -1;*/ return this->fileStream->tellg(); } bool LocalFileStream::Eof() { - //return feof(this->file)!=0; return this->fileStream->eof(); } diff --git a/src/core/sdk/IPlugin.h b/src/core/sdk/IPlugin.h index 1c8c74d67..1c912dc06 100644 --- a/src/core/sdk/IPlugin.h +++ b/src/core/sdk/IPlugin.h @@ -37,17 +37,12 @@ #pragma once namespace musik { namespace core { - - class IPlugin{ - protected: - virtual ~IPlugin() {}; + class IPlugin{ public: - virtual void Destroy() =0; - - virtual const utfchar* Name()=0; - virtual const utfchar* Version()=0; - virtual const utfchar* Author()=0; + virtual void Destroy() = 0; + virtual const utfchar* Name() = 0; + virtual const utfchar* Version() = 0; + virtual const utfchar* Author() = 0; }; - } } diff --git a/src/core/sdk/IRequestParser.h b/src/core/sdk/IRequestParser.h new file mode 100644 index 000000000..c55f27851 --- /dev/null +++ b/src/core/sdk/IRequestParser.h @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright © 2008, Daniel Önnerby +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +////////////////////////////////////////////////////////////////////////////// + +namespace musik{ namespace core{ namespace http{ + +////////////////////////////////////////////////////////////////////////////// + +class IRequestParser{ + public: + virtual const char* Attribute(const char* key)=0; + virtual const char* Path()=0; + virtual const char* SubPath(int position)=0; +}; + +////////////////////////////////////////////////////////////////////////////// +} } } // musik::core:http +////////////////////////////////////////////////////////////////////////////// + + diff --git a/src/core/sdk/IRequestPlugin.h b/src/core/sdk/IRequestPlugin.h new file mode 100644 index 000000000..e25eb1598 --- /dev/null +++ b/src/core/sdk/IRequestPlugin.h @@ -0,0 +1,61 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright © 2008, Daniel Önnerby +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include "IResponder.h" +#include "IRequestParser.h" +#include "ITrack.h" + +////////////////////////////////////////////////////////////////////////////// + +namespace musik{ namespace core{ namespace http{ + +////////////////////////////////////////////////////////////////////////////// + +class IRequestPlugin{ + public: + virtual void Destroy()=0; + virtual const char* WatchPath()=0; + virtual void Execute(musik::core::http::IResponder* responder,musik::core::http::IRequestParser* request,musik::core::ITrack* track)=0; +}; + +////////////////////////////////////////////////////////////////////////////// +} } } +////////////////////////////////////////////////////////////////////////////// + + diff --git a/src/core/sdk/IResponder.h b/src/core/sdk/IResponder.h new file mode 100644 index 000000000..1041f72a6 --- /dev/null +++ b/src/core/sdk/IResponder.h @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright © 2008, Daniel Önnerby +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +namespace musik{ namespace core{ namespace http{ + +////////////////////////////////////////////////////////////////////////////// + +class IResponder{ + public: + virtual void SendContent(const char* buffer,const std::size_t bufferSize)=0; + virtual bool Exited()=0; +}; + +////////////////////////////////////////////////////////////////////////////// +} } } +////////////////////////////////////////////////////////////////////////////// + +