This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
1 Repository map & touch-points
What you have | Where to extend / create | ||
---|---|---|---|
app/src/main/java/com/urkob/wittrail_android/CameraXRecordingService.kt (Wittrail Gitea) |
Extend: add an EncoderPipeline inner object and a WebRtcStreamer helper. | ||
app/src/main/java/com/urkob/wittrail_android/MainActivity.kt (Wittrail Gitea) |
Minor: request the new foreground-service types at runtime (API 34). | ||
no data/ layer yet |
Add a repository package that holds an UploadRepository to push encrypted chunks via gRPC–WebRTC DTLS. |
||
AndroidManifest.xml (root) (Wittrail Gitea) |
Add <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/> (API 34+) and declare the service type `<foregroundServiceType camera |
microphone | dataSync>` (Android Developers) |
build.gradle (app) |
Add implementation("org.webrtc:google-webrtc:1.0.32006") , implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1") and the CameraX BOM (androidx.camera:camera-bom:1.3.0 ) (WebRTC) |
2 Client-side capture → encoder → WebRTC pipeline
2.1 Capture & encode on-device
// inside CameraXRecordingService.kt (new)
private val encoderPipeline by lazy {
val video = MutableSharedFlow<EncodedVideoChunk>(replay = 0)
val audio = MutableSharedFlow<EncodedAudioChunk>(replay = 0)
// Register camera surface
VideoCapture.withOutput(MediaStoreOutputOptions.Builder(...).build())
.also { it.setVideoEncoder(VideoEncoderConfig.H264(2_000_000)) } // ≈2 Mbps
.also { it.setAudioEncoder(AudioEncoderConfig.AAC(128_000)) }
.registerPipeline(video, audio) // <-- extension function you’ll add
EncoderPipeline(video, audio) // data-class you create
}
Why H-264 + AAC? They are hardware-accelerated on every device since API 21 ✔️ and directly understood by org.webrtc
’s MediaCodecVideoEncoder
(GitHub).
CameraX’s VideoCapture already feeds a MediaCodec
session internally (WebRTC), so you only tap its encoded output instead of raw YUV/PCM.
2.2 Secure streaming with WebRTC PeerConnection
- Create
WebRtcStreamer.kt
that owns a singlePeerConnection
+ twoRtpSender
s (audio/video). - Call
webRtcStreamer.sendVideo(chunk)
each timeencoderPipeline.video.emit(chunk)
fires. - Negotiate DTLS-SRTP with the server; the signalling channel can be a lightweight REST call to your back-end (later replaceable by gRPC bidirectional).
- Enable SFrame end-to-end media encryption if you need payload privacy; the hash for the timestamp is calculated server-side after DTLS decryption.
A bare-bones set-up (no ICE-servers, only TURN) is under 50 lines – see Google’s minimal Kotlin sample .
3 Server-side hash + qualified time-stamp
-
Deploy a tiny Go service that
- Receives SRTP packets from
webrtc::TrackLocalStaticRtp
; - Re-orders & re-assembles them into MP4 fragments every N seconds (2–5 s gives smooth playback);
- Calculates a SHA-256 digest for each fragment and calls the Camerfirma Q-TSA REST endpoint (
/timestamp
) – they follow ETSI EN 319-421 / 422 .
- Receives SRTP packets from
-
Store
{hash, RFC3161_tsToken, fragmentURI}
in Postgres. Because the time-stamps are qualified, Art. 41.2 eIDAS les da “valor probatorio equivalente al de una firma notarial” in la UE.
4 Permissions & API-level quirks
Feature | API ≤ 33 | API 34+ (Android 14) |
---|---|---|
Foreground-service | android.permission.FOREGROUND_SERVICE |
MUST also declare type in manifest and request FOREGROUND_SERVICE_MEDIA_PROJECTION at runtime (Android Developers) |
Camera + Audio | CAMERA , RECORD_AUDIO (Android Developers) |
Igual, pero si target 34, the Privacy Sandbox dialog is automatic. |
External write | Scoped-storage; use MediaStore (already in your code) |
Same; WRITE_EXTERNAL_STORAGE not needed ≥ API 30. |
5 Examples of good Issues for non-devs (compliance stream)
Title | Description (plain language) | Labels | Milestone |
---|---|---|---|
“Review ETSI 319-421 compliance gap” | “Read the norm, tick each MUST & SHOULD in an excel, flag red items.” | legal , doc , research |
✍ ETSI analysis |
“Choose EU funding window” | “Compare Digital Europe vs Horizon Europe: eligibility, calendar, TRL. Write 1-page summary.” | funding , planning |
💶 Grant Scan Q3 |
“Draft DPIA (Data Protection Impact Assessment)” | “Fill the AEPD template for the pilot.” | privacy , regulation |
📜 Trust Ops MVP |
Your UX guide on how to create them—complete with screenshots—already lives in docs/onboarding/issues_guide.md; link to that in every new employee e-mail.
6 Pros / contras of this architecture
Aspect | Pros | Contras / Mitigation |
---|---|---|
CameraX + MediaCodec | HW-accelerated, low battery, single API | Needs targetSdk 33+; some Samsung A-series ships buggy encoder → keep device-quirks table. |
WebRTC SRTP path | No open port on device; NAT traversal built-in | TURN fees if many users → deploy coturn on cheap edge VMs. |
Qualified TSA | Probative value by default (Art. 41 eIDAS) | Each token ≈ €0.05 at volume → batch 5 s fragments. |
Hash first, TSA second | Small payload; privacy (only digest leaves device) | Requires buffering until TSA response (<300 ms). |
Next steps
- Add the new permissions to
AndroidManifest.xml
. - Drop the code snippets above and run on API 33 for smoke-test.
- Spin up
pion/webrtc
demo server (one-liner) and verify you see live video. - Swap in Camerfirma sandbox credentials and log the RFC-3161 token.
Once that works end-to-end, you can harden (device attestation, FIDO key-sealed AES, etc.) and then move to the larger roadmap we drafted earlier