Repository navigation
Conversation
PS4 titles build AJM batches with the SDK's inline helpers, which call sceAjmBatchJobControlBufferRa, sceAjmBatchJobRunBufferRa and sceAjmBatchJobRunSplitBufferRa and start the buffer with sceAjmBatchStartBuffer. The buffer belongs to the title, so it has to use the console's chunk layout rather than this library's private records. The builders write console jobs (job, return address, buffer and flags chunks) and return the position after them. StartBuffer checks the context, walks the chunks, skips inline data and runs each job as the library's existing control, run or statistics job. Chunk headers are read as the console's builders write them: bits 0-3 the kind, bit 4 a buffer's output direction, bits 6-25 the payload; the other bits keep a reused buffer's old bytes on a PS4. Malformed batches return MALFORMED_BATCH, unknown chunk kinds and unimplemented control flags throw. An ATRAC9 run with RUN_MULTIPLE_FRAMES reports which side ran out as a PS4 does (0x8 input, 0x10 room, 0x18 both), and the ATRAC9 format reports the frame's bitrate; both were measured on a PS4 with Knowledge is Power: Decades (Wwise) batch dumps and probe runs. The vibration test's exact-fit run expects 0x18 accordingly. The throwing stubs in libSceAjm and the libSceAjmi copy of sceAjmBatchJobRunBufferRa are dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Progress report (5e6ae6e → d924eb2)📈 System libraries: 48.41% (+0.01%, +2 implemented, +1 declared, -1 removed functions) ✅ 2 implemented
🆕 1 declared as stubs
🗑️ 1 removed
🔗 1 now sharing sources
|
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
Two findings from review, the first is the one I would block on. 1. The removed libSceAjmi stub turns a runtime error into an unresolved import. The diff deletes Verified on the branch: the file now holds only the InlineBuffer stub, and the debt file is byte-identical to main's. 2. Asymmetric input/output buffering in Also worth folding into the debt entry: the ATRAC9 result-flag values that the new The chunk-walk bounds checks, the ATRAC9 bitrate math and the result-identity with the PS5 path all check out; no null-deref path reaches |
MarcZX10
left a comment
There was a problem hiding this comment.
The PS4 trace evidence and title stop are substantial, and the batch bounds/result handling have received useful independent review. Current-head blockers remain:
- The deletion of
sceAjmBatchJobRunBufferRafromlibSceAjmiremoves an existing throwing export. That changes a title importing this module from a call-timeNotImplemented_nid_no_patcherror to an unresolved import at startup, anddocs/dev/debt/libSceAjmi.mdstill claims five exports throw although only one remains. Preserve the stub (the NID-name disambiguation supports the collision) or intentionally remove it with aligned debt documentation and evidence. - In
RunConsoleJob, inputs are queued for any nonzero size even with a null pointer, while outputs require both pointer and size. That can feed a null input into the copy path and silently omit a zero-size output buffer. Please align the predicates or add PS4-measured evidence and debt text for these cases. - The tested title evidence is for PS4 CUSA12435, while the checklist says broad PS4 titles and does not link a Game bring-up discussion. Please identify the title ID/discussion that this is unblocking and scope claims to observed behavior.
Hosted eligibility/conventions/intake/labels/report pass; product test jobs were skipped by path filters. The detailed Windows tests and PS4 probes are author-reported; I did not rerun the audio suite locally. The shared-code overlaps with #9483 and debt overlap with #8468 require an agreed order/dependency before merge.
…s as a PS4 does Review of the PS4 batch buffer change. The libSceAjmi stub of sceAjmBatchJobRunBufferRa stays, declared with the _nid_disambig1 suffix so that both libraries export the NID without defining one name. sceAjmBatchStartBuffer reads the whole batch before running any job, as probe batches on a PS4 showed: a buffer chunk of size zero is dropped whatever its address, and a null address with a nonzero size refuses the batch with INVALID_ADDRESS in the error record together with the job chunk, the chunk's offset in the job and the job's return address, with nothing of the batch run. Inputs and outputs share that rule. The console-measured result flags move from test comments to the debt entries. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he PS4 probe The gapless entry no longer says the one-frame behaviour is unverified, since the probe measured it, and the libSceAjmi entry names the two exports its file declares. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Thanks both. Pushed cb3e854 and 589189b; point by point:
AI-assisted: yes (Claude Code) |
MarcZX10
left a comment
There was a problem hiding this comment.
Thanks for the follow-up evidence. The latest head addresses my earlier findings: the libSceAjmi throwing export is restored with NID disambiguation, and the buffer edge rules now match the reported PS4 probes. The title is linked to the correct Game bring-up discussion, and the current-main conventions check and git diff --check pass.
One new correctness issue: sceAjmBatchStartBuffer allows (batch == nullptr, batch_size == 0) past its parameter check, then evaluates batch + batch_size. Pointer arithmetic on a null pointer is undefined even for an offset of zero. Please either reject a null batch explicitly or avoid forming the end pointer unless batch is nonnull, and add a regression for the chosen empty-batch contract.
Before merge, the current base also needs updating: this PR targets 4a17c71, 62 commits behind main at 8b3a6ba. It still overlaps open #9483 in Ajm.cpp and #8468 in the AJM debt file; CONTRIBUTING.md requires agreeing with those authors on landing order and recording any dependency, while the checklist currently says Depends on: none. Please coordinate and correct the checklist before the rebase/merge.
Validation on this Linux host: exact-head git diff --check and tools/check_conventions.py against current main pass. I attempted a focused full configure, but it stops before compilation because this host has no SDL2 development package and the SDL2 submodule is not initialized; no local guest_ajm run is claimed. Hosted product jobs are skipped by path filters. The author reports Windows guest_ajm/vibration tests and PS4 FW 10.71 probes; those are not independently reproduced here.
sceAjmBatchStartBuffer let a null batch of zero bytes through its parameter check and formed the end pointer from it. A null batch now returns INVALID_PARAMETER whatever the size, as the PS5 builders' sceAjmBatchInitialize does; a batch of zero bytes still starts, runs nothing and completes at once. A test covers both; neither was measured on a console, which the debt entry says. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Thanks. Pushed ef01ffa (on top of the main merge 29364e1):
AI-assisted: yes (Claude Code) |
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tch-buffer # Conflicts: # docs/dev/debt/libSceAjm.native.md
|
#8468 landed, so AI-assisted: yes (Claude Code) |
…ULTIPLE_FRAMES A probe on a PS4 decoded exactly one frame and reported 0 for an ATRAC9 run job without RUN_MULTIPLE_FRAMES. Jobs read from a PS4 batch buffer now do the same. Jobs from the PS5 builders keep decoding their whole input, which FMOD in PPSA29141 relies on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
One measured behaviour I had left as a debt note is now implemented (50838e6): an ATRAC9 run job without AI-assisted: yes (Claude Code) |
|
One remaining issue in I independently checked the current PR head |
…dress A null batch address is refused whatever the size, so the accepted batch of zero bytes is one at a real address, which is what TestConsoleEmptyBatch starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@MarcZX10 Thanks, agreed: the description was the problem, not the code. The contract is the second option you describe. A null batch address is refused with 0x80930005 whatever the size, including size 0, and that is what the two Pushed d924eb2, which says this in the debt entry ("a batch of zero bytes at a non-null address is accepted … a null address with size 0 is refused like any null address"); the Tested line in the description now says the same. AI-assisted: yes (Claude Code) |
MarcZX10
left a comment
There was a problem hiding this comment.
The previous findings are addressed on the current head: null batch storage is rejected before end-pointer formation, the empty-batch test uses valid non-null storage, and the debt/description now state that contract consistently. The branch merges cleanly with current main, and conventions, labels and report pass. Product build/test jobs are skipped by repository path filters; the author reports guest_ajm and guest_ajm_vibration pass 3/3 on this head, which I did not independently rerun. #9483 remains correctly listed as a dependency and must land first per the agreed order.
…s in the console's chunk layout Took the PR's Ajm.cpp buffer path, ATRAC9 run-result/bitrate changes and the libSceAjm stub removal / libSceAjmi disambig as-is; kept our test declarations and debt bullets (DecodeSplit, codec info, Encode, helpers) beside the PR's, GetInfo and gapless bullets take the PR's wording.
What
Knowledge is Power: Decades (CUSA12435, Wwise), the one PS4 title observed, builds its AJM batches with the PS4 SDK's inline batch helpers, which end in four libSceAjm exports:
sceAjmBatchJobControlBufferRa,sceAjmBatchJobRunBufferRa,sceAjmBatchJobRunSplitBufferRaandsceAjmBatchStartBuffer. Unlike the PS5 builders, whose batch records are private to the library, here the batch buffer belongs to the title: the SDK code reads the position each builder returns, sizes the buffer for the console's jobs and may write chunks itself. So the buffer has to use the console's layout. Onmain, #9433 added the PS4libSceAjmwith three of the four as throwing stubs, andsceAjmBatchJobRunBufferRa(ElslOCpOIns) is only a throwing stub inlibSceAjmi.This implements the layout in
libSceAjm.native/src/Ajm.cpp, whichlibSceAjmis built from:sceAjmBatchStartBufferwalks the chunks, skips inline-data chunks, turns each job into the library's existing control, run or statistics job and runs it with the existing decoders (ATRAC9, MP3, M4AAC, Opus), so the sideband results are the ones the PS5 path writes. LikesceAjmBatchStart, it rejects a context that initialization did not allocate, and the batch belongs to its context.0x11output run,0x12output control), bits 6-25 the payload. The builders leave bits 5, 26, 27 and 31 as they were, and a title that reuses its batch memory carries the previous batch's bytes there, so those bits are ignored.RUN_MULTIPLE_FRAMESreports which side ran out, as the console does:PARTIAL_INPUT(0x8) when the input ran out with room left, on a superframe boundary or not;NOT_ENOUGH_ROOM(0x10) when the room ran out with input left, after any number of frames, and with nothing consumed for a zero room; both (0x18) when the input ended just as the output filled, which is every Wwise run job. The ATRAC9 format reports the frame's bitrate (frame bytes x 8 x sample rate / 256: 168000, 84000 and 384000 measured). Resampled runs keep the earlier rule, as they were not measured.RUN_MULTIPLE_FRAMESdecodes exactly one ATRAC9 frame and reports 0, as the probe measured on the PS4. A job from the PS5 builders still decodes its whole input, which FMOD in PPSA29141 relies on; the PS5 console's behaviour there is not measured.sceAjmBatchStartBufferreturns0x80930011(MALFORMED_BATCH) and fills the error record with0x80930016(INVALID_ADDRESS), the job chunk's address, the chunk's offset in the job and the job's return address. A size that is not a multiple of 8, a chunk that overruns its job or the batch, and a job without a flags chunk are refused the same way, not measured; the record then holds0x80930011. Unknown chunk kinds and control flags other than RESET, INITIALIZE and SIDEBAND_GAPLESS_DECODE throw.libSceAjm/Export.cppare dropped. The throwingsceAjmBatchJobRunBufferRaoflibSceAjmistays, declared assceAjmBatchJobRunBufferRa_nid_disambig1: the NID patcher exports it under the name's NID, so a title importing it fromlibSceAjmistill gets the not-implemented error at call time, and the two libraries no longer export one name.The layout (chunk kinds 0, 1, 2, 3, 4, 6, 7, 17, 18, the builders' chunk order, statistics instance
0x80000) follows shadPS4's PS4 library reimplementation. A GoldHEN user-mode plugin dumped 32 545 batches that Knowledge is Power: Decades (CUSA12435, Wwise) started on a PS4. They confirmed the 64-byte control and 80-byte run jobs byte for byte, the header bits above, and the0x18result and bitrate of all 14 680 traced run jobs, which each decode 4 frames into exactly 4 frames of room. Probe runs of one of the title's ATRAC9 streams through the same builders on the PS4 (fresh instance per case: input ending with room left, room ending with input left, half a superframe of room, zero room, exact fit) gave the result rules above, showed that a run withoutRUN_MULTIPLE_FRAMESdecodes exactly one frame on the console (kept as the whole input here, which a PS5 title needs; noted in the debt), that the console rejects the tests' synthetic silent superframe after three frames where LibAtrac9 decodes four, and that LibAtrac9 matches the console's PCM of that stream within 4 LSB (83.5% of samples exactly). The statistics instance and the inline chunk come from shadPS4 only; the debt entries say what is measured and what is not. The PS5sceAjmBatchStartpath and its records are unchanged, apart from the ATRAC9 exact-fit result and bitrate, which both paths share.Tested
Windows 11 Pro 26200, WinLibs GCC 15.2.0 r7, NVIDIA RTX 2080, on
mainat7e69be6793, merged into this branch. This was first opened as Get-fix#17 against #6977's branch, where it was reviewed and extended with the PS4 measurements; it is opened here as one commit at Get-fix's request.guest_ajmpasses, with seven new cases:TestConsoleBufferJobsbuilds a control job (with a return address), a run job and a split run job with the three builders, checks the returned positions and the chunk words, starts the batch withsceAjmBatchStartBufferand checks the control result and both run sidebands (result, consumed, written, total samples, frames) and the decoded PCM.TestConsoleHandWrittenJobswrites a batch word by word: an inline chunk holding ATRAC9 initialize parameters, a control job whose input points into it, a run job and a statistics job. It checks their results, then that a size not a multiple of 8, a job without flags and an overrunning job return0x80930011, and that an unknown chunk kind throws.TestConsoleStaleHeaderBitsruns a hand-written batch with every bit the console's builders never write set, and checks it runs exactly as the clean batch.TestAt9FlagRulesruns the five fits above and checks the result, the bytes consumed, the output written and the frame count of each.TestConsoleBufferEdgesruns a job with zero-size input and output chunks beside real ones (decodes as without them), a job whose only output has size zero (0x10, nothing consumed), and two batches with a null input or output address, which are refused with the measured error record while the control job before them stays unrun.TestConsoleEmptyBatchchecks the empty-batch contract: a null batch address is0x80930005with size 0 or 16, a null batch id is0x80930005, and a batch of zero bytes at a non-null address starts, returns an id and completes at once.TestConsoleSingleFrameRunruns a console job withoutRUN_MULTIPLE_FRAMESon a whole superframe with room for four frames and checks that one frame is decoded with result 0, the PCM after it untouched.0x18; the helpers that stream a decode accept0x8and0x10where one side runs out.guest_ajm_vibrationpasses; its exact-fit run now expects0x18(it expected 0 before). Vibration streams were not in the trace.check_conventionspasses; the patchedlibSceAjmi.prxstill exportsElslOCpOIns(objdump).ps4probe, the console's builders, a control job before each run job): zero-size input and output chunks alone, beside a real chunk and with a null address; null addresses with a nonzero size as the first or second input chunk and as the output chunk. They gave the rules above; the refused batches ran nothing.0x6001, run flags0xc00000001001, 56-byte sidebands), every one with result 0 under that commit's rules, about 650 s of decoded PCM per run, and the title reached its animated title screen. One of the four runs stopped before that on aUnityGfxDeviceWorkerfault in the guest heap that runs with every AJM job skipped also hit; it is not in AJM. Without this PR the title aborts at its firstsceAjmBatchJobControlBufferRa(not implemented).#9483 changes the last lines of
sceAjmBatchStart's job loop, next to where this moves the batch registration intoRegisterBatch, so the two conflict in three lines; #9481 and #9034 also add debt entries tolibSceAjm.native.md. I can rebase onto whichever lands first.Checklist
main(7e69be6793, merged in); no other open PR implements the same functions (searched boykopovar/AnyPS5 and Get-fix/AnyPS5 for Ajm, BufferRa and StartBuffer)NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)sceAjmBatchJobControlBufferRawithout this