Overview
Ant Media Server supports push notifications to notify mobile app users about stream events in real-time. This feature integrates with:
Firebase Cloud Messaging (FCM) - For Android and iOS apps
Apple Push Notification (APN) - For iOS apps
Use cases include:
Notify users when a streamer goes live
Alert viewers about stream status changes
Send custom messages during broadcasts
Trigger app actions from server events
Architecture
The push notification system uses a service interface pattern:
IPushNotificationService.java
public interface IPushNotificationService {
static final String BEAN_NAME = "push.notification.service" ;
public enum PushNotificationServiceTypes {
FIREBASE_CLOUD_MESSAGING ( "fcm" ),
APPLE_PUSH_NOTIFICATION ( "apn" );
private String name ;
PushNotificationServiceTypes ( String name ) {
this . name = name;
}
@ Override
public String toString () {
return this . name ;
}
}
/**
* Send notification to a topic
*/
Result sendNotification ( String topic , JSONObject jsonMessage , String serviceName );
/**
* Send notification to both FCM and APN
*/
Result sendNotification ( String topic , JSONObject jsonMessage );
/**
* Send notification to specific subscriber IDs
*/
Result sendNotification ( List < String > subscriberIds , JSONObject jsonMessage );
/**
* Send notification to specific subscribers via specific service
*/
Result sendNotification ( List < String > subscriberIds , JSONObject jsonMessage , String serviceName );
}
Firebase Cloud Messaging (FCM) Setup
Prerequisites
Create Firebase Project
Go to Firebase Console
Click Add Project
Enter project name and follow setup wizard
Get Service Account Key
Navigate to Project Settings → Service Accounts
Click Generate New Private Key
Save the JSON file securely
Upload to Ant Media Server
Upload the service account JSON file to: /usr/local/antmedia/webapps/LiveApp/WEB-INF/firebase-service-account.json
Configuration
Enable FCM in application settings:
Web Panel Settings
REST API
{
"pushNotificationEnabled" : true ,
"firebaseServiceAccountFile" : "/usr/local/antmedia/webapps/LiveApp/WEB-INF/firebase-service-account.json"
}
Apple Push Notification (APN) Setup
Prerequisites
Create APN Key
Go to Apple Developer Portal
Click + to create a new key
Enable Apple Push Notifications service (APNs)
Download the .p8 key file
Note Your Credentials
You’ll need:
Key ID - From the downloaded key filename
Team ID - From Apple Developer account
Bundle ID - Your iOS app’s bundle identifier
Upload Key to Server
/usr/local/antmedia/webapps/LiveApp/WEB-INF/apn-key.p8
Configuration
{
"apnEnabled" : true ,
"apnKeyPath" : "/usr/local/antmedia/webapps/LiveApp/WEB-INF/apn-key.p8" ,
"apnKeyId" : "YOUR_KEY_ID" ,
"apnTeamId" : "YOUR_TEAM_ID" ,
"apnBundleId" : "com.yourcompany.yourapp" ,
"apnProduction" : false
}
Set apnProduction to true for production apps, false for development/sandbox.
Sending Notifications
Via REST API
Topic-based Notification
Subscriber-based Notification
Both FCM and APN
# Send to all subscribers of a topic
curl -X POST "http://localhost:5080/LiveApp/rest/v2/push-notification/send" \
-H "Content-Type: application/json" \
-d '{
"topic": "stream-updates",
"message": {
"title": "Stream Started",
"body": "Your favorite streamer is now live!",
"streamId": "stream123"
},
"service": "fcm"
}'
Programmatic Usage
import io.antmedia.pushnotification.IPushNotificationService;
import org.json.simple.JSONObject;
public class NotificationExample {
public void notifyStreamStart ( String streamId , String streamerName ) {
IPushNotificationService pushService =
(IPushNotificationService) context . getBean (
IPushNotificationService . BEAN_NAME );
JSONObject message = new JSONObject ();
message . put ( "title" , "Stream Started" );
message . put ( "body" , streamerName + " is now live!" );
message . put ( "streamId" , streamId);
message . put ( "action" , "watch-stream" );
// Send to topic
Result result = pushService . sendNotification (
"stream-" + streamId,
message
);
if ( result . isSuccess ()) {
logger . info ( "Notification sent successfully" );
}
}
}
Standard Fields
Field Type Description Required titlestring Notification title Yes bodystring Notification message Yes iconstring Icon URL or name No imagestring Large image URL No soundstring Notification sound No badgeinteger Badge count (iOS) No
Custom Data
Add any custom fields for your app logic:
{
"title" : "New Comment" ,
"body" : "Someone commented on your stream" ,
"streamId" : "stream123" ,
"commentId" : "comment456" ,
"action" : "view-comment" ,
"timestamp" : 1709566230000
}
Topic Management
Subscribe Users to Topics
Manage topic subscriptions from your mobile app:
FirebaseMessaging . getInstance (). subscribeToTopic ( "stream-updates" )
. addOnCompleteListener (task -> {
if ( task . isSuccessful ()) {
Log . d (TAG, "Subscribed to stream-updates" );
}
});
Messaging. messaging (). subscribe ( toTopic : "stream-updates" ) { error in
if let error = error {
print ( "Error subscribing: \( error ) " )
} else {
print ( "Subscribed to stream-updates" )
}
}
Topic Naming Conventions
Organize topics logically:
stream-{streamId} # Stream-specific notifications
user-{userId} # User-specific notifications
live-alerts # All live stream alerts
category-{category} # Category-based notifications
language-{lang} # Language-specific content
Integration with Stream Events
Automatic Notifications
Trigger notifications on stream events using webhooks:
Webhook Configuration
Webhook Handler (Node.js)
{
"listenerHookURL" : "http://localhost:3000/webhook" ,
"pushNotificationEnabled" : true
}
Supported Events
Event Action Value Use Case Stream Started liveStreamStartedNotify followers Stream Ended liveStreamEndedUpdate watch history Recording Ready vodReadyNotify about available replay Viewer Milestone - ”100 viewers watching” Comment Added - Notify streamer of comments
Mobile App Implementation
Android (FCM)
MainActivity.kt
MyFirebaseMessagingService.kt
import com.google.firebase.messaging.FirebaseMessaging
class MainActivity : AppCompatActivity () {
override fun onCreate (savedInstanceState: Bundle ?) {
super . onCreate (savedInstanceState)
// Get FCM token
FirebaseMessaging. getInstance ().token. addOnCompleteListener { task ->
if (task.isSuccessful) {
val token = task.result
// Send token to your server for subscriber management
registerDevice (token)
}
}
// Subscribe to topics
FirebaseMessaging. getInstance (). subscribeToTopic ( "stream-updates" )
}
private fun registerDevice (token: String ) {
// Send to AMS or your backend
// Store token with user ID for targeted notifications
}
}
iOS (APN)
import UIKit
import UserNotifications
import Firebase
@UIApplicationMain
class AppDelegate : UIResponder , UIApplicationDelegate {
func application ( _ application : UIApplication,
didFinishLaunchingWithOptions launchOptions : [UIApplication.LaunchOptionsKey: Any ] ? ) -> Bool {
// Configure Firebase
FirebaseApp. configure ()
// Request notification permissions
UNUserNotificationCenter. current (). requestAuthorization ( options : [. alert , . badge , . sound ]) { granted, error in
if granted {
DispatchQueue. main . async {
application. registerForRemoteNotifications ()
}
}
}
return true
}
func application ( _ application : UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken : Data) {
// Send token to server
let token = deviceToken. map { String ( format : "%02.2hhx" , $0 ) }. joined ()
registerDevice ( token : token)
}
func userNotificationCenter ( _ center : UNUserNotificationCenter,
didReceive response : UNNotificationResponse,
withCompletionHandler completionHandler : @escaping () -> Void ) {
let userInfo = response. notification . request . content . userInfo
if let streamId = userInfo[ "streamId" ] as? String ,
let action = userInfo[ "action" ] as? String {
switch action {
case "watch-stream" :
openStream ( streamId : streamId)
default :
break
}
}
completionHandler ()
}
}
Testing Notifications
Test FCM
curl -X POST "http://localhost:5080/LiveApp/rest/v2/push-notification/send" \
-H "Content-Type: application/json" \
-d '{
"topic": "test",
"message": {
"title": "Test Notification",
"body": "This is a test"
},
"service": "fcm"
}'
Test APN
curl -X POST "http://localhost:5080/LiveApp/rest/v2/push-notification/send" \
-H "Content-Type: application/json" \
-d '{
"subscriberIds": ["YOUR_DEVICE_TOKEN"],
"message": {
"title": "Test APN",
"body": "Testing Apple Push Notification"
},
"service": "apn"
}'
Troubleshooting
Notifications not received (FCM)
Check:
Service account JSON file is correct and in right location
Device/app is subscribed to the topic
FCM token is valid and not expired
App has notification permissions
Debug: # Check AMS logs
tail -f /usr/local/antmedia/log/ant-media-server.log | grep -i "push"
# Verify Firebase project settings in JSON file
cat /usr/local/antmedia/webapps/LiveApp/WEB-INF/firebase-service-account.json
Notifications not received (APN)
Common issues:
Using production key with development app (or vice versa)
Wrong bundle ID
Invalid .p8 key file
Device token format incorrect
Solutions:
Match apnProduction setting with app build type
Verify bundle ID matches app’s bundle identifier
Regenerate .p8 key if necessary
Ensure device token is properly formatted (no spaces/special chars)
High notification latency
Causes:
Network issues between AMS and FCM/APN servers
Rate limiting by FCM/APN
Server overload
Solutions:
Check server internet connectivity
Implement batching for bulk notifications
Monitor notification send rates
Best Practices
Personalize Messages Use subscriber-specific data to make notifications relevant. Include streamer names, custom actions, etc.
Rate Limiting Don’t spam users. Implement throttling for frequent events like viewer count updates.
Action Buttons Include actionable data in notifications so users can directly interact (watch stream, reply, etc.).
Analytics Track notification delivery rates and user engagement to optimize messaging strategy.