# Signaling Quickstart (/en/realtime-media/rtm/quickstart/linux-java)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

Use Signaling SDK to add low-latency, high-concurrency signaling and synchronization capabilities to your app.

Signaling also helps you enhance the user experience in Video Calling, Voice Calling, Interactive Live Streaming, and Broadcast Streaming applications.

This page shows you how to use the Signaling SDK to rapidly build a simple application that sends and receives messages. It shows you how to integrate the Signaling SDK in your project and implement pub/sub messaging through [Message channels](/en/realtime-media/rtm/build/work-with-channels/message-channel). To get started with stream channels, follow this guide to create a basic Signaling app and then refer to the [Stream channels](/en/realtime-media/rtm/build/work-with-channels/stream-channel) guide.

      
  
      
  
      
  
      
  
      
## Understand the tech

To use Signaling features in your app, you initialize a Signaling client instance and add event listeners. To connect to Signaling, you login using an authentication token. To send a message to a message channel, you publish the message. Signaling creates a channel when a user subscribes to it. To receive messages other users publish to a channel, your app listens for events.

To create a pub/sub session for Signaling, implement the following steps in your app:

<Accordions>
  <Accordion title="Signaling workflow">
    ![Signaling workflow for Linux Java](https://assets-docs.agora.io/images/signaling/get-started-workflow-linux.svg)
  </Accordion>
</Accordions>

## Prerequisites

To implement the code presented on this page you need to have:

* An Agora [account](/en/introduction/account#sign-up-for-an-agora-account) and [project](/en/introduction/account#your-first-agora-project).

* [Enabled Signaling](/en/realtime-media/rtm/enable-signaling) in Agora Console

* A device running Ubuntu 18.04 or Debian 9.9, aarch64 (arm64) or x86-64 architecture.

* Java 8 or above.

* Maven.

* Ensure that a firewall is not blocking your network communication.

<CalloutContainer type="info">
  <CalloutDescription>
    Signaling 2.x is an enhanced version compared to 1.x with a wide range of new features. It follows a new pricing structure. See [Pricing](/en/realtime-media/rtm/reference/pricing) for details.
  </CalloutDescription>
</CalloutContainer>

## Project setup

### Create a project

Create the following folder structure for your project:

```bash
RTM_quickstart/
├── src/main/java/io/agora/
└── lib/
```

### Integrate the SDK using Maven Central

To integrate the Linux Java Signaling SDK into your project using Maven:

1. Create a `pom.xml` file in the `RTM_quickstart` folder with the following content:

   <Accordions>
     <Accordion title="pom.xml">
       ```xml
       <?xml version="1.0" encoding="UTF-8"?>
       <project xmlns="http://maven.apache.org/POM/4.0.0"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
           <modelVersion>4.0.0</modelVersion>

           <groupId>io.agora</groupId>
           <artifactId>RTM-Java-Demo</artifactId>
           <version>1.0-SNAPSHOT</version>

           <properties>
               <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
               <maven.compiler.source>1.8</maven.compiler.source>
               <maven.compiler.target>1.8</maven.compiler.target>
           </properties>

           <!-- [!code highlight:7] -->
           <dependencies>
               <dependency>
                   <groupId>io.agora</groupId>
                   <artifactId>rtm-java-aarch64</artifactId>
                   <version>x.y.z</version>
               </dependency>
           </dependencies>

           <build>
               <plugins>
                   <plugin>
                       <groupId>org.apache.maven.plugins</groupId>
                       <artifactId>maven-shade-plugin</artifactId>
                       <version>3.2.0</version>
                       <executions>
                           <!-- Attach the shade into the package phase -->
                           <execution>
                               <phase>package</phase>
                               <goals>
                                   <goal>shade</goal>
                               </goals>
                               <configuration>
                                   <transformers>
                                       <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                           <mainClass>io.agora.RtmJavaDemo</mainClass>
                                       </transformer>
                                   </transformers>
                               </configuration>
                           </execution>
                       </executions>
                   </plugin>
               </plugins>
           </build>
       </project>
       ```
     </Accordion>
   </Accordions>

   Replace `x.y.z` with the specific SDK version number, such as `2.3.0`. To get the latest version number, check the [Release notes](/en/realtime-media/rtm/reference/release-notes).

   The `artifactId` is architecture-specific. Use `rtm-java-aarch64` for aarch64 (arm64) devices, or `rtm-java-x86_64` for x86-64 devices.

2. Maven doesn't distribute the native libraries the SDK depends on, so [download](/en/api-reference/sdks?product=signaling\&platform=linux-java) the SDK package separately, unzip it, and copy the `*.so` files to the project's `lib` folder.

## Implement Signaling

A complete code sample that implements the basic features of Signaling is presented here for your reference. To use the sample code, copy the following lines into the `src/main/java/io/agora/RtmJavaDemo.java` file.

<Accordions>
  <Accordion title="Complete sample code for Signaling">
    ```java
    package io.agora;

    import java.util.Scanner;
    import io.agora.rtm.*;

    public class RtmJavaDemo {
        // Pass in your App ID and token
        private static final String APP_ID = "<Your App ID>";
        private static final String TOKEN = "<Your token>";

        private RtmClient rtmClient;

        private final RtmEventListener eventListener = new RtmEventListener() {
            @Override
            public void onMessageEvent(MessageEvent event) {
                System.out.println("Message received from " + event.getPublisherId()
                        + ", Message: " + event.getMessage().getData());
            }

            @Override
            public void onPresenceEvent(PresenceEvent event) {
                System.out.println("Received presence event, user: " + event.getPublisherId()
                        + ", Event: " + event.getEventType());
            }

            @Override
            public void onLinkStateEvent(LinkStateEvent event) {
                System.out.println("Connection state changed to " + event.getCurrentState()
                        + ", Reason: " + event.getReason());
            }
        };

        private boolean createClient(String userId) {
            try {
                RtmConfig config = new RtmConfig.Builder(APP_ID, userId)
                        .eventListener(eventListener)
                        .build();
                rtmClient = RtmClient.create(config);
                return true;
            } catch (Exception e) {
                System.out.println("Error creating Signaling client: " + e);
                return false;
            }
        }

        private void login(String token) {
            rtmClient.login(token, new ResultCallback<Void>() {
                @Override
                public void onSuccess(Void responseInfo) {
                    System.out.println("Successfully logged in to Signaling!");
                }

                @Override
                public void onFailure(ErrorInfo errorInfo) {
                    System.out.println("Failed to log in to Signaling: " + errorInfo);
                }
            });
        }

        private void logout() {
            rtmClient.logout(new ResultCallback<Void>() {
                @Override
                public void onSuccess(Void responseInfo) {
                    System.out.println("Successfully logged out.");
                }

                @Override
                public void onFailure(ErrorInfo errorInfo) {
                    System.out.println("Failed to log out: " + errorInfo);
                }
            });
        }

        private void subscribe(String channelName) {
            SubscribeOptions options = new SubscribeOptions();
            options.setWithMessage(true);

            rtmClient.subscribe(channelName, options, new ResultCallback<Void>() {
                @Override
                public void onSuccess(Void responseInfo) {
                    System.out.println("Successfully subscribed to the channel!");
                }

                @Override
                public void onFailure(ErrorInfo errorInfo) {
                    System.out.println("Failed to subscribe to the channel: " + errorInfo);
                }
            });
        }

        private void unsubscribe(String channelName) {
            rtmClient.unsubscribe(channelName, new ResultCallback<Void>() {
                @Override
                public void onSuccess(Void responseInfo) {
                    System.out.println("Successfully unsubscribed from the channel!");
                }

                @Override
                public void onFailure(ErrorInfo errorInfo) {
                    System.out.println("Failed to unsubscribe from the channel: " + errorInfo);
                }
            });
        }

        private void publishMessage(String channelName, String message) {
            PublishOptions options = new PublishOptions();
            options.setCustomType("");

            rtmClient.publish(channelName, message, options, new ResultCallback<Void>() {
                @Override
                public void onSuccess(Void responseInfo) {
                    System.out.println("Message sent to channel " + channelName + ": " + message);
                }

                @Override
                public void onFailure(ErrorInfo errorInfo) {
                    System.out.println("Failed to send message to channel " + channelName + ": " + errorInfo);
                }
            });
        }

        public static void main(String[] args) throws InterruptedException {
            Scanner scanner = new Scanner(System.in);
            RtmJavaDemo demo = new RtmJavaDemo();

            System.out.println("Enter your user ID:");
            String userId = scanner.nextLine();
            if (!demo.createClient(userId)) {
                return;
            }

            demo.login(TOKEN);
            Thread.sleep(1000);

            System.out.println("Enter a channel name to subscribe to:");
            String channelName = scanner.nextLine();
            demo.subscribe(channelName);
            Thread.sleep(1000);

            System.out.println("Type a message to publish, or type 'quit' to log out:");
            String input;
            while (!(input = scanner.nextLine()).equals("quit")) {
                demo.publishMessage(channelName, input);
            }

            demo.unsubscribe(channelName);
            demo.logout();
            Thread.sleep(1000);
            RtmClient.release();
        }
    }
    ```
  </Accordion>
</Accordions>

Follow the implementation steps to understand the core API calls in the sample code or use the snippets in your own code.

### Import Agora classes

To use Signaling APIs in your project, import the relevant Agora classes and interfaces:

```java
import io.agora.rtm.*;
```

### Initialize the Signaling engine

Before calling any other Signaling SDK API, initialize an `RtmClient` object instance:

```java
RtmConfig config = new RtmConfig.Builder(APP_ID, userId)
        .eventListener(eventListener)
        .build();
rtmClient = RtmClient.create(config);
```

### Add an event listener

Add an event listener to receive message, presence, and connection state events:

```java
private final RtmEventListener eventListener = new RtmEventListener() {
    @Override
    public void onMessageEvent(MessageEvent event) {
        // Handle incoming messages
    }

    @Override
    public void onPresenceEvent(PresenceEvent event) {
        // Handle presence events
    }

    @Override
    public void onLinkStateEvent(LinkStateEvent event) {
        // Handle connection state changes
    }
};
```

### Log in to Signaling

To log in to Signaling, call `login` and pass in a token:

```java
rtmClient.login(token, new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void responseInfo) {
        // Handle login success
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        // Handle login failure
    }
});
```

### Publish a message

To send a message to a channel, call `publish`. If no user has subscribed to the channel yet, Signaling creates it:

```java
rtmClient.publish(channelName, message, options, new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void responseInfo) {
        // Handle publish success
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        // Handle publish failure
    }
});
```

### Subscribe and unsubscribe

To receive messages published to a channel, call `subscribe`:

```java
SubscribeOptions options = new SubscribeOptions();
options.setWithMessage(true);

rtmClient.subscribe(channelName, options, new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void responseInfo) {
        // Handle subscribe success
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        // Handle subscribe failure
    }
});
```

When you no longer need to receive messages from a channel, call `unsubscribe`:

```java
rtmClient.unsubscribe(channelName, new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void responseInfo) {
        // Handle unsubscribe success
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        // Handle unsubscribe failure
    }
});
```

### Log out of Signaling

When you no longer need to use Signaling, log out and release the client instance:

```java
rtmClient.logout(new ResultCallback<Void>() {
    @Override
    public void onSuccess(Void responseInfo) {
        // Handle logout success
    }

    @Override
    public void onFailure(ErrorInfo errorInfo) {
        // Handle logout failure
    }
});

RtmClient.release();
```

## Test Signaling

Take the following steps to test the sample code:

1. [Generate a temporary token](/en/introduction/account#generate-temporary-tokens) for your project.

2. In your code, replace `<Your App ID>` with your app ID from Agora Console and `<Your token>` with the generated token. Make sure Signaling is activated for your project in [Agora Console](https://console.agora.io/).

3. In the terminal, run the following commands to compile the project:

   ```bash
   mvn clean
   mvn package
   ```

4. Set the library path and run the app:

   ```bash
   export LD_LIBRARY_PATH=<path to your lib folder>
   java -jar target/RTM-Java-Demo-1.0-SNAPSHOT.jar
   ```

5. Follow the prompts to log in and **subscribe** to a channel.

6. Run another instance of the app using a different user ID. Follow the prompts to **publish** a message to the same channel that you subscribed to from the other instance.

7. You see the message displayed in the instance that you used to subscribe to the channel.

   Congratulations! You have successfully integrated Signaling into your project.

## Reference

This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

### Token authentication

In this guide you retrieve a temporary token from Agora Console. To understand how to create an authentication server for development purposes, see [Secure authentication with tokens](./build/connect-and-authenticate/authentication-workflow).

### Sample project

Agora provides an open source [sample project](https://github.com/AgoraIO/RTM2/tree/main/Agora-RTM2-QuickStart-Linux-Java) on GitHub for your reference. Download it or view the source code for a more detailed example.

### API reference

* [API reference](/en/api-reference/api-ref/signaling)
* [Event listeners](./build/send-and-receive-messages/add-event-listener)

    
  
      
  
      
  
