Microphone support (#3228)

* initial drafts

* initial implementation

* clang+reuse

* restore main

* improved AudioInInput

* fix microphone

* +

* +

* adds microphone selection to the interface

* added squidbus review fixes

* Update src/core/libraries/audio/audioin.cpp

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>

* Update src/core/libraries/audio/audioin.cpp

Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>

* Increased entries in config.cpp

---------

Co-authored-by: DanielSvoboda <daniel.svoboda@hotmail.com>
Co-authored-by: squidbus <175574877+squidbus@users.noreply.github.com>
This commit is contained in:
georgemoralis
2025-07-23 06:54:18 +03:00
committed by GitHub
parent 16a6469b75
commit 0ad7fcb341
11 changed files with 494 additions and 75 deletions

View File

@@ -3,18 +3,21 @@
#include "common/logging/log.h"
#include "core/libraries/audio/audioin.h"
#include "core/libraries/audio/sdl_in.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
namespace Libraries::AudioIn {
static std::unique_ptr<SDLAudioIn> audio = std::make_unique<SDLAudioIn>();
int PS4_SYSV_ABI sceAudioInChangeAppModuleState() {
LOG_ERROR(Lib_AudioIn, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudioInClose() {
LOG_ERROR(Lib_AudioIn, "(STUBBED) called");
int PS4_SYSV_ABI sceAudioInClose(s32 handle) {
audio->AudioInClose(handle);
return ORBIS_OK;
}
@@ -93,9 +96,13 @@ int PS4_SYSV_ABI sceAudioInGetSilentState() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudioInHqOpen() {
LOG_ERROR(Lib_AudioIn, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAudioInHqOpen(Libraries::UserService::OrbisUserServiceUserId userId, u32 type,
u32 index, u32 len, u32 freq, u32 param) {
int result = audio->AudioInOpen(type, len, freq, param);
if (result < 0) {
LOG_ERROR(Lib_AudioIn, "Error returned {:#x}", result);
}
return result;
}
int PS4_SYSV_ABI sceAudioInHqOpenEx() {
@@ -108,9 +115,8 @@ int PS4_SYSV_ABI sceAudioInInit() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudioInInput() {
LOG_ERROR(Lib_AudioIn, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceAudioInInput(s32 handle, void* dest) {
return audio->AudioInInput(handle, dest);
}
int PS4_SYSV_ABI sceAudioInInputs() {
@@ -123,9 +129,13 @@ int PS4_SYSV_ABI sceAudioInIsSharedDevice() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceAudioInOpen() {
LOG_ERROR(Lib_AudioIn, "(DUMMY) called");
return 0x80260005; // ports are full return
int PS4_SYSV_ABI sceAudioInOpen(Libraries::UserService::OrbisUserServiceUserId userId, u32 type,
u32 index, u32 len, u32 freq, u32 param) {
int result = audio->AudioInOpen(type, len, freq, param);
if (result < 0) {
LOG_ERROR(Lib_AudioIn, "Error returned {:#x}", result);
}
return result;
}
int PS4_SYSV_ABI sceAudioInOpenEx() {

View File

@@ -3,6 +3,7 @@
#pragma once
#include <core/libraries/system/userservice.h>
#include "common/types.h"
namespace Core::Loader {
@@ -11,8 +12,12 @@ class SymbolsResolver;
namespace Libraries::AudioIn {
enum class OrbisAudioInParamFormat : u32 { S16Mono = 0, S16Stereo = 2 };
enum class OrbisAudioInType : u32 { VoiceChat = 0, General = 1, VoiceRecognition = 5 };
int PS4_SYSV_ABI sceAudioInChangeAppModuleState();
int PS4_SYSV_ABI sceAudioInClose();
int PS4_SYSV_ABI sceAudioInClose(s32 handle);
int PS4_SYSV_ABI sceAudioInCountPorts();
int PS4_SYSV_ABI sceAudioInDeviceHqOpen();
int PS4_SYSV_ABI sceAudioInDeviceIdHqOpen();
@@ -28,13 +33,15 @@ int PS4_SYSV_ABI sceAudioInGetGain();
int PS4_SYSV_ABI sceAudioInGetHandleStatusInfo();
int PS4_SYSV_ABI sceAudioInGetRerouteCount();
int PS4_SYSV_ABI sceAudioInGetSilentState();
int PS4_SYSV_ABI sceAudioInHqOpen();
int PS4_SYSV_ABI sceAudioInHqOpen(Libraries::UserService::OrbisUserServiceUserId userId, u32 type,
u32 index, u32 len, u32 freq, u32 param);
int PS4_SYSV_ABI sceAudioInHqOpenEx();
int PS4_SYSV_ABI sceAudioInInit();
int PS4_SYSV_ABI sceAudioInInput();
int PS4_SYSV_ABI sceAudioInInput(s32 handle, void* dest);
int PS4_SYSV_ABI sceAudioInInputs();
int PS4_SYSV_ABI sceAudioInIsSharedDevice();
int PS4_SYSV_ABI sceAudioInOpen();
int PS4_SYSV_ABI sceAudioInOpen(Libraries::UserService::OrbisUserServiceUserId userId, u32 type,
u32 index, u32 len, u32 freq, u32 param);
int PS4_SYSV_ABI sceAudioInOpenEx();
int PS4_SYSV_ABI sceAudioInSetAllMute();
int PS4_SYSV_ABI sceAudioInSetCompressorPreGain();

View File

@@ -0,0 +1,135 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include <common/config.h>
#include <common/logging/log.h>
#include "sdl_in.h"
int SDLAudioIn::AudioInit() {
return SDL_InitSubSystem(SDL_INIT_AUDIO);
}
int SDLAudioIn::AudioInOpen(int type, uint32_t samples_num, uint32_t freq, uint32_t format) {
std::scoped_lock lock{m_mutex};
for (int id = 0; id < static_cast<int>(portsIn.size()); ++id) {
auto& port = portsIn[id];
if (!port.isOpen) {
port.isOpen = true;
port.type = type;
port.samples_num = samples_num;
port.freq = freq;
port.format = format;
SDL_AudioFormat sampleFormat;
switch (format) {
case Libraries::AudioIn::ORBIS_AUDIO_IN_PARAM_FORMAT_S16_MONO:
sampleFormat = SDL_AUDIO_S16;
port.channels_num = 1;
port.sample_size = 2;
break;
case Libraries::AudioIn::ORBIS_AUDIO_IN_PARAM_FORMAT_S16_STEREO:
sampleFormat = SDL_AUDIO_S16;
port.channels_num = 2;
port.sample_size = 2;
break;
default:
port.isOpen = false;
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
}
SDL_AudioSpec fmt;
SDL_zero(fmt);
fmt.format = sampleFormat;
fmt.channels = port.channels_num;
fmt.freq = port.freq;
std::string micDevStr = Config::getMicDevice();
uint32_t devId;
if (micDevStr == "None") {
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
} else if (micDevStr == "Default Device") {
devId = SDL_AUDIO_DEVICE_DEFAULT_RECORDING;
} else {
try {
devId = static_cast<uint32_t>(std::stoul(micDevStr));
} catch (const std::exception& e) {
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
}
}
port.stream = SDL_OpenAudioDeviceStream(devId, &fmt, nullptr, nullptr);
if (!port.stream) {
port.isOpen = false;
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
}
if (SDL_ResumeAudioStreamDevice(port.stream) == false) {
SDL_DestroyAudioStream(port.stream);
port = {};
return ORBIS_AUDIO_IN_ERROR_STREAM_FAIL;
}
return id + 1;
}
}
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
}
int SDLAudioIn::AudioInInput(int handle, void* out_buffer) {
std::scoped_lock lock{m_mutex};
if (handle < 1 || handle > static_cast<int>(portsIn.size()) || !out_buffer)
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
auto& port = portsIn[handle - 1];
if (!port.isOpen)
return ORBIS_AUDIO_IN_ERROR_INVALID_PORT;
const int bytesToRead = port.samples_num * port.sample_size * port.channels_num;
if (out_buffer == nullptr) {
int attempts = 0;
while (SDL_GetAudioStreamAvailable(port.stream) > 0) {
SDL_Delay(1);
if (++attempts > 1000) {
return ORBIS_AUDIO_IN_ERROR_TIMEOUT;
}
}
return 0; // done
}
int attempts = 0;
while (SDL_GetAudioStreamAvailable(port.stream) < bytesToRead) {
SDL_Delay(1);
if (++attempts > 1000) {
return ORBIS_AUDIO_IN_ERROR_TIMEOUT;
}
}
const int bytesRead = SDL_GetAudioStreamData(port.stream, out_buffer, bytesToRead);
if (bytesRead < 0) {
// SDL_GetAudioStreamData failed
LOG_ERROR(Lib_AudioIn, "AudioInInput error: {}", SDL_GetError());
return ORBIS_AUDIO_IN_ERROR_STREAM_FAIL;
}
const int framesRead = bytesRead / (port.sample_size * port.channels_num);
return framesRead;
}
void SDLAudioIn::AudioInClose(int handle) {
std::scoped_lock lock{m_mutex};
if (handle < 1 || handle > (int)portsIn.size())
return;
auto& port = portsIn[handle - 1];
if (!port.isOpen)
return;
SDL_DestroyAudioStream(port.stream);
port = {};
}

View File

@@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <mutex>
#include <SDL3/SDL.h>
namespace Libraries::AudioIn {
enum OrbisAudioInParam {
ORBIS_AUDIO_IN_PARAM_FORMAT_S16_MONO = 0,
ORBIS_AUDIO_IN_PARAM_FORMAT_S16_STEREO = 2
};
}
#define ORBIS_AUDIO_IN_ERROR_INVALID_PORT -1
#define ORBIS_AUDIO_IN_ERROR_TIMEOUT -2
#define ORBIS_AUDIO_IN_ERROR_STREAM_FAIL -3
class SDLAudioIn {
public:
int AudioInit();
int AudioInOpen(int type, uint32_t samples_num, uint32_t freq, uint32_t format);
int AudioInInput(int handle, void* out_buffer);
void AudioInClose(int handle);
private:
struct AudioInPort {
bool isOpen = false;
int type = 0;
uint32_t samples_num = 0;
uint32_t freq = 0;
int channels_num = 0;
int sample_size = 0;
uint32_t format = 0;
SDL_AudioStream* stream = nullptr;
};
std::array<AudioInPort, 8> portsIn;
std::mutex m_mutex;
};

View File

@@ -186,7 +186,7 @@ int PS4_SYSV_ABI sceHttpGetAcceptEncodingGZIPEnabled() {
int PS4_SYSV_ABI sceHttpGetAllResponseHeaders() {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
return ORBIS_FAIL;
}
int PS4_SYSV_ABI sceHttpGetAuthEnabled() {