mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-10 05:38:49 +00:00
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:
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
135
src/core/libraries/audio/sdl_in.cpp
Normal file
135
src/core/libraries/audio/sdl_in.cpp
Normal 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 = {};
|
||||
}
|
||||
42
src/core/libraries/audio/sdl_in.h
Normal file
42
src/core/libraries/audio/sdl_in.h
Normal 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;
|
||||
};
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user