Skip to content

Commit a265e37

Browse files
committed
[LINUX][ZH] Add OpenAL stream implementations
1 parent 23122a4 commit a265e37

File tree

5 files changed

+245
-2
lines changed

5 files changed

+245
-2
lines changed

GeneralsMD/Code/GameEngineDevice/CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,14 @@ if(RTS_BUILD_OPTION_OPENAL)
254254

255255
if(OpenAL_FOUND)
256256
target_sources(z_gameenginedevice PRIVATE
257+
Include/OpenALDevice/FFmpegOpenALAudioStream.h
257258
Include/OpenALDevice/OpenALAudioManager.h
258-
# Include/OpenALDevice/OpenALAudioStream.h
259+
Include/OpenALDevice/OpenALAudioStream.h
260+
Source/OpenALDevice/FFmpegOpenALAudioStream.cpp
259261
Source/OpenALDevice/OpenALAudioFileCache.h
260262
Source/OpenALDevice/OpenALAudioFileCache.cpp
261263
Source/OpenALDevice/OpenALAudioManager.cpp
262-
# Source/OpenALDevice/OpenALAudioStream.cpp
264+
Source/OpenALDevice/OpenALAudioStream.cpp
263265
)
264266

265267
target_link_libraries(z_gameenginedevice PRIVATE OpenAL::OpenAL)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 Electronic Arts Inc.
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
// FILE: FFmpegOpenALAudioStream.h //////////////////////////////////////////////////////////////////////////
20+
// FFmpegOpenALAudioStream implementation
21+
// Author: Stephan Vedder, May 2025
22+
#pragma once
23+
24+
#include "OpenALAudioManager.h"
25+
26+
class FFmpegFile;
27+
class FFmpegOpenALAudioStream : public OpenALAudioStream
28+
{
29+
public:
30+
FFmpegOpenALAudioStream(FFmpegFile* file);
31+
~FFmpegOpenALAudioStream();
32+
33+
34+
protected:
35+
FFmpegFile* m_ffmpegFile;
36+
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 Electronic Arts Inc.
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
// FILE: OpenALAudioStream.h //////////////////////////////////////////////////////////////////////////
20+
// OpenALAudioStream implementation
21+
// Author: Stephan Vedder, May 2025
22+
#pragma once
23+
24+
#include "always.h"
25+
#include <AL/al.h>
26+
#include <stdint.h>
27+
#include <functional>
28+
29+
#define AL_STREAM_BUFFER_COUNT 32
30+
31+
class OpenALAudioStream
32+
{
33+
public:
34+
OpenALAudioStream();
35+
virtual ~OpenALAudioStream();
36+
37+
void setRequireDataCallback(std::function<void()> callback) { m_requireDataCallback = callback; }
38+
ALuint getSource() const { return m_source; }
39+
40+
bool bufferData(uint8_t *data, size_t data_size, ALenum format, int samplerate);
41+
bool isPlaying();
42+
void update();
43+
void reset();
44+
45+
void play() { alSourcePlay(m_source); }
46+
void pause() { alSourcePause(m_source); }
47+
void stop() { alSourceStop(m_source); }
48+
49+
void setVolume(float vol) { alSourcef(m_source, AL_GAIN, vol); }
50+
51+
protected:
52+
std::function<void()> m_requireDataCallback = nullptr;
53+
ALuint m_source = 0;
54+
ALuint m_buffers[AL_STREAM_BUFFER_COUNT] = {};
55+
unsigned int m_currentBufferIndex = 0;
56+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 Electronic Arts Inc.
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
// FILE: FFmpegOpenALAudioStream.cpp //////////////////////////////////////////////////////////////////////////
20+
// FFmpegOpenALAudioStream implementation
21+
// Author: Stephan Vedder, May 2025
22+
#include "OpenALAudioDevice/FFmpegOpenALAudioStream.h"
23+
24+
FFmpegOpenALAudioStream::FFmpegOpenALAudioStream(FFmpegFile* file) :
25+
OpenALAudioStream(),
26+
m_ffmpegFile(file)
27+
{
28+
}
29+
30+
FFmpegOpenALAudioStream::~FFmpegOpenALAudioStream()
31+
{
32+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 TheSuperHackers
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
////////////////////////////////////////////////////////////////////////////////
20+
// //
21+
// (c) 2001-2003 Electronic Arts Inc. //
22+
// //
23+
////////////////////////////////////////////////////////////////////////////////
24+
25+
// FILE: OpenALAudioStream.cpp //////////////////////////////////////////////////////////////////////////
26+
// OpenALAudioStream implementation
27+
// Author: Stephan Vedder, May 2025
28+
#include "OpenALAudioDevice/OpenALAudioStream.h"
29+
#include "OpenALAudioDevice/OpenALAudioManager.h"
30+
31+
OpenALAudioStream::OpenALAudioStream()
32+
{
33+
alGenSources(1, &m_source);
34+
alGenBuffers(AL_STREAM_BUFFER_COUNT, m_buffers);
35+
36+
// Make stream ignore positioning
37+
alSourcei(m_source, AL_SOURCE_RELATIVE, AL_TRUE);
38+
39+
DEBUG_LOG(("OpenALAudioStream created: %i\n", m_source));
40+
}
41+
42+
OpenALAudioStream::~OpenALAudioStream()
43+
{
44+
DEBUG_LOG(("OpenALAudioStream freed: %i\n", m_source));
45+
// Unbind the buffers first
46+
alSourceStop(m_source);
47+
alSourcei(m_source, AL_BUFFER, 0);
48+
alDeleteSources(1, &m_source);
49+
// Now delete the buffers
50+
alDeleteBuffers(AL_STREAM_BUFFER_COUNT, m_buffers);
51+
}
52+
53+
bool OpenALAudioStream::bufferData(uint8_t *data, size_t data_size, ALenum format, int samplerate)
54+
{
55+
DEBUG_LOG(("Buffering %zu bytes of data (samplerate: %i, format: %i)\n", data_size, samplerate, format));
56+
ALint numQueued;
57+
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &numQueued);
58+
if (numQueued >= AL_STREAM_BUFFER_COUNT) {
59+
DEBUG_LOG(("Having too many buffers already queued: %i", numQueued));
60+
return false;
61+
}
62+
63+
ALuint &currentBuffer = m_buffers[m_currentBufferIndex];
64+
alBufferData(currentBuffer, format, data, data_size, samplerate);
65+
alSourceQueueBuffers(m_source, 1, &currentBuffer);
66+
m_currentBufferIndex++;
67+
68+
if (m_currentBufferIndex >= AL_STREAM_BUFFER_COUNT)
69+
m_currentBufferIndex = 0;
70+
71+
return true;
72+
}
73+
74+
void OpenALAudioStream::update()
75+
{
76+
ALint sourceState;
77+
alGetSourcei(m_source, AL_SOURCE_STATE, &sourceState);
78+
79+
ALint processed;
80+
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processed);
81+
DEBUG_LOG(("%i buffers have been processed\n", processed));
82+
while (processed > 0) {
83+
ALuint buffer;
84+
alSourceUnqueueBuffers(m_source, 1, &buffer);
85+
processed--;
86+
}
87+
88+
ALint numQueued;
89+
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &numQueued);
90+
DEBUG_LOG(("Having %i buffers queued\n", numQueued));
91+
if (numQueued < AL_STREAM_BUFFER_COUNT && m_requireDataCallback) {
92+
// Ask for more data to be buffered
93+
while (numQueued < AL_STREAM_BUFFER_COUNT) {
94+
m_requireDataCallback();
95+
numQueued++;
96+
}
97+
}
98+
99+
if (sourceState == AL_STOPPED) {
100+
play();
101+
}
102+
}
103+
104+
void OpenALAudioStream::reset()
105+
{
106+
DEBUG_LOG(("Resetting stream\n"));
107+
alSourceRewind(m_source);
108+
alSourcei(m_source, AL_BUFFER, 0);
109+
m_currentBufferIndex = 0;
110+
}
111+
112+
bool OpenALAudioStream::isPlaying()
113+
{
114+
ALint state;
115+
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
116+
return state == AL_PLAYING;
117+
}

0 commit comments

Comments
 (0)