From 33d07388592cf8514ed45066600eb40eae834c8e Mon Sep 17 00:00:00 2001 From: Zyx-2000 Date: Sat, 30 Jan 2016 22:34:46 +0100 Subject: [PATCH] support for music streaming --- client/CMakeLists.txt | 1 + client/CMusicHandler.cpp | 21 +++++----- client/CMusicHandler.h | 4 +- client/SDLRWwrapper.cpp | 85 ++++++++++++++++++++++++++++++++++++++++ client/SDLRWwrapper.h | 6 +++ client/VCMI_client.cbp | 2 + 6 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 client/SDLRWwrapper.cpp create mode 100644 client/SDLRWwrapper.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index ed86e969e..9eb3bc802 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -57,6 +57,7 @@ set(client_SRCS Graphics.cpp mapHandler.cpp NetPacksClient.cpp + SDLRWwrapper.cpp ) set(client_HEADERS diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index 2bc5853b2..b3e49d413 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -3,6 +3,7 @@ #include "CMusicHandler.h" #include "CGameInfo.h" +#include "SDLRWwrapper.h" #include "../lib/CCreatureHandler.h" #include "../lib/spells/CSpellHandler.h" #include "../lib/JsonNode.h" @@ -86,7 +87,7 @@ CSoundHandler::CSoundHandler(): listener(std::bind(&CSoundHandler::onVolumeChange, this, _1)); // Vectors for helper(s) - pickupSounds = + pickupSounds = { soundBase::pickup01, soundBase::pickup02, soundBase::pickup03, soundBase::pickup04, soundBase::pickup05, soundBase::pickup06, soundBase::pickup07 @@ -303,7 +304,7 @@ void CMusicHandler::release() void CMusicHandler::playMusic(std::string musicURI, bool loop) { - if (current && current->isTrack( musicURI)) + if (current && current->isTrack(musicURI)) return; queueNext(this, "", musicURI, loop); @@ -342,7 +343,7 @@ void CMusicHandler::playMusicFromSet(std::string whichSet, int entryID, bool loo return; } - if (current && current->isTrack( selectedEntry->second)) + if (current && current->isTrack(selectedEntry->second)) return; // in this mode - play specific track from set @@ -421,12 +422,11 @@ void CMusicHandler::musicFinishedCallback(void) MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped): owner(owner), music(nullptr), - musicFile(nullptr), loop(looped ? -1 : 1), - setName(setName) + setName(std::move(setName)) { if (!musicURI.empty()) - load(musicURI); + load(std::move(musicURI)); } MusicEntry::~MusicEntry() { @@ -448,15 +448,12 @@ void MusicEntry::load(std::string musicURI) logGlobal->traceStream()<<"Loading music file "<load(ResourceID(musicURI, EResType::MUSIC))->readAll(); - musicFile = SDL_RWFromConstMem(data.first.get(), data.second); - - music = Mix_LoadMUS_RW(musicFile, SDL_FALSE); + auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(ResourceID(std::move(musicURI), EResType::MUSIC))); + + music = Mix_LoadMUS_RW(musicFile, SDL_TRUE); if(!music) { - SDL_FreeRW(musicFile); - musicFile = nullptr; logGlobal->warnStream() << "Warning: Cannot open " << currentName << ": " << Mix_GetError(); return; } diff --git a/client/CMusicHandler.h b/client/CMusicHandler.h index f0031d56a..eaafa8bf9 100644 --- a/client/CMusicHandler.h +++ b/client/CMusicHandler.h @@ -80,10 +80,8 @@ class CMusicHandler; //Class for handling one music file class MusicEntry { - std::pair, size_t> data; CMusicHandler *owner; Mix_Music *music; - SDL_RWops *musicFile; int loop; // -1 = indefinite //if not null - set from which music will be randomly selected @@ -116,7 +114,7 @@ private: std::unique_ptr current; std::unique_ptr next; - + void queueNext(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped); void queueNext(std::unique_ptr queued); diff --git a/client/SDLRWwrapper.cpp b/client/SDLRWwrapper.cpp new file mode 100644 index 000000000..2ce1a1e96 --- /dev/null +++ b/client/SDLRWwrapper.cpp @@ -0,0 +1,85 @@ +#include "StdInc.h" +#include "SDLRWwrapper.h" +#include "../lib/filesystem/CInputStream.h" +#include + +static inline CInputStream* get_stream(SDL_RWops* context) +{ + return static_cast(context->hidden.unknown.data1); +} + +static Sint64 impl_size(SDL_RWops* context) +{ + return get_stream(context)->getSize(); +} + +static Sint64 impl_seek(SDL_RWops* context, Sint64 offset, int whence) +{ + auto stream = get_stream(context); + switch (whence) + { + case RW_SEEK_SET: + return stream->seek(offset); + break; + case RW_SEEK_CUR: + return stream->seek(stream->tell() + offset); + break; + case RW_SEEK_END: + return stream->seek(stream->getSize() + offset); + break; + default: + return -1; + } + +} + +static std::size_t impl_read(SDL_RWops* context, void *ptr, size_t size, size_t maxnum) +{ + auto stream = get_stream(context); + auto oldpos = stream->tell(); + + auto count = stream->read(static_cast(ptr), size*maxnum); + + if (count != 0 && count != size*maxnum) + { + // if not a whole amount of objects of size has been read, we need to seek + stream->seek(oldpos + size * (count / size)); + } + + return count / size; +} + +static std::size_t impl_write(SDL_RWops* context, const void *ptr, size_t size, size_t num) +{ + // writing is not supported + return 0; +} + +static int impl_close(SDL_RWops* context) +{ + if (context == nullptr) + return 0; + + delete get_stream(context); + SDL_FreeRW(context); + return 0; +} + + +SDL_RWops* MakeSDLRWops(std::unique_ptr in) +{ + SDL_RWops* result = SDL_AllocRW(); + if (!result) + return nullptr; + + result->size = &impl_size; + result->seek = &impl_seek; + result->read = &impl_read; + result->write = &impl_write; + result->close = &impl_close; + + result->type = SDL_RWOPS_UNKNOWN; + result->hidden.unknown.data1 = in.release(); + + return result; +} diff --git a/client/SDLRWwrapper.h b/client/SDLRWwrapper.h new file mode 100644 index 000000000..e5b7c2bb5 --- /dev/null +++ b/client/SDLRWwrapper.h @@ -0,0 +1,6 @@ +#pragma once + +struct SDL_RWops; +class CInputStream; + +SDL_RWops* MakeSDLRWops(std::unique_ptr in); diff --git a/client/VCMI_client.cbp b/client/VCMI_client.cbp index dff43308e..5099d1efd 100644 --- a/client/VCMI_client.cbp +++ b/client/VCMI_client.cbp @@ -126,6 +126,8 @@ + +