Add audio element removal support with binaural renderer lifecycle management - #32
Add audio element removal support with binaural renderer lifecycle management#32jingbo-marquis wants to merge 5 commits into
Conversation
jingbo-marquis
commented
Aug 27, 2026
- Implement oar_remove_audio_element with separate paths for binaural (multi-element) and single-element renderers; binaural renderer is retained after element removal, tied to audio group lifecycle
- Add OBR LIFO-only element removal via obr_remove_last_audio_element and ck_attribute_remove_element attribute
- Add remove_element callback to AudioRendererAPI and implement audio_elements_renderer_remove_element with index/offset rebasing
- Add crash-isolated test framework (test_framework.c/h) with fork-based process isolation
- Add 5 test scenarios covering single/multiple removal, re-add, and binaural non-LIFO failure cases
| /* Notify the underlying renderer library to release per-element DSP | ||
| * resources. If the library does not support removal (e.g., OBR only | ||
| * supports LIFO), abort the removal so that OAR and library state stay | ||
| * consistent. The element remains functional and rendering is unaffected. */ |
There was a problem hiding this comment.
Maybe document this behavior for the oar_remove_audio_element() function in oar.h? So that users know what to expect.
There was a problem hiding this comment.
Thank you for the suggestion.
I have moved the relevant content to the comments for the oar_remove_audio_element function in oar.h. Please refer to: 64d7b4a
…nagement - Implement oar_remove_audio_element with separate paths for binaural (multi-element) and single-element renderers; binaural renderer is retained after element removal, tied to audio group lifecycle - Add OBR LIFO-only element removal via obr_remove_last_audio_element and ck_attribute_remove_element attribute - Add remove_element callback to AudioRendererAPI and implement audio_elements_renderer_remove_element with index/offset rebasing - Add crash-isolated test framework (test_framework.c/h) with fork-based process isolation - Add 5 test scenarios covering single/multiple removal, re-add, and binaural non-LIFO failure cases Signed-off-by: Jingbo Hou <jingbo.hou@samsung.com>
Signed-off-by: Jingbo Hou <jingbo.hou@samsung.com>
- Replace raw error numbers with ck_oar_error_* enum constants across all API functions - Add binaural renderer LIFO removal behavior notes to oar_remove_audio_element Signed-off-by: Jingbo Hou <jingbo.hou@samsung.com>
- Rename get_channels to get_channel_count and get_element_channels to get_element_channel_count across renderer API - Add get_element_count interface to return actual element count instead of renderer count - Free staging buffer on element removal to prevent stale data rendering - Return ck_oar_error_notsup when remove_element is not implemented - Update test to expect element count 0 after removing all elements Signed-off-by: Jingbo Hou <jingbo.hou@samsung.com>
Signed-off-by: Jingbo Hou <jingbo.hou@samsung.com>
05d8bf3 to
e15db7a
Compare
trsonic
left a comment
There was a problem hiding this comment.
Approving. I built the branch with CMake (Debug and ASan) and with Bazel, ran the five new test cases plus the five existing example tests, and checked the removal paths for leaks.
What I verified:
- Issue #31 is fixed.
leaks --atExiton each of the five cases (run one per process via the--child Nmode) reports 0 leaks / 0 bytes, and the ASan build is clean. - Non-LIFO removal is rejected in
obr.cbefore any OAR-side state changes, so a failed removal leaves nothing inconsistent. hash_map_removeruns beforevector_remove, which owns the free, so there is no double free of the element context.- The renames (
get_channelstoget_channel_countand the rest) leave no stale references insrc/,include/ortests/. - The new
@returndoc comments ininclude/oar.hmatchenum EOarStatusand the actual returns. I spot-checkedoar_add_audio_group,oar_add_audio_element,oar_set_metadata_unit_to_processandoar_update_metadata. bazelisk build //tests/examples:test_remove_audio_elementsucceeds.
Two non-blocking comments inline.
One behaviour I measured that I will file as a separate issue rather than ask for here. audio_elements_renderer_add_element calls lib->open() whenever ctx->index == 0. Before this PR that could only happen once per renderer; now that a binaural group can be drained to zero elements, adding the next element re-enters _open(), which does if (ctx->renderer) _close(ctx); and creates a fresh OBR handle. head_tracking_enabled is re-propagated explicitly, but the head rotation cached in oar->head_rotation is not. Rendering the same mono sine through a binaural group with head tracking on and a 90 degree yaw set:
A = yaw set, no removal
B = yaw set, then remove-all and re-add
C = no rotation ever set
sum of absolute differences over the 256-sample stereo frame:
|A - B| = 122.792226 |B - C| = 0.000000 |A - C| = 122.792226
B comes out bit-identical to C. A host that streams rotation every frame recovers on the next update, so the exposure is limited to a host that enables head tracking and then sets a single static orientation.
| add_test(NAME test_object_based_rendering COMMAND test_object_based_rendering) | ||
| add_test(NAME test_metadata_unit_processing COMMAND test_metadata_unit_processing) | ||
|
|
||
| add_test(NAME test_remove_audio_element COMMAND test_remove_audio_element) |
There was a problem hiding this comment.
This entry is inert as things stand. Nothing in the tree calls enable_testing(), so ctest -N in a configured build tree reports Total Tests: 0, and .github/workflows/ci-cmake.yml runs a hardcoded list of four binaries rather than ctest. test_remove_audio_element therefore never runs in the CMake CI job. The Bazel job does pick up the new cc_test, so the test is not entirely uncovered.
Either add the binary to the smoke-test list in ci-cmake.yml (test_metadata_unit_processing has the same gap already), or add enable_testing() at the root and switch that CI step to ctest.
|
|
||
| /* Parent: wait for the child and interpret the exit status. */ | ||
| int status = 0; | ||
| waitpid(pid, &status, 0); |
There was a problem hiding this comment.
The return value is discarded. If waitpid returns -1 (EINTR, or any other error) status stays 0, so WIFEXITED(0) is true and WEXITSTATUS(0) is 0, and the runner prints PASSED for a test it never reaped.
int r;
while ((r = waitpid(pid, &status, 0)) < 0 && errno == EINTR) {
}
if (r < 0) {
perror("waitpid");
return TEST_FAIL;
}errno.h is already included. Minor, in the same function: num_tests is unused on the POSIX path.