Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 245 additions & 0 deletions packages/calling/src/CallingClient/ai-docs/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
# CallingClient Module

## AI Agent Routing Instructions
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something we could add in README.md or root AGENTS.md and we do not need to add this every AGENTS.md file

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have simplified it a bit. This will be a bit redundant for now. We can groom it once we have all the spec files in place

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still feel this is not needed


**If you are an AI assistant or automated tool:**

Do **not** use this file as your only entry point for reasoning or code generation.

- **How to proceed:**
- For changes within the `line/` subdirectory, also load [line/ai-docs/AGENTS.md](../line/ai-docs/AGENTS.md).
- For changes within the `registration/` subdirectory, also load [registration/ai-docs/AGENTS.md](../registration/ai-docs/AGENTS.md).
- For changes within the `calling/` subdirectory (Call, CallManager, CallerId), refer to the calling subdirectory source files directly.
- **Important:** Load the module-specific docs in this file first, then drill into subdirectory docs as needed.

---

## Overview

The `CallingClient` is one of the significant modules in the Webex Calling SDK, responsible for the main WebRTC call flow implementation. It manages line registration, call lifecycle coordination, Mobius server discovery, and network resilience.

Applications create a `CallingClient` via the `createClient()` factory function and interact with lines and calls through it.

**Package:** `@webex/calling`

**Entry point:** `packages/calling/src/CallingClient/CallingClient.ts`

**Factory:** `createClient(webex, config?) → ICallingClient`

---

### Key Capabilities

| Capability | Description |
| ----------- | ----------- |
| **Mobius Discovery** | Performs region-based Mobius server discovery to select optimal primary and backup endpoints for registration, calls, and media. |
| **Line Registration** | Creates and registers Lines with Mobius, establishing signaling sessions, subscribing for events, and managing registration/status. Includes Line keepalives and failover routines. |
| **Media Engine Management** | Initializes and configures the `@webex/internal-media-core` engine to negotiate, establish, and manage WebRTC media streams for audio and video calls. |
| **Call Keepalive** | Periodically sends keepalive messages for both Lines and active Calls, ensuring session continuity and timely detection of network or signaling issues. |
| **Call Control** | Orchestrates all aspects of call initiation, handling, and features. Divided into the following subcapabilities: |
|   • Outbound Calls | Enables agents to initiate outbound calls using `line.makeCall()`. Handles call setup, signaling, and media path establishment, including error cases. |
Comment thread
Kesari3008 marked this conversation as resolved.
|   • Inbound Calls | Receives and processes incoming calls via `LINE_EVENTS.INCOMING_CALL`, triggers session setup, and allocates resources for the new call. |
|   • Supplementary Services | Provides additional in-call features including hold, resume, transfer, mute, and sending DTMF using `ICall` interface methods and underlying SIP signaling. Hold and resume suspend and reestablish the audio+video media while maintaining session context. Transfer allows the redirection of calls to alternate destinations. |
| **Active Call Monitoring** | Monitors and tracks all ongoing calls, connection state (connected, held, disconnected), participant media status, and synchronization across lines and devices. |
| **Network Resilience** | Detects network outages or Mercury channel disconnects; triggers reconnection, re-registration, and call state recovery logic to restore service with minimal interruption. |
| **Diagnostics & Logging** | Collects and uploads diagnostic logs and metrics for calls, registrations, and failures to Webex cloud for troubleshooting, monitoring, and analytics purposes. |
| **Service Indicators & Access Flows** | Supports various service flows and user types (`calling`, `guestcalling`, `contactcenter`) through the `ServiceIndicator`, enabling correct registration and feature availability based on license and context. |

---

## Public API

### ICallingClient Interface

The following methods are defined on the `ICallingClient` interface and are the officially supported public API:

| Method | Signature | Description |
| ------------------ | ------------------------------------------ | ----------------------------------------------- |
| `getSDKConnector` | `(): ISDKConnector` | Returns the SDK connector singleton |
| `getLoggingLevel` | `(): LOGGER` | Returns the current log level |
| `getLines` | `(): Record<string, ILine>` | Returns all the lines |
| `getDevices` | `(userId?: string): Promise<DeviceType[]>` | Fetches devices from Mobius for the user |
| `getActiveCalls` | `(): Record<string, ICall[]>` | Returns active calls grouped by lineId |
| `getConnectedCall` | `(): ICall \| undefined` | Returns the currently connected (non-held) call |
| `mediaEngine` | `typeof Media` | The `@webex/internal-media-core` engine |

### CallingClient Class Methods (not on ICallingClient interface)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of saying not on ICallingClient interface, we should simply talk about where its imported from

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have uploadLogs defined inside the CallingClient which uses the uploadLogs from util

  /**
   * Uploads logs to help troubleshoot SDK issues.
   *
   * This method collects the current SDK logs including network requests, WebSocket
   * messages, and client-side events, then securely submits them to Webex's diagnostics
   * service. The returned tracking ID, feedbackID can be provided to Webex support for faster
   * issue resolution.
   * @returns Promise<UploadLogsResponse>
   * @throws Error
   */
  public async uploadLogs(): Promise<UploadLogsResponse> {
    const result = await uploadLogs({}, true);
    if (!result) {
      throw new Error('Failed to upload logs: No response received.');
    }

    return result;
  }


| Method | Signature | Description |
| ------------ | --------------------------------- | ---------------------------------------------------- |
| `uploadLogs` | `(): Promise<UploadLogsResponse>` | Uploads diagnostic logs to Webex (class method only) |

### Events Emitted

| Event | Enum Key | Payload | Description |
| ------------------------------------ | --------------------------------------------- | -------------------- | ---------------------------- |
| `callingClient:error` | `CALLING_CLIENT_EVENT_KEYS.ERROR` | `CallingClientError` | Client-level error |
| `callingClient:outgoing_call` | `CALLING_CLIENT_EVENT_KEYS.OUTGOING_CALL` | `string` (callId) | Outbound call initiated |
Comment thread
Kesari3008 marked this conversation as resolved.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove unsupported outgoing_call client event from API table

This event is documented as emitted, but the runtime does not dispatch it: CallingClient emits ERROR and USER_SESSION_INFO, and CallManager emits ALL_CALLS_CLEARED; there is no emit(CALLING_CLIENT_EVENT_KEYS.OUTGOING_CALL) path. Applications that subscribe to callingClient:outgoing_call based on this table will never receive callbacks, which can break outbound-call telemetry and UI state handling.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting this point. We will need to fix the code as well

| `callingClient:user_recent_sessions` | `CALLING_CLIENT_EVENT_KEYS.USER_SESSION_INFO` | `CallSessionEvent` | User session info from Janus |
| `callingClient:all_calls_cleared` | `CALLING_CLIENT_EVENT_KEYS.ALL_CALLS_CLEARED` | _(none)_ | All active calls have ended |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove unsupported all_calls_cleared client event

This table documents callingClient:all_calls_cleared as a CallingClient event, but CallingClient never emits it: registerCallsClearedListener() only subscribes to callManager and runs callsClearedHandler, while the actual emit occurs inside CallManager.createCall() when the collection is emptied. Apps that subscribe on callingClient.on('callingClient:all_calls_cleared', ...) based on this doc will never receive callbacks.

Useful? React with 👍 / 👎.


---

## Configuration

### CallingClientConfig

```typescript
interface CallingClientConfig {
logger?: {level: LOGGER};
discovery?: {country: string; region: string};
serviceData?: {indicator: ServiceIndicator; domain?: string};
jwe?: string;
}
```

| Property | Required | Default | Description |
| ----------------------- | -------- | ------------- | ----------------------------------------------------------- |
| `logger.level` | No | `ERROR` | Log verbosity level |
| `discovery.country` | No | Auto-detected | Override country for Mobius discovery |
| `discovery.region` | No | Auto-detected | Override region for Mobius discovery |
| `serviceData.indicator` | No | `CALLING` | Service flow: `calling`, `guestcalling`, or `contactcenter` |
| `serviceData.domain` | No | `''` | RTMS domain required for contact center flow |
| `jwe` | No | - | JSON Web Encryption token having destination information. This is only required for guest calling flow |

---

## Examples and Use Cases

### Getting Started

#### Create and Initialize a CallingClient

```typescript
import {createClient, ServiceIndicator} from '@webex/calling';

const callingClient = await createClient(webex, {
logger: {level: 'info'},
serviceData: {indicator: ServiceIndicator.CALLING, domain: ''},
});
```

The `createClient` factory instantiates `CallingClient` and calls `init()`, which:

1. Performs ICE warmup (Windows Chromium only)
Comment thread
Shreyas281299 marked this conversation as resolved.
2. Discovers Mobius servers for the client region (via `ds.ciscospark.com`)
3. Creates a Line object internally

**Note:** `init()` does NOT register the line. The application must call `line.register()` explicitly after obtaining the line via `getLines()`.

#### Register a Line and Listen for Events

```typescript
const lines = callingClient.getLines();
const line = Object.values(lines)[0];

line.on('registered', (registeredLine) => {
console.log('Line registered:', registeredLine.lineId);
console.log('Phone number:', registeredLine.phoneNumber);
});

line.on('error', (error) => {
console.error('Line error:', error.getError());
});

line.on('line:incoming_call', (call) => {
console.log('Incoming call from:', call.getCallerInfo());
call.answer(localAudioStream);
});

line.register();
```

#### Make an Outbound Call

```typescript
const callDetails = {type: 'uri', address: 'sip:user@example.com'};
const call = line.makeCall(callDetails);
Comment on lines +156 to +157
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use a dialable address in outbound call example

This quick-start example uses address: 'sip:user@example.com', but Line.makeCall() validates dest.address with VALID_PHONE_REGEX and only accepts dialable number formats before converting to tel:; a SIP URI like this is rejected, emits LINE_EVENTS.ERROR, and returns undefined. Users copying this snippet will fail to place a call immediately.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct. No change required


call.on('connect', (callId) => {
console.log('Call connecting:', callId);
});

call.on('established', (callId) => {
console.log('Call established:', callId);
});

call.on('disconnect', (callId) => {
console.log('Call ended:', callId);
});

call.dial(localAudioStream);
```

#### Handle Network Disruptions

```typescript
line.on('reconnecting', () => {
console.log('Network disruption — attempting to reconnect...');
});

line.on('reconnected', () => {
console.log('Successfully reconnected to Mobius');
});
```

#### Upload Diagnostic Logs

```typescript
try {
const response = await callingClient.uploadLogs();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove unsupported uploadLogs call from quick-start snippet

This example calls callingClient.uploadLogs(), but createClient() is typed to return Promise<ICallingClient> and ICallingClient does not expose uploadLogs; TypeScript users copying this snippet will get a property-missing compile error unless they cast to the concrete CallingClient class. Please either show class-level usage explicitly or replace this with an API that exists on ICallingClient.

Useful? React with 👍 / 👎.

console.log('Logs uploaded:', response);
} catch (error) {
console.error('Log upload failed:', error);
}
```

#### Query Active Calls and Devices

```typescript
const activeCalls = callingClient.getActiveCalls();
const connectedCall = callingClient.getConnectedCall();
const devices = await callingClient.getDevices();
```

---

## Dependencies

### Runtime Dependencies

| Package | Purpose |
| -------------------------------- | ------------------------------------------- |
| `@webex/internal-media-core` | WebRTC, ROAP media connections |
| `@webex/media-helpers` | Microphone stream, noise reduction |
| `@webex/internal-plugin-metrics` | Telemetry and metrics |
| `async-mutex` | Concurrency control for registration |
| `xstate` | State machines for call and media lifecycle |
| `uuid` | Unique identifier generation |

### Internal Dependencies

| Module | Purpose |
| --------------- | --------------------------------------------------- |
| `SDKConnector` | Singleton bridge to Webex SDK and Mercury WebSocket |
| `CallManager` | Singleton managing all active Call instances |
| `MetricManager` | Singleton for telemetry submission |
| `Logger` | Structured logging with file/method context |
| `Eventing<T>` | Typed event emitter base class |

---

## Subdirectory Documentation

For detailed documentation on specific subsystems:

| Subdirectory | AGENTS.md | ARCHITECTURE.md | Description |
| --------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| `line/` | [line/ai-docs/AGENTS.md](../line/ai-docs/AGENTS.md) | [line/ai-docs/ARCHITECTURE.md](../line/ai-docs/ARCHITECTURE.md) | Line management, registration orchestration, call initiation |
| `registration/` | [registration/ai-docs/AGENTS.md](../registration/ai-docs/AGENTS.md) | [registration/ai-docs/ARCHITECTURE.md](../registration/ai-docs/ARCHITECTURE.md) | Device registration, keepalive, failover, web worker |

---

## Related Documentation

- [Architecture](./ARCHITECTURE.md) — Component overview, data flows, sequence diagrams
Comment thread
Kesari3008 marked this conversation as resolved.
Loading
Loading