ajm: rewrite using new ioctl handling api
Some checks failed
Formatting check / formatting-check (push) Has been cancelled
Build RPCSX / build-linux (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8.1-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8.2-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8.4-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv8.5-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv9-a) (push) Has been cancelled
Build RPCSX / build-android (arm64-v8a, armv9.1-a) (push) Has been cancelled
Build RPCSX / build-android (x86_64, x86-64) (push) Has been cancelled

This commit is contained in:
DH 2025-10-11 20:22:03 +03:00
parent 8cfb4e8d16
commit e27926d629

View file

@ -1,6 +1,7 @@
#include "ajm.hpp"
#include "io-device.hpp"
#include "orbis-config.hpp"
#include "orbis/IoDevice.hpp"
#include "orbis/KernelAllocator.hpp"
#include "orbis/file.hpp"
#include "orbis/thread/Thread.hpp"
@ -40,7 +41,20 @@ enum {
AJM_RESULT_CODEC_ERROR = 0x40000000,
};
struct AjmDevice : orbis::IoDevice {
enum {
AJM_IOCTL_FINALIZE = 0xc0288900,
AJM_IOCTL_MODULE_REGISTER = 0xc0288903,
AJM_IOCTL_MODULE_UNREGISTER = 0xc0288904,
AJM_IOCTL_INSTANCE_CREATE = 0xc0288905,
AJM_IOCTL_INSTANCE_DESTROY = 0xc0288906,
AJM_IOCTL_START_BATCH_BUFFER = 0xc0288907,
AJM_IOCTL_WAIT_BATCH_BUFFER = 0xc0288908,
AJM_IOCTL_INSTANCE_EXTEND = 0xc028890a,
AJM_IOCTL_INSTANCE_SWITCH = 0xc028890b,
};
struct AjmDevice
: orbis::IoDeviceWithIoctl<orbis::ioctl::group(AJM_IOCTL_FINALIZE)> {
rx::shared_mutex mtx;
orbis::uint32_t batchId = 1; // temp
@ -50,6 +64,8 @@ struct AjmDevice : orbis::IoDevice {
orbis::ErrorCode open(rx::Ref<orbis::File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode,
orbis::Thread *thread) override;
AjmDevice();
};
AVSampleFormat ajmToAvFormat(AJMFormat ajmFormat) {
@ -105,70 +121,83 @@ void resetAt9(Instance *instance) {
}
}
static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
void *argp, orbis::Thread *thread) {
auto device = static_cast<AjmDevice *>(file->device.get());
// 0xc0288900 - finalize
// 0xc0288903 - module register
// 0xc0288904 - module unregister
// 0xc0288905 - instance create
// 0xc0288906 - instance destroy
// 0xc028890a - instance extend
// 0xc028890b - intasnce switch
// 0xc0288907 - start batch buffer
// 0xc0288908 - wait batch buffer
// 0xc0288900 - unregister context
if (request == 0xc0288906) {
struct InstanceDestroyArgs {
struct AjmIoctlInstanceFinalize {
orbis::uint32_t result;
orbis::uint32_t unk0;
orbis::uint32_t instanceId;
orbis::uint32_t unk[7];
};
auto args = reinterpret_cast<InstanceDestroyArgs *>(argp);
if (device->instanceMap.erase(args->instanceId) == 0) {
return orbis::ErrorCode::INVAL;
}
args->result = 0;
static orbis::ErrorCode ajm_ioctl_finalize(orbis::Thread *, AjmDevice *device,
AjmIoctlInstanceFinalize &args) {
ORBIS_LOG_ERROR(__FUNCTION__, args.instanceId);
args.result = 0;
args.unk0 = 0;
return {};
}
if (request == 0xc0288903 || request == 0xc0288904 || request == 0xc0288900) {
auto arg = reinterpret_cast<std::uint32_t *>(argp)[2];
ORBIS_LOG_ERROR(__FUNCTION__, request, arg);
*reinterpret_cast<std::uint64_t *>(argp) = 0;
struct AjmIoctlModuleRegister {
orbis::uint32_t result;
orbis::uint32_t unk0;
orbis::uint32_t instanceId;
orbis::uint32_t unk[7];
};
static orbis::ErrorCode
ajm_ioctl_module_register(orbis::Thread *, AjmDevice *device,
AjmIoctlModuleRegister &args) {
ORBIS_LOG_ERROR(__FUNCTION__, args.instanceId);
args.result = 0;
args.unk0 = 0;
return {};
}
if (request == 0xc0288905) {
struct InstanceCreateArgs {
struct AjmIoctlModuleUnregister {
orbis::uint32_t result;
orbis::uint32_t unk0;
orbis::uint32_t instanceId;
orbis::uint32_t unk[7];
};
static orbis::ErrorCode
ajm_ioctl_module_unregister(orbis::Thread *, AjmDevice *device,
AjmIoctlModuleUnregister &args) {
ORBIS_LOG_ERROR(__FUNCTION__, args.instanceId);
args.result = 0;
args.unk0 = 0;
return {};
}
struct AjmIoctlInstanceCreate {
orbis::uint32_t result;
orbis::uint32_t unk0;
orbis::uint64_t flags;
orbis::uint32_t codec;
orbis::uint32_t instanceId;
orbis::uint32_t unk[4];
};
static orbis::ErrorCode
ajm_ioctl_instance_create(orbis::Thread *, AjmDevice *device,
AjmIoctlInstanceCreate &args) {
ORBIS_LOG_WARNING(__FUNCTION__, args.flags, args.codec);
std::lock_guard lock(device->mtx);
auto args = reinterpret_cast<InstanceCreateArgs *>(argp);
auto codecId = AJMCodecs(args->codec);
auto codecId = AJMCodecs(args.codec);
auto codecOffset = codecId << 0xe;
args.result = 0;
if (codecId < AJM_CODEC_COUNT) {
args->result = 0;
args->instanceId = codecOffset + device->instanceIds[codecId]++;
args.instanceId = codecOffset + device->instanceIds[codecId]++;
auto [it, inserted] = device->instanceMap.try_emplace(args->instanceId);
auto [it, inserted] = device->instanceMap.try_emplace(args.instanceId);
assert(inserted);
auto &instance = it->second;
instance.codec = codecId;
instance.maxChannels =
AJMChannels(((args->flags & ~7) & (0xFF & ~0b11)) >> 3);
instance.outputFormat = AJMFormat((args->flags & ~7) & 0b11);
AJMChannels(((args.flags & ~7) & (0xFF & ~0b11)) >> 3);
instance.outputFormat = AJMFormat((args.flags & ~7) & 0b11);
if (codecId == AJM_CODEC_AAC) {
instance.aac.isHeaac = ((args->flags & ~7) & 0x100000000) != 0;
instance.aac.isFrameSkipEnabled =
((args->flags & ~7) & 0x200000000) == 0;
instance.aac.isHeaac = ((args.flags & ~7) & 0x100000000) != 0;
instance.aac.isFrameSkipEnabled = ((args.flags & ~7) & 0x200000000) == 0;
}
if (codecId == AJM_CODEC_At9) {
instance.at9.handle = Atrac9GetHandle();
@ -207,41 +236,91 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
instance.codecCtx = codecCtx;
}
ORBIS_LOG_ERROR(__FUNCTION__, request, args->result, args->unk0,
args->flags, args->codec, args->instanceId,
ORBIS_LOG_ERROR(__FUNCTION__, args.result, args.unk0, args.flags,
args.codec, args.instanceId,
(std::uint16_t)instance.outputFormat,
(std::uint16_t)instance.maxChannels);
} else {
args->instanceId = codecOffset + device->unimplementedInstanceId++;
ORBIS_LOG_ERROR(__FUNCTION__, request, "unimplemented codec",
args->result, args->unk0, args->flags, args->codec,
args->instanceId);
args.instanceId = codecOffset + device->unimplementedInstanceId++;
ORBIS_LOG_ERROR(__FUNCTION__, "unimplemented codec", args.result, args.unk0,
args.flags, args.codec, args.instanceId);
}
return {};
}
if (request == 0xc0288907) {
struct StartBatchBufferArgs {
struct AjmIoctlInstanceDestroy {
orbis::uint32_t result;
orbis::uint32_t unk0;
std::byte *pBatch;
orbis::uint32_t instanceId;
orbis::uint32_t unk[7];
};
static orbis::ErrorCode
ajm_ioctl_instance_destroy(orbis::Thread *, AjmDevice *device,
AjmIoctlInstanceDestroy &args) {
ORBIS_LOG_ERROR(__FUNCTION__, args.instanceId);
std::lock_guard lock(device->mtx);
if (device->instanceMap.erase(args.instanceId) == 0) {
return orbis::ErrorCode::INVAL;
}
args.result = 0;
return {};
}
struct AjmIoctlInstanceExtend {
orbis::uint32_t result;
orbis::uint32_t unk0;
orbis::uint32_t instanceId;
orbis::uint32_t unk[7];
};
static orbis::ErrorCode
ajm_ioctl_instance_extend(orbis::Thread *thread, AjmDevice *device,
AjmIoctlInstanceExtend &args) {
ORBIS_LOG_ERROR(__FUNCTION__);
thread->where();
args.result = 0;
args.unk0 = 0;
return {};
}
struct AjmIoctlInstanceSwitch {
orbis::uint32_t result;
orbis::uint32_t unk0;
orbis::uint32_t instanceId;
orbis::uint32_t unk[7];
};
static orbis::ErrorCode
ajm_ioctl_instance_switch(orbis::Thread *thread, AjmDevice *device,
AjmIoctlInstanceSwitch &args) {
ORBIS_LOG_ERROR(__FUNCTION__);
thread->where();
args.result = 0;
args.unk0 = 0;
return {};
}
struct AjmIoctlStartBatchBuffer {
orbis::uint32_t result;
orbis::uint32_t unk0;
orbis::ptr<std::byte> pBatch;
orbis::uint32_t batchSize;
orbis::uint32_t priority;
orbis::uint64_t batchError;
orbis::uint32_t batchId;
};
auto args = reinterpret_cast<StartBatchBufferArgs *>(argp);
args->result = 0;
args->batchId = device->batchId++;
// ORBIS_LOG_ERROR(__FUNCTION__, request, args->result, args->unk0,
// args->pBatch, args->batchSize, args->priority,
// args->batchError, args->batchId);
static orbis::ErrorCode
ajm_ioctl_start_batch_buffer(orbis::Thread *, AjmDevice *device,
AjmIoctlStartBatchBuffer &args) {
args.result = 0;
args.batchId = device->batchId++;
// ORBIS_LOG_ERROR(__FUNCTION__, args.result, args.unk0, args.pBatch,
// args.batchSize, args.priority, args.batchError, args.batchId);
// thread->where();
auto ptr = args->pBatch;
auto endPtr = args->pBatch + args->batchSize;
auto ptr = args.pBatch;
auto endPtr = args.pBatch + args.batchSize;
while (ptr < endPtr) {
auto header = (InstructionHeader *)ptr;
@ -271,7 +350,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
reinterpret_cast<AJMSidebandResult *>(ctrl->pSidebandOutput);
*result = {};
ORBIS_LOG_ERROR(__FUNCTION__, request, "control buffer", ctrl->opcode,
ORBIS_LOG_ERROR(__FUNCTION__, "control buffer", ctrl->opcode,
ctrl->commandId, ctrl->flagsHi, ctrl->flagsLo,
ctrl->sidebandInputSize, ctrl->sidebandOutputSize);
if (ctrl->getFlags() & CONTROL_RESET) {
@ -301,8 +380,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
? maxChannels
: instance.at9.inputChannels;
// TODO: check max channels
ORBIS_LOG_TODO("CONTROL_INITIALIZE AT9",
instance.at9.inputChannels,
ORBIS_LOG_TODO("CONTROL_INITIALIZE AT9", instance.at9.inputChannels,
instance.at9.sampleRate, instance.at9.frameSamples,
instance.at9.superFrameSize, maxChannels,
outputChannels, initializeBuffer->configData,
@ -323,8 +401,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
AVCodecContext *codecCtx =
avcodec_alloc_context3(instance.avCodec);
if (!codecCtx) {
ORBIS_LOG_FATAL(
"Failed to allocate codec context for raw aac");
ORBIS_LOG_FATAL("Failed to allocate codec context for raw aac");
std::abort();
}
@ -338,8 +415,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
codecCtx->ch_layout = chLayout;
codecCtx->sample_rate = instance.aac.sampleRate;
if (int err =
avcodec_open2(codecCtx, instance.avCodec, nullptr);
if (int err = avcodec_open2(codecCtx, instance.avCodec, nullptr);
err < 0) {
ORBIS_LOG_FATAL("Could not open codec for raw aac", err);
std::abort();
@ -347,10 +423,9 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
instance.codecCtx = codecCtx;
}
ORBIS_LOG_TODO("CONTROL_INITIALIZE AAC",
(std::int16_t)instance.aac.headerType,
instance.aac.sampleRate,
(std::int16_t)instance.maxChannels,
ORBIS_LOG_TODO(
"CONTROL_INITIALIZE AAC", (std::int16_t)instance.aac.headerType,
instance.aac.sampleRate, (std::int16_t)instance.maxChannels,
(orbis::uint32_t)instance.outputFormat);
}
}
@ -471,8 +546,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
if (instance.codec == AJM_CODEC_At9) {
inputFrameSize = 4;
outputBufferSize = av_samples_get_buffer_size(
nullptr, instance.at9.inputChannels,
instance.at9.frameSamples,
nullptr, instance.at9.inputChannels, instance.at9.frameSamples,
ajmToAvFormat(instance.outputFormat), 0);
} else if (instance.codec == AJM_CODEC_MP3) {
if (instance.inputBuffer.size() - totalDecodedBytes < 4) {
@ -533,8 +607,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
instance.at9.superFrameDataIdx++;
if (instance.at9.superFrameDataIdx ==
instance.at9.framesInSuperframe) {
instance.at9.estimatedSizeUsed +=
instance.at9.superFrameDataLeft;
instance.at9.estimatedSizeUsed += instance.at9.superFrameDataLeft;
instance.at9.superFrameDataIdx = 0;
instance.at9.superFrameDataLeft = instance.at9.superFrameSize;
}
@ -573,8 +646,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
// we simply call this method directly (but it can be very
// unstable)
int gotFrame;
int len =
ffcodec(instance.codecCtx->codec)
int len = ffcodec(instance.codecCtx->codec)
->cb.decode(instance.codecCtx, frame, &gotFrame, pkt);
if (len < 0) {
ORBIS_LOG_FATAL("Error during decoding AAC");
@ -634,8 +706,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
av_opt_set_sample_fmt(resampler, "out_sample_fmt",
ajmToAvFormat(instance.outputFormat), 0);
if (swr_init(resampler) < 0) {
ORBIS_LOG_FATAL(
"Failed to initialize the resampling context");
ORBIS_LOG_FATAL("Failed to initialize the resampling context");
std::abort();
}
}
@ -657,9 +728,9 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
if (bufferOffset <= outputWritten &&
bufferOffset + buffer.size > outputWritten) {
auto byteOffset = outputWritten - bufferOffset;
auto size = std::min(buffer.size - byteOffset,
instance.outputBuffer.size() -
bufferOutputWritten);
auto size =
std::min(buffer.size - byteOffset,
instance.outputBuffer.size() - bufferOutputWritten);
ORBIS_RET_ON_ERROR(orbis::uwrite(
buffer.pOutput + byteOffset,
instance.outputBuffer.data() + bufferOutputWritten, size));
@ -684,8 +755,8 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
if (runJob.flags & SIDEBAND_STREAM) {
// ORBIS_LOG_TODO("SIDEBAND_STREAM", currentSize, outputWritten,
// instance.processedSamples);
auto *stream = reinterpret_cast<AJMSidebandStream *>(
runJob.pSideband + currentSize);
auto *stream = reinterpret_cast<AJMSidebandStream *>(runJob.pSideband +
currentSize);
stream->inputSize = totalDecodedBytes;
stream->outputSize = outputWritten;
stream->decodedSamples = instance.processedSamples;
@ -697,8 +768,8 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
// (std::uint16_t)instance.lastDecode.channels,
// (std::uint16_t)instance.outputFormat,
// instance.lastDecode.sampleRate);
auto *format = reinterpret_cast<AJMSidebandFormat *>(
runJob.pSideband + currentSize);
auto *format = reinterpret_cast<AJMSidebandFormat *>(runJob.pSideband +
currentSize);
format->channels = AJMChannels(instance.lastDecode.channels);
format->sampleRate = instance.lastDecode.sampleRate;
format->sampleFormat = instance.outputFormat;
@ -753,30 +824,37 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
return {};
}
if (request == 0xc0288908) {
struct Args {
struct AjmIoctlWaitBatchBuffer {
orbis::uint32_t result;
orbis::uint32_t unk0;
orbis::uint32_t unk1;
orbis::uint32_t batchId;
orbis::uint32_t timeout;
orbis::uint64_t batchError;
orbis::uint32_t unk[4];
};
auto args = reinterpret_cast<Args *>(argp);
args->unk0 = 0;
// ORBIS_LOG_ERROR(__FUNCTION__, request, args->unk0, args->unk1,
// args->batchId, args->timeout, args->batchError);
static orbis::ErrorCode
ajm_ioctl_wait_batch_buffer(orbis::Thread *thread, AjmDevice *device,
AjmIoctlWaitBatchBuffer &args) {
args.result = 0;
// ORBIS_LOG_ERROR(__FUNCTION__, request, args.result, args.unk0,
// args.batchId, args.timeout, args.batchError);
// thread->where();
return {};
}
ORBIS_LOG_FATAL("Unhandled AJM ioctl", request);
thread->where();
return {};
}
static const orbis::FileOps fileOps = {};
static const orbis::FileOps fileOps = {
.ioctl = ajm_ioctl,
};
AjmDevice::AjmDevice() {
addIoctl<AJM_IOCTL_FINALIZE>(ajm_ioctl_finalize);
addIoctl<AJM_IOCTL_MODULE_REGISTER>(ajm_ioctl_module_register);
addIoctl<AJM_IOCTL_MODULE_UNREGISTER>(ajm_ioctl_module_unregister);
addIoctl<AJM_IOCTL_INSTANCE_CREATE>(ajm_ioctl_instance_create);
addIoctl<AJM_IOCTL_INSTANCE_DESTROY>(ajm_ioctl_instance_destroy);
addIoctl<AJM_IOCTL_START_BATCH_BUFFER>(ajm_ioctl_start_batch_buffer);
addIoctl<AJM_IOCTL_WAIT_BATCH_BUFFER>(ajm_ioctl_wait_batch_buffer);
addIoctl<AJM_IOCTL_INSTANCE_EXTEND>(ajm_ioctl_instance_extend);
addIoctl<AJM_IOCTL_INSTANCE_SWITCH>(ajm_ioctl_instance_switch);
}
orbis::ErrorCode AjmDevice::open(rx::Ref<orbis::File> *file, const char *path,
std::uint32_t flags, std::uint32_t mode,