浏览代码

support for music streaming

Zyx-2000 9 年之前
父节点
当前提交
33d0738859
共有 6 个文件被更改,包括 104 次插入15 次删除
  1. 1 0
      client/CMakeLists.txt
  2. 9 12
      client/CMusicHandler.cpp
  3. 1 3
      client/CMusicHandler.h
  4. 85 0
      client/SDLRWwrapper.cpp
  5. 6 0
      client/SDLRWwrapper.h
  6. 2 0
      client/VCMI_client.cbp

+ 1 - 0
client/CMakeLists.txt

@@ -57,6 +57,7 @@ set(client_SRCS
 		Graphics.cpp
 		mapHandler.cpp
 		NetPacksClient.cpp
+		SDLRWwrapper.cpp
 )
 
 set(client_HEADERS

+ 9 - 12
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 "<<musicURI;
 
-	data = CResourceHandler::get()->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;
 	}

+ 1 - 3
client/CMusicHandler.h

@@ -80,10 +80,8 @@ class CMusicHandler;
 //Class for handling one music file
 class MusicEntry
 {
-	std::pair<std::unique_ptr<ui8[]>, 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<MusicEntry> current;
 	std::unique_ptr<MusicEntry> next;
-	
+
 	void queueNext(CMusicHandler *owner, std::string setName, std::string musicURI, bool looped);
 	void queueNext(std::unique_ptr<MusicEntry> queued);
 

+ 85 - 0
client/SDLRWwrapper.cpp

@@ -0,0 +1,85 @@
+#include "StdInc.h"
+#include "SDLRWwrapper.h"
+#include "../lib/filesystem/CInputStream.h"
+#include <SDL_rwops.h>
+
+static inline CInputStream* get_stream(SDL_RWops* context)
+{
+	return static_cast<CInputStream*>(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<ui8*>(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<CInputStream> 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;
+}

+ 6 - 0
client/SDLRWwrapper.h

@@ -0,0 +1,6 @@
+#pragma once
+
+struct SDL_RWops;
+class CInputStream;
+
+SDL_RWops* MakeSDLRWops(std::unique_ptr<CInputStream> in);

+ 2 - 0
client/VCMI_client.cbp

@@ -126,6 +126,8 @@
 		<Unit filename="Graphics.h" />
 		<Unit filename="NetPacksClient.cpp" />
 		<Unit filename="SDLMain.h" />
+		<Unit filename="SDLRWwrapper.cpp" />
+		<Unit filename="SDLRWwrapper.h" />
 		<Unit filename="StdInc.h">
 			<Option weight="0" />
 		</Unit>