aws-samples / aws-samples/amazon-ivs-broadcast-android-sample
Subscriber video preview stays black while audio plays correctly (React Native / Fabric integration)
- Dominant language
- Kotlin
- Stars
- 13
- Forks
- 8
- PR merge metrics
- No merged PRs in 30d
Description
### SDK Version
Amazon IVS Broadcast Android SDK **1.44.0**
### Environment
- Android device: physical device, GPU "Adreno (TM) 610" (Qualcomm SoC), OMX.qcom.video.decoder.avc used for H264 decode
- App is a React Native app using the New Architecture (Fabric) with a custom native `FrameLayout`-based ViewManager wrapping the Stages subscriber APIs
- Use case: subscribe-only (no publish), single remote participant, AUDIO_VIDEO subscribe type
### Summary
When subscribing to a remote participant's stage, **audio plays back correctly**, but the video preview view remains completely black. This happens consistently across many repeated join/leave cycles and multiple approaches to preview attachment.
### What we've confirmed is working
- WebRTC/ICE negotiation completes successfully (`ice connection state: connected` / `completed`)
- `onStreamsAdded` fires with both `AudioStageStream` and `ImageStageStream`
- `IVSVideoDecoder` is created for H264 (`OMX.qcom.video.decoder.avc`)
- `SurfaceTextureHelper` sets its listener
- Shader compilation succeeds, program link succeeds
- Audio plays correctly (`AAudio play stream`, `RTCAndroidAudioDevice::StartPlayout`)
- The native view is correctly attached to the window before the preview is requested (confirmed via `isAttachedToWindow` and layout logs)
- `ImageStageStream.device` is a valid `ImageDevice`, and the preview object returned is `com.amazonaws.ivs.broadcast.ImagePreviewView` (confirmed via `preview.javaClass.name`)
- `attachPreview()` executes with no exceptions; the `ImagePreviewView` is added to the view hierarchy with `MATCH_PARENT` layout params
### What we've tried, in order
1. **`ImageDevice.getPreviewView(aspectMode)`** — attaches an `ImagePreviewView` (`TextureView` subclass) to our custom `FrameLayout`. Video area stays black.
2. **Deferring attachment** until the view is confirmed attached to the window (`isAttachedToWindow`, then later `ViewTreeObserver.OnGlobalLayoutListener` as a more robust check) — ruled out an attach-timing race, but video still doesn't render once attachment is confirmed.
3. **`ImageStageStream.getPreview()`** (per the "Display and Remove Participants" section of the developer guide) instead of `ImageDevice.getPreviewView()` — same result.
4. Removed all caching/reuse of previously-detached preview views (aware of the documented known issue that a detached `ImagePreviewView` cannot be reused) — always request a fresh preview on every `onStreamsAdded`. No change.
5. Attempted to attach a `TextureView.SurfaceTextureListener` to the returned `ImagePreviewView` for diagnostic purposes — **this may have actively interfered** with the SDK's own internal listener on the same `TextureView`, so we removed this and left the view untouched (just `addView()`), matching the developer guide's sample code exactly. Still black.
6. Confirmed via repeated logcat captures that the `Surface=... EGLSurface=0x0` log line appears on every run regardless of whether our preview attachment code runs at all (including sessions where we deliberately deferred/skipped attaching the preview entirely) — this line appears to originate from the decoder/internal rendering pipeline and does not seem to correlate with whether our app-level `attachPreview()` succeeds.
7. Ruled out layout/clipping issues on the RN side (removed `overflow: hidden` and `borderRadius` from the parent view hierarchy) — no change.
### Representative logcat excerpt (single join, our preview attach succeeding)
```
Stage: onStreamsAdded OlcpCm90xjuV
TYPE = com.amazonaws.ivs.broadcast.AudioStageStream
Audio stream received
TYPE = com.amazonaws.ivs.broadcast.ImageStageStream
Image stream received
attachImageStream() entered
Creating PictureSample 720.000000x1569.000000 for
Surface=0x7606 SurfaceTexture=0x75e6 EGLSurface=0xb400007826320200
preview=com.amazonaws.ivs.broadcast.ImagePreviewView
ENTER attachPreview, class=com.amazonaws.ivs.broadcast.ImagePreviewView
IVSVideoDecoder: Created decoder: OMX.qcom.video.decoder.avc for codec: H264
SurfaceTextureHelper: Setting listener to com.amazonaws.ivs.webrtc.IVSVideoDecoder@e12877
StageSource Event for participant: OlcpCm90xjuV, Type: 5, Error: 0
Surface=0x7986 SurfaceTexture=0x7966 EGLSurface=0x0
StageSource Event for participant: OlcpCm90xjuV, Type: 5, Error: 0
Shader compilation succeeded.
Shader compilation succeeded.
Program link success
Signalling Event for participant: OlcpCm90xjuV, Type: SelectLayer, Error: 0
```
Note the **two separate `Surface=...` log lines** with different EGLSurface values — the first (`0xb40000...`) appears valid, the second (`0x0`) appears immediately after the decoder is created and consistently shows `EGLSurface=0x0`. We were unable to determine from the SDK's public API/docs which of these corresponds to our attached preview view versus an internal decoder target, and whether `EGLSurface=0x0` here is expected/benign or indicative of a real failure.
### Minimal reproduction (native, no RN) — NOT YET DONE
We have not yet isolated this down to a plain Android sample app outside of React Native/Fabric. We plan to test whether `stream.getPreview()` + `previewHolder.addView(preview)` in a bare Activity (following the developer guide's sample exactly) renders correctly. **We are opening this issue partly to ask**: given the log signature above (successful decoder creation, successful shader/program linking, but persistent `EGLSurface=0x0` on the second surface, and no visible frames), is this a recognized pattern, and does it point to a specific known cause?
### Questions for the SDK team
1. Is the `Surface=... EGLSurface=0x0` log line expected/benign in some cases, or does it always indicate a real rendering failure?
2. Are there additional requirements for attaching `ImagePreviewView` / `ImagePreviewSurfaceView` inside a custom Android `ViewGroup` (as opposed to directly in an Activity's layout) that aren't covered in the developer guide — e.g. regarding hardware layer type, view hierarchy depth, or GL context sharing?
3. Is it safe to assign a custom `TextureView.SurfaceTextureListener` to an `ImagePreviewView` for diagnostic purposes, or does the SDK rely on being the sole listener?
4. Are there known issues with `ImagePreviewView`/`ImagePreviewSurfaceView` rendering under React Native's Fabric renderer (custom `FrameLayout`-based Fabric components), given that Fabric can mount/measure/layout native views somewhat independently from the standard Android view attach lifecycle?
### Relevant code (custom Fabric ViewManager + View)
Available on request — happy to share the full `ReactIVSBroadcastView.kt` / `ReactIVSBroadcastManager.kt` / `LivestreamPlayer.tsx` if useful for reproducing.
Contributor guide
Research direction
Start by reproducing the documented stream.getPreview() and previewHolder.addView(preview) flow in a bare Android Activity, then compare it with the custom Fabric view in ReactIVSBroadcastView.kt and ReactIVSBroadcastManager.kt. Check whether the preview renders outside React Native and whether EGLSurface=0x0 still appears; done means identifying whether the failure is Fabric-specific or reproducible in the native sample.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin, react-native
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 28/100