# Use Nosmai Effects with Agora on Android

> Publish the processed Android camera feed to Agora through a shared EGL texture path while keeping the local preview visible.

> For AI agents: the complete documentation index is at https://nosmai.com/llms/effects.txt

Product: Nosmai Effects
Group: integrations
Source: https://nosmai.com/docs/effects/integrations/agora/android/

## The streaming path

![Camera frames pass through Nosmai Effects before Agora publishes them](/images/docs/agora-streaming-flow-v1.svg)

Nosmai owns and processes the camera feed. Agora publishes only the processed
output while the application keeps its local preview and session controls.

## Prerequisites

- Configure Agora broadcaster authentication, audio, and channel lifecycle.
- Disable Agora's camera track because Nosmai owns the camera.
- Pin and test the provider version used by your application.

## Register Agora's EGL context first

Create the Agora engine, get its shared EGL context, and register its native
handle before Nosmai initialization:

```java
long agoraContext = EglBaseProvider.instance()
    .getRootEglBase()
    .getEglBaseContext()
    .getNativeEglContext();

NosmaiSDK.setAgoraShareContext(agoraContext);
```

This order is required. A context registered after Nosmai initialization cannot
join the existing share group and can produce a correct local preview with
black remote video.

## Publish processed textures

```java
NosmaiSDK.setRenderMode(NosmaiSDK.RenderMode.DUAL_OUTPUT);

NosmaiSDK.setTextureFrameCallback((textureId, width, height,
                                   timestampNs, fence) -> {
    agoraAdapter.pushTexture(
        textureId, width, height, timestampNs, fence,
        () -> NosmaiSDK.releaseStreamSlot(textureId)
    );
});
```

The adapter must wait for the EGL fence before sampling. Release every stream
slot after Agora finishes with it, including dropped-frame and error paths.

## Stop in the correct order

1. Stop Agora publishing so it cannot request another frame.
2. Clear the Nosmai texture callback.
3. Return Nosmai to `PREVIEW_ONLY`.
4. Leave the channel and release Agora when the session ends.

```java
NosmaiSDK.setTextureFrameCallback(null);
NosmaiSDK.setRenderMode(NosmaiSDK.RenderMode.PREVIEW_ONLY);
```

## Common errors

| Symptom | Cause | Fix |
| --- | --- | --- |
| Local preview works but remote video is black | The EGL share context was registered too late | Create Agora and call `setAgoraShareContext` before Nosmai initialization |
| Stream stalls after several frames | Texture slots are not returned | Call `releaseStreamSlot` on success, drop, and error paths |
| Remote video is cropped | Encoder dimensions or orientation do not match the pushed frames | Keep the provider configuration aligned with actual output |

## Verify it worked

Apply a visible effect, join from a second device, and confirm the remote video
is filtered, correctly oriented, and stable through camera switch and rejoin.

## Next steps

- [Compare live-streaming routes](/docs/effects/integrations/live-streaming/)
- [Understand off-screen rendering](/docs/effects/concepts/off-screen-rendering/)
- [Review Android platform support](/docs/effects/platforms/android/)

## References

- [Off-screen rendering](/docs/effects/concepts/off-screen-rendering/)
- [Android platform guide](/docs/effects/platforms/android/)
- [Agora documentation](https://docs.agora.io/en/video-calling/advanced-features/custom-video)
