Skip to content

Subscriber video preview stays black while audio plays correctly (React Native / Fabric integration) #68

Description

@hmgyoo

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions