Add WebRTC Implementation

urko 2025-05-11 21:05:56 +01:00
commit dc82d318ce

105
WebRTC-Implementation.md Normal file

@ -0,0 +1,105 @@
## 1 Repository map & touch-points
| What you have | Where to extend / create | | |
| ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------------------------------- |
| `app/src/main/java/com/urkob/wittrail_android/CameraXRecordingService.kt` ([Wittrail Gitea][1]) | **Extend**: add an **EncoderPipeline** inner object and a **WebRtcStreamer** helper. | | |
| `app/src/main/java/com/urkob/wittrail_android/MainActivity.kt` ([Wittrail Gitea][1]) | **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 gRPCWebRTC DTLS. | | |
| `AndroidManifest.xml` (root) ([Wittrail Gitea][2]) | **Add** `<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/>` (API 34+) and declare the service type \`\<foregroundServiceType camera | microphone | dataSync>\` ([Android Developers][3]) |
| `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][4]) | | |
---
## 2 Client-side capture → encoder → WebRTC pipeline
### 2.1 Capture & encode on-device
```kotlin
// 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 youll 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][5]).
CameraXs *VideoCapture* already feeds a `MediaCodec` session internally ([WebRTC][4]), so you only tap its encoded output instead of raw YUV/PCM.
### 2.2 Secure streaming with WebRTC `PeerConnection`
1. **Create** `WebRtcStreamer.kt` that owns a single `PeerConnection` + two `RtpSender`s (audio/video).
2. Call `webRtcStreamer.sendVideo(chunk)` each time `encoderPipeline.video.emit(chunk)` fires.
3. Negotiate DTLS-SRTP with the server; the signalling channel can be a lightweight REST call to your back-end (later replaceable by gRPC bidirectional).
4. 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 Googles minimal Kotlin sample .
---
## 3 Server-side hash + qualified time-stamp
* Deploy a tiny Go service that
1. Receives SRTP packets from `webrtc::TrackLocalStaticRtp`;
2. Re-orders & re-assembles them into MP4 fragments every **N seconds** (25 s gives smooth playback);
3. Calculates a SHA-256 digest for each fragment and calls the **Camerfirma Q-TSA** REST endpoint (`/timestamp`) they follow ETSI EN 319-421 / 422 .
* 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][3]) |
| Camera + Audio | `CAMERA`, `RECORD_AUDIO` ([Android Developers][6]) | 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
1. **Add the new permissions** to `AndroidManifest.xml`.
2. Drop the code snippets above and run on API 33 for smoke-test.
3. Spin up `pion/webrtc` demo server (one-liner) and verify you see live video.
4. 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
[1]: https://gitea.urkob.com/wittrail/client-android/src/branch/master/app/src/main/java/com/urkob/wittrail_android "client-android/wittrail_android at master - client-android - Wittrail Gitea"
[2]: https://gitea.urkob.com/wittrail/client-android/src/branch/master/app "client-android/app at master - client-android - Wittrail Gitea"
[3]: https://developer.android.com/develop/background-work/services/fgs/declare?utm_source=chatgpt.com "Declare foreground services and request permissions"
[4]: https://issues.webrtc.org/issues/40644339?utm_source=chatgpt.com "Large amounts of CPU time spent in Thread::ClearInternal when ..."
[5]: https://github.com/developerspace-samples/WebRTC-Kotlin-Sample?utm_source=chatgpt.com "developerspace-samples/WebRTC-Kotlin-Sample - GitHub"
[6]: https://developer.android.com/media/camera/camera-deprecated/camera-api?utm_source=chatgpt.com "Camera API | Android media - Android Developers"