Skip to content

Commit 7df3538

Browse files
Fixing Dual Output audio by moving encoder ownership out of AudioTrackFactory and into each advanced output (#1694)
1 parent 0d8411e commit 7df3538

11 files changed

Lines changed: 275 additions & 88 deletions

obs-studio-server/source/nodeobs_api.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,17 +1695,6 @@ void OBS_API::destroyOBS_API(void)
16951695
}
16961696
});
16971697

1698-
// Release all audio track encoders
1699-
std::vector<osn::AudioTrack *> audioTrackEncoders;
1700-
// osn::IAudioTrack::Manager::GetInstance().
1701-
// for_each([&audioTrackEncoders](osn::AudioTrack* audioTrackEncoder)
1702-
for (auto const &audioTrack : osn::IAudioTrack::audioTracks) {
1703-
if (audioTrack && audioTrack->audioEnc) {
1704-
obs_encoder_release(audioTrack->audioEnc);
1705-
audioTrack->audioEnc = nullptr;
1706-
}
1707-
};
1708-
17091698
// Release all services
17101699
osn::Service::Manager::GetInstance().for_each([](obs_service_t *service) {
17111700
if (service) {

obs-studio-server/source/osn-advanced-recording.cpp

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,33 @@ void osn::IAdvancedRecording::Destroy(void *data, const int64_t id, const std::v
9696
AUTO_DEBUG;
9797
}
9898

99+
void osn::AdvancedRecording::ClearAudioEncoders()
100+
{
101+
if (GetOutput()) {
102+
for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++)
103+
obs_output_set_audio_encoder(GetOutput(), nullptr, idx);
104+
}
105+
106+
for (auto *encoder : audioEncoders) {
107+
if (!encoder)
108+
continue;
109+
110+
if (obs_encoder_active(encoder)) {
111+
blog(LOG_WARNING, "AdvancedRecording audio encoder is still active during cleanup; releasing owner reference.");
112+
}
113+
114+
obs_encoder_release(encoder);
115+
}
116+
117+
audioEncoders.clear();
118+
}
119+
120+
osn::AdvancedRecording::~AdvancedRecording()
121+
{
122+
DeleteOutput();
123+
ClearAudioEncoders();
124+
}
125+
99126
void osn::IAdvancedRecording::GetRescaling(void *data, const int64_t id, const std::vector<ipc::value> &args, std::vector<ipc::value> &rval)
100127
{
101128
AdvancedRecording *recording = static_cast<AdvancedRecording *>(osn::IFileOutput::Manager::GetInstance().find(args[0].value_union.ui64));
@@ -210,16 +237,25 @@ void osn::IAdvancedRecording::Start(void *data, const int64_t id, const std::vec
210237
PRETTY_ERROR_RETURN(ErrorCode::InvalidReference, "Error while creating the recording output.");
211238
}
212239

213-
int idx = 0;
214-
for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
215-
osn::AudioTrack *audioTrack = osn::IAudioTrack::audioTracks[i];
216-
if ((recording->mixer & (1 << i)) != 0 && audioTrack && audioTrack->audioEnc) {
217-
obs_encoder_set_audio(audioTrack->audioEnc, obs_get_audio());
218-
obs_output_set_audio_encoder(recording->GetOutput(), audioTrack->audioEnc, idx);
240+
recording->ClearAudioEncoders();
219241

220-
obs_encoder_set_video_mix(audioTrack->audioEnc, obs_video_mix_get(recording->GetCanvas(), OBS_RECORDING_VIDEO_RENDERING));
221-
idx++;
222-
}
242+
int outputEncoderIndex = 0;
243+
for (int mixerIndex = 0; mixerIndex < MAX_AUDIO_MIXES; mixerIndex++) {
244+
if ((recording->mixer & (1 << mixerIndex)) == 0)
245+
continue;
246+
247+
const uint32_t trackNumber = mixerIndex + 1;
248+
std::string encoderName = "audio-encoder-recording-track";
249+
encoderName += std::to_string(trackNumber);
250+
obs_encoder_t *audioEncoder = osn::IAudioTrack::CreateEncoderForTrack(trackNumber, encoderName);
251+
if (!audioEncoder)
252+
continue;
253+
254+
recording->audioEncoders.push_back(audioEncoder);
255+
obs_encoder_set_audio(audioEncoder, obs_get_audio());
256+
obs_output_set_audio_encoder(recording->GetOutput(), audioEncoder, outputEncoderIndex);
257+
obs_encoder_set_video_mix(audioEncoder, obs_video_mix_get(recording->GetCanvas(), OBS_RECORDING_VIDEO_RENDERING));
258+
outputEncoderIndex++;
223259
}
224260

225261
if (!recording->UpdateEncoders() || !recording->videoEncoder) {

obs-studio-server/source/osn-advanced-recording.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "utility.hpp"
2323
#include "osn-recording.hpp"
2424
#include "osn-advanced-streaming.hpp"
25+
#include <vector>
2526

2627
namespace osn {
2728
class AdvancedRecording : public Recording {
@@ -36,7 +37,7 @@ class AdvancedRecording : public Recording {
3637
streaming = nullptr;
3738
simple = false;
3839
}
39-
~AdvancedRecording() {}
40+
~AdvancedRecording();
4041

4142
public:
4243
uint32_t mixer;
@@ -45,8 +46,10 @@ class AdvancedRecording : public Recording {
4546
uint32_t outputHeight;
4647
bool useStreamEncoders;
4748
AdvancedStreaming *streaming;
49+
std::vector<obs_encoder_t *> audioEncoders;
4850

4951
bool UpdateEncoders();
52+
void ClearAudioEncoders();
5053
};
5154

5255
class IAdvancedRecording : public IRecording {

obs-studio-server/source/osn-advanced-replay-buffer.cpp

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,33 @@ void osn::IAdvancedReplayBuffer::Destroy(void *data, const int64_t id, const std
7979
AUTO_DEBUG;
8080
}
8181

82+
void osn::AdvancedReplayBuffer::ClearAudioEncoders()
83+
{
84+
if (GetOutput()) {
85+
for (int idx = 0; idx < MAX_AUDIO_MIXES; idx++)
86+
obs_output_set_audio_encoder(GetOutput(), nullptr, idx);
87+
}
88+
89+
for (auto *encoder : audioEncoders) {
90+
if (!encoder)
91+
continue;
92+
93+
if (obs_encoder_active(encoder)) {
94+
blog(LOG_WARNING, "AdvancedReplayBuffer audio encoder is still active during cleanup; releasing owner reference.");
95+
}
96+
97+
obs_encoder_release(encoder);
98+
}
99+
100+
audioEncoders.clear();
101+
}
102+
103+
osn::AdvancedReplayBuffer::~AdvancedReplayBuffer()
104+
{
105+
DeleteOutput();
106+
ClearAudioEncoders();
107+
}
108+
82109
void osn::IAdvancedReplayBuffer::GetMixer(void *data, const int64_t id, const std::vector<ipc::value> &args, std::vector<ipc::value> &rval)
83110
{
84111
AdvancedReplayBuffer *replayBuffer = static_cast<AdvancedReplayBuffer *>(osn::IFileOutput::Manager::GetInstance().find(args[0].value_union.ui64));
@@ -127,14 +154,24 @@ void osn::IAdvancedReplayBuffer::Start(void *data, const int64_t id, const std::
127154
if (!replayBuffer->GetOutput())
128155
replayBuffer->CreateOutput("replay_buffer", "replay-buffer");
129156

130-
int idx = 0;
131-
for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
132-
osn::AudioTrack *audioTrack = osn::IAudioTrack::audioTracks[i];
133-
if ((replayBuffer->mixer & (1 << i)) != 0 && audioTrack && audioTrack->audioEnc) {
134-
obs_encoder_set_audio(audioTrack->audioEnc, obs_get_audio());
135-
obs_output_set_audio_encoder(replayBuffer->GetOutput(), audioTrack->audioEnc, idx);
136-
idx++;
137-
}
157+
replayBuffer->ClearAudioEncoders();
158+
159+
int outputEncoderIndex = 0;
160+
for (int mixerIndex = 0; mixerIndex < MAX_AUDIO_MIXES; mixerIndex++) {
161+
if ((replayBuffer->mixer & (1 << mixerIndex)) == 0)
162+
continue;
163+
164+
const uint32_t trackNumber = mixerIndex + 1;
165+
std::string encoderName = "audio-encoder-replay-buffer-track";
166+
encoderName += std::to_string(trackNumber);
167+
obs_encoder_t *audioEncoder = osn::IAudioTrack::CreateEncoderForTrack(trackNumber, encoderName);
168+
if (!audioEncoder)
169+
continue;
170+
171+
replayBuffer->audioEncoders.push_back(audioEncoder);
172+
obs_encoder_set_audio(audioEncoder, obs_get_audio());
173+
obs_output_set_audio_encoder(replayBuffer->GetOutput(), audioEncoder, outputEncoderIndex);
174+
outputEncoderIndex++;
138175
}
139176

140177
obs_encoder_t *videoEncoder = nullptr;
@@ -337,4 +374,4 @@ void osn::IAdvancedReplayBuffer::SetRecording(void *data, const int64_t id, cons
337374

338375
rval.push_back(ipc::value((uint64_t)ErrorCode::Ok));
339376
AUTO_DEBUG;
340-
}
377+
}

obs-studio-server/source/osn-advanced-replay-buffer.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "osn-replay-buffer.hpp"
2424
#include "osn-advanced-recording.hpp"
2525
#include "osn-advanced-streaming.hpp"
26+
#include <vector>
2627

2728
namespace osn {
2829
class AdvancedReplayBuffer : public ReplayBuffer {
@@ -33,12 +34,15 @@ class AdvancedReplayBuffer : public ReplayBuffer {
3334
streaming = nullptr;
3435
recording = nullptr;
3536
}
36-
~AdvancedReplayBuffer() {}
37+
~AdvancedReplayBuffer();
3738

3839
public:
3940
uint32_t mixer;
4041
AdvancedStreaming *streaming;
4142
AdvancedRecording *recording;
43+
std::vector<obs_encoder_t *> audioEncoders;
44+
45+
void ClearAudioEncoders();
4246
};
4347

4448
class IAdvancedReplayBuffer : public IReplayBuffer {

obs-studio-server/source/osn-advanced-streaming.cpp

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,38 @@ void osn::IAdvancedStreaming::SetOutputHeight(void *data, const int64_t id, cons
260260

261261
static bool setAudioEncoder(osn::AdvancedStreaming *streaming)
262262
{
263-
osn::AudioTrack *audioTrack = osn::IAudioTrack::audioTracks[streaming->audioTrack - 1];
264-
if (!audioTrack)
263+
if (!osn::IAudioTrack::GetTrackConfig(streaming->audioTrack))
265264
return false;
266-
if (!audioTrack->audioEnc)
265+
266+
const uint32_t mixerIndex = osn::IAudioTrack::GetMixerIndex(streaming->audioTrack);
267+
if (streaming->audioEncoder && streaming->audioEncoderTrack != mixerIndex) {
268+
if (obs_encoder_active(streaming->audioEncoder))
269+
return false;
270+
271+
obs_encoder_release(streaming->audioEncoder);
272+
streaming->audioEncoder = nullptr;
273+
streaming->audioEncoderTrack = 0;
274+
}
275+
276+
if (!streaming->audioEncoder) {
277+
streaming->audioEncoder = osn::IAudioTrack::CreateEncoderForTrack(streaming->audioTrack, "audio-encoder-streaming");
278+
streaming->audioEncoderTrack = mixerIndex;
279+
} else if (!obs_encoder_active(streaming->audioEncoder)) {
280+
osn::AudioTrack *audioTrack = osn::IAudioTrack::GetTrackConfig(streaming->audioTrack);
281+
if (audioTrack) {
282+
obs_data_t *settings = obs_data_create();
283+
obs_data_set_int(settings, "bitrate", audioTrack->bitrate);
284+
obs_encoder_update(streaming->audioEncoder, settings);
285+
obs_data_release(settings);
286+
}
287+
}
288+
289+
if (!streaming->audioEncoder)
267290
return false;
268291

269-
obs_encoder_set_audio(audioTrack->audioEnc, obs_get_audio());
270-
obs_output_set_audio_encoder(streaming->GetOutput(), audioTrack->audioEnc, 0);
271-
obs_encoder_set_video_mix(audioTrack->audioEnc, obs_video_mix_get(streaming->GetCanvas(), OBS_STREAMING_VIDEO_RENDERING));
292+
obs_encoder_set_audio(streaming->audioEncoder, obs_get_audio());
293+
obs_output_set_audio_encoder(streaming->GetOutput(), streaming->audioEncoder, 0);
294+
obs_encoder_set_video_mix(streaming->audioEncoder, obs_video_mix_get(streaming->GetCanvas(), OBS_STREAMING_VIDEO_RENDERING));
272295

273296
return true;
274297
}
@@ -318,7 +341,7 @@ static void SetupTwitchSoundtrackAudio(osn::AdvancedStreaming *streaming)
318341
obs_output_set_audio_encoder(streaming->GetOutput(), streaming->streamArchive, kSoundtrackArchiveEncoderIdx);
319342
obs_encoder_set_video_mix(streaming->streamArchive, obs_video_mix_get(streaming->GetCanvas(), OBS_STREAMING_VIDEO_RENDERING));
320343

321-
osn::AudioTrack *audioTrack = osn::IAudioTrack::audioTracks[streaming->twitchTrack];
344+
osn::AudioTrack *audioTrack = osn::IAudioTrack::audioTrackConfigs[streaming->twitchTrack];
322345
if (!audioTrack)
323346
return;
324347

@@ -388,6 +411,21 @@ void osn::AdvancedStreaming::UpdateEncoders()
388411
}
389412
}
390413

414+
osn::AdvancedStreaming::~AdvancedStreaming()
415+
{
416+
DeleteOutput();
417+
418+
if (audioEncoder) {
419+
if (obs_encoder_active(audioEncoder)) {
420+
blog(LOG_WARNING, "AdvancedStreaming audio encoder is still active after DeleteOutput; releasing owner reference.");
421+
}
422+
423+
obs_encoder_release(audioEncoder);
424+
audioEncoder = nullptr;
425+
audioEncoderTrack = 0;
426+
}
427+
}
428+
391429
void osn::IAdvancedStreaming::Start(void *data, const int64_t id, const std::vector<ipc::value> &args, std::vector<ipc::value> &rval)
392430
{
393431
AdvancedStreaming *streaming = static_cast<AdvancedStreaming *>(osn::IAdvancedStreaming::Manager::GetInstance().find(args[0].value_union.ui64));

obs-studio-server/source/osn-advanced-streaming.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,21 @@ class AdvancedStreaming : public Streaming {
3131
AdvancedStreaming() : Streaming()
3232
{
3333
audioTrack = 1;
34+
audioEncoder = nullptr;
35+
audioEncoderTrack = 0;
3436
twitchTrack = 2;
3537
rescaling = false;
3638
rescaleFilter = OBS_SCALE_DISABLE;
3739
outputWidth = 1280;
3840
outputHeight = 720;
3941
simple = false;
4042
}
41-
~AdvancedStreaming() {}
43+
~AdvancedStreaming();
4244

4345
public:
4446
uint32_t audioTrack;
47+
obs_encoder_t *audioEncoder;
48+
uint32_t audioEncoderTrack;
4549
uint32_t twitchTrack;
4650
bool rescaling;
4751
uint32_t rescaleFilter;

0 commit comments

Comments
 (0)