mirror of
https://github.com/Almamu/linux-wallpaperengine.git
synced 2025-07-14 05:12:25 +08:00
Applied the same context-driver treatment to the audio subsystem (still needs some extra work to ensure all audio plays fine and a good cleanup)
Fixed README.md to properly reflect all dependencies in the command examples Added support for audio looping Signed-off-by: Alexis Maiquez <almamu@almamu.com>
This commit is contained in:
parent
97ddc91ff5
commit
ecd8ff3757
2
.github/workflows/cmake.yml
vendored
2
.github/workflows/cmake.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get update && sudo apt-get -y install libxrandr-dev libfreeimage-dev libxinerama-dev libxcursor-dev libxi-dev libgl-dev libglew-dev freeglut3-dev libsdl1.2-dev libsdl-mixer1.2-dev liblz4-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libxxf86vm-dev libglm-dev libglfw3-dev libmpv-dev mpv libmpv1
|
run: sudo apt-get update && sudo apt-get -y install libxrandr-dev libfreeimage-dev libxinerama-dev libxcursor-dev libxi-dev libgl-dev libglew-dev freeglut3-dev libsdl2-dev liblz4-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libxxf86vm-dev libglm-dev libglfw3-dev libmpv-dev mpv libmpv1
|
||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||||
|
@ -7,7 +7,7 @@ set(OpenGL_GL_PREFERENCE "LEGACY")
|
|||||||
|
|
||||||
# if you're developing you might find this debug option useful for shader output, although RenderDoc is encouraged
|
# if you're developing you might find this debug option useful for shader output, although RenderDoc is encouraged
|
||||||
add_compile_definitions(DEBUG=1)
|
add_compile_definitions(DEBUG=1)
|
||||||
add_compile_definitions(ERRORONLY=0)
|
add_compile_definitions(ERRORONLY=1)
|
||||||
|
|
||||||
find_package(X11 REQUIRED)
|
find_package(X11 REQUIRED)
|
||||||
find_package(Xrandr REQUIRED)
|
find_package(Xrandr REQUIRED)
|
||||||
@ -15,7 +15,7 @@ find_package(OpenGL REQUIRED)
|
|||||||
find_package(GLEW REQUIRED)
|
find_package(GLEW REQUIRED)
|
||||||
find_package(GLUT REQUIRED)
|
find_package(GLUT REQUIRED)
|
||||||
find_package(ZLIB REQUIRED)
|
find_package(ZLIB REQUIRED)
|
||||||
find_package(SDL REQUIRED)
|
find_package(SDL2 REQUIRED)
|
||||||
find_package(MPV REQUIRED)
|
find_package(MPV REQUIRED)
|
||||||
find_package(LZ4 REQUIRED)
|
find_package(LZ4 REQUIRED)
|
||||||
find_package(FFMPEG REQUIRED)
|
find_package(FFMPEG REQUIRED)
|
||||||
@ -27,8 +27,7 @@ include_directories(
|
|||||||
${XRANDR_INCLUDE_DIR}
|
${XRANDR_INCLUDE_DIR}
|
||||||
${GLEW_INCLUDE_DIR}
|
${GLEW_INCLUDE_DIR}
|
||||||
${LZ4_INCLUDE_DIR}
|
${LZ4_INCLUDE_DIR}
|
||||||
${SDL_INCLUDE_DIRS}
|
${SDL2_INCLUDE_DIRS}
|
||||||
${SDL_MIXER_INCLUDE_DIRS}
|
|
||||||
${FFMPEG_INCLUDE_DIR}
|
${FFMPEG_INCLUDE_DIR}
|
||||||
${FREEIMAGE_INCLUDE_DIR}
|
${FREEIMAGE_INCLUDE_DIR}
|
||||||
src
|
src
|
||||||
@ -65,6 +64,12 @@ add_executable(
|
|||||||
src/WallpaperEngine/Core/Core.h
|
src/WallpaperEngine/Core/Core.h
|
||||||
src/WallpaperEngine/Core/Core.cpp
|
src/WallpaperEngine/Core/Core.cpp
|
||||||
|
|
||||||
|
src/WallpaperEngine/Audio/Drivers/CAudioDriver.cpp
|
||||||
|
src/WallpaperEngine/Audio/Drivers/CAudioDriver.h
|
||||||
|
src/WallpaperEngine/Audio/Drivers/CSDLAudioDriver.cpp
|
||||||
|
src/WallpaperEngine/Audio/Drivers/CSDLAudioDriver.h
|
||||||
|
src/WallpaperEngine/Audio/CAudioContext.cpp
|
||||||
|
src/WallpaperEngine/Audio/CAudioContext.h
|
||||||
src/WallpaperEngine/Audio/CAudioStream.cpp
|
src/WallpaperEngine/Audio/CAudioStream.cpp
|
||||||
src/WallpaperEngine/Audio/CAudioStream.h
|
src/WallpaperEngine/Audio/CAudioStream.h
|
||||||
|
|
||||||
@ -227,8 +232,7 @@ target_link_libraries(linux-wallpaperengine
|
|||||||
${GLUT_LIBRARIES}
|
${GLUT_LIBRARIES}
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
${LZ4_LIBRARY}
|
${LZ4_LIBRARY}
|
||||||
${SDL_LIBRARY}
|
${SDL2_LIBRARIES}
|
||||||
${SDL_MIXER_LIBRARIES}
|
|
||||||
${FFMPEG_LIBRARIES}
|
${FFMPEG_LIBRARIES}
|
||||||
${FREEIMAGE_LIBRARIES}
|
${FREEIMAGE_LIBRARIES}
|
||||||
${MPV_LIBRARY}
|
${MPV_LIBRARY}
|
||||||
|
10
README.md
10
README.md
@ -37,16 +37,8 @@ Wallpaper Engine is a software designed by [Kristjan Skutta](https://store.steam
|
|||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
```
|
```
|
||||||
sudo apt update
|
|
||||||
```
|
|
||||||
```
|
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
```
|
sudo apt-get install build-essential cmake libxrandr-dev libfreeimage-dev libxinerama-dev libxcursor-dev libxi-dev libgl-dev libglew-dev freeglut3-dev libsdl2-dev liblz4-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libxxf86vm-dev libglm-dev libglfw3-dev libmpv-dev mpv libmpv1
|
||||||
```
|
|
||||||
sudo apt -y install cmake lz4 zlib1g ffmpeg libxxf86vm-dev libglm-dev freeglut3-dev libxrandr-dev libavcodec-dev libavformat-dev libavfilter-dev libsdl1.2-dev libsdl-mixer1.2-dev
|
|
||||||
```
|
|
||||||
```
|
|
||||||
sudo apt-get -y install libsdl2-2.0 libsdl-image1.2-dev libsdl1.2-dev libglfw3 libglfw3-dev libmpv-dev mpv libmpv1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# 5. How to use
|
# 5. How to use
|
||||||
|
21
main.cpp
21
main.cpp
@ -2,7 +2,6 @@
|
|||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_mixer.h>
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -23,8 +22,10 @@
|
|||||||
#include "WallpaperEngine/Assets/CCombinedContainer.h"
|
#include "WallpaperEngine/Assets/CCombinedContainer.h"
|
||||||
#include "WallpaperEngine/Assets/CPackageLoadException.h"
|
#include "WallpaperEngine/Assets/CPackageLoadException.h"
|
||||||
|
|
||||||
#include "WallpaperEngine/Render/Drivers/COpenGLDriver.h"
|
|
||||||
#include "Steam/FileSystem/FileSystem.h"
|
#include "Steam/FileSystem/FileSystem.h"
|
||||||
|
#include "WallpaperEngine/Audio/CAudioContext.h"
|
||||||
|
#include "WallpaperEngine/Audio/Drivers/CSDLAudioDriver.h"
|
||||||
|
#include "WallpaperEngine/Render/Drivers/COpenGLDriver.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define WORKSHOP_APP_ID 431960
|
#define WORKSHOP_APP_ID 431960
|
||||||
@ -34,7 +35,7 @@ float g_Time;
|
|||||||
float g_TimeLast;
|
float g_TimeLast;
|
||||||
bool g_KeepRunning = true;
|
bool g_KeepRunning = true;
|
||||||
bool g_AudioEnabled = true;
|
bool g_AudioEnabled = true;
|
||||||
int g_AudioVolume = 15;
|
int g_AudioVolume = 128;
|
||||||
|
|
||||||
void print_help (const char* route)
|
void print_help (const char* route)
|
||||||
{
|
{
|
||||||
@ -445,12 +446,10 @@ int main (int argc, char* argv[])
|
|||||||
std::signal(SIGINT, signalhandler);
|
std::signal(SIGINT, signalhandler);
|
||||||
std::signal(SIGTERM, signalhandler);
|
std::signal(SIGTERM, signalhandler);
|
||||||
|
|
||||||
if (g_AudioEnabled == true && SDL_Init (SDL_INIT_AUDIO) < 0)
|
// initialize sdl audio driver
|
||||||
{
|
WallpaperEngine::Audio::Drivers::CSDLAudioDriver audioDriver;
|
||||||
sLog.error ("Cannot initialize SDL audio system, SDL_GetError: ", SDL_GetError());
|
// initialize audio context
|
||||||
sLog.error ("Continuing without audio support");
|
WallpaperEngine::Audio::CAudioContext audioContext (&audioDriver);
|
||||||
}
|
|
||||||
|
|
||||||
// initialize OpenGL driver
|
// initialize OpenGL driver
|
||||||
WallpaperEngine::Render::Drivers::COpenGLDriver videoDriver ("Wallpaper Engine");
|
WallpaperEngine::Render::Drivers::COpenGLDriver videoDriver ("Wallpaper Engine");
|
||||||
// initialize render context
|
// initialize render context
|
||||||
@ -459,7 +458,7 @@ int main (int argc, char* argv[])
|
|||||||
context.setMouse (new CMouseInput (videoDriver.getWindow ()));
|
context.setMouse (new CMouseInput (videoDriver.getWindow ()));
|
||||||
// ensure the context knows what wallpaper to render
|
// ensure the context knows what wallpaper to render
|
||||||
context.setWallpaper (
|
context.setWallpaper (
|
||||||
WallpaperEngine::Render::CWallpaper::fromWallpaper (project->getWallpaper (), &context)
|
WallpaperEngine::Render::CWallpaper::fromWallpaper (project->getWallpaper (), &context, &audioContext)
|
||||||
);
|
);
|
||||||
|
|
||||||
float startTime, endTime, minimumTime = 1.0f / maximumFPS;
|
float startTime, endTime, minimumTime = 1.0f / maximumFPS;
|
||||||
@ -494,8 +493,6 @@ int main (int argc, char* argv[])
|
|||||||
|
|
||||||
sLog.out ("Stop requested");
|
sLog.out ("Stop requested");
|
||||||
|
|
||||||
// terminate SDL
|
|
||||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
|
||||||
SDL_Quit ();
|
SDL_Quit ();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
31
src/WallpaperEngine/Audio/CAudioContext.cpp
Normal file
31
src/WallpaperEngine/Audio/CAudioContext.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include "CAudioContext.h"
|
||||||
|
#include "WallpaperEngine/Audio/Drivers/CAudioDriver.h"
|
||||||
|
|
||||||
|
using namespace WallpaperEngine::Audio;
|
||||||
|
using namespace WallpaperEngine::Audio::Drivers;
|
||||||
|
|
||||||
|
CAudioContext::CAudioContext (CAudioDriver* driver) :
|
||||||
|
m_driver (driver)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAudioContext::addStream (CAudioStream* stream)
|
||||||
|
{
|
||||||
|
this->m_driver->addStream (stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
AVSampleFormat CAudioContext::getFormat () const
|
||||||
|
{
|
||||||
|
return this->m_driver->getFormat ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CAudioContext::getSampleRate () const
|
||||||
|
{
|
||||||
|
return this->m_driver->getSampleRate ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CAudioContext::getChannels () const
|
||||||
|
{
|
||||||
|
return this->m_driver->getChannels ();
|
||||||
|
}
|
28
src/WallpaperEngine/Audio/CAudioContext.h
Normal file
28
src/WallpaperEngine/Audio/CAudioContext.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libavutil/samplefmt.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace WallpaperEngine::Audio::Drivers
|
||||||
|
{
|
||||||
|
class CAudioDriver;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace WallpaperEngine::Audio
|
||||||
|
{
|
||||||
|
class CAudioStream;
|
||||||
|
|
||||||
|
class CAudioContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CAudioContext (Drivers::CAudioDriver* driver);
|
||||||
|
|
||||||
|
void addStream (CAudioStream* stream);
|
||||||
|
|
||||||
|
AVSampleFormat getFormat () const;
|
||||||
|
int getSampleRate () const;
|
||||||
|
int getChannels () const;
|
||||||
|
private:
|
||||||
|
Drivers::CAudioDriver* m_driver;
|
||||||
|
};
|
||||||
|
}
|
@ -4,74 +4,52 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
// maximum size of the queue to prevent reading too much data
|
||||||
|
#define MAX_QUEUE_SIZE (5 * 1024 * 1024)
|
||||||
|
#define MIN_FRAMES 25
|
||||||
|
|
||||||
extern int g_AudioVolume;
|
extern int g_AudioVolume;
|
||||||
extern bool g_KeepRunning;
|
extern bool g_KeepRunning;
|
||||||
|
|
||||||
using namespace WallpaperEngine::Audio;
|
using namespace WallpaperEngine::Audio;
|
||||||
|
|
||||||
// callback for sdl to play our audio
|
|
||||||
void audio_callback (void* userdata, uint8_t* stream, int length)
|
|
||||||
{
|
|
||||||
auto audioStream = static_cast <CAudioStream*> (userdata);
|
|
||||||
int len1, audio_size;
|
|
||||||
|
|
||||||
static uint8_t audio_buf[(MAX_AUDIO_FRAME_SIZE * 3) / 2];
|
|
||||||
static unsigned int audio_buf_size = 0;
|
|
||||||
static unsigned int audio_buf_index = 0;
|
|
||||||
|
|
||||||
while (length > 0 && g_KeepRunning)
|
|
||||||
{
|
|
||||||
if (audio_buf_index >= audio_buf_size)
|
|
||||||
{
|
|
||||||
/* We have already sent all our data; get more */
|
|
||||||
audio_size = audioStream->decodeFrame (audio_buf, sizeof (audio_buf));
|
|
||||||
|
|
||||||
if (audio_size < 0)
|
|
||||||
{
|
|
||||||
/* If error, output silence */
|
|
||||||
audio_buf_size = 1024; // arbitrary?
|
|
||||||
memset(audio_buf, 0, audio_buf_size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
audio_buf_size = audio_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
audio_buf_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
len1 = audio_buf_size - audio_buf_index;
|
|
||||||
|
|
||||||
if (len1 > length)
|
|
||||||
len1 = length;
|
|
||||||
|
|
||||||
// mix the audio so the volume is right
|
|
||||||
SDL_MixAudio (stream, (uint8_t*) audio_buf + audio_buf_index, len1, g_AudioVolume);
|
|
||||||
|
|
||||||
length -= len1;
|
|
||||||
stream += len1;
|
|
||||||
audio_buf_index += len1;
|
|
||||||
|
|
||||||
if (audioStream->isInitialized () == false)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int audio_read_thread (void* arg)
|
int audio_read_thread (void* arg)
|
||||||
{
|
{
|
||||||
|
SDL_mutex* waitMutex = SDL_CreateMutex ();
|
||||||
CAudioStream* stream = static_cast <CAudioStream*> (arg);
|
CAudioStream* stream = static_cast <CAudioStream*> (arg);
|
||||||
AVPacket* packet = av_packet_alloc ();
|
AVPacket* packet = av_packet_alloc ();
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (waitMutex == nullptr)
|
||||||
|
sLog.exception ("Cannot create mutex for audio playback waiting");
|
||||||
|
|
||||||
while (ret >= 0 && g_KeepRunning == true)
|
while (ret >= 0 && g_KeepRunning == true)
|
||||||
{
|
{
|
||||||
|
// give the cpu some time to play the queued frames if there's enough info there
|
||||||
|
if (
|
||||||
|
stream->getQueueSize () >= MAX_QUEUE_SIZE ||
|
||||||
|
(stream->getQueuePacketCount () > MIN_FRAMES &&
|
||||||
|
(av_q2d (stream->getTimeBase ()) * stream->getQueueDuration () > 1.0))
|
||||||
|
)
|
||||||
|
{
|
||||||
|
SDL_LockMutex (waitMutex);
|
||||||
|
SDL_CondWaitTimeout (stream->getWaitCondition (), waitMutex, 10);
|
||||||
|
SDL_UnlockMutex (waitMutex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ret = av_read_frame (stream->getFormatContext (), packet);
|
ret = av_read_frame (stream->getFormatContext (), packet);
|
||||||
|
|
||||||
if (ret == AVERROR_EOF)
|
if (ret == AVERROR_EOF)
|
||||||
{
|
{
|
||||||
// seek to the beginning of the file again
|
// seek to the beginning of the file again
|
||||||
av_seek_frame (stream->getFormatContext (), stream->getAudioStream (), 0, AVSEEK_FLAG_FRAME);
|
avformat_seek_file (stream->getFormatContext (), stream->getAudioStream (), 0, 0, 0, ~AVSEEK_FLAG_FRAME);
|
||||||
avcodec_flush_buffers (stream->getContext ());
|
avcodec_flush_buffers (stream->getContext ());
|
||||||
|
|
||||||
|
// ensure the thread is not killed if audio has to be looped
|
||||||
|
if (stream->isRepeat() == true)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +57,7 @@ int audio_read_thread (void* arg)
|
|||||||
if (packet->stream_index == stream->getAudioStream ())
|
if (packet->stream_index == stream->getAudioStream ())
|
||||||
stream->queuePacket (packet);
|
stream->queuePacket (packet);
|
||||||
else
|
else
|
||||||
av_packet_unref (packet);
|
av_packet_free (&packet);
|
||||||
|
|
||||||
if (stream->isInitialized () == false)
|
if (stream->isInitialized () == false)
|
||||||
break;
|
break;
|
||||||
@ -87,6 +65,7 @@ int audio_read_thread (void* arg)
|
|||||||
|
|
||||||
// stop the audio too just in case
|
// stop the audio too just in case
|
||||||
stream->stop ();
|
stream->stop ();
|
||||||
|
SDL_DestroyMutex (waitMutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -126,21 +105,15 @@ int64_t audio_seek_data_callback (void* streamarg, int64_t offset, int whence)
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
CAudioStream::CAudioStream (const std::string& filename)
|
CAudioStream::CAudioStream (CAudioContext* context, const std::string& filename) :
|
||||||
|
m_audioContext (context)
|
||||||
{
|
{
|
||||||
// do not do anything if sdl audio was not initialized
|
|
||||||
if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this->loadCustomContent (filename.c_str ());
|
this->loadCustomContent (filename.c_str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
CAudioStream::CAudioStream (const void* buffer, int length)
|
CAudioStream::CAudioStream (CAudioContext* context, const void* buffer, int length) :
|
||||||
|
m_audioContext (context)
|
||||||
{
|
{
|
||||||
// do not do anything if sdl audio was not initialized
|
|
||||||
if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// setup a custom context first
|
// setup a custom context first
|
||||||
this->m_formatContext = avformat_alloc_context ();
|
this->m_formatContext = avformat_alloc_context ();
|
||||||
|
|
||||||
@ -169,14 +142,11 @@ CAudioStream::CAudioStream (const void* buffer, int length)
|
|||||||
this->loadCustomContent ();
|
this->loadCustomContent ();
|
||||||
}
|
}
|
||||||
|
|
||||||
CAudioStream::CAudioStream(AVCodecContext* context)
|
CAudioStream::CAudioStream(CAudioContext* audioContext, AVCodecContext* context) :
|
||||||
: m_context (context),
|
m_context (context),
|
||||||
m_queue (new PacketQueue)
|
m_queue (new PacketQueue),
|
||||||
|
m_audioContext (audioContext)
|
||||||
{
|
{
|
||||||
// do not do anything if sdl audio was not initialized
|
|
||||||
if (SDL_WasInit (SDL_INIT_AUDIO) != SDL_INIT_AUDIO)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this->initialize ();
|
this->initialize ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,38 +192,18 @@ void CAudioStream::loadCustomContent (const char* filename)
|
|||||||
this->initialize ();
|
this->initialize ();
|
||||||
|
|
||||||
// initialize an SDL thread to read the file
|
// initialize an SDL thread to read the file
|
||||||
SDL_CreateThread (audio_read_thread, this);
|
SDL_CreateThread (audio_read_thread, filename, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAudioStream::initialize ()
|
void CAudioStream::initialize ()
|
||||||
{
|
{
|
||||||
// allocate the FIFO buffer
|
// allocate the FIFO buffer
|
||||||
this->m_queue->packetList = av_fifo_alloc (sizeof (MyAVPacketList));
|
this->m_queue->packetList = av_fifo_alloc2 (1, sizeof (MyAVPacketList), AV_FIFO_FLAG_AUTO_GROW);
|
||||||
|
|
||||||
// setup the queue information
|
// setup the queue information
|
||||||
this->m_queue->mutex = SDL_CreateMutex ();
|
this->m_queue->mutex = SDL_CreateMutex ();
|
||||||
this->m_queue->cond = SDL_CreateCond ();
|
this->m_queue->cond = SDL_CreateCond ();
|
||||||
|
this->m_queue->wait = SDL_CreateCond ();
|
||||||
// take control of the audio device
|
|
||||||
|
|
||||||
SDL_AudioSpec requestedSpec, finalSpec;
|
|
||||||
|
|
||||||
// Set audio settings from codec info
|
|
||||||
requestedSpec.freq = this->m_context->sample_rate;
|
|
||||||
requestedSpec.format = AUDIO_S16SYS;
|
|
||||||
requestedSpec.channels = this->m_context->channels;
|
|
||||||
requestedSpec.silence = 0;
|
|
||||||
requestedSpec.samples = SDL_AUDIO_BUFFER_SIZE;
|
|
||||||
requestedSpec.callback = audio_callback;
|
|
||||||
requestedSpec.userdata = this;
|
|
||||||
|
|
||||||
if (SDL_OpenAudio (&requestedSpec, &finalSpec) < 0)
|
|
||||||
{
|
|
||||||
sLog.error ("SDL_OpenAudio: ", SDL_GetError ());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_PauseAudio (0);
|
|
||||||
|
|
||||||
this->m_initialized = true;
|
this->m_initialized = true;
|
||||||
}
|
}
|
||||||
@ -281,21 +231,11 @@ void CAudioStream::queuePacket(AVPacket *pkt)
|
|||||||
|
|
||||||
bool CAudioStream::doQueue (AVPacket* pkt)
|
bool CAudioStream::doQueue (AVPacket* pkt)
|
||||||
{
|
{
|
||||||
MyAVPacketList entry;
|
MyAVPacketList entry { pkt };
|
||||||
|
|
||||||
// ensure the FIFO has enough space to hold the new entry
|
// write the entry if possible
|
||||||
if (av_fifo_space (this->m_queue->packetList) < sizeof (entry))
|
if (av_fifo_write (this->m_queue->packetList, &entry, 1) < 0)
|
||||||
{
|
return false;
|
||||||
if (av_fifo_grow (this->m_queue->packetList, sizeof (entry)) < 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.packet = pkt;
|
|
||||||
|
|
||||||
// write to the FIFO
|
|
||||||
av_fifo_generic_write (this->m_queue->packetList, &entry, sizeof (entry), nullptr);
|
|
||||||
|
|
||||||
this->m_queue->nb_packets ++;
|
this->m_queue->nb_packets ++;
|
||||||
this->m_queue->size += entry.packet->size + sizeof (entry);
|
this->m_queue->size += entry.packet->size + sizeof (entry);
|
||||||
@ -315,12 +255,11 @@ void CAudioStream::dequeuePacket (AVPacket* output)
|
|||||||
while (g_KeepRunning)
|
while (g_KeepRunning)
|
||||||
{
|
{
|
||||||
// enough data available, read it
|
// enough data available, read it
|
||||||
if (av_fifo_size (this->m_queue->packetList) >= sizeof (entry))
|
if (av_fifo_read (this->m_queue->packetList, &entry, 1) >= 0)
|
||||||
{
|
{
|
||||||
av_fifo_generic_read (this->m_queue->packetList, &entry, sizeof (entry), nullptr);
|
|
||||||
|
|
||||||
this->m_queue->nb_packets --;
|
this->m_queue->nb_packets --;
|
||||||
this->m_queue->size -= entry.packet->duration;
|
this->m_queue->size -= entry.packet->size + sizeof (entry);
|
||||||
|
this->m_queue->duration -= entry.packet->duration;
|
||||||
|
|
||||||
// move the reference and free the old one
|
// move the reference and free the old one
|
||||||
av_packet_move_ref (output, entry.packet);
|
av_packet_move_ref (output, entry.packet);
|
||||||
@ -329,7 +268,7 @@ void CAudioStream::dequeuePacket (AVPacket* output)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make the thread wait if nothing was available
|
// make the thread wait if nothing was available
|
||||||
SDL_CondWaitTimeout (this->m_queue->cond, this->m_queue->mutex, 1000);
|
SDL_CondWait (this->m_queue->cond, this->m_queue->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_UnlockMutex (this->m_queue->mutex);
|
SDL_UnlockMutex (this->m_queue->mutex);
|
||||||
@ -385,14 +324,46 @@ void CAudioStream::setPosition (int current)
|
|||||||
this->m_position = current;
|
this->m_position = current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_cond* CAudioStream::getWaitCondition ()
|
||||||
|
{
|
||||||
|
return this->m_queue->wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CAudioStream::getQueueSize ()
|
||||||
|
{
|
||||||
|
return this->m_queue->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CAudioStream::getQueuePacketCount ()
|
||||||
|
{
|
||||||
|
return this->m_queue->nb_packets;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVRational CAudioStream::getTimeBase ()
|
||||||
|
{
|
||||||
|
return this->m_formatContext->streams [this->m_audioStream]->time_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t CAudioStream::getQueueDuration ()
|
||||||
|
{
|
||||||
|
return this->m_queue->duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAudioStream::isQueueEmpty ()
|
||||||
|
{
|
||||||
|
return this->m_queue->nb_packets == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_mutex* CAudioStream::getMutex ()
|
||||||
|
{
|
||||||
|
return this->m_queue->mutex;
|
||||||
|
}
|
||||||
|
|
||||||
void CAudioStream::stop ()
|
void CAudioStream::stop ()
|
||||||
{
|
{
|
||||||
if (this->isInitialized () == false)
|
if (this->isInitialized () == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// pause audio
|
|
||||||
SDL_PauseAudio (1);
|
|
||||||
|
|
||||||
// stop the threads running
|
// stop the threads running
|
||||||
this->m_initialized = false;
|
this->m_initialized = false;
|
||||||
}
|
}
|
||||||
@ -421,7 +392,7 @@ int CAudioStream::resampleAudio (
|
|||||||
|
|
||||||
if (!swr_ctx)
|
if (!swr_ctx)
|
||||||
{
|
{
|
||||||
printf("swr_alloc error.\n");
|
sLog.error("swr_alloc error.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +405,7 @@ int CAudioStream::resampleAudio (
|
|||||||
// check input audio channels correctly retrieved
|
// check input audio channels correctly retrieved
|
||||||
if (in_channel_layout <= 0)
|
if (in_channel_layout <= 0)
|
||||||
{
|
{
|
||||||
printf("in_channel_layout error.\n");
|
sLog.error("in_channel_layout error.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +427,7 @@ int CAudioStream::resampleAudio (
|
|||||||
in_nb_samples = decoded_audio_frame->nb_samples;
|
in_nb_samples = decoded_audio_frame->nb_samples;
|
||||||
if (in_nb_samples <= 0)
|
if (in_nb_samples <= 0)
|
||||||
{
|
{
|
||||||
printf("in_nb_samples error.\n");
|
sLog.error("in_nb_samples error.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +484,7 @@ int CAudioStream::resampleAudio (
|
|||||||
ret = swr_init(swr_ctx);;
|
ret = swr_init(swr_ctx);;
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
printf("Failed to initialize the resampling context.\n");
|
sLog.error("Failed to initialize the resampling context.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,7 +498,7 @@ int CAudioStream::resampleAudio (
|
|||||||
// check rescaling was successful
|
// check rescaling was successful
|
||||||
if (max_out_nb_samples <= 0)
|
if (max_out_nb_samples <= 0)
|
||||||
{
|
{
|
||||||
printf("av_rescale_rnd error.\n");
|
sLog.error("av_rescale_rnd error.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,7 +516,7 @@ int CAudioStream::resampleAudio (
|
|||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
printf("av_samples_alloc_array_and_samples() error: Could not allocate destination samples.\n");
|
sLog.error("av_samples_alloc_array_and_samples() error: Could not allocate destination samples.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,7 +531,7 @@ int CAudioStream::resampleAudio (
|
|||||||
// check output samples number was correctly retrieved
|
// check output samples number was correctly retrieved
|
||||||
if (out_nb_samples <= 0)
|
if (out_nb_samples <= 0)
|
||||||
{
|
{
|
||||||
printf("av_rescale_rnd error\n");
|
sLog.error("av_rescale_rnd error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,50 +553,42 @@ int CAudioStream::resampleAudio (
|
|||||||
// check samples buffer correctly allocated
|
// check samples buffer correctly allocated
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
printf("av_samples_alloc failed.\n");
|
sLog.error("av_samples_alloc failed.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
max_out_nb_samples = out_nb_samples;
|
max_out_nb_samples = out_nb_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swr_ctx)
|
// do the actual audio data resampling
|
||||||
|
ret = swr_convert(
|
||||||
|
swr_ctx,
|
||||||
|
resampled_data,
|
||||||
|
out_nb_samples,
|
||||||
|
(const uint8_t **) decoded_audio_frame->data,
|
||||||
|
decoded_audio_frame->nb_samples
|
||||||
|
);
|
||||||
|
|
||||||
|
// check audio conversion was successful
|
||||||
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
// do the actual audio data resampling
|
sLog.error("swr_convert_error.");
|
||||||
ret = swr_convert(
|
return -1;
|
||||||
swr_ctx,
|
|
||||||
resampled_data,
|
|
||||||
out_nb_samples,
|
|
||||||
(const uint8_t **) decoded_audio_frame->data,
|
|
||||||
decoded_audio_frame->nb_samples
|
|
||||||
);
|
|
||||||
|
|
||||||
// check audio conversion was successful
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
printf("swr_convert_error.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the required buffer size for the given audio parameters
|
|
||||||
resampled_data_size = av_samples_get_buffer_size(
|
|
||||||
&out_linesize,
|
|
||||||
out_nb_channels,
|
|
||||||
ret,
|
|
||||||
out_sample_fmt,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
// check audio buffer size
|
|
||||||
if (resampled_data_size < 0)
|
|
||||||
{
|
|
||||||
printf("av_samples_get_buffer_size error.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Get the required buffer size for the given audio parameters
|
||||||
|
resampled_data_size = av_samples_get_buffer_size(
|
||||||
|
&out_linesize,
|
||||||
|
out_nb_channels,
|
||||||
|
ret,
|
||||||
|
out_sample_fmt,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
// check audio buffer size
|
||||||
|
if (resampled_data_size < 0)
|
||||||
{
|
{
|
||||||
printf("swr_ctx null error.\n");
|
sLog.error ("av_samples_get_buffer_size error.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,39 +629,28 @@ int CAudioStream::decodeFrame (uint8_t* audioBuffer, int bufferSize)
|
|||||||
avFrame = av_frame_alloc();
|
avFrame = av_frame_alloc();
|
||||||
if (!avFrame)
|
if (!avFrame)
|
||||||
{
|
{
|
||||||
printf("Could not allocate AVFrame.\n");
|
sLog.error("Could not allocate AVFrame.\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; g_KeepRunning;) {
|
// block until there's any data in the buffers
|
||||||
|
while (g_KeepRunning) {
|
||||||
while (audio_pkt_size > 0) {
|
while (audio_pkt_size > 0) {
|
||||||
int got_frame = 0;
|
int got_frame = 0;
|
||||||
int ret = avcodec_receive_frame(this->getContext (), avFrame);
|
int ret = avcodec_receive_frame(this->getContext (), avFrame);
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
{
|
|
||||||
got_frame = 1;
|
got_frame = 1;
|
||||||
}
|
|
||||||
if (ret == AVERROR(EAGAIN))
|
if (ret == AVERROR(EAGAIN))
|
||||||
{
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
{
|
|
||||||
ret = avcodec_send_packet(this->getContext (), pkt);
|
ret = avcodec_send_packet(this->getContext (), pkt);
|
||||||
}
|
|
||||||
if (ret == AVERROR(EAGAIN))
|
if (ret == AVERROR(EAGAIN))
|
||||||
{
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
|
||||||
else if (ret < 0)
|
else if (ret < 0)
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
len1 = pkt->size;
|
len1 = pkt->size;
|
||||||
}
|
|
||||||
|
|
||||||
if (len1 < 0)
|
if (len1 < 0)
|
||||||
{
|
{
|
||||||
@ -715,18 +667,18 @@ int CAudioStream::decodeFrame (uint8_t* audioBuffer, int bufferSize)
|
|||||||
// audio resampling
|
// audio resampling
|
||||||
data_size = this->resampleAudio (
|
data_size = this->resampleAudio (
|
||||||
avFrame,
|
avFrame,
|
||||||
AV_SAMPLE_FMT_S16,
|
this->m_audioContext->getFormat (),
|
||||||
this->getContext ()->channels,
|
this->m_audioContext->getChannels (),
|
||||||
this->getContext ()->sample_rate,
|
this->m_audioContext->getSampleRate (),
|
||||||
audioBuffer
|
audioBuffer
|
||||||
);
|
);
|
||||||
assert(data_size <= bufferSize);
|
assert(data_size <= bufferSize);
|
||||||
}
|
}
|
||||||
if (data_size <= 0) {
|
if (data_size <= 0) {
|
||||||
/* No data yet, get more frames */
|
// no data found, keep waiting
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* We have data, return it and come back for more later */
|
// some data was found
|
||||||
return data_size;
|
return data_size;
|
||||||
}
|
}
|
||||||
if (pkt->data)
|
if (pkt->data)
|
||||||
|
@ -15,74 +15,79 @@ extern "C"
|
|||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_thread.h>
|
#include <SDL_thread.h>
|
||||||
|
|
||||||
#define SDL_AUDIO_BUFFER_SIZE 1024
|
#include "WallpaperEngine/Audio/CAudioContext.h"
|
||||||
#define MAX_AUDIO_FRAME_SIZE 192000
|
|
||||||
|
|
||||||
namespace WallpaperEngine
|
namespace WallpaperEngine::Audio
|
||||||
{
|
{
|
||||||
namespace Audio
|
class CAudioStream
|
||||||
{
|
{
|
||||||
class CAudioStream
|
public:
|
||||||
|
CAudioStream (CAudioContext* context, const std::string& filename);
|
||||||
|
CAudioStream (CAudioContext* context, const void* buffer, int length);
|
||||||
|
CAudioStream (CAudioContext* audioContext, AVCodecContext* context);
|
||||||
|
|
||||||
|
void queuePacket (AVPacket* pkt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the next packet in the queue
|
||||||
|
*
|
||||||
|
* WARNING: BLOCKS UNTIL SOME DATA IS READ FROM IT
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
void dequeuePacket (AVPacket* output);
|
||||||
|
|
||||||
|
AVCodecContext* getContext ();
|
||||||
|
AVFormatContext* getFormatContext ();
|
||||||
|
int getAudioStream ();
|
||||||
|
bool isInitialized ();
|
||||||
|
void setRepeat (bool newRepeat = true);
|
||||||
|
bool isRepeat ();
|
||||||
|
void stop ();
|
||||||
|
const void* getBuffer ();
|
||||||
|
int getLength ();
|
||||||
|
int getPosition ();
|
||||||
|
void setPosition (int current);
|
||||||
|
SDL_cond* getWaitCondition ();
|
||||||
|
int getQueueSize ();
|
||||||
|
int getQueuePacketCount ();
|
||||||
|
int64_t getQueueDuration ();
|
||||||
|
AVRational getTimeBase ();
|
||||||
|
bool isQueueEmpty ();
|
||||||
|
SDL_mutex* getMutex ();
|
||||||
|
|
||||||
|
int decodeFrame (uint8_t* audioBuffer, int bufferSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void loadCustomContent (const char* filename = nullptr);
|
||||||
|
int resampleAudio (AVFrame * decoded_audio_frame, enum AVSampleFormat out_sample_fmt, int out_channels, int out_sample_rate, uint8_t* out_buf);
|
||||||
|
bool doQueue (AVPacket* pkt);
|
||||||
|
void initialize ();
|
||||||
|
|
||||||
|
CAudioContext* m_audioContext;
|
||||||
|
bool m_initialized;
|
||||||
|
bool m_repeat;
|
||||||
|
AVCodecContext* m_context = nullptr;
|
||||||
|
AVFormatContext* m_formatContext = nullptr;
|
||||||
|
int m_audioStream = -1;
|
||||||
|
const void* m_buffer;
|
||||||
|
int m_length;
|
||||||
|
int m_position = 0;
|
||||||
|
|
||||||
|
struct MyAVPacketList
|
||||||
{
|
{
|
||||||
public:
|
AVPacket *packet;
|
||||||
CAudioStream (const std::string& filename);
|
|
||||||
CAudioStream (const void* buffer, int length);
|
|
||||||
CAudioStream (AVCodecContext* context);
|
|
||||||
|
|
||||||
void queuePacket (AVPacket* pkt);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the next packet in the queue
|
|
||||||
*
|
|
||||||
* WARNING: BLOCKS UNTIL SOME DATA IS READ FROM IT
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
void dequeuePacket (AVPacket* output);
|
|
||||||
|
|
||||||
AVCodecContext* getContext ();
|
|
||||||
AVFormatContext* getFormatContext ();
|
|
||||||
int getAudioStream ();
|
|
||||||
bool isInitialized ();
|
|
||||||
void setRepeat (bool newRepeat = true);
|
|
||||||
bool isRepeat ();
|
|
||||||
void stop ();
|
|
||||||
const void* getBuffer ();
|
|
||||||
int getLength ();
|
|
||||||
int getPosition ();
|
|
||||||
void setPosition (int current);
|
|
||||||
|
|
||||||
int decodeFrame (uint8_t* audioBuffer, int bufferSize);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void loadCustomContent (const char* filename = nullptr);
|
|
||||||
int resampleAudio (AVFrame * decoded_audio_frame, enum AVSampleFormat out_sample_fmt, int out_channels, int out_sample_rate, uint8_t* out_buf);
|
|
||||||
bool doQueue (AVPacket* pkt);
|
|
||||||
void initialize ();
|
|
||||||
|
|
||||||
bool m_initialized;
|
|
||||||
bool m_repeat;
|
|
||||||
AVCodecContext* m_context = nullptr;
|
|
||||||
AVFormatContext* m_formatContext = nullptr;
|
|
||||||
int m_audioStream = -1;
|
|
||||||
const void* m_buffer;
|
|
||||||
int m_length;
|
|
||||||
int m_position = 0;
|
|
||||||
|
|
||||||
struct MyAVPacketList
|
|
||||||
{
|
|
||||||
AVPacket *packet;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PacketQueue
|
|
||||||
{
|
|
||||||
AVFifoBuffer* packetList;
|
|
||||||
int nb_packets;
|
|
||||||
int size;
|
|
||||||
int64_t duration;
|
|
||||||
SDL_mutex *mutex;
|
|
||||||
SDL_cond *cond;
|
|
||||||
} *m_queue;
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
struct PacketQueue
|
||||||
|
{
|
||||||
|
AVFifo* packetList;
|
||||||
|
int nb_packets;
|
||||||
|
int size;
|
||||||
|
int64_t duration;
|
||||||
|
SDL_mutex *mutex;
|
||||||
|
SDL_cond *wait;
|
||||||
|
SDL_cond *cond;
|
||||||
|
} *m_queue;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
4
src/WallpaperEngine/Audio/Drivers/CAudioDriver.cpp
Normal file
4
src/WallpaperEngine/Audio/Drivers/CAudioDriver.cpp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include "CAudioDriver.h"
|
||||||
|
|
||||||
|
using namespace WallpaperEngine::Audio;
|
||||||
|
using namespace WallpaperEngine::Audio::Drivers;
|
24
src/WallpaperEngine/Audio/Drivers/CAudioDriver.h
Normal file
24
src/WallpaperEngine/Audio/Drivers/CAudioDriver.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "WallpaperEngine/Audio/CAudioStream.h"
|
||||||
|
|
||||||
|
namespace WallpaperEngine::Audio
|
||||||
|
{
|
||||||
|
class CAudioStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace WallpaperEngine::Audio::Drivers
|
||||||
|
{
|
||||||
|
class CAudioDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void addStream (CAudioStream* stream) = 0;
|
||||||
|
|
||||||
|
virtual AVSampleFormat getFormat () const = 0;
|
||||||
|
virtual int getSampleRate () const = 0;
|
||||||
|
virtual int getChannels () const = 0;
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
}
|
154
src/WallpaperEngine/Audio/Drivers/CSDLAudioDriver.cpp
Normal file
154
src/WallpaperEngine/Audio/Drivers/CSDLAudioDriver.cpp
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "CSDLAudioDriver.h"
|
||||||
|
|
||||||
|
#define SDL_AUDIO_BUFFER_SIZE 4096
|
||||||
|
#define MAX_AUDIO_FRAME_SIZE 192000
|
||||||
|
|
||||||
|
extern int g_AudioVolume;
|
||||||
|
extern bool g_KeepRunning;
|
||||||
|
|
||||||
|
using namespace WallpaperEngine::Audio;
|
||||||
|
using namespace WallpaperEngine::Audio::Drivers;
|
||||||
|
|
||||||
|
void audio_callback (void* userdata, uint8_t* streamData, int length)
|
||||||
|
{
|
||||||
|
CSDLAudioDriver* driver = reinterpret_cast <CSDLAudioDriver*> (userdata);
|
||||||
|
|
||||||
|
memset (streamData, 0, length);
|
||||||
|
|
||||||
|
for (const auto& buffer : driver->getStreams ())
|
||||||
|
{
|
||||||
|
uint8_t* streamDataPointer = streamData;
|
||||||
|
int streamLength = length;
|
||||||
|
int len1, audio_size;
|
||||||
|
|
||||||
|
// sound is not initialized or stopped and is not in loop mode
|
||||||
|
// ignore mixing it in
|
||||||
|
if (buffer->stream->isInitialized () == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check if thread is empty and signal the read thread
|
||||||
|
if (buffer->stream->isQueueEmpty () == true)
|
||||||
|
{
|
||||||
|
SDL_CondSignal (buffer->stream->getWaitCondition ());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (streamLength > 0 && g_KeepRunning)
|
||||||
|
{
|
||||||
|
if (buffer->audio_buf_index >= buffer->audio_buf_size)
|
||||||
|
{
|
||||||
|
// get more data to fill the buffer
|
||||||
|
audio_size = buffer->stream->decodeFrame (buffer->audio_buf, sizeof (buffer->audio_buf));
|
||||||
|
|
||||||
|
if (audio_size < 0)
|
||||||
|
{
|
||||||
|
// fallback for errors, silence
|
||||||
|
buffer->audio_buf_size = 1024;
|
||||||
|
memset(buffer->audio_buf, 0, buffer->audio_buf_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer->audio_buf_size = audio_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->audio_buf_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len1 = buffer->audio_buf_size - buffer->audio_buf_index;
|
||||||
|
|
||||||
|
if (len1 > streamLength)
|
||||||
|
len1 = streamLength;
|
||||||
|
|
||||||
|
// mix the audio
|
||||||
|
SDL_MixAudioFormat (
|
||||||
|
streamDataPointer, &buffer->audio_buf [buffer->audio_buf_index],
|
||||||
|
driver->getSpec ().format, len1, g_AudioVolume
|
||||||
|
);
|
||||||
|
|
||||||
|
streamLength -= len1;
|
||||||
|
streamDataPointer += len1;
|
||||||
|
buffer->audio_buf_index += len1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSDLAudioDriver::CSDLAudioDriver () :
|
||||||
|
m_initialized (false)
|
||||||
|
{
|
||||||
|
if (SDL_InitSubSystem (SDL_INIT_AUDIO) < 0)
|
||||||
|
{
|
||||||
|
sLog.error ("Cannot initialize SDL audio system, SDL_GetError: ", SDL_GetError ());
|
||||||
|
sLog.error ("Continuing without audio support");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_AudioSpec requestedSpec;
|
||||||
|
|
||||||
|
memset (&requestedSpec, 0, sizeof (requestedSpec));
|
||||||
|
|
||||||
|
requestedSpec.freq = 48000;
|
||||||
|
requestedSpec.format = AUDIO_F32;
|
||||||
|
requestedSpec.channels = 2;
|
||||||
|
requestedSpec.samples = SDL_AUDIO_BUFFER_SIZE;
|
||||||
|
requestedSpec.callback = audio_callback;
|
||||||
|
requestedSpec.userdata = this;
|
||||||
|
|
||||||
|
this->m_deviceID = SDL_OpenAudioDevice (nullptr, false, &requestedSpec, &this->m_audioSpec, SDL_AUDIO_ALLOW_ANY_CHANGE);
|
||||||
|
|
||||||
|
if (this->m_deviceID == 0)
|
||||||
|
{
|
||||||
|
sLog.error ("SDL_OpenAudioDevice: ", SDL_GetError ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_PauseAudioDevice (this->m_deviceID, 0);
|
||||||
|
|
||||||
|
this->m_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CSDLAudioDriver::~CSDLAudioDriver ()
|
||||||
|
{
|
||||||
|
if (this->m_initialized == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SDL_CloseAudioDevice (this->m_deviceID);
|
||||||
|
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSDLAudioDriver::addStream (CAudioStream* stream)
|
||||||
|
{
|
||||||
|
this->m_streams.push_back (new CSDLAudioBuffer { stream });
|
||||||
|
}
|
||||||
|
const std::vector <CSDLAudioBuffer*>& CSDLAudioDriver::getStreams ()
|
||||||
|
{
|
||||||
|
return this->m_streams;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVSampleFormat CSDLAudioDriver::getFormat () const
|
||||||
|
{
|
||||||
|
switch (this->m_audioSpec.format)
|
||||||
|
{
|
||||||
|
case AUDIO_U8: case AUDIO_S8: return AV_SAMPLE_FMT_U8;
|
||||||
|
case AUDIO_U16MSB: case AUDIO_U16LSB: case AUDIO_S16LSB: case AUDIO_S16MSB: return AV_SAMPLE_FMT_S16;
|
||||||
|
case AUDIO_S32LSB: case AUDIO_S32MSB: return AV_SAMPLE_FMT_S32;
|
||||||
|
case AUDIO_F32LSB: case AUDIO_F32MSB: return AV_SAMPLE_FMT_FLT;
|
||||||
|
}
|
||||||
|
|
||||||
|
sLog.exception ("Cannot convert from SDL format to ffmpeg format, aborting...");
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSDLAudioDriver::getSampleRate () const
|
||||||
|
{
|
||||||
|
return this->m_audioSpec.freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CSDLAudioDriver::getChannels () const
|
||||||
|
{
|
||||||
|
return this->m_audioSpec.channels;
|
||||||
|
}
|
||||||
|
const SDL_AudioSpec& CSDLAudioDriver::getSpec () const
|
||||||
|
{
|
||||||
|
return this->m_audioSpec;
|
||||||
|
}
|
42
src/WallpaperEngine/Audio/Drivers/CSDLAudioDriver.h
Normal file
42
src/WallpaperEngine/Audio/Drivers/CSDLAudioDriver.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "WallpaperEngine/Audio/CAudioStream.h"
|
||||||
|
#include "WallpaperEngine/Audio/Drivers/CAudioDriver.h"
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#define MAX_AUDIO_FRAME_SIZE 192000
|
||||||
|
|
||||||
|
namespace WallpaperEngine::Audio::Drivers
|
||||||
|
{
|
||||||
|
struct CSDLAudioBuffer
|
||||||
|
{
|
||||||
|
CAudioStream* stream;
|
||||||
|
uint8_t audio_buf[(MAX_AUDIO_FRAME_SIZE * 3) / 2];
|
||||||
|
unsigned int audio_buf_size = 0;
|
||||||
|
unsigned int audio_buf_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CSDLAudioDriver : public CAudioDriver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CSDLAudioDriver ();
|
||||||
|
~CSDLAudioDriver ();
|
||||||
|
|
||||||
|
void addStream (CAudioStream* stream) override;
|
||||||
|
const std::vector <CSDLAudioBuffer*>& getStreams ();
|
||||||
|
|
||||||
|
AVSampleFormat getFormat () const override;
|
||||||
|
int getSampleRate () const override;
|
||||||
|
int getChannels () const override;
|
||||||
|
const SDL_AudioSpec& getSpec () const;
|
||||||
|
private:
|
||||||
|
SDL_AudioDeviceID m_deviceID;
|
||||||
|
bool m_initialized;
|
||||||
|
SDL_AudioSpec m_audioSpec;
|
||||||
|
std::vector <CSDLAudioBuffer*> m_streams;
|
||||||
|
};
|
||||||
|
}
|
@ -5,14 +5,17 @@
|
|||||||
using namespace WallpaperEngine::Core::Objects;
|
using namespace WallpaperEngine::Core::Objects;
|
||||||
|
|
||||||
CSound::CSound (
|
CSound::CSound (
|
||||||
CScene* scene,
|
CScene* scene,
|
||||||
CUserSettingBoolean* visible,
|
CUserSettingBoolean* visible,
|
||||||
uint32_t id,
|
uint32_t id,
|
||||||
std::string name,
|
std::string name,
|
||||||
CUserSettingVector3* origin,
|
CUserSettingVector3* origin,
|
||||||
CUserSettingVector3* scale,
|
CUserSettingVector3* scale,
|
||||||
const glm::vec3& angles) :
|
const glm::vec3& angles,
|
||||||
CObject (scene, visible, id, std::move(name), Type, origin, scale, angles)
|
bool repeat
|
||||||
|
) :
|
||||||
|
CObject (scene, visible, id, std::move(name), Type, origin, scale, angles),
|
||||||
|
m_repeat (repeat)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,8 +29,13 @@ WallpaperEngine::Core::CObject* CSound::fromJSON (
|
|||||||
CUserSettingVector3* scale,
|
CUserSettingVector3* scale,
|
||||||
const glm::vec3& angles)
|
const glm::vec3& angles)
|
||||||
{
|
{
|
||||||
|
bool repeat = false;
|
||||||
// TODO: PARSE AUDIO VOLUME
|
// TODO: PARSE AUDIO VOLUME
|
||||||
auto sound_it = jsonFindRequired (data, "sound", "Sound information not present");
|
auto sound_it = jsonFindRequired (data, "sound", "Sound information not present");
|
||||||
|
auto playbackmode = jsonFindDefault <std::string> (data, "playbackmode", "");
|
||||||
|
|
||||||
|
if (playbackmode == "loop")
|
||||||
|
repeat = true;
|
||||||
|
|
||||||
if ((*sound_it).is_array () == false)
|
if ((*sound_it).is_array () == false)
|
||||||
sLog.exception ("Expected sound list on element ", name);
|
sLog.exception ("Expected sound list on element ", name);
|
||||||
@ -39,7 +47,8 @@ WallpaperEngine::Core::CObject* CSound::fromJSON (
|
|||||||
name,
|
name,
|
||||||
origin,
|
origin,
|
||||||
scale,
|
scale,
|
||||||
angles
|
angles,
|
||||||
|
repeat
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const auto& cur : (*sound_it))
|
for (const auto& cur : (*sound_it))
|
||||||
@ -57,5 +66,9 @@ const std::vector<std::string>& CSound::getSounds () const
|
|||||||
{
|
{
|
||||||
return this->m_sounds;
|
return this->m_sounds;
|
||||||
}
|
}
|
||||||
|
bool CSound::isRepeat () const
|
||||||
|
{
|
||||||
|
return this->m_repeat;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string CSound::Type = "sound";
|
const std::string CSound::Type = "sound";
|
@ -27,6 +27,7 @@ namespace WallpaperEngine::Core::Objects
|
|||||||
|
|
||||||
void insertSound (std::string filename);
|
void insertSound (std::string filename);
|
||||||
const std::vector<std::string>& getSounds () const;
|
const std::vector<std::string>& getSounds () const;
|
||||||
|
bool isRepeat () const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CSound (
|
CSound (
|
||||||
@ -36,11 +37,13 @@ namespace WallpaperEngine::Core::Objects
|
|||||||
std::string name,
|
std::string name,
|
||||||
CUserSettingVector3* origin,
|
CUserSettingVector3* origin,
|
||||||
CUserSettingVector3* scale,
|
CUserSettingVector3* scale,
|
||||||
const glm::vec3& angles
|
const glm::vec3& angles,
|
||||||
|
bool repeat
|
||||||
);
|
);
|
||||||
|
|
||||||
static const std::string Type;
|
static const std::string Type;
|
||||||
private:
|
private:
|
||||||
|
bool m_repeat;
|
||||||
std::vector<std::string> m_sounds;
|
std::vector<std::string> m_sounds;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ extern float g_TimeLast;
|
|||||||
using namespace WallpaperEngine;
|
using namespace WallpaperEngine;
|
||||||
using namespace WallpaperEngine::Render;
|
using namespace WallpaperEngine::Render;
|
||||||
|
|
||||||
CScene::CScene (Core::CScene* scene, CRenderContext* context) :
|
CScene::CScene (Core::CScene* scene, CRenderContext* context, CAudioContext* audioContext) :
|
||||||
CWallpaper (scene, Type, context)
|
CWallpaper (scene, Type, context, audioContext)
|
||||||
{
|
{
|
||||||
// setup the scene camera
|
// setup the scene camera
|
||||||
this->m_camera = new CCamera (this, scene->getCamera ());
|
this->m_camera = new CCamera (this, scene->getCamera ());
|
||||||
|
@ -15,7 +15,7 @@ namespace WallpaperEngine::Render
|
|||||||
class CScene : public CWallpaper
|
class CScene : public CWallpaper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CScene (Core::CScene* scene, CRenderContext* context);
|
CScene (Core::CScene* scene, CRenderContext* context, CAudioContext* audioContext);
|
||||||
|
|
||||||
CCamera* getCamera () const;
|
CCamera* getCamera () const;
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ void* get_proc_address (void* ctx, const char* name)
|
|||||||
return reinterpret_cast <void*> (glfwGetProcAddress (name));
|
return reinterpret_cast <void*> (glfwGetProcAddress (name));
|
||||||
}
|
}
|
||||||
|
|
||||||
CVideo::CVideo (Core::CVideo* video, CRenderContext* context) :
|
CVideo::CVideo (Core::CVideo* video, CRenderContext* context, CAudioContext* audioContext) :
|
||||||
CWallpaper (video, Type, context),
|
CWallpaper (video, Type, context, audioContext),
|
||||||
m_width (16),
|
m_width (16),
|
||||||
m_height (16)
|
m_height (16)
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ namespace WallpaperEngine::Render
|
|||||||
class CVideo : public CWallpaper
|
class CVideo : public CWallpaper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CVideo (Core::CVideo* video, CRenderContext* context);
|
CVideo (Core::CVideo* video, CRenderContext* context, CAudioContext* audioContext);
|
||||||
|
|
||||||
Core::CVideo* getVideo ();
|
Core::CVideo* getVideo ();
|
||||||
|
|
||||||
|
@ -9,11 +9,12 @@
|
|||||||
|
|
||||||
using namespace WallpaperEngine::Render;
|
using namespace WallpaperEngine::Render;
|
||||||
|
|
||||||
CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext* context) :
|
CWallpaper::CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext* context, CAudioContext* audioContext) :
|
||||||
m_wallpaperData (wallpaperData),
|
m_wallpaperData (wallpaperData),
|
||||||
m_type (std::move(type)),
|
m_type (std::move(type)),
|
||||||
m_context (context),
|
m_context (context),
|
||||||
m_destFramebuffer (GL_NONE)
|
m_destFramebuffer (GL_NONE),
|
||||||
|
m_audioContext (audioContext)
|
||||||
{
|
{
|
||||||
// generate the VAO to stop opengl from complaining
|
// generate the VAO to stop opengl from complaining
|
||||||
glGenVertexArrays (1, &this->m_vaoBuffer);
|
glGenVertexArrays (1, &this->m_vaoBuffer);
|
||||||
@ -329,6 +330,11 @@ CRenderContext* CWallpaper::getContext ()
|
|||||||
return this->m_context;
|
return this->m_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CAudioContext* CWallpaper::getAudioContext ()
|
||||||
|
{
|
||||||
|
return this->m_audioContext;
|
||||||
|
}
|
||||||
|
|
||||||
CFBO* CWallpaper::createFBO (const std::string& name, ITexture::TextureFormat format, ITexture::TextureFlags flags, float scale, uint32_t realWidth, uint32_t realHeight, uint32_t textureWidth, uint32_t textureHeight)
|
CFBO* CWallpaper::createFBO (const std::string& name, ITexture::TextureFormat format, ITexture::TextureFlags flags, float scale, uint32_t realWidth, uint32_t realHeight, uint32_t textureWidth, uint32_t textureHeight)
|
||||||
{
|
{
|
||||||
CFBO* fbo = new CFBO (name, format, flags, scale, realWidth, realHeight, textureWidth, textureHeight);
|
CFBO* fbo = new CFBO (name, format, flags, scale, realWidth, realHeight, textureWidth, textureHeight);
|
||||||
@ -359,12 +365,12 @@ CFBO* CWallpaper::getFBO () const
|
|||||||
return this->m_sceneFBO;
|
return this->m_sceneFBO;
|
||||||
}
|
}
|
||||||
|
|
||||||
CWallpaper* CWallpaper::fromWallpaper (Core::CWallpaper* wallpaper, CRenderContext* context)
|
CWallpaper* CWallpaper::fromWallpaper (Core::CWallpaper* wallpaper, CRenderContext* context, CAudioContext* audioContext)
|
||||||
{
|
{
|
||||||
if (wallpaper->is <Core::CScene> () == true)
|
if (wallpaper->is <Core::CScene> () == true)
|
||||||
return new WallpaperEngine::Render::CScene (wallpaper->as <Core::CScene> (), context);
|
return new WallpaperEngine::Render::CScene (wallpaper->as <Core::CScene> (), context, audioContext);
|
||||||
else if (wallpaper->is <Core::CVideo> () == true)
|
else if (wallpaper->is <Core::CVideo> () == true)
|
||||||
return new WallpaperEngine::Render::CVideo (wallpaper->as <Core::CVideo> (), context);
|
return new WallpaperEngine::Render::CVideo (wallpaper->as <Core::CVideo> (), context, audioContext);
|
||||||
else
|
else
|
||||||
sLog.exception ("Unsupported wallpaper type");
|
sLog.exception ("Unsupported wallpaper type");
|
||||||
}
|
}
|
@ -10,8 +10,10 @@
|
|||||||
#include "CFBO.h"
|
#include "CFBO.h"
|
||||||
#include "CRenderContext.h"
|
#include "CRenderContext.h"
|
||||||
#include "WallpaperEngine/Assets/CContainer.h"
|
#include "WallpaperEngine/Assets/CContainer.h"
|
||||||
|
#include "WallpaperEngine/Audio/CAudioContext.h"
|
||||||
|
|
||||||
using namespace WallpaperEngine::Assets;
|
using namespace WallpaperEngine::Assets;
|
||||||
|
using namespace WallpaperEngine::Audio;
|
||||||
|
|
||||||
namespace WallpaperEngine::Render
|
namespace WallpaperEngine::Render
|
||||||
{
|
{
|
||||||
@ -25,7 +27,7 @@ namespace WallpaperEngine::Render
|
|||||||
|
|
||||||
template<class T> bool is () { return this->m_type == T::Type; }
|
template<class T> bool is () { return this->m_type == T::Type; }
|
||||||
|
|
||||||
CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext* context);
|
CWallpaper (Core::CWallpaper* wallpaperData, std::string type, CRenderContext* context, CAudioContext* audioContext);
|
||||||
~CWallpaper ();
|
~CWallpaper ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,6 +45,11 @@ namespace WallpaperEngine::Render
|
|||||||
*/
|
*/
|
||||||
CRenderContext* getContext ();
|
CRenderContext* getContext ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The current audio context for this wallpaper
|
||||||
|
*/
|
||||||
|
CAudioContext* getAudioContext ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The scene's framebuffer
|
* @return The scene's framebuffer
|
||||||
*/
|
*/
|
||||||
@ -105,7 +112,7 @@ namespace WallpaperEngine::Render
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static CWallpaper* fromWallpaper (Core::CWallpaper* wallpaper, CRenderContext* context);
|
static CWallpaper* fromWallpaper (Core::CWallpaper* wallpaper, CRenderContext* context, CAudioContext* audioContext);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -160,5 +167,9 @@ namespace WallpaperEngine::Render
|
|||||||
* Context that is using this wallpaper
|
* Context that is using this wallpaper
|
||||||
*/
|
*/
|
||||||
CRenderContext* m_context;
|
CRenderContext* m_context;
|
||||||
|
/*
|
||||||
|
* Audio context that is using this wallpaper
|
||||||
|
*/
|
||||||
|
CAudioContext* m_audioContext;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,15 @@ void CSound::load ()
|
|||||||
uint32_t filesize = 0;
|
uint32_t filesize = 0;
|
||||||
const void* filebuffer = this->getContainer ()->readFile (cur, &filesize);
|
const void* filebuffer = this->getContainer ()->readFile (cur, &filesize);
|
||||||
|
|
||||||
this->m_audioStreams.push_back (new Audio::CAudioStream (filebuffer, filesize));
|
auto stream = new Audio::CAudioStream (this->getScene ()->getAudioContext (), filebuffer, filesize);
|
||||||
|
|
||||||
|
stream->setRepeat (this->m_sound->isRepeat ());
|
||||||
|
|
||||||
|
this->m_audioStreams.push_back (stream);
|
||||||
this->m_soundBuffer.push_back (filebuffer);
|
this->m_soundBuffer.push_back (filebuffer);
|
||||||
|
|
||||||
|
// add the stream to the context so it can be played
|
||||||
|
this->getScene ()->getAudioContext ()->addStream (stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user