Skip to content

Жизненный цикл звонка

Звонок проходит через несколько этапов от инициализации до завершения.

Схема жизненного цикла

┌─────────────┐
│   init()    │  ← Инициализация SDK
└──────┬──────┘

┌──────▼──────┐
│ authorize() │  ← Авторизация (для не-анонимов)
└──────┬──────┘

   ┌───┴───┐
   │       │
┌──▼───┐ ┌─▼──────────────┐
│callTo│ │joinCallByLink  │  ← Создание или присоединение
└──┬───┘ └─┬──────────────┘
   │       │
   └───┬───┘

┌──────▼──────┐
│ onConversation │  ← Звонок активен
└──────┬──────┘

    Коллбэки

┌──────▼──────┐
│   hangup()  │  ← Завершение
└─────────────┘

1. Инициализация

javascript
import * as SDK from '@vkontakte/calls-sdk';

// Проверка поддержки браузера
if (!SDK.browser.isBrowserSupported()) {
    console.error('Браузер не поддерживается');
    return;
}

// Инициализация с коллбэками
await SDK.init({
    apiKey: API_APP_KEY,
    
    // Локальный стрим готов
    onLocalStream: (stream, mediaSettings) => {
        videoElement.srcObject = stream;
    },
    
    // Информация о звонке получена
    onConversation: (externalId, mediaModifiers, muteStates, participants, rooms) => {
        console.log('Вошли в звонок');
    },
    
    // Звонок завершён
    onHangup: (type, conversationId) => {
        console.log('Звонок завершён:', type);
    },
    
    // ...другие коллбэки
});

2. Авторизация

javascript
// Для авторизованных пользователей
await SDK.authorize(authTokenFromBackend);

// Для анонимных - токен передаётся в init()
// authorize() вызывать не нужно

3. Создание или присоединение к звонку

Создать новый звонок

javascript
import { MediaOption, ExternalIdType } from '@vkontakte/calls-sdk';

// Звонок конкретным пользователям
const conversation = await SDK.callTo(
    [{ id: 'user123', type: ExternalIdType.USER }],
    [MediaOption.AUDIO, MediaOption.VIDEO]
);

// Звонок с созданием ссылки для подключения
const conversation = await SDK.callTo(
    [],  // без участников
    [MediaOption.AUDIO],
    '',   // payload
    true  // создать ссылку
);
console.log('Ссылка:', conversation.joinLink);

Присоединиться к существующему звонку

javascript
// По ссылке
await SDK.joinCallByLink(
    joinLink,
    [MediaOption.AUDIO, MediaOption.VIDEO]
);

// По ID звонка
await SDK.joinCall(
    conversationId,
    [MediaOption.AUDIO]
);

4. Активный звонок

Во время звонка SDK вызывает коллбэки для различных событий:

javascript
await SDK.init({
    // Стримы
    onLocalStream: (stream, mediaSettings) => {},
    onRemoteStream: (userId, stream) => {},
    onScreenStream: (stream, mediaSettings) => {},
    onRemoteScreenStream: (userId, stream) => {},
    
    // Участники
    onRemoteStatus: (userIds, status, data) => {},
    onRemoteMediaSettings: (userId, mediaSettings) => {},
    onRemoteRemoved: (userId) => {},
    
    // Состояние
    onLocalStatus: (status) => {},
    onCallState: (isCallActive, canAddParticipants, conversation) => {},
    
    // ...
});

Управление медиа

javascript
// Включить/выключить камеру
await SDK.toggleLocalVideo(true);
await SDK.toggleLocalVideo(false);

// Включить/выключить микрофон
await SDK.toggleLocalAudio(true);
await SDK.toggleLocalAudio(false);

// Демонстрация экрана
await SDK.captureScreen(true);
await SDK.captureScreen(false);

5. Завершение звонка

Инициировать завершение

javascript
await SDK.hangup();

Обработка завершения

javascript
await SDK.init({
    // ...
    onHangup: (type, conversationId) => {
        // type может быть:
        // - HangupType.HANGUP - нормальное завершение
        // - HangupType.DECLINED - отклонён
        // - HangupType.BUSY - занято
        // - HangupType.TIMEOUT - таймаут
        // - HangupType.FAILED - ошибка
        // - HangupReason с деталями ошибки
        
        // Очистить UI
        cleanupCall();
    }
});

Очистка состояния

После onHangup рекомендуется:

  • Очистить список участников
  • Остановить все медиапотоки
  • Сбросить UI в исходное состояние
javascript
function cleanupCall() {
    participants = [];
    localStream = null;
    isInCall = false;
}

Обработка ошибок

javascript
try {
    await SDK.callTo(/* ... */);
} catch (error) {
    if (error instanceof SDK.HangupReason) {
        switch (error.hangup) {
            case SDK.HangupType.FAILED:
                console.error('Не удалось подключиться');
                break;
            case SDK.FatalError.UNSUPPORTED:
                console.error('Браузер не поддерживается');
                break;
        }
    }
}

Переподключение

SDK автоматически пытается переподключиться при потере соединения. Статус можно отслеживать через onLocalStatus:

javascript
await SDK.init({
    // ...
    onLocalStatus: (status) => {
        // ParticipantStatus.CONNECTING - переподключение
        // ParticipantStatus.CONNECTED - подключен
        
        if (status === ParticipantStatus.CONNECTING) {
            showReconnectingUI();
        }
    }
});