Home / References / ESP32 Library / AsyncUDP Library
Description
The isMulticast() method is used to determine whether a received UDP packet was sent as a multicast message. This method examines the local IP address of the received packet and checks if it matches multicast address patterns. A multicast packet is sent to a specific group of devices that have joined the multicast group, and is typically used for streaming media, group communications, network protocols like mDNS (Multicast DNS), service discovery, and distributed applications. The method returns true if the packet was sent to a multicast address such as IPv4 multicast addresses in the range 224.0.0.0 to 239.255.255.255, or IPv6 multicast addresses that start with FF00::/8. This functionality is essential for implementing protocols like UPnP, SSDP, Bonjour/Zeroconf, streaming protocols, and any application that needs to distinguish between unicast, broadcast, and multicast communications. The method works by analyzing the destination IP address that was used when the packet was received, supporting both IPv4 and IPv6 multicast detection using the underlying lwIP stack’s ip_addr_ismulticast() function.
Syntax and Usage
The isMulticast() method is called on an AsyncUDPPacket object:
bool isMulticastPacket = packet.isMulticast()Returns true if the received packet was sent as a multicast.
Arguments
The isMulticast() method takes no arguments. It operates on the packet data that was already received and stored in the AsyncUDPPacket object.
For more ESP32 development resources and tutorials, visit the All About ESP32 Resources Hub on AvantMaker.com
Return Value
The isMulticast() method returns a bool value indicating whether the received packet was sent as a multicast message. It returns true if the packet’s destination address matches any multicast address pattern: IPv4 multicast addresses (224.0.0.0 to 239.255.255.255) or IPv6 multicast addresses (FF00::/8). It returns false for unicast packets (sent to a specific device), broadcast packets (sent to all devices), or when the destination address doesn’t fall within multicast ranges. The method helps applications distinguish between different types of network communications and can be used to implement multicast-specific handling logic, group communication protocols, or service discovery mechanisms. This is particularly useful in multimedia streaming applications, network service discovery protocols like mDNS, distributed systems that use multicast for coordination, and IoT applications that need to participate in multicast groups for efficient group communications.
Example Code
Multicast Media Streaming System with Group Communication and Device Discovery
This example demonstrates how to use the isMulticast() method to create a comprehensive multicast streaming system where devices can join multicast groups for receiving streamed content, participate in group communications, and discover services using multicast protocols. The system distinguishes between multicast, broadcast, and unicast communications, maintains group memberships, and provides real-time media streaming capabilities.
Multi-Device Testing Setup Instructions
Required Hardware: 2-4 ESP32 development boards on the same WiFi network
Step-by-Step Testing Guide:
- Upload Streaming Server Code: Upload the code below to your first ESP32 (this will be the multicast streaming server)
- Upload Client Receivers Code: Upload the client code (provided after the main example) to 2-3 additional ESP32 boards
- Monitor Serial Outputs: Open Serial Monitor for all devices at 115200 baud
- Verify Network Connection: Ensure all devices connect to the same WiFi network
- Watch Multicast Streaming: Observe how the server sends multicast streams and clients receive them
- Test Group Membership: See how devices join and leave multicast groups
- Verify Multicast Detection: Notice how devices differentiate between multicast, broadcast, and unicast messages
What You’ll See:
- Automatic multicast-based media streaming across the network
- Distinction between multicast, broadcast, and unicast packet handling
- Real-time group membership management and streaming coordination
- Multicast service discovery and announcement systems
- Network monitoring and streaming quality metrics
Testing Scenarios:
- Stream Distribution: Watch the server distribute media streams to multiple receivers simultaneously
- Group Communication: See how devices communicate within multicast groups
- Packet Classification: Observe different handling for multicast vs broadcast vs unicast messages
- Service Discovery: Test multicast-based service announcement and discovery
/*
* Author: Avant Maker
* Date: June 18, 2025
* Version: 1.0
* License: MIT
*
* Description:
* This example demonstrates how to use the isMulticast() method to create a
* comprehensive multicast streaming system where devices can join multicast groups
* for receiving streamed content, participate in group communications, and discover
* services using multicast protocols. The system distinguishes between multicast,
* broadcast, and unicast communications, maintains group memberships, and provides
* real-time media streaming capabilities.
*
* How to use this example:
* Upload this code to your ESP32 and replace the WiFi credentials. The system
* will stream content to multicast groups, handle multicast service discovery,
* manage group memberships, and provide streaming quality metrics. Use the
* isMulticast() method to differentiate between multicast streams and other
* types of network communications.
*
* Code Source:
* This example code is sourced from the Comprehensive Guide
* to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
* For additional code examples and in-depth documentation related to
* the ESP32 Arduino Core Library, please visit:
*
* https://avantmaker.com/home/all-about-esp32-arduino-core-library/
*
* AvantMaker.com, your premier destination for all things
* DIY, IoT, Smart Home, and STEM projects. We are dedicated
* to empowering makers, learners, and enthusiasts with
* the resources they need to bring their innovative ideas to life.
*/
#include <WiFi.h>
#include <AsyncUDP.h>
#include <ArduinoJson.h>
// WiFi credentials
const char* ssid = "your_SSID"; // Replace with your Wi-Fi SSID
const char* password = "your_PASSWORD"; // Replace with your Wi-Fi password
// Multicast streaming configuration
const IPAddress STREAM_MULTICAST_IP(239, 255, 1, 100); // Multicast group for streaming
const IPAddress SERVICE_MULTICAST_IP(239, 255, 1, 200); // Multicast group for service discovery
const IPAddress CONTROL_MULTICAST_IP(239, 255, 1, 300); // Multicast group for control messages
const uint16_t STREAM_PORT = 9000;
const uint16_t SERVICE_PORT = 9001;
const uint16_t CONTROL_PORT = 9002;
const uint16_t RESPONSE_PORT = 9003;
// Streaming configuration
const unsigned long STREAM_INTERVAL = 100; // Send stream data every 100ms
const unsigned long SERVICE_ANNOUNCE_INTERVAL = 15000; // Announce service every 15 seconds
const unsigned long GROUP_MANAGEMENT_INTERVAL = 30000; // Manage groups every 30 seconds
const unsigned long STATS_REPORT_INTERVAL = 60000; // Report stats every minute
// Media content types
enum ContentType {
AUDIO_STREAM = 1,
VIDEO_STREAM = 2,
DATA_STREAM = 3,
CONTROL_MESSAGE = 4,
SERVICE_ANNOUNCEMENT = 5
};
// Stream information structure
struct StreamInfo {
String streamId;
String streamName;
ContentType contentType;
IPAddress multicastAddress;
uint16_t port;
String description;
int bitrate;
String codec;
bool isActive;
unsigned long startTime;
unsigned long totalPacketsSent;
unsigned long totalBytesSent;
std::vector<IPAddress> subscribers;
};
// System configuration
struct MulticastStreamingSystem {
String serverId;
String serverName;
AsyncUDP streamUDP;
AsyncUDP serviceUDP;
AsyncUDP controlUDP;
AsyncUDP responseUDP;
std::vector<StreamInfo> availableStreams;
unsigned long systemStartTime;
unsigned long lastStreamSend;
unsigned long lastServiceAnnounce;
unsigned long lastGroupManagement;
unsigned long totalMulticastsReceived;
unsigned long totalBroadcastsReceived;
unsigned long totalUnicastsReceived;
unsigned long totalMulticastsSent;
unsigned long totalBroadcastsSent;
unsigned long totalUnicastsSent;
int currentSequenceNumber;
bool streamingActive;
} streaming;
void setup() {
Serial.begin(115200);
Serial.println("Starting ESP32 Multicast Streaming Server...");
// Initialize server configuration
streaming.serverId = "ESP32_STREAM_" + String((uint32_t)ESP.getEfuseMac(), HEX);
streaming.serverName = "ESP32 Multicast Media Server";
streaming.systemStartTime = millis();
streaming.currentSequenceNumber = 0;
streaming.streamingActive = true;
Serial.print("Server ID: ");
Serial.println(streaming.serverId);
Serial.print("Server Name: ");
Serial.println(streaming.serverName);
// Initialize WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected successfully!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Signal strength: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
// Initialize multicast listeners and streams
setupMulticastListeners();
initializeStreamingServices();
Serial.println("🎬 Multicast Streaming Server is ready...");
}
void setupMulticastListeners() {
Serial.println("=== Setting Up Multicast Listeners ===");
// Setup streaming multicast listener
if (streaming.streamUDP.listenMulticast(STREAM_MULTICAST_IP, STREAM_PORT)) {
Serial.print("✅ Stream multicast listener started on ");
Serial.print(STREAM_MULTICAST_IP);
Serial.print(":");
Serial.println(STREAM_PORT);
streaming.streamUDP.onPacket([](AsyncUDPPacket packet) {
handleStreamPacket(packet);
});
} else {
Serial.println("❌ Failed to start stream multicast listener");
}
// Setup service discovery multicast listener
if (streaming.serviceUDP.listenMulticast(SERVICE_MULTICAST_IP, SERVICE_PORT)) {
Serial.print("✅ Service multicast listener started on ");
Serial.print(SERVICE_MULTICAST_IP);
Serial.print(":");
Serial.println(SERVICE_PORT);
streaming.serviceUDP.onPacket([](AsyncUDPPacket packet) {
handleServicePacket(packet);
});
} else {
Serial.println("❌ Failed to start service multicast listener");
}
// Setup control multicast listener
if (streaming.controlUDP.listenMulticast(CONTROL_MULTICAST_IP, CONTROL_PORT)) {
Serial.print("✅ Control multicast listener started on ");
Serial.print(CONTROL_MULTICAST_IP);
Serial.print(":");
Serial.println(CONTROL_PORT);
streaming.controlUDP.onPacket([](AsyncUDPPacket packet) {
handleControlPacket(packet);
});
} else {
Serial.println("❌ Failed to start control multicast listener");
}
// Setup response listener for unicast responses
if (streaming.responseUDP.listen(RESPONSE_PORT)) {
Serial.print("✅ Response listener started on port ");
Serial.println(RESPONSE_PORT);
streaming.responseUDP.onPacket([](AsyncUDPPacket packet) {
handleResponsePacket(packet);
});
} else {
Serial.println("❌ Failed to start response listener");
}
}
void handleStreamPacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Use isMulticast() to verify this is a multicast packet
bool isMulticastPacket = packet.isMulticast();
bool isBroadcastPacket = packet.isBroadcast();
Serial.println("🎬 === Stream Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
Serial.print("Message: ");
Serial.println(message.substring(0, 50) + "...");
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST MESSAGE" : "NON-MULTICAST MESSAGE");
Serial.print("Is Broadcast: ");
Serial.println(isBroadcastPacket ? "YES" : "NO");
// Update statistics based on packet type
if (isMulticastPacket) {
streaming.totalMulticastsReceived++;
Serial.println("📊 Multicast packet counter incremented");
} else if (isBroadcastPacket) {
streaming.totalBroadcastsReceived++;
Serial.println("📊 Broadcast packet counter incremented");
} else {
streaming.totalUnicastsReceived++;
Serial.println("📊 Unicast packet counter incremented");
}
// Skip processing our own messages
if (message.indexOf(streaming.serverId) >= 0) {
Serial.println("⚠️ Ignoring own stream message");
return;
}
// Process different types of stream messages
if (message.startsWith("STREAM_REQUEST")) {
if (isMulticastPacket) {
Serial.println("🎬 Processing multicast stream request");
processStreamRequest(message, packet);
} else {
Serial.println("🎬 Processing direct stream request");
processStreamRequest(message, packet);
}
}
else if (message.startsWith("STREAM_DATA")) {
Serial.println("📡 Processing incoming stream data");
processIncomingStreamData(message, packet);
}
else if (message.startsWith("QUALITY_REPORT")) {
Serial.println("📊 Processing quality report");
processQualityReport(message, packet);
}
Serial.println("=== End Stream Packet Processing ===");
}
void handleServicePacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Check packet type using isMulticast()
bool isMulticastPacket = packet.isMulticast();
bool isBroadcastPacket = packet.isBroadcast();
Serial.println("🔍 === Service Discovery Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
Serial.print("Message: ");
Serial.println(message);
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST SERVICE MESSAGE" : "NON-MULTICAST SERVICE MESSAGE");
Serial.print("Is Broadcast: ");
Serial.println(isBroadcastPacket ? "YES" : "NO");
// Update statistics
if (isMulticastPacket) {
streaming.totalMulticastsReceived++;
} else if (isBroadcastPacket) {
streaming.totalBroadcastsReceived++;
} else {
streaming.totalUnicastsReceived++;
}
// Skip processing our own messages
if (message.indexOf(streaming.serverId) >= 0) {
Serial.println("⚠️ Ignoring own service message");
return;
}
// Process service discovery messages
if (message.startsWith("SERVICE_DISCOVERY")) {
if (isMulticastPacket) {
Serial.println("🔍 Responding to multicast service discovery");
respondToServiceDiscovery(packet);
} else {
Serial.println("🔍 Responding to direct service discovery");
respondToServiceDiscovery(packet);
}
}
else if (message.startsWith("SERVICE_ANNOUNCE")) {
Serial.println("📢 Processing service announcement");
processServiceAnnouncement(message, packet);
}
Serial.println("=== End Service Discovery Packet Processing ===");
}
void handleControlPacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Verify multicast nature using isMulticast()
bool isMulticastPacket = packet.isMulticast();
Serial.println("🎛️ === Control Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
Serial.print("Command: ");
Serial.println(message);
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST CONTROL" : "NON-MULTICAST CONTROL");
// Update statistics
if (isMulticastPacket) {
streaming.totalMulticastsReceived++;
} else if (packet.isBroadcast()) {
streaming.totalBroadcastsReceived++;
} else {
streaming.totalUnicastsReceived++;
}
// Process control commands
if (message.startsWith("START_STREAM")) {
Serial.println("▶️ Processing start stream command");
processStartStreamCommand(message, packet);
}
else if (message.startsWith("STOP_STREAM")) {
Serial.println("⏹️ Processing stop stream command");
processStopStreamCommand(message, packet);
}
else if (message.startsWith("JOIN_GROUP")) {
Serial.println("➕ Processing join group command");
processJoinGroupCommand(message, packet);
}
else if (message.startsWith("LEAVE_GROUP")) {
Serial.println("➖ Processing leave group command");
processLeaveGroupCommand(message, packet);
}
Serial.println("=== End Control Packet Processing ===");
}
void handleResponsePacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Check if this is a multicast response (unusual but possible)
bool isMulticastPacket = packet.isMulticast();
bool isBroadcastPacket = packet.isBroadcast();
Serial.println("📨 === Response Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
Serial.print("Message Length: ");
Serial.println(packet.length());
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST RESPONSE" : "NON-MULTICAST RESPONSE");
Serial.print("Is Broadcast: ");
Serial.println(isBroadcastPacket ? "YES" : "NO");
// Update statistics
if (isMulticastPacket) {
streaming.totalMulticastsReceived++;
} else if (isBroadcastPacket) {
streaming.totalBroadcastsReceived++;
} else {
streaming.totalUnicastsReceived++;
}
// Process responses
if (message.startsWith("STREAM_ACK")) {
Serial.println("✅ Processing stream acknowledgment");
processStreamAcknowledgment(message, packet);
}
else if (message.startsWith("SERVICE_INFO")) {
Serial.println("📋 Processing service information");
processServiceInformation(message, packet);
}
else if (message.startsWith("QUALITY_FEEDBACK")) {
Serial.println("📊 Processing quality feedback");
processQualityFeedback(message, packet);
}
Serial.println("=== End Response Packet Processing ===");
}
void initializeStreamingServices() {
Serial.println("🎬 === Initializing Streaming Services ===");
// Create audio stream
StreamInfo audioStream;
audioStream.streamId = "AUDIO_001";
audioStream.streamName = "Live Audio Feed";
audioStream.contentType = AUDIO_STREAM;
audioStream.multicastAddress = STREAM_MULTICAST_IP;
audioStream.port = STREAM_PORT;
audioStream.description = "High-quality audio stream";
audioStream.bitrate = 128000; // 128 kbps
audioStream.codec = "MP3";
audioStream.isActive = true;
audioStream.startTime = millis();
audioStream.totalPacketsSent = 0;
audioStream.totalBytesSent = 0;
streaming.availableStreams.push_back(audioStream);
// Create video stream
StreamInfo videoStream;
videoStream.streamId = "VIDEO_001";
videoStream.streamName = "Live Video Feed";
videoStream.contentType = VIDEO_STREAM;
videoStream.multicastAddress = IPAddress(239, 255, 1, 101);
videoStream.port = STREAM_PORT + 1;
videoStream.description = "HD video stream";
videoStream.bitrate = 2000000; // 2 Mbps
videoStream.codec = "H.264";
videoStream.isActive = true;
videoStream.startTime = millis();
videoStream.totalPacketsSent = 0;
videoStream.totalBytesSent = 0;
streaming.availableStreams.push_back(videoStream);
// Create data stream
StreamInfo dataStream;
dataStream.streamId = "DATA_001";
dataStream.streamName = "Sensor Data Stream";
dataStream.contentType = DATA_STREAM;
dataStream.multicastAddress = IPAddress(239, 255, 1, 102);
dataStream.port = STREAM_PORT + 2;
dataStream.description = "Real-time sensor data";
dataStream.bitrate = 64000; // 64 kbps
dataStream.codec = "JSON";
dataStream.isActive = true;
dataStream.startTime = millis();
dataStream.totalPacketsSent = 0;
dataStream.totalBytesSent = 0;
streaming.availableStreams.push_back(dataStream);
Serial.print("✅ Initialized ");
Serial.print(streaming.availableStreams.size());
Serial.println(" streaming services");
}
String createStreamDataPacket(StreamInfo& stream) {
String packet = "{";
packet += "\"type\":\"STREAM_DATA\",";
packet += "\"streamId\":\"" + stream.streamId + "\",";
packet += "\"sequence\":" + String(streaming.currentSequenceNumber++) + ",";
packet += "\"timestamp\":" + String(millis()) + ",";
packet += "\"serverId\":\"" + streaming.serverId + "\",";
packet += "\"contentType\":" + String((int)stream.contentType) + ",";
packet += "\"bitrate\":" + String(stream.bitrate) + ",";
packet += "\"codec\":\"" + stream.codec + "\",";
// Simulate content based on stream type
if (stream.contentType == AUDIO_STREAM) {
packet += "\"audioData\":\"" + generateSimulatedAudioData() + "\",";
} else if (stream.contentType == VIDEO_STREAM) {
packet += "\"videoFrame\":\"" + generateSimulatedVideoFrame() + "\",";
} else if (stream.contentType == DATA_STREAM) {
packet += "\"sensorData\":{" + generateSimulatedSensorData() + "},";
}
packet += "\"quality\":\"HIGH\"";
packet += "}";
return packet;
}
String generateSimulatedAudioData() {
// Simulate audio data with frequency and amplitude
float frequency = 440.0 + random(-50, 50); // A4 note with variation
float amplitude = 0.8 + (random(0, 40) / 100.0);
return "freq:" + String(frequency, 2) + ",amp:" + String(amplitude, 2);
}
String generateSimulatedVideoFrame() {
// Simulate video frame metadata
int frameNumber = streaming.currentSequenceNumber;
int width = 1920;
int height = 1080;
String frameType = (frameNumber % 30 == 0) ? "I" : "P"; // I-frame every 30 frames
return "frame:" + String(frameNumber) + ",res:" + String(width) + "x" + String(height) + ",type:" + frameType;
}
String generateSimulatedSensorData() {
// Simulate sensor readings
float temperature = 20.0 + random(-10, 15) + (random(0, 100) / 100.0);
float humidity = 45.0 + random(-15, 25) + (random(0, 100) / 100.0);
float pressure = 1013.25 + random(-20, 20) + (random(0, 100) / 100.0);
String data = "\"temperature\":" + String(temperature, 2) + ",";
data += "\"humidity\":" + String(humidity, 2) + ",";
data += "\"pressure\":" + String(pressure, 2);
return data;
}
void sendMulticastStream() {
if (!streaming.streamingActive) {
return;
}
Serial.println("📡 === Sending Multicast Streams ===");
for (size_t i = 0; i < streaming.availableStreams.size(); i++) {
StreamInfo& stream = streaming.availableStreams[i];
if (stream.isActive) {
String streamData = createStreamDataPacket(stream);
// Send to multicast group
size_t sentBytes = streaming.streamUDP.writeTo(
(uint8_t*)streamData.c_str(),
streamData.length(),
stream.multicastAddress,
stream.port
);
if (sentBytes > 0) {
streaming.totalMulticastsSent++;
stream.totalPacketsSent++;
stream.totalBytesSent += sentBytes;
Serial.print("✅ Stream ");
Serial.print(stream.streamId);
Serial.print(" sent to multicast group ");
Serial.print(stream.multicastAddress);
Serial.print(" (");
Serial.print(sentBytes);
Serial.println(" bytes)");
Serial.println("🔍 This multicast will be detected by isMulticast() on receiving devices");
} else {
Serial.print("❌ Failed to send stream ");
Serial.println(stream.streamId);
}
}
}
streaming.lastStreamSend = millis();
}
void sendServiceAnnouncement() {
Serial.println("📢 === Sending Service Announcement ===");
String announcement = "{";
announcement += "\"type\":\"SERVICE_ANNOUNCE\",";
announcement += "\"serverId\":\"" + streaming.serverId + "\",";
announcement += "\"serverName\":\"" + streaming.serverName + "\",";
announcement += "\"timestamp\":" + String(millis()) + ",";
announcement += "\"services\":[";
for (size_t i = 0; i < streaming.availableStreams.size(); i++) {
if (i > 0) announcement += ",";
StreamInfo& stream = streaming.availableStreams[i];
announcement += "{";
announcement += "\"id\":\"" + stream.streamId + "\",";
announcement += "\"name\":\"" + stream.streamName + "\",";
announcement += "\"type\":" + String((int)stream.contentType) + ",";
announcement += "\"multicastIP\":\"" + stream.multicastAddress.toString() + "\",";
announcement += "\"port\":" + String(stream.port) + ",";
announcement += "\"bitrate\":" + String(stream.bitrate) + ",";
announcement += "\"codec\":\"" + stream.codec + "\",";
announcement += "\"active\":" + String(stream.isActive ? "true" : "false");
announcement += "}";
}
announcement += "],";
announcement += "\"uptime\":" + String((millis() - streaming.systemStartTime) / 1000);
announcement += "}";
// Send to service discovery multicast group
size_t sentBytes = streaming.serviceUDP.writeTo(
(uint8_t*)announcement.c_str(),
announcement.length(),
SERVICE_MULTICAST_IP,
SERVICE_PORT
);
if (sentBytes > 0) {
streaming.totalMulticastsSent++;
streaming.lastServiceAnnounce = millis();
Serial.print("✅ Service announcement sent to multicast group ");
Serial.print(SERVICE_MULTICAST_IP);
Serial.print(" (");
Serial.print(sentBytes);
Serial.println(" bytes)");
Serial.println("🔍 This multicast will be detected by isMulticast() on receiving devices");
} else {
Serial.println("❌ Failed to send service announcement");
}
}
void processStreamRequest(const String& message, AsyncUDPPacket& packet) {
Serial.println("📤 Processing stream request");
// Parse stream request
String streamId = extractValueFromMessage(message, "streamId");
// Find requested stream
for (size_t i = 0; i < streaming.availableStreams.size(); i++) {
if (streaming.availableStreams[i].streamId == streamId) {
String response = "{";
response += "\"type\":\"STREAM_ACK\",";
response += "\"streamId\":\"" + streamId + "\",";
response += "\"multicastIP\":\"" + streaming.availableStreams[i].multicastAddress.toString() + "\",";
response += "\"port\":" + String(streaming.availableStreams[i].port) + ",";
response += "\"status\":\"AVAILABLE\"";
response += "}";
// Send unicast response
size_t sentBytes = packet.printf("%s", response.c_str());
if (sentBytes > 0) {
streaming.totalUnicastsSent++;
Serial.println("✅ Stream acknowledgment sent");
}
return;
}
}
// Stream not found
String response = "{\"type\":\"STREAM_ACK\",\"streamId\":\"" + streamId + "\",\"status\":\"NOT_FOUND\"}";
size_t sentBytes = packet.printf("%s", response.c_str());
if (sentBytes > 0) {
streaming.totalUnicastsSent++;
}
}
void processIncomingStreamData(const String& message, AsyncUDPPacket& packet) {
// Process incoming stream data from other servers
String streamId = extractValueFromMessage(message, "streamId");
Serial.print("📡 Processing incoming stream data for: ");
Serial.println(streamId);
}
void processQualityReport(const String& message, AsyncUDPPacket& packet) {
// Process quality reports from clients
String streamId = extractValueFromMessage(message, "streamId");
String quality = extractValueFromMessage(message, "quality");
Serial.print("📊 Quality report for ");
Serial.print(streamId);
Serial.print(": ");
Serial.println(quality);
}
void respondToServiceDiscovery(AsyncUDPPacket& packet) {
Serial.println("📤 Responding to service discovery");
String response = "{";
response += "\"type\":\"SERVICE_INFO\",";
response += "\"serverId\":\"" + streaming.serverId + "\",";
response += "\"serverName\":\"" + streaming.serverName + "\",";
response += "\"serviceCount\":" + String(streaming.availableStreams.size()) + ",";
response += "\"multicastGroups\":[";
response += "\"" + STREAM_MULTICAST_IP.toString() + "\",";
response += "\"" + SERVICE_MULTICAST_IP.toString() + "\",";
response += "\"" + CONTROL_MULTICAST_IP.toString() + "\"";
response += "],";
response += "\"capabilities\":\"streaming,discovery,control\"";
response += "}";
// Send unicast response
size_t sentBytes = packet.printf("%s", response.c_str());
if (sentBytes > 0) {
streaming.totalUnicastsSent++;
Serial.println("✅ Service discovery response sent");
}
}
void processServiceAnnouncement(const String& message, AsyncUDPPacket& packet) {
String serverId = extractValueFromMessage(message, "serverId");
Serial.print("📢 Processing service announcement from: ");
Serial.println(serverId);
}
void processStartStreamCommand(const String& message, AsyncUDPPacket& packet) {
String streamId = extractValueFromMessage(message, "streamId");
Serial.print("▶️ Starting stream: ");
Serial.println(streamId);
for (size_t i = 0; i < streaming.availableStreams.size(); i++) {
if (streaming.availableStreams[i].streamId == streamId) {
streaming.availableStreams[i].isActive = true;
break;
}
}
}
void processStopStreamCommand(const String& message, AsyncUDPPacket& packet) {
String streamId = extractValueFromMessage(message, "streamId");
Serial.print("⏹️ Stopping stream: ");
Serial.println(streamId);
for (size_t i = 0; i < streaming.availableStreams.size(); i++) {
if (streaming.availableStreams[i].streamId == streamId) {
streaming.availableStreams[i].isActive = false;
break;
}
}
}
void processJoinGroupCommand(const String& message, AsyncUDPPacket& packet) {
String groupIP = extractValueFromMessage(message, "groupIP");
Serial.print("➕ Device joining multicast group: ");
Serial.println(groupIP);
}
void processLeaveGroupCommand(const String& message, AsyncUDPPacket& packet) {
String groupIP = extractValueFromMessage(message, "groupIP");
Serial.print("➖ Device leaving multicast group: ");
Serial.println(groupIP);
}
void processStreamAcknowledgment(const String& message, AsyncUDPPacket& packet) {
String streamId = extractValueFromMessage(message, "streamId");
Serial.print("✅ Stream acknowledgment for: ");
Serial.println(streamId);
}
void processServiceInformation(const String& message, AsyncUDPPacket& packet) {
String serverId = extractValueFromMessage(message, "serverId");
Serial.print("📋 Service information from: ");
Serial.println(serverId);
}
void processQualityFeedback(const String& message, AsyncUDPPacket& packet) {
String streamId = extractValueFromMessage(message, "streamId");
String feedback = extractValueFromMessage(message, "feedback");
Serial.print("📊 Quality feedback for ");
Serial.print(streamId);
Serial.print(": ");
Serial.println(feedback);
}
String extractValueFromMessage(const String& message, const String& key) {
int keyIndex = message.indexOf("\"" + key + "\":");
if (keyIndex == -1) return "";
int valueStart = message.indexOf("\"", keyIndex + key.length() + 3) + 1;
int valueEnd = message.indexOf("\"", valueStart);
if (valueStart > 0 && valueEnd > valueStart) {
return message.substring(valueStart, valueEnd);
}
return "";
}
void printStreamingStatus() {
Serial.println("📊 === MULTICAST STREAMING SYSTEM STATUS ===");
Serial.print("Server: ");
Serial.print(streaming.serverName);
Serial.print(" (");
Serial.print(streaming.serverId);
Serial.println(")");
Serial.print("Uptime: ");
Serial.print((millis() - streaming.systemStartTime) / 1000);
Serial.println(" seconds");
Serial.println("=== MULTICAST vs BROADCAST vs UNICAST STATISTICS ===");
Serial.print("📡 Multicasts Received: ");
Serial.println(streaming.totalMulticastsReceived);
Serial.print("📻 Broadcasts Received: ");
Serial.println(streaming.totalBroadcastsReceived);
Serial.print("📨 Unicasts Received: ");
Serial.println(streaming.totalUnicastsReceived);
Serial.print("📡 Multicasts Sent: ");
Serial.println(streaming.totalMulticastsSent);
Serial.print("📻 Broadcasts Sent: ");
Serial.println(streaming.totalBroadcastsSent);
Serial.print("📨 Unicasts Sent: ");
Serial.println(streaming.totalUnicastsSent);
Serial.println("=== ACTIVE STREAMS ===");
for (size_t i = 0; i < streaming.availableStreams.size(); i++) {
StreamInfo& stream = streaming.availableStreams[i];
Serial.print(" ");
Serial.print(stream.streamId);
Serial.print(" (");
Serial.print(stream.streamName);
Serial.print(") - ");
Serial.print(stream.isActive ? "ACTIVE" : "INACTIVE");
Serial.print(" - Multicast: ");
Serial.print(stream.multicastAddress);
Serial.print(":");
Serial.print(stream.port);
Serial.print(" - Packets: ");
Serial.print(stream.totalPacketsSent);
Serial.print(" - Bytes: ");
Serial.println(stream.totalBytesSent);
}
Serial.print("WiFi Signal: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
Serial.print("Free Heap: ");
Serial.print(ESP.getFreeHeap());
Serial.println(" bytes");
Serial.println("===============================================");
}
void loop() {
unsigned long currentTime = millis();
// Send periodic multicast streams
if (currentTime - streaming.lastStreamSend >= STREAM_INTERVAL) {
sendMulticastStream();
}
// Send periodic service announcements
if (currentTime - streaming.lastServiceAnnounce >= SERVICE_ANNOUNCE_INTERVAL) {
sendServiceAnnouncement();
}
// Print system status periodically
static unsigned long lastStatusPrint = 0;
if (currentTime - lastStatusPrint >= STATS_REPORT_INTERVAL) {
lastStatusPrint = currentTime;
printStreamingStatus();
}
// Monitor WiFi connection
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠️ WiFi connection lost! Attempting reconnection...");
WiFi.reconnect();
delay(5000);
}
delay(50);
}Multicast Streaming Client Receiver Code
Upload this code to 2-3 additional ESP32 devices to create client receivers that will join multicast groups and receive streamed content. Each client will demonstrate multicast group membership and use isMulticast() to verify packet types.
Client Receiver Features:
- Joins multiple multicast groups for different content types
- Receives multicast streams (audio, video, data)
- Uses isMulticast() to verify multicast packet reception
- Maintains statistics of multicast vs broadcast vs unicast communications
- Provides stream quality monitoring and feedback
/*
* Author: Avant Maker
* Date: June 18, 2025
* Version: 1.0
* License: MIT
*
* Description:
* This is the client receiver code for testing multicast streaming communication
* with multiple ESP32 devices. Upload this code to additional ESP32 boards to create
* multicast stream receivers that can join groups and receive streamed content.
* Use this code together with the multicast streaming server code above.
*
* Testing Instructions:
* 1. Upload the main streaming server code to one ESP32
* 2. Upload this client receiver code to 2-3 additional ESP32 devices
* 3. All devices will automatically join multicast groups and receive streams
* 4. Monitor all Serial outputs to see the multicast vs broadcast vs unicast communication
* 5. Clients will receive multicast streams and provide quality feedback
*/
#include <WiFi.h>
#include <AsyncUDP.h>
// WiFi credentials (must match streaming server)
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
// Multicast streaming configuration (must match server)
const IPAddress STREAM_MULTICAST_IP(239, 255, 1, 100);
const IPAddress SERVICE_MULTICAST_IP(239, 255, 1, 200);
const IPAddress CONTROL_MULTICAST_IP(239, 255, 1, 300);
const IPAddress VIDEO_MULTICAST_IP(239, 255, 1, 101);
const IPAddress DATA_MULTICAST_IP(239, 255, 1, 102);
const uint16_t STREAM_PORT = 9000;
const uint16_t SERVICE_PORT = 9001;
const uint16_t CONTROL_PORT = 9002;
const uint16_t RESPONSE_PORT = 9003;
// Client configuration
const unsigned long DISCOVERY_INTERVAL = 45000; // Send discovery requests every 45 seconds
const unsigned long QUALITY_REPORT_INTERVAL = 30000; // Send quality reports every 30 seconds
const unsigned long STATS_REPORT_INTERVAL = 60000; // Report stats every minute
// Client receiver system
struct MulticastClient {
String clientId;
String clientName;
AsyncUDP streamUDP;
AsyncUDP serviceUDP;
AsyncUDP controlUDP;
AsyncUDP responseUDP;
AsyncUDP videoUDP;
AsyncUDP dataUDP;
unsigned long systemStartTime;
unsigned long lastDiscovery;
unsigned long lastQualityReport;
unsigned long totalMulticastsReceived;
unsigned long totalBroadcastsReceived;
unsigned long totalUnicastsReceived;
unsigned long totalMulticastsSent;
unsigned long totalBroadcastsSent;
unsigned long totalUnicastsSent;
unsigned long totalStreamPacketsReceived;
unsigned long totalStreamBytesReceived;
std::vector<String> joinedGroups;
String lastStreamContent;
String lastServiceInfo;
bool receivingStreams;
} client;
void setup() {
Serial.begin(115200);
Serial.println("Starting ESP32 Multicast Streaming Client...");
// Initialize client configuration
client.clientId = "ESP32_CLIENT_" + String((uint32_t)ESP.getEfuseMac(), HEX);
client.clientName = "ESP32 Multicast Receiver " + String((uint32_t)ESP.getEfuseMac() & 0xFFFF, HEX);
client.systemStartTime = millis();
client.receivingStreams = true;
Serial.print("Client ID: ");
Serial.println(client.clientId);
Serial.print("Client Name: ");
Serial.println(client.clientName);
// Initialize WiFi
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("✅ WiFi connected successfully!");
Serial.print("Client IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Signal strength: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
// Join multicast groups and setup listeners
joinMulticastGroups();
// Send initial service discovery
delay(3000);
sendServiceDiscovery();
Serial.println("🎬 Multicast Streaming Client is ready to receive...");
}
void joinMulticastGroups() {
Serial.println("=== Joining Multicast Groups ===");
// Join main streaming multicast group
if (client.streamUDP.listenMulticast(STREAM_MULTICAST_IP, STREAM_PORT)) {
Serial.print("✅ Joined audio stream multicast group ");
Serial.print(STREAM_MULTICAST_IP);
Serial.print(":");
Serial.println(STREAM_PORT);
client.joinedGroups.push_back("AUDIO:" + STREAM_MULTICAST_IP.toString());
client.streamUDP.onPacket([](AsyncUDPPacket packet) {
handleClientStreamPacket(packet);
});
} else {
Serial.println("❌ Failed to join audio stream multicast group");
}
// Join video streaming multicast group
if (client.videoUDP.listenMulticast(VIDEO_MULTICAST_IP, STREAM_PORT + 1)) {
Serial.print("✅ Joined video stream multicast group ");
Serial.print(VIDEO_MULTICAST_IP);
Serial.print(":");
Serial.println(STREAM_PORT + 1);
client.joinedGroups.push_back("VIDEO:" + VIDEO_MULTICAST_IP.toString());
client.videoUDP.onPacket([](AsyncUDPPacket packet) {
handleClientVideoPacket(packet);
});
} else {
Serial.println("❌ Failed to join video stream multicast group");
}
// Join data streaming multicast group
if (client.dataUDP.listenMulticast(DATA_MULTICAST_IP, STREAM_PORT + 2)) {
Serial.print("✅ Joined data stream multicast group ");
Serial.print(DATA_MULTICAST_IP);
Serial.print(":");
Serial.println(STREAM_PORT + 2);
client.joinedGroups.push_back("DATA:" + DATA_MULTICAST_IP.toString());
client.dataUDP.onPacket([](AsyncUDPPacket packet) {
handleClientDataPacket(packet);
});
} else {
Serial.println("❌ Failed to join data stream multicast group");
}
// Join service discovery multicast group
if (client.serviceUDP.listenMulticast(SERVICE_MULTICAST_IP, SERVICE_PORT)) {
Serial.print("✅ Joined service discovery multicast group ");
Serial.print(SERVICE_MULTICAST_IP);
Serial.print(":");
Serial.println(SERVICE_PORT);
client.joinedGroups.push_back("SERVICE:" + SERVICE_MULTICAST_IP.toString());
client.serviceUDP.onPacket([](AsyncUDPPacket packet) {
handleClientServicePacket(packet);
});
} else {
Serial.println("❌ Failed to join service discovery multicast group");
}
// Join control multicast group
if (client.controlUDP.listenMulticast(CONTROL_MULTICAST_IP, CONTROL_PORT)) {
Serial.print("✅ Joined control multicast group ");
Serial.print(CONTROL_MULTICAST_IP);
Serial.print(":");
Serial.println(CONTROL_PORT);
client.joinedGroups.push_back("CONTROL:" + CONTROL_MULTICAST_IP.toString());
client.controlUDP.onPacket([](AsyncUDPPacket packet) {
handleClientControlPacket(packet);
});
} else {
Serial.println("❌ Failed to join control multicast group");
}
// Setup response listener for unicast communications
if (client.responseUDP.listen(RESPONSE_PORT)) {
Serial.print("✅ Response listener started on port ");
Serial.println(RESPONSE_PORT);
client.responseUDP.onPacket([](AsyncUDPPacket packet) {
handleClientResponsePacket(packet);
});
} else {
Serial.println("❌ Failed to start response listener");
}
Serial.print("📊 Total multicast groups joined: ");
Serial.println(client.joinedGroups.size());
}
void handleClientStreamPacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Use isMulticast() to verify this is a multicast stream - this is the key demonstration
bool isMulticastPacket = packet.isMulticast();
bool isBroadcastPacket = packet.isBroadcast();
Serial.println("🎬 === Client Audio Stream Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print(":");
Serial.println(packet.remotePort());
Serial.print("Size: ");
Serial.print(packet.length());
Serial.println(" bytes");
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST STREAM" : "NON-MULTICAST STREAM");
Serial.print("Is Broadcast: ");
Serial.println(isBroadcastPacket ? "YES" : "NO");
// Update statistics based on packet type
if (isMulticastPacket) {
client.totalMulticastsReceived++;
client.totalStreamPacketsReceived++;
client.totalStreamBytesReceived += packet.length();
Serial.println("📊 Multicast stream counter incremented");
} else if (isBroadcastPacket) {
client.totalBroadcastsReceived++;
Serial.println("📊 Broadcast counter incremented");
} else {
client.totalUnicastsReceived++;
Serial.println("📊 Unicast counter incremented");
}
// Skip processing our own messages
if (message.indexOf(client.clientId) >= 0) {
Serial.println("⚠️ Ignoring own stream message");
return;
}
// Process stream content
if (message.startsWith("{") && isMulticastPacket) {
Serial.println("📡 Processing multicast stream data");
processStreamContent(message, "AUDIO");
client.lastStreamContent = message.substring(0, 100);
}
Serial.println("=== End Client Audio Stream Processing ===");
}
void handleClientVideoPacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Verify multicast nature using isMulticast()
bool isMulticastPacket = packet.isMulticast();
Serial.println("📹 === Client Video Stream Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print("Size: ");
Serial.print(packet.length());
Serial.println(" bytes");
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST VIDEO" : "NON-MULTICAST VIDEO");
// Update statistics
if (isMulticastPacket) {
client.totalMulticastsReceived++;
client.totalStreamPacketsReceived++;
client.totalStreamBytesReceived += packet.length();
Serial.println("📊 Multicast video stream counter incremented");
} else if (packet.isBroadcast()) {
client.totalBroadcastsReceived++;
} else {
client.totalUnicastsReceived++;
}
// Process video stream content
if (message.startsWith("{") && isMulticastPacket) {
Serial.println("📹 Processing multicast video stream data");
processStreamContent(message, "VIDEO");
}
Serial.println("=== End Client Video Stream Processing ===");
}
void handleClientDataPacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Check multicast nature using isMulticast()
bool isMulticastPacket = packet.isMulticast();
Serial.println("📊 === Client Data Stream Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print("Size: ");
Serial.print(packet.length());
Serial.println(" bytes");
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST DATA" : "NON-MULTICAST DATA");
// Update statistics
if (isMulticastPacket) {
client.totalMulticastsReceived++;
client.totalStreamPacketsReceived++;
client.totalStreamBytesReceived += packet.length();
Serial.println("📊 Multicast data stream counter incremented");
} else if (packet.isBroadcast()) {
client.totalBroadcastsReceived++;
} else {
client.totalUnicastsReceived++;
}
// Process data stream content
if (message.startsWith("{") && isMulticastPacket) {
Serial.println("📊 Processing multicast sensor data stream");
processStreamContent(message, "DATA");
}
Serial.println("=== End Client Data Stream Processing ===");
}
void handleClientServicePacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Verify multicast service using isMulticast()
bool isMulticastPacket = packet.isMulticast();
Serial.println("🔍 === Client Service Discovery Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print("Message: ");
Serial.println(message.substring(0, 50) + "...");
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST SERVICE" : "NON-MULTICAST SERVICE");
// Update statistics
if (isMulticastPacket) {
client.totalMulticastsReceived++;
} else if (packet.isBroadcast()) {
client.totalBroadcastsReceived++;
} else {
client.totalUnicastsReceived++;
}
// Skip processing our own messages
if (message.indexOf(client.clientId) >= 0) {
Serial.println("⚠️ Ignoring own service message");
return;
}
// Process service announcements
if (message.startsWith("SERVICE_ANNOUNCE") && isMulticastPacket) {
Serial.println("📢 Processing multicast service announcement");
processServiceAnnouncement(message, packet);
client.lastServiceInfo = message.substring(0, 100);
}
Serial.println("=== End Client Service Processing ===");
}
void handleClientControlPacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Check multicast control using isMulticast()
bool isMulticastPacket = packet.isMulticast();
Serial.println("🎛️ === Client Control Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print("Command: ");
Serial.println(message);
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST CONTROL" : "NON-MULTICAST CONTROL");
// Update statistics
if (isMulticastPacket) {
client.totalMulticastsReceived++;
} else if (packet.isBroadcast()) {
client.totalBroadcastsReceived++;
} else {
client.totalUnicastsReceived++;
}
// Process control commands
if (isMulticastPacket) {
Serial.println("🎛️ Processing multicast control command");
processControlCommand(message);
}
Serial.println("=== End Client Control Processing ===");
}
void handleClientResponsePacket(AsyncUDPPacket packet) {
// Extract message content
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
message.trim();
// Check response packet type
bool isMulticastPacket = packet.isMulticast();
bool isBroadcastPacket = packet.isBroadcast();
Serial.println("📨 === Client Response Packet Received ===");
Serial.print("From: ");
Serial.print(packet.remoteIP());
Serial.print("Message: ");
Serial.println(message.substring(0, 50) + "...");
Serial.print("🔍 MULTICAST DETECTION: ");
Serial.println(isMulticastPacket ? "MULTICAST RESPONSE" : "NON-MULTICAST RESPONSE");
Serial.print("Is Broadcast: ");
Serial.println(isBroadcastPacket ? "YES" : "NO");
// Update statistics
if (isMulticastPacket) {
client.totalMulticastsReceived++;
} else if (isBroadcastPacket) {
client.totalBroadcastsReceived++;
} else {
client.totalUnicastsReceived++;
}
// Process responses
if (message.startsWith("SERVICE_INFO")) {
Serial.println("📋 Processing service information response");
processServiceInformation(message);
}
Serial.println("=== End Client Response Processing ===");
}
void processStreamContent(const String& content, const String& streamType) {
Serial.print("📡 Processing ");
Serial.print(streamType);
Serial.println(" stream content");
// Extract stream information
if (content.indexOf("streamId") >= 0) {
String streamId = extractJSONValue(content, "streamId");
String sequence = extractJSONValue(content, "sequence");
Serial.print(" Stream ID: ");
Serial.print(streamId);
Serial.print(", Sequence: ");
Serial.println(sequence);
}
// Process content based on type
if (streamType == "AUDIO" && content.indexOf("audioData") >= 0) {
String audioData = extractJSONValue(content, "audioData");
Serial.print(" 🎵 Audio Data: ");
Serial.println(audioData);
} else if (streamType == "VIDEO" && content.indexOf("videoFrame") >= 0) {
String videoFrame = extractJSONValue(content, "videoFrame");
Serial.print(" 📹 Video Frame: ");
Serial.println(videoFrame);
} else if (streamType == "DATA" && content.indexOf("sensorData") >= 0) {
Serial.println(" 📊 Sensor Data Received");
}
}
void processServiceAnnouncement(const String& message, AsyncUDPPacket& packet) {
String serverId = extractJSONValue(message, "serverId");
String serverName = extractJSONValue(message, "serverName");
Serial.print("📢 Service from: ");
Serial.print(serverName);
Serial.print(" (");
Serial.print(serverId);
Serial.println(")");
}
void processControlCommand(const String& message) {
if (message.startsWith("START_STREAM")) {
Serial.println("▶️ Received start stream command");
client.receivingStreams = true;
} else if (message.startsWith("STOP_STREAM")) {
Serial.println("⏹️ Received stop stream command");
client.receivingStreams = false;
}
}
void processServiceInformation(const String& message) {
String serverId = extractJSONValue(message, "serverId");
String capabilities = extractJSONValue(message, "capabilities");
Serial.print("📋 Service capabilities from ");
Serial.print(serverId);
Serial.print(": ");
Serial.println(capabilities);
}
void sendServiceDiscovery() {
Serial.println("🔍 === Sending Service Discovery Request ===");
String request = "{";
request += "\"type\":\"SERVICE_DISCOVERY\",";
request += "\"clientId\":\"" + client.clientId + "\",";
request += "\"clientName\":\"" + client.clientName + "\",";
request += "\"timestamp\":" + String(millis()) + ",";
request += "\"requestedServices\":\"streaming,discovery,control\"";
request += "}";
// Send to service discovery multicast group
size_t sentBytes = client.serviceUDP.writeTo(
(uint8_t*)request.c_str(),
request.length(),
SERVICE_MULTICAST_IP,
SERVICE_PORT
);
if (sentBytes > 0) {
client.totalMulticastsSent++;
client.lastDiscovery = millis();
Serial.print("✅ Service discovery request sent to multicast group ");
Serial.print(SERVICE_MULTICAST_IP);
Serial.print(" (");
Serial.print(sentBytes);
Serial.println(" bytes)");
Serial.println("🔍 This multicast will be detected by isMulticast() on receiving devices");
} else {
Serial.println("❌ Failed to send service discovery request");
}
}
void sendQualityReport() {
Serial.println("📊 === Sending Quality Report ===");
String report = "{";
report += "\"type\":\"QUALITY_REPORT\",";
report += "\"clientId\":\"" + client.clientId + "\",";
report += "\"timestamp\":" + String(millis()) + ",";
report += "\"packetsReceived\":" + String(client.totalStreamPacketsReceived) + ",";
report += "\"bytesReceived\":" + String(client.totalStreamBytesReceived) + ",";
report += "\"quality\":\"HIGH\",";
report += "\"signalStrength\":" + String(WiFi.RSSI()) + ",";
report += "\"multicastGroups\":" + String(client.joinedGroups.size());
report += "}";
// Send to control multicast group
size_t sentBytes = client.controlUDP.writeTo(
(uint8_t*)report.c_str(),
report.length(),
CONTROL_MULTICAST_IP,
CONTROL_PORT
);
if (sentBytes > 0) {
client.totalMulticastsSent++;
client.lastQualityReport = millis();
Serial.print("✅ Quality report sent to multicast group ");
Serial.print(CONTROL_MULTICAST_IP);
Serial.print(" (");
Serial.print(sentBytes);
Serial.println(" bytes)");
Serial.println("🔍 This multicast will be detected by isMulticast() on receiving devices");
} else {
Serial.println("❌ Failed to send quality report");
}
}
String extractJSONValue(const String& json, const String& key) {
int keyIndex = json.indexOf("\"" + key + "\":");
if (keyIndex == -1) return "";
int valueStart = json.indexOf("\"", keyIndex + key.length() + 3) + 1;
int valueEnd = json.indexOf("\"", valueStart);
if (valueStart > 0 && valueEnd > valueStart) {
return json.substring(valueStart, valueEnd);
}
return "";
}
void printClientStatus() {
Serial.println("📊 === MULTICAST CLIENT STATUS REPORT ===");
Serial.print("Client: ");
Serial.print(client.clientName);
Serial.print(" (");
Serial.print(client.clientId);
Serial.println(")");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
Serial.print("Uptime: ");
Serial.print((millis() - client.systemStartTime) / 1000);
Serial.println(" seconds");
Serial.println("=== MULTICAST vs BROADCAST vs UNICAST STATISTICS ===");
Serial.print("📡 Multicasts Received: ");
Serial.println(client.totalMulticastsReceived);
Serial.print("📻 Broadcasts Received: ");
Serial.println(client.totalBroadcastsReceived);
Serial.print("📨 Unicasts Received: ");
Serial.println(client.totalUnicastsReceived);
Serial.print("📡 Multicasts Sent: ");
Serial.println(client.totalMulticastsSent);
Serial.print("📻 Broadcasts Sent: ");
Serial.println(client.totalBroadcastsSent);
Serial.print("📨 Unicasts Sent: ");
Serial.println(client.totalUnicastsSent);
Serial.println("=== MULTICAST GROUP MEMBERSHIPS ===");
Serial.print("Total Groups Joined: ");
Serial.println(client.joinedGroups.size());
for (size_t i = 0; i < client.joinedGroups.size(); i++) {
Serial.print(" ");
Serial.print(i + 1);
Serial.print(". ");
Serial.println(client.joinedGroups[i]);
}
Serial.println("=== STREAMING STATISTICS ===");
Serial.print("Stream Packets Received: ");
Serial.println(client.totalStreamPacketsReceived);
Serial.print("Stream Bytes Received: ");
Serial.print(client.totalStreamBytesReceived);
Serial.println(" bytes");
Serial.print("Receiving Streams: ");
Serial.println(client.receivingStreams ? "YES" : "NO");
Serial.print("WiFi Signal: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
Serial.print("Free Heap: ");
Serial.print(ESP.getFreeHeap());
Serial.println(" bytes");
Serial.println("=============================================");
}
void loop() {
unsigned long currentTime = millis();
// Send periodic service discovery requests
if (currentTime - client.lastDiscovery >= DISCOVERY_INTERVAL) {
sendServiceDiscovery();
}
// Send periodic quality reports
if (currentTime - client.lastQualityReport >= QUALITY_REPORT_INTERVAL) {
sendQualityReport();
}
// Print client status periodically
static unsigned long lastStatusPrint = 0;
if (currentTime - lastStatusPrint >= STATS_REPORT_INTERVAL) {
lastStatusPrint = currentTime;
printClientStatus();
}
// Monitor WiFi connection
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠️ WiFi connection lost! Attempting reconnection...");
WiFi.reconnect();
delay(5000);
}
delay(100);
}Expected Output and Testing Results
On the Streaming Server (Main Device), you should see:
- Detection of multicast packets using isMulticast() method
- Distinction between multicast service discovery and unicast responses
- Multicast streaming to different groups (audio, video, data)
- Statistics showing multicast vs broadcast vs unicast packet counts
- Multicast service announcements and group management
On the Client Devices, you should see:
- Successful joining of multiple multicast groups
- Reception and identification of multicast packets from the server
- Multicast discovery requests and service announcements
- Real-time stream reception with quality monitoring
- Clear differentiation between multicast, broadcast, and unicast communications
Key isMulticast() Testing Points:
- Multicast Detection: Verify that isMulticast() correctly identifies multicast packets as true
- Non-Multicast Detection: Confirm that isMulticast() returns false for unicast and broadcast responses
- Group Communication: Check that devices can join multicast groups and receive group-specific content
- Stream Classification: Observe how devices handle different multicast streams (audio, video, data)
- Service Discovery: See how multicast enables efficient service discovery and group management
Simple Multicast Detection Example
This simpler example demonstrates the basic usage of the isMulticast() method for identifying multicast packets in a minimal setup.
/*
* Author: Avant Maker
* Date: June 18, 2025
* Version: 1.0
* License: MIT
*
* Description:
* This example shows basic usage of the isBroadcast() method
* to detect and handle broadcast UDP packets differently from unicast packets.
*
* Code Source:
* This example code is sourced from the Comprehensive Guide
* to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
* For additional code examples and in-depth documentation related to
* the ESP32 Arduino Core Library, please visit:
*
* https://avantmaker.com/home/all-about-esp32-arduino-core-library/
*
* AvantMaker.com, your premier destination for all things
* DIY, IoT, Smart Home, and STEM projects. We are dedicated
* to empowering makers, learners, and enthusiasts with
* the resources they need to bring their innovative ideas to life.
*/
#include <WiFi.h>
#include <AsyncUDP.h>
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
AsyncUDP udp;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("WiFi connected");
Serial.println(WiFi.localIP());
// Listen on port 8888 for any UDP packets
if (udp.listen(8888)) {
Serial.println("UDP Listening on port 8888");
udp.onPacket([](AsyncUDPPacket packet) {
// Extract message
String message = "";
for (size_t i = 0; i < packet.length(); i++) {
message += (char)packet.data()[i];
}
// Use isBroadcast() to check packet type
if (packet.isBroadcast()) {
Serial.println("📡 BROADCAST packet received:");
Serial.print(" From: ");
Serial.println(packet.remoteIP());
Serial.print(" Message: ");
Serial.println(message);
Serial.println(" → This is a broadcast message sent to all devices");
// Send acknowledgment back (unicast response)
packet.printf("ACK: Broadcast received from %s", WiFi.localIP().toString().c_str());
} else {
Serial.println("📨 UNICAST packet received:");
Serial.print(" From: ");
Serial.println(packet.remoteIP());
Serial.print(" Message: ");
Serial.println(message);
Serial.println(" → This is a direct message sent specifically to this device");
}
});
}
}
void loop() {
delay(1000);
}For more ESP32 development resources and tutorials, visit the All About ESP32 Resources Hub on AvantMaker.com
ESP32 Library Index
- ESP32 WiFi Library
- ESP32 WiFiClient Library
- ESP32 HTTPClient Library
- ESP32 WiFiClientSecure Library
- ESP32 WebServer Library
- ESP32 AsyncUDP Librarry
- Connection Management
- Data Transimission
- Broadcast Multicast
- Network Information
- Which ESP32 Boards are Recommended for Learners
- How to Copy Codes from AvantMaker.com
- What is SPIFFS and how to upload files to it?
- What is LIttleFS and how to upload files to it?
Ready to experiment and explore more about ESP32? Visit our website’s All About ESP32 Resources Hub, packed with tutorials, guides, and tools to inspire your maker journey. Experiment, explore, and elevate your skills with everything you need to master this powerful microcontroller platform!