3
3
4
4
#include < memory>
5
5
#include < mutex>
6
- #include < stop_token>
7
- #include < thread>
6
+ #include < shared_mutex>
8
7
#include < magic_enum/magic_enum.hpp>
9
8
10
9
#include " common/assert.h"
11
10
#include " common/config.h"
12
11
#include " common/logging/log.h"
12
+ #include " common/polyfill_thread.h"
13
13
#include " common/thread.h"
14
14
#include " core/libraries/audio/audioout.h"
15
15
#include " core/libraries/audio/audioout_backend.h"
18
18
19
19
namespace Libraries ::AudioOut {
20
20
21
- std::mutex port_open_mutex{} ;
21
+ std::shared_mutex ports_mutex ;
22
22
std::array<PortOut, SCE_AUDIO_OUT_NUM_PORTS> ports_out{};
23
23
24
24
static std::unique_ptr<AudioOutBackend> audio;
@@ -93,20 +93,17 @@ int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
93
93
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
94
94
}
95
95
96
- std::unique_lock open_lock{port_open_mutex} ;
96
+ std::scoped_lock lock (ports_mutex) ;
97
97
auto & port = ports_out.at (handle - 1 );
98
- {
99
- std::unique_lock lock{port.mutex };
100
- if (!port.IsOpen ()) {
101
- return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
102
- }
103
- std::free (port.output_buffer );
104
- port.output_buffer = nullptr ;
105
- port.output_ready = false ;
106
- port.impl = nullptr ;
98
+ if (!port.impl ) {
99
+ return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
107
100
}
108
- // Stop outside of port lock scope to prevent deadlocks.
101
+
109
102
port.output_thread .Stop ();
103
+ std::free (port.output_buffer );
104
+ port.output_buffer = nullptr ;
105
+ port.output_ready = false ;
106
+ port.impl = nullptr ;
110
107
return ORBIS_OK;
111
108
}
112
109
@@ -175,34 +172,35 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
175
172
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
176
173
}
177
174
178
- auto & port = ports_out. at (handle - 1 );
179
- {
180
- std::unique_lock lock{ port.mutex };
181
- if (!port. IsOpen ()) {
182
- return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
183
- }
184
- switch (port. type ) {
185
- case OrbisAudioOutPort::Main:
186
- case OrbisAudioOutPort::Bgm:
187
- case OrbisAudioOutPort::Voice:
188
- state-> output = 1 ;
189
- state-> channel = port. format_info . num_channels > 2 ? 2 : port. format_info . num_channels ;
190
- break ;
191
- case OrbisAudioOutPort::Personal:
192
- case OrbisAudioOutPort::Padspk:
193
- state-> output = 4 ;
194
- state-> channel = 1 ;
195
- break ;
196
- case OrbisAudioOutPort::Aux:
197
- state->output = 0 ;
198
- state-> channel = 0 ;
199
- break ;
200
- default :
201
- UNREACHABLE () ;
202
- }
203
- state-> rerouteCounter = 0 ;
204
- state-> volume = 127 ;
175
+ std::scoped_lock lock (ports_mutex );
176
+ const auto & port = ports_out. at (handle - 1 );
177
+ if (! port.impl ) {
178
+ return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
179
+ }
180
+
181
+ state-> rerouteCounter = 0 ;
182
+ state-> volume = 127 ;
183
+
184
+ switch (port. type ) {
185
+ case OrbisAudioOutPort::Main:
186
+ case OrbisAudioOutPort::Bgm:
187
+ case OrbisAudioOutPort::Voice:
188
+ state-> output = 1 ;
189
+ state-> channel = port. format_info . num_channels > 2 ? 2 : port. format_info . num_channels ;
190
+ break ;
191
+ case OrbisAudioOutPort::Personal:
192
+ case OrbisAudioOutPort::Padspk:
193
+ state-> output = 4 ;
194
+ state->channel = 1 ;
195
+ break ;
196
+ case OrbisAudioOutPort::Aux:
197
+ state-> output = 0 ;
198
+ state-> channel = 0 ;
199
+ break ;
200
+ default :
201
+ UNREACHABLE () ;
205
202
}
203
+
206
204
return ORBIS_OK;
207
205
}
208
206
@@ -281,16 +279,15 @@ static void AudioOutputThread(PortOut* port, const std::stop_token& stop) {
281
279
while (true ) {
282
280
timer.Start ();
283
281
{
284
- std::unique_lock lock{port->mutex };
285
- if (port->output_cv . wait ( lock, stop, [&] { return port->output_ready ; })) {
286
- port-> impl -> Output (port-> output_buffer );
287
- port-> output_ready = false ;
282
+ std::unique_lock lock{port->output_mutex };
283
+ Common::CondvarWait (port->output_cv , lock, stop, [&] { return port->output_ready ; });
284
+ if (stop. stop_requested ()) {
285
+ break ;
288
286
}
287
+ port->impl ->Output (port->output_buffer );
288
+ port->output_ready = false ;
289
289
}
290
290
port->output_cv .notify_one ();
291
- if (stop.stop_requested ()) {
292
- break ;
293
- }
294
291
timer.End ();
295
292
}
296
293
}
@@ -335,30 +332,27 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
335
332
return ORBIS_AUDIO_OUT_ERROR_INVALID_FORMAT;
336
333
}
337
334
338
- std::unique_lock open_lock{port_open_mutex };
335
+ std::scoped_lock lock{ports_mutex };
339
336
const auto port =
340
- std::ranges::find_if (ports_out, [&](const PortOut& p) { return !p. IsOpen () ; });
337
+ std::ranges::find_if (ports_out, [&](const PortOut& p) { return p. impl == nullptr ; });
341
338
if (port == ports_out.end ()) {
342
339
LOG_ERROR (Lib_AudioOut, " Audio ports are full" );
343
340
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL;
344
341
}
345
342
346
- {
347
- std::unique_lock port_lock (port->mutex );
343
+ port->type = port_type;
344
+ port->format_info = GetFormatInfo (format);
345
+ port->sample_rate = sample_rate;
346
+ port->buffer_frames = length;
347
+ port->volume .fill (SCE_AUDIO_OUT_VOLUME_0DB);
348
348
349
- port->type = port_type;
350
- port->format_info = GetFormatInfo (format);
351
- port->sample_rate = sample_rate;
352
- port->buffer_frames = length;
353
- port->volume .fill (SCE_AUDIO_OUT_VOLUME_0DB);
349
+ port->impl = audio->Open (*port);
354
350
355
- port->impl = audio->Open (*port);
351
+ port->output_buffer = std::malloc (port->BufferSize ());
352
+ port->output_ready = false ;
353
+ port->output_thread .Run (
354
+ [port](const std::stop_token& stop) { AudioOutputThread (&*port, stop); });
356
355
357
- port->output_buffer = std::malloc (port->BufferSize ());
358
- port->output_ready = false ;
359
- port->output_thread .Run (
360
- [port](const std::stop_token& stop) { AudioOutputThread (&*port, stop); });
361
- }
362
356
return std::distance (ports_out.begin (), port) + 1 ;
363
357
}
364
358
@@ -373,13 +367,14 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
373
367
}
374
368
375
369
auto & port = ports_out.at (handle - 1 );
370
+ if (!port.impl ) {
371
+ return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
372
+ }
373
+
376
374
{
377
- std::unique_lock lock{port.mutex };
378
- if (!port.IsOpen ()) {
379
- return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
380
- }
375
+ std::unique_lock lock{port.output_mutex };
381
376
port.output_cv .wait (lock, [&] { return !port.output_ready ; });
382
- if (ptr != nullptr && port. IsOpen () ) {
377
+ if (ptr != nullptr ) {
383
378
std::memcpy (port.output_buffer , ptr, port.BufferSize ());
384
379
port.output_ready = true ;
385
380
}
@@ -493,19 +488,19 @@ s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
493
488
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
494
489
}
495
490
491
+ std::scoped_lock lock (ports_mutex);
496
492
auto & port = ports_out.at (handle - 1 );
497
- {
498
- std::unique_lock lock{port.mutex };
499
- if (!port.IsOpen ()) {
500
- return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
501
- }
502
- for (int i = 0 ; i < port.format_info .num_channels ; i++, flag >>= 1u ) {
503
- if (flag & 0x1u ) {
504
- port.volume [i] = vol[i];
505
- }
493
+ if (!port.impl ) {
494
+ return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
495
+ }
496
+
497
+ for (int i = 0 ; i < port.format_info .num_channels ; i++, flag >>= 1u ) {
498
+ if (flag & 0x1u ) {
499
+ port.volume [i] = vol[i];
506
500
}
507
- port.impl ->SetVolume (port.volume );
508
501
}
502
+
503
+ port.impl ->SetVolume (port.volume );
509
504
return ORBIS_OK;
510
505
}
511
506
0 commit comments