# libSceOpusCeltEnc technical debt ### Unknown function info - [sceOpusCeltEncCtl, sceOpusCeltEncEncodeFloatWithPriority and sceOpusCeltEncEncodeWithPriority](../../../core/libs/prx/libSceOpusCeltEnc/Export.cpp) (libSceOpusCeltEnc) - names and NIDs are present in the [PS5 3.20 export inventory](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceOpusCeltEnc.c). The prototypes mirror the sibling encoder declarations and libopus's own ctl and priority entry points, but the console's request codes, priority and batch semantics were not recovered. They throw through `NotImplemented_nid_no_patch`; this is not an ABI claim. ### Functional - [libSceOpusCeltEnc](../../../core/libs/prx/libSceOpusCeltEnc/Export.cpp) is an AJM frontend on the console: apart from libc runtime support and `sceKernelUsleep` the module imports only `sceAjmi*` calls, Create runs `sceAjmiInstanceCreate` with codec 15 and the flags 0x200000009 mono or 0x200000011 stereo, `sceAjmiBatchJobControlBufferRa` with request 0x6001 over state +0x10 with size 0x38 and results at state +0xA0, then `sceAjmiBatchStartBuffer` and `sceAjmiBatchWait`, Encode hands the samples to `sceAjmiBatchJobRunBufferRa`, and Destroy calls `sceAjmiInstanceDestroy` [per module runs with stubbed AJM](https://github.com/boykopovar/AnyPS5/pull/10563#issuecomment-6412138282). Our encoders build libopus without AJM, so packets come from libopus and whether they equal the console's is unknown. Closes when: encoder packets are compared against console-produced ones or the library runs through our AJM - [Create and CreateEx](../../../core/libs/prx/libSceOpusCeltEnc/Export.cpp) zero-fill the 728-byte state and write the word table [measured on the modules](https://github.com/boykopovar/AnyPS5/pull/10563#issuecomment-6412138282): the instance id at +0x00, this implementation's id because our AJM does not run, 8 × channels at +0x08, channels at +0x10, rate at +0x14 and rate/50 at +0x40 and +0xC8, the bitrate at +0x1C and +0xC0 with the per-rate per-channel table 11000/19000 to 51000/99000, the constants 2, 0x451, 0x5E0, 10, 0x803, 1, 0xFFFFFC18 and 0x10, and the 0x17B2 marker at +0xCC. The console's live AJM may write further result bytes into +0xA0 and +0xD8. Closes when: a console run with live AJM settles those result bytes - [Create and CreateEx](../../../core/libs/prx/libSceOpusCeltEnc/Export.cpp) replacement rule is this implementation's choice: a create over a marked state retires the encoder its instance id names before any state write or allocation, so a later failure cannot strand an entry the state no longer names; explicit libopus error branches leave the state zeroed, while make-unique throwing after setupState or a later registry insert throw leaves the filled state without a live encoder. The console behaviour for its own allocation failure after a create over a live state is unmeasured, and the tests cannot force our failure paths because the library is a shared module against libopus, which has no allocator hook, while a process-wide memory limit fails an unknown allocation first. Closes when: a deterministic allocation-failure injection or a console measurement of the failed replace exists - [Encode and EncodeFloat](../../../core/libs/prx/libSceOpusCeltEnc/Export.cpp) refuse with the [measured codes](https://github.com/boykopovar/AnyPS5/pull/10563#issuecomment-6412138282): null state +0x01, null samples +0x02 before the state marker, a markerless state +0x16, null data +0x04 before the frame check and maxDataBytes 0 +0x05; maxDataBytes below zero is not refused and reaches our libopus backend, where a rejection throws. Frame sizes outside the durations 2.5, 5, 10, 20, 40 and 60 ms, the measured 120 to 2880 at 48000, give +0x03; we scale the counts by rate while the module's rule for other rates is unmeasured. Closes when: the frame rule and the console outcome for a buffer AJM rejects are measured - [sceOpusCeltEncEncodeFloat](../../../core/libs/prx/libSceOpusCeltEnc/Export.cpp) checks null state, null samples, frame 0 and the marker, then reserves the converted frame on the stack before its remaining checks; the reservation frame × channels × 4 bytes kills the console module for the [measured frame -1](https://github.com/boykopovar/AnyPS5/pull/10563#issuecomment-6412138282), and our implementation throws once it exceeds 8 MiB instead, so the failure reports. The bound beyond the measured deaths is our host stack model, not a console measurement. Closes when: the console's stack behaviour for such frames is measured - [Create, CreateEx, Destroy, GetSize, Terminate and Initialize](../../../core/libs/prx/libSceOpusCeltEnc/Export.cpp) refuse with base 0x813F0000, the null pointer +0x01, the sample rate +0x10, channels +0x0D, application +0x11, the marker in Destroy +0x16 and `Initialize(nullptr)` +0x19, all from the [firmware 13.42 export measurements](https://github.com/boykopovar/AnyPS5/pull/10563#issuecomment-6401539314); Destroy clears the marker and leaves the other bytes, GetSize returns 728 on channels 1 and 2 and refuses other counts with +0x0D. CreateEx context handling, duplicate initialization and termination with live encoders throw as the recovered decoder analogue does. Closes when: those paths are measured on the console