Skip to content

feat(types): add StreamTypes newtype for stream-kind bit masks#52

Merged
BlindMaster24 merged 2 commits intomainfrom
devin/1776940958-stream-types
Apr 24, 2026
Merged

feat(types): add StreamTypes newtype for stream-kind bit masks#52
BlindMaster24 merged 2 commits intomainfrom
devin/1776940958-stream-types

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 23, 2026

Summary

Public recording APIs previously accepted the TeamTalk stream-kind bitmask as a raw u32, which made it easy to pass an unrelated integer or to lose the intent of a combined mask (voice + desktop, etc.). This PR introduces a type-safe StreamTypes newtype in teamtalk::types and migrates the public recording surfaces to use it.

New type (teamtalk::types::StreamTypes):

  • Associated constants mirroring teamtalk_sys::StreamType::STREAMTYPE_*: NONE, VOICE, VIDEO_CAPTURE, MEDIAFILE_AUDIO, MEDIAFILE_VIDEO, DESKTOP, DESKTOP_INPUT, MEDIAFILE, CHANNEL_MSG, LOCAL_MEDIAPLAYBACK_AUDIO, CLASSROOM_ALL.
  • Standard bit operators (|, |=, &, &=, !).
  • contains_any / contains_all / is_empty inspectors.
  • raw() / from_raw() round-trip with any u32 so callers reading a mask from an event do not lose unknown bits.
  • From<u32> / From<StreamTypes> for u32 so the new type slides into existing impl Into<StreamTypes> parameters without caller changes at raw-u32 call sites.

Migrated public surfaces:

  • RecordingTarget::Streams { stream_types: StreamTypes, .. }
  • SyncedUserRecordingOptions.stream_types: StreamTypes (default now StreamTypes::VOICE instead of a raw STREAMTYPE_VOICE as u32 cast).
  • Client::start_recording_streams(stream_types: impl Into<StreamTypes>, ..)
  • RecordingSession::start_streams(stream_types: impl Into<StreamTypes>, ..)
  • SyncedUserRecordingOptions::with_stream_types(types: impl Into<StreamTypes>)

Existing callers that pass a raw u32 continue to compile via Into<StreamTypes>.

Left at u32 (intentional, follow-up scope):

Internal boundaries stay u32: the sealed TeamTalkBackend trait, FFI surfaces (acquire_user_audio_block, enable_audio_block_event, stream_audio_blocks*), AudioBlockView.stream_types, and Client::dbg_set_input_tone. The newtype converts at the public boundary via into().raw(), so this PR is strictly additive at those layers — a subsequent PR can tighten them without touching FFI.

Tests: crates/teamtalk/tests/stream_types_tests.rs adds 9 new integration tests (FFI-value-parity, round-trip, bit ops, contains_*, Into<StreamTypes>, CLASSROOM_ALL composition). tests/recording_synced_tests.rs updated to compare via StreamTypes.

Local verification: cargo fmt --all --check clean. cargo clippy --workspace --all-targets --all-features -- -D warnings clean. cargo test --workspace --all-features — all tests pass, including the 9 new stream_types_tests.rs integration tests.

Review & Testing Checklist for Human

  • Confirm the list of constants matches the current TEAMTALK_DLL/TeamTalk.h StreamType_* values. The test constants_match_ffi_stream_type_values runs this check against the generated bindings at compile time, so if the header diverges the test will catch it — but a human eyeball pass on the constant list in crates/teamtalk/src/types/base.rs is still worth it.
  • Confirm the choice to keep AudioBlockView.stream_types as u32 is acceptable. The rationale is that it is a raw read of an FFI event field; a follow-up PR can convert it if you want full type-safety on the read side too.
  • Try the three existing call patterns locally if convenient to make sure ergonomics hold: with_stream_types(StreamTypes::VOICE), with_stream_types(StreamTypes::VOICE | StreamTypes::DESKTOP), and with_stream_types(0x5u32).

Notes

Second P1 API improvement after the ExponentialBackoff jitter PR (#51). Branches from clean main, independent of the other PRs in flight, so can be merged in any order.

Next up: SdkErrorCode mapping for Error::CommandFailed, TimeoutKind enum for Error::Timeout, SecretString/zeroize for passwords, indexed EventBus::dispatch / Router::dispatch via HashMap, then a big coverage-gap test-fill PR driven by scripts/audit_teamtalk_coverage.py.

The pre-existing semver CI gate is expected to remain red; release-plz handles the eventual version bump.

Link to Devin session: https://app.devin.ai/sessions/71fdd6196cb74723a2e277bb81993a9c
Requested by: @BlindMaster24


Open in Devin Review

Public recording APIs previously accepted the TeamTalk stream-kind
bitmask as a raw `u32`, which made it easy to pass an unrelated
integer or to lose the intent of a combined mask (e.g. voice +
desktop). The new `StreamTypes` newtype wraps the same `u32`
bitmask with:

* Associated constants mirroring
  `teamtalk_sys::StreamType::STREAMTYPE_*` (VOICE, VIDEO_CAPTURE,
  MEDIAFILE_AUDIO, MEDIAFILE_VIDEO, DESKTOP, DESKTOP_INPUT,
  MEDIAFILE, CHANNEL_MSG, LOCAL_MEDIAPLAYBACK_AUDIO,
  CLASSROOM_ALL).
* Standard bit operators (`|`, `|=`, `&`, `&=`, `!`).
* `contains_any` / `contains_all` / `is_empty` inspectors.
* `raw()` / `from_raw()` round-trip with arbitrary `u32` so
  callers reading a mask from an event do not lose unknown bits.
* `From<u32>` / `From<StreamTypes> for u32` so the new type
  slides into existing `impl Into<StreamTypes>` parameters with
  no caller changes at the `u32` call sites.

Public recording surfaces are migrated to the new type:

* `RecordingTarget::Streams { stream_types: StreamTypes, .. }`
* `SyncedUserRecordingOptions.stream_types: StreamTypes`
  (default now `StreamTypes::VOICE` instead of a raw
  `STREAMTYPE_VOICE as u32` cast).
* `Client::start_recording_streams(stream_types: impl Into<StreamTypes>, ..)`
* `RecordingSession::start_streams(stream_types: impl Into<StreamTypes>, ..)`
* `SyncedUserRecordingOptions::with_stream_types(types: impl Into<StreamTypes>)`

Internal boundaries (the `TeamTalkBackend` trait, FFI
`acquire_user_audio_block` / `enable_audio_block_event`,
`AudioBlockView.stream_types`, and low-level debug helpers) stay
`u32` for now; the newtype converts at the public boundary via
`into().raw()` so this PR is strictly additive at those layers
and can be followed up with further type-safety passes later
without touching FFI.

Tests:

* `crates/teamtalk/tests/stream_types_tests.rs` adds 9 new
  integration tests:
  - Constants match the FFI enum values bit-for-bit.
  - `empty()` is zero and equals `Default::default()`.
  - `from_raw` round-trips arbitrary 32-bit patterns.
  - `|`, `|=`, `&`, `&=`, `!` behave as expected.
  - `contains_any` vs `contains_all` semantics.
  - `impl Into<StreamTypes>` accepts both raw `u32` and typed
    combinations.
  - `CLASSROOM_ALL` composition (voice + video_capture +
    mediafile_audio + mediafile_video + desktop + channel_msg =
    95; desktop_input intentionally excluded).
* `tests/recording_synced_tests.rs` is updated to compare the
  field as a `StreamTypes` and also asserts the raw value.

Local verification:

* cargo fmt --all clean.
* cargo clippy --workspace --all-targets --all-features -- -D warnings
  clean.
* cargo test --workspace --all-features — all tests pass, including
  the 9 new stream_types integration tests.
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

devin-ai-integration[bot]

This comment was marked as resolved.

Devin Review pointed out that the previous doc comment on
StreamTypes::CLASSROOM_ALL listed "voice + media file + desktop +
desktop input" but the actual value 95 decomposes to voice(1) +
video_capture(2) + mediafile_audio(4) + mediafile_video(8) +
desktop(16) + channel_msg(64). DESKTOP_INPUT(32) is intentionally
**not** part of this mask.

The test `classroom_all_matches_documented_value` already pins
down this composition, so only the doc comment needed fixing.
Also mention the intentional absence of DESKTOP_INPUT so future
readers do not try to add it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant