allgram Meet - Enterprise-Grade Video Conferencing Platform

Build secure, scalable, and feature-rich video conferencing applications with our comprehensive meeting API. From P2P technology to AI-powered scheduling, from HD video calls to seamless calendar integration.

allgram Meet provides enterprise-level security, GDPR compliance, and seamless integration with popular platforms. Perfect for businesses, developers, and organizations requiring professional video conferencing solutions.

P2P Security

E2EE, FIPS 140-2, GDPR compliant

HD Video Quality

Jitsi Meet SDK, WebRTC, instant delivery

AI Scheduling

Smart calendar, time zones, automation

  • Quick Start Guide
  • Node.js
    Server-side implementation with Express.js, Jitsi Meet SDK, and comprehensive API integration

  • Swift
    iOS native development with UIKit/SwiftUI, real-time video calls, and secure P2P implementation

  • Kotlin
    Android development with Jetpack Compose, WebRTC integration, and P2P video capabilities

  • WebRTC
    P2P video communication, data channels, and real-time media streaming

  • Calendar Integration
    Event management, AI scheduling, time zones, and participant coordination

  • Additional Resources
    Security, performance, API reference, and community support

  • Meet Services
    Explore enterprise features, pricing, and integration options
  • Licensing
    Commercial licenses, compliance, and enterprise agreements
  • Full Documentation
    Complete API reference, tutorials, and best practices

Node.js Integration

Build robust video conferencing applications with Node.js and Express.js. Our comprehensive API provides real-time video calls, Jitsi Meet SDK integration, and enterprise-grade security features. Perfect for building scalable backend services and real-time meeting applications.

  • Full API Support: Complete REST API with Jitsi Meet SDK integration
  • Enterprise Security: E2EE, P2P technology, FIPS 140-2, GDPR compliance
  • Real-time Performance: WebSocket-based instant video communication
  • Scalable Architecture: Built for high-load production environments
Explore Meet Services

// allgram Meet Node.js Integration Example
const express = require('express');
const WebSocket = require('ws');
const crypto = require('crypto');
const axios = require('axios');

class allgramMeetClient {
    constructor(apiKey, baseUrl = 'https://api.allgram.best') {
        this.apiKey = apiKey;
        this.baseUrl = baseUrl;
        this.ws = null;
        this.meetings = new Map();
        this.jitsiConfig = {
            domain: 'meet.allgram.best',
            configOverwrite: {
                startWithVideoMuted: true,
                startAudioOnly: false,
                videoQuality: {
                    persist: true,
                    codecPreferenceOrder: ['VP8', 'VP9', 'H264']
                }
            }
        };
    }

    // Initialize WebSocket connection for real-time updates
    async connectWebSocket() {
        try {
            this.ws = new WebSocket(`wss://api.allgram.best/ws/meetings/`);

            this.ws.on('open', () => {
                console.log('✅ WebSocket connected for meetings');
                // Authenticate with API key
                this.ws.send(JSON.stringify({
                    type: 'auth',
                    api_key: this.apiKey
                }));
            });

            this.ws.on('message', (data) => {
                this.handleWebSocketMessage(JSON.parse(data));
            });

            this.ws.on('error', (error) => {
                console.error('WebSocket error:', error);
                this.reconnect();
            });

        } catch (error) {
            console.error('Failed to connect WebSocket:', error);
        }
    }

    // Create a new meeting with calendar integration
    async createMeeting(name, description, participants, startTime, endTime, isP2P = false) {
        try {
            const response = await axios.post(`${this.baseUrl}/meetings/create`, {
                meeting_name: name,
                meeting_description: description,
                participants: participants,
                start_datetime: startTime,
                end_datetime: endTime,
                is_p2p: isP2P,
                is_public: false,
                max_participants: 50
            }, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                }
            });

            if (response.status === 200) {
                const meeting = response.data;
                this.meetings.set(meeting.meeting_id, meeting);
                console.log(`✅ Meeting created: ${meeting.meeting_name}`);
                return meeting;
            }
        } catch (error) {
            console.error('Failed to create meeting:', error.response?.data || error.message);
            throw error;
        }
    }

    // Generate Jitsi Meet room configuration
    generateJitsiConfig(meetingId, isP2P = false) {
        const roomName = `meet_${meetingId}_${Date.now()}`;

        const config = {
            ...this.jitsiConfig,
            roomName: roomName,
            configOverwrite: {
                ...this.jitsiConfig.configOverwrite,
                p2p: {
                    enabled: isP2P,
                    preferH264: true,
                    disableH264: false
                }
            }
        };

        return config;
    }

    // Handle WebSocket messages for meetings
    handleWebSocketMessage(message) {
        if (message.content.action) {
            this.handleSystemEvent(message);
        } else if (message.content.meeting_data) {
            this.handleMeetingUpdate(message);
        }
    }

    // Handle system events
    handleSystemEvent(message) {
        switch (message.content.action) {
            case 'participant_joined':
                console.log(`👥 Participant joined meeting: ${message.participant}`);
                break;
            case 'meeting_started':
                console.log(`🎬 Meeting started: ${message.meeting_id}`);
                break;
            case 'meeting_ended':
                console.log(`🏁 Meeting ended: ${message.meeting_id}`);
                this.updateMeetingStatus(message.meeting_id, 'ended');
                break;
        }
    }

    // Handle meeting updates
    handleMeetingUpdate(message) {
        const meetingId = message.meeting_id;
        const meetingData = message.content.meeting_data;

        if (this.meetings.has(meetingId)) {
            const meeting = this.meetings.get(meetingId);
            Object.assign(meeting, meetingData);
            this.meetings.set(meetingId, meeting);
            console.log(`📊 Meeting updated: ${meetingId}`);
        }
    }

    // Update meeting status
    updateMeetingStatus(meetingId, status) {
        if (this.meetings.has(meetingId)) {
            const meeting = this.meetings.get(meetingId);
            meeting.status = status;
            meeting.end_time = new Date().toISOString();
            this.meetings.set(meetingId, meeting);
        }
    }

    // Get meeting analytics
    async getMeetingAnalytics(meetingId) {
        try {
            const response = await axios.get(`${this.baseUrl}/meetings/${meetingId}/analytics`, {
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`
                }
            });

            if (response.status === 200) {
                return response.data;
            }
        } catch (error) {
            console.error('Failed to get meeting analytics:', error.response?.data || error.message);
            throw error;
        }
    }

    // Reconnection logic
    reconnect() {
        setTimeout(() => {
            console.log('🔄 Attempting to reconnect...');
            this.connectWebSocket();
        }, 5000);
    }
}

// Usage example
const meetClient = new allgramMeetClient('your-api-key-here');

// Initialize connection
meetClient.connectWebSocket();

// Create a P2P meeting
const startTime = new Date(Date.now() + 30 * 60 * 1000); // 30 minutes from now
const endTime = new Date(startTime.getTime() + 60 * 60 * 1000); // 1 hour duration

meetClient.createMeeting(
    'Team Standup',
    'Daily team synchronization meeting',
    ['user1', 'user2', 'user3'],
    startTime.toISOString(),
    endTime.toISOString(),
    true // Enable P2P
).then(meeting => {
    console.log('Meeting created successfully:', meeting);

    // Generate Jitsi configuration
    const jitsiConfig = meetClient.generateJitsiConfig(meeting.meeting_id, true);
    console.log('Jitsi configuration:', jitsiConfig);
}).catch(error => {
    console.error('Failed to create meeting:', error);
});
                                    

Key Features & Benefits

Our Node.js integration provides enterprise-grade video conferencing capabilities with minimal setup. Built on proven technologies like Express.js and Jitsi Meet SDK, it offers exceptional performance and reliability for production applications.

  • Jitsi Meet SDK Integration: Professional video conferencing with custom configuration
  • P2P Technology: Direct peer-to-peer communication for enhanced security
  • Calendar Integration: Seamless event management and scheduling
  • Real-time Updates: WebSocket-based instant meeting notifications
View Licensing Options

Swift iOS Integration

Build native iOS video conferencing applications with Swift and SwiftUI. Our iOS SDK provides seamless integration with UIKit and SwiftUI, real-time video calls, and secure P2P implementation. Perfect for creating professional iOS meeting applications with modern design patterns.

  • Native iOS Support: Full SwiftUI and UIKit compatibility
  • Real-time Video Calls: Jitsi Meet SDK integration with custom UI
  • Secure P2P: Military-grade encryption for sensitive meetings
  • Modern Architecture: MVVM, Combine, and async/await support
Explore Meet Services

// allgram Meet Swift iOS Integration Example
import SwiftUI
import Combine
import CryptoKit
import JitsiMeetSDK

// MARK: - Meeting Models
struct Meeting: Codable, Identifiable {
    let id: String
    let name: String
    let description: String
    let isP2P: Bool
    let participants: [String]
    let startTime: Date
    let endTime: Date
    let maxParticipants: Int
    let status: MeetingStatus

    enum CodingKeys: String, CodingKey {
        case id = "meeting_id"
        case name = "meeting_name"
        case description = "meeting_description"
        case isP2P = "is_p2p"
        case participants
        case startTime = "start_datetime"
        case endTime = "end_datetime"
        case maxParticipants = "max_participants"
        case status
    }
}

enum MeetingStatus: String, Codable {
    case scheduled = "scheduled"
    case active = "active"
    case ended = "ended"
    case cancelled = "cancelled"
}

struct Participant: Codable, Identifiable {
    let id: String
    let username: String
    let displayName: String
    let avatar: String?
    let isHost: Bool
    let joinTime: Date?

    enum CodingKeys: String, CodingKey {
        case id = "user_id"
        case username
        case displayName = "display_name"
        case avatar
        case isHost = "is_host"
        case joinTime = "join_time"
    }
}

// MARK: - Meet Service
class allgramMeetService: ObservableObject {
    @Published var meetings: [Meeting] = []
    @Published var currentMeeting: Meeting?
    @Published var participants: [Participant] = []
    @Published var isConnected = false
    @Published var meetingStatus: MeetingStatus = .scheduled

    private var webSocket: URLSessionWebSocketTask?
    private var cancellables = Set<AnyCancellable>()
    private let baseURL = "https://api.allgram.best"
    private let apiKey: String
    private var jitsiMeetView: JitsiMeetView?

    init(apiKey: String) {
        self.apiKey = apiKey
        setupWebSocket()
    }

    // MARK: - WebSocket Setup
    private func setupWebSocket() {
        guard let url = URL(string: "wss://api.allgram.best/ws/meetings/") else { return }

        let session = URLSession(configuration: .default)
        webSocket = session.webSocketTask(with: url)
        webSocket?.resume()

        // Authenticate
        let authMessage = WebSocketMessage(type: "auth", apiKey: apiKey)
        sendWebSocketMessage(authMessage)

        // Start receiving messages
        receiveMessage()
    }

    // MARK: - Meeting Management
    func createMeeting(name: String, description: String, participants: [String], startTime: Date, endTime: Date, isP2P: Bool = false) async throws -> Meeting {
        let url = URL(string: "\(baseURL)/meetings/create")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        let meetingData = [
            "meeting_name": name,
            "meeting_description": description,
            "participants": participants,
            "start_datetime": ISO8601DateFormatter().string(from: startTime),
            "end_datetime": ISO8601DateFormatter().string(from: endTime),
            "is_p2p": isP2P,
            "is_public": false,
            "max_participants": 50
        ]

        request.httpBody = try JSONSerialization.data(withJSONObject: meetingData)

        let (data, response) = try await URLSession.shared.data(for: request)

        guard let httpResponse = response as? HTTPURLResponse,
              httpResponse.statusCode == 200 else {
            throw MeetError.serverError
        }

        let meeting = try JSONDecoder().decode(Meeting.self, from: data)

        DispatchQueue.main.async {
            self.meetings.append(meeting)
        }

        return meeting
    }

    // MARK: - Jitsi Meet Integration
    func joinMeeting(_ meeting: Meeting) {
        let options = JitsiMeetConferenceOptions.fromBuilder { builder in
            builder.room = "meet_\(meeting.id)_\(Date().timeIntervalSince1970)"
            builder.serverURL = URL(string: "https://meet.allgram.best")

            // P2P configuration
            if meeting.isP2P {
                builder.p2pEnabled = true
                builder.preferH264 = true
            }

            // Video quality settings
            builder.videoMuted = false
            builder.audioMuted = false

            // User information
            builder.userInfo = JitsiMeetUserInfo()
            builder.userInfo?.displayName = "iOS User"
            builder.userInfo?.email = "user@example.com"
        }

        // Present Jitsi Meet view
        DispatchQueue.main.async {
            self.meetingStatus = .active
            self.currentMeeting = meeting
            self.presentJitsiMeet(options: options)
        }
    }

    private func presentJitsiMeet(options: JitsiMeetConferenceOptions) {
        // This would typically be presented modally or in a navigation stack
        // Implementation depends on your app's navigation structure
        print("🎬 Joining meeting with options: \(options)")
    }

    // MARK: - WebSocket Communication
    private func sendWebSocketMessage(_ message: WebSocketMessage) {
        guard let data = try? JSONEncoder().encode(message),
              let jsonString = String(data: data, encoding: .utf8) else { return }

        let wsMessage = URLSessionWebSocketTask.Message.string(jsonString)
        webSocket?.send(wsMessage) { error in
            if let error = error {
                print("❌ Failed to send WebSocket message: \(error)")
            }
        }
    }

    private func receiveMessage() {
        webSocket?.receive { [weak self] result in
            switch result {
            case .success(let message):
                self?.handleWebSocketMessage(message)
                self?.receiveMessage() // Continue receiving
            case .failure(let error):
                print("❌ WebSocket receive error: \(error)")
                DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                    self?.reconnect()
                }
            }
        }
    }

    private func handleWebSocketMessage(_ message: URLSessionWebSocketTask.Message) {
        switch message {
        case .string(let text):
            guard let data = text.data(using: .utf8),
                  let wsMessage = try? JSONDecoder().decode(WebSocketMessage.self, from: data) else { return }

            DispatchQueue.main.async {
                self.processWebSocketMessage(wsMessage)
            }
        default:
            break
        }
    }

    private func processWebSocketMessage(_ message: WebSocketMessage) {
        if let action = message.action {
            handleSystemEvent(action, message: message)
        } else if message.content?.meetingData != nil {
            handleMeetingUpdate(message)
        }
    }

    private func handleSystemEvent(_ action: String, message: WebSocketMessage) {
        switch action {
        case "participant_joined":
            print("👥 Participant joined meeting: \(message.participant ?? "Unknown")")
            if let participant = message.participant {
                addParticipant(participant)
            }
        case "meeting_started":
            print("🎬 Meeting started: \(message.meetingId ?? "Unknown")")
            DispatchQueue.main.async {
                self.meetingStatus = .active
            }
        case "meeting_ended":
            print("🏁 Meeting ended: \(message.meetingId ?? "Unknown")")
            DispatchQueue.main.async {
                self.meetingStatus = .ended
                self.currentMeeting = nil
            }
        default:
            break
        }
    }

    private func handleMeetingUpdate(_ message: WebSocketMessage) {
        guard let meetingId = message.meetingId,
              let meetingData = message.content?.meetingData else { return }

        // Update meeting data
        if let index = meetings.firstIndex(where: { $0.id == meetingId }) {
            DispatchQueue.main.async {
                // Update meeting with new data
                // Implementation depends on your data structure
                print("📊 Meeting updated: \(meetingId)")
            }
        }
    }

    private func addParticipant(_ username: String) {
        let participant = Participant(
            id: UUID().uuidString,
            username: username,
            displayName: username,
            avatar: nil,
            isHost: false,
            joinTime: Date()
        )

        DispatchQueue.main.async {
            self.participants.append(participant)
        }
    }

    // MARK: - Utility Methods
    private func reconnect() {
        print("🔄 Attempting to reconnect...")
        setupWebSocket()
    }
}

// MARK: - WebSocket Message Model
struct WebSocketMessage: Codable {
    let type: String?
    let apiKey: String?
    let meetingId: String?
    let participant: String?
    let content: MessageContent?
    let action: String?

    enum CodingKeys: String, CodingKey {
        case type
        case apiKey = "api_key"
        case meetingId = "meeting_id"
        case participant
        case content
        case action
    }
}

struct MessageContent: Codable {
    let meetingData: [String: Any]?

    enum CodingKeys: String, CodingKey {
        case meetingData = "meeting_data"
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        meetingData = try container.decodeIfPresent([String: Any].self, forKey: .meetingData)
    }
}

// MARK: - Error Handling
enum MeetError: Error, LocalizedError {
    case serverError
    case networkError
    case authenticationError

    var errorDescription: String? {
        switch self {
        case .serverError:
            return "Server error occurred"
        case .networkError:
            return "Network connection failed"
        case .authenticationError:
            return "Authentication failed"
        }
    }
}

// MARK: - SwiftUI Views
struct MeetingListView: View {
    @StateObject private var meetService = allgramMeetService(apiKey: "your-api-key")

    var body: some View {
        NavigationView {
            List(meetService.meetings) { meeting in
                NavigationLink(destination: MeetingDetailView(meeting: meeting, meetService: meetService)) {
                    MeetingRowView(meeting: meeting)
                }
            }
            .navigationTitle("Meetings")
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("New Meeting") {
                        // Show new meeting creation
                    }
                }
            }
        }
    }
}

struct MeetingRowView: View {
    let meeting: Meeting

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            HStack {
                Text(meeting.name)
                    .font(.headline)
                Spacer()
                if meeting.isP2P {
                    Image(systemName: "network")
                        .foregroundColor(.green)
                }
            }
            Text(meeting.description)
                .font(.subheadline)
                .foregroundColor(.secondary)
            Text("\(meeting.participants.count) participants")
                .font(.caption)
                .foregroundColor(.secondary)
            Text(meeting.status.rawValue.capitalized)
                .font(.caption)
                .foregroundColor(.blue)
        }
        .padding(.vertical, 4)
    }
}
                                    

iOS Development Features

Our Swift SDK leverages the latest iOS technologies including SwiftUI, Combine, and async/await. Built with modern iOS development patterns, it provides a seamless developer experience while maintaining high performance and security standards.

  • SwiftUI Integration: Native SwiftUI components and data binding
  • Combine Framework: Reactive programming with publishers and subscribers
  • Async/Await: Modern concurrency for better performance
  • Jitsi Meet SDK: Professional video conferencing with custom UI
View Licensing Options

Kotlin Android Integration

Build powerful Android video conferencing applications with Kotlin and Jetpack Compose. Our Android SDK provides seamless integration with modern Android development tools, real-time video calls, and P2P video capabilities. Perfect for creating professional Android meeting applications.

  • Jetpack Compose: Modern declarative UI toolkit
  • WebRTC Integration: Real-time video communication
  • P2P Video: Direct peer-to-peer video capabilities
  • Android Architecture: MVVM, Repository pattern, and Coroutines
Explore Meet Services

// allgram Meet Kotlin Android Integration Example
package com.allgram.meet

import android.util.Log
import androidx.compose.runtime.*
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject
import org.webrtc.*
import java.security.MessageDigest
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec

// MARK: - Data Models
data class Meeting(
    val meetingId: String,
    val meetingName: String,
    val meetingDescription: String,
    val isP2P: Boolean,
    val participants: List<String>,
    val startDatetime: Long,
    val endDatetime: Long,
    val maxParticipants: Int,
    val status: MeetingStatus = MeetingStatus.SCHEDULED
)

enum class MeetingStatus {
    SCHEDULED, ACTIVE, ENDED, CANCELLED
}

data class Participant(
    val userId: String,
    val username: String,
    val displayName: String,
    val avatar: String?,
    val isHost: Boolean,
    val joinTime: Long?
)

// MARK: - Meet Service
class allgramMeetService(
    private val apiKey: String,
    private val baseUrl: String = "https://api.allgram.best"
) {
    private val client = OkHttpClient.Builder()
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .build()

    private var webSocket: WebSocket? = null
    private val messageCallbacks = mutableListOf<(String) -> Unit>()
    private val systemEventCallbacks = mutableListOf<(String, String) -> Unit>()

    // WebRTC components
    private var peerConnection: PeerConnection? = null
    private var localVideoTrack: VideoTrack? = null
    private var localAudioTrack: AudioTrack? = null

    // MARK: - WebSocket Management
    fun connectWebSocket() {
        val request = Request.Builder()
            .url("wss://api.allgram.best/ws/meetings/")
            .build()

        webSocket = client.newWebSocket(request, object : WebSocketListener() {
            override fun onOpen(webSocket: WebSocket, response: Response) {
                Log.d("allgramMeet", "✅ WebSocket connected for meetings")
                // Authenticate
                sendWebSocketMessage(JSONObject().apply {
                    put("type", "auth")
                    put("api_key", apiKey)
                }.toString())
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                try {
                    val json = JSONObject(text)
                    handleWebSocketMessage(json)
                } catch (e: Exception) {
                    Log.e("allgramMeet", "Failed to parse WebSocket message", e)
                }
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                Log.e("allgramMeet", "WebSocket failure", t)
                // Attempt reconnection
                CoroutineScope(Dispatchers.IO).launch {
                    delay(5000)
                    connectWebSocket()
                }
            }
        })
    }

    // MARK: - Meeting Management
    suspend fun createMeeting(
        name: String,
        description: String,
        participants: List<String>,
        startTime: Long,
        endTime: Long,
        isP2P: Boolean = false
    ): Result<Meeting> = withContext(Dispatchers.IO) {
        try {
            val requestBody = JSONObject().apply {
                put("meeting_name", name)
                put("meeting_description", description)
                put("participants", JSONObject().apply {
                    participants.forEachIndexed { index, participant ->
                        put(index.toString(), participant)
                    }
                })
                put("start_datetime", startTime)
                put("end_datetime", endTime)
                put("is_p2p", isP2P)
                put("is_public", false)
                put("max_participants", 50)
            }.toString()

            val request = Request.Builder()
                .url("$baseUrl/meetings/create")
                .post(requestBody.toRequestBody("application/json".toMediaType()))
                .addHeader("Authorization", "Bearer $apiKey")
                .build()

            val response = client.newCall(request).execute()

            if (response.isSuccessful) {
                val responseBody = response.body?.string()
                val meetingJson = JSONObject(responseBody ?: "")

                val meeting = Meeting(
                    meetingId = meetingJson.getString("meeting_id"),
                    meetingName = meetingJson.getString("meeting_name"),
                    meetingDescription = meetingJson.getString("meeting_description"),
                    isP2P = meetingJson.optBoolean("is_p2p", false),
                    participants = participants,
                    startDatetime = meetingJson.optLong("start_datetime", startTime),
                    endDatetime = meetingJson.optLong("end_datetime", endTime),
                    maxParticipants = meetingJson.optInt("max_participants", 50)
                )

                Log.d("allgramMeet", "✅ Meeting created: ${meeting.meetingName}")
                Result.success(meeting)
            } else {
                Log.e("allgramMeet", "Failed to create meeting: ${response.code}")
                Result.failure(Exception("Server error: ${response.code}"))
            }
        } catch (e: Exception) {
            Log.e("allgramMeet", "Exception creating meeting", e)
            Result.failure(e)
        }
    }

    // MARK: - WebRTC Setup
    fun initializeWebRTC(meetingId: String, isP2P: Boolean) {
        val rtcConfig = RTCConfiguration(
            listOf(
                PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer(),
                PeerConnection.IceServer.builder("stun:stun1.l.google.com:19302").createIceServer()
            )
        ).apply {
            iceTransportsType = PeerConnection.IceTransportsType.ALL
            bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE
            rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE
            if (isP2P) {
                iceCandidatePoolSize = 10
            }
        }

        val factory = PeerConnectionFactory.builder()
            .setVideoDecoderFactory(DefaultVideoDecoderFactory())
            .setVideoEncoderFactory(DefaultVideoEncoderFactory())
            .setOptions(PeerConnectionFactory.Options().apply {
                disableEncryption = false
                disableNetworkMonitor = false
            })
            .createPeerConnectionFactory()

        peerConnection = factory.createPeerConnection(rtcConfig, object : PeerConnection.Observer {
            override fun onIceCandidate(candidate: IceCandidate) {
                // Send ICE candidate to other participants
                sendIceCandidate(candidate, meetingId)
            }

            override fun onAddStream(stream: MediaStream) {
                // Handle incoming media stream
                Log.d("allgramMeet", "📹 Incoming media stream: ${stream.videoTracks.size} video tracks")
            }

            override fun onConnectionChange(newState: PeerConnection.PeerConnectionState) {
                when (newState) {
                    PeerConnection.PeerConnectionState.CONNECTED -> {
                        Log.d("allgramMeet", "✅ WebRTC connection established")
                    }
                    PeerConnection.PeerConnectionState.DISCONNECTED -> {
                        Log.d("allgramMeet", "❌ WebRTC connection lost")
                    }
                    else -> {
                        Log.d("allgramMeet", "🔄 WebRTC state: $newState")
                    }
                }
            }

            // Implement other required methods...
            override fun onSignalingChange(state: PeerConnection.SignalingState) {}
            override fun onIceConnectionChange(state: PeerConnection.IceConnectionState) {}
            override fun onIceConnectionReceivingChange(receiving: Boolean) {}
            override fun onIceGatheringChange(state: PeerConnection.IceGatheringState) {}
            override fun onAddTrack(receiver: RtpReceiver, streams: Array<out MediaStream>) {}
            override fun onTrack(transceiver: RtpTransceiver) {}
            override fun onRemoveStream(stream: MediaStream) {}
            override fun onDataChannel(channel: DataChannel) {}
            override fun onRenegotiationNeeded() {}
            override fun onAddIceCandidate(candidate: IceCandidate) {}
        })

        // Create local video track
        val videoCapturer = createCameraCapturer()
        val videoSource = factory.createVideoSource(videoCapturer.isScreencast)
        localVideoTrack = factory.createVideoTrack(videoSource)
        videoCapturer.initialize(SurfaceTextureHelper.create("CaptureThread", null), null)
        videoCapturer.startCapture(480, 640, 30)

        // Create local audio track
        val audioSource = factory.createAudioSource(MediaConstraints())
        localAudioTrack = factory.createAudioTrack(audioSource)

        // Add tracks to peer connection
        peerConnection?.addTrack(localVideoTrack)
        peerConnection?.addTrack(localAudioTrack)
    }

    private fun createCameraCapturer(): CameraVideoCapturer {
        val cameraEnumerator = Camera2Enumerator(context)
        val deviceNames = cameraEnumerator.deviceNames

        // Find front camera
        for (deviceName in deviceNames) {
            if (cameraEnumerator.isFrontFacing(deviceName)) {
                return cameraEnumerator.createCapturer(deviceName, null)
            }
        }

        // Fallback to back camera
        return cameraEnumerator.createCapturer(deviceNames[0], null)
    }

    private fun sendIceCandidate(candidate: IceCandidate, meetingId: String) {
        val candidateData = JSONObject().apply {
            put("type", "ice_candidate")
            put("meeting_id", meetingId)
            put("candidate", candidate.sdp)
            put("sdpMLineIndex", candidate.sdpMLineIndex)
            put("sdpMid", candidate.sdpMid)
        }

        webSocket?.send(candidateData.toString())
    }

    // MARK: - WebSocket Communication
    private fun sendWebSocketMessage(message: String) {
        webSocket?.send(message) ?: run {
            Log.w("allgramMeet", "WebSocket not connected")
        }
    }

    private fun handleWebSocketMessage(json: JSONObject) {
        when {
            json.has("action") -> {
                val action = json.getString("action")
                val meetingId = json.optString("meeting_id", "")
                handleSystemEvent(action, meetingId)
            }
            json.has("ice_candidate") -> {
                handleIceCandidate(json)
            }
            json.has("meeting_data") -> {
                // Handle meeting updates
                Log.d("allgramMeet", "📊 Meeting data update received")
            }
        }
    }

    private fun handleSystemEvent(action: String, meetingId: String) {
        Log.d("allgramMeet", "System event: $action in meeting: $meetingId")
        systemEventCallbacks.forEach { callback ->
            callback(action, meetingId)
        }
    }

    private fun handleIceCandidate(json: JSONObject) {
        val candidate = IceCandidate(
            json.getString("sdpMid"),
            json.getInt("sdpMLineIndex"),
            json.getString("candidate")
        )
        peerConnection?.addIceCandidate(candidate)
    }

    // MARK: - Callbacks
    fun addMessageCallback(callback: (String) -> Unit) {
        messageCallbacks.add(callback)
    }

    fun addSystemEventCallback(callback: (String, String) -> Unit) {
        systemEventCallbacks.add(callback)
    }

    // MARK: - Cleanup
    fun disconnect() {
        webSocket?.close(1000, "Disconnecting")
        webSocket = null

        localVideoTrack?.dispose()
        localAudioTrack?.dispose()
        peerConnection?.dispose()
    }
}

// MARK: - ViewModel
class MeetViewModel(
    private val meetService: allgramMeetService
) : ViewModel() {

    private val _meetings = MutableStateFlow<List<Meeting>>(emptyList())
    val meetings: StateFlow<List<Meeting>> = _meetings.asStateFlow()

    private val _currentMeeting = MutableStateFlow<Meeting?>(null)
    val currentMeeting: StateFlow<Meeting?> = _currentMeeting.asStateFlow()

    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()

    init {
        setupMeetService()
    }

    private fun setupMeetService() {
        meetService.addSystemEventCallback { action, meetingId ->
            when (action) {
                "meeting_started" -> {
                    // Handle meeting start
                }
                "meeting_ended" -> {
                    // Handle meeting end
                }
            }
        }
    }

    fun createMeeting(name: String, description: String, participants: List<String>, startTime: Long, endTime: Long, isP2P: Boolean = false) {
        viewModelScope.launch {
            _isLoading.value = true
            try {
                val result = meetService.createMeeting(name, description, participants, startTime, endTime, isP2P)
                result.onSuccess { meeting ->
                    _meetings.value = _meetings.value + meeting
                }.onFailure { error ->
                    Log.e("MeetViewModel", "Failed to create meeting", error)
                }
            } finally {
                _isLoading.value = false
            }
        }
    }

    fun joinMeeting(meeting: Meeting) {
        _currentMeeting.value = meeting
        meetService.initializeWebRTC(meeting.meetingId, meeting.isP2P)
    }

    override fun onCleared() {
        super.onCleared()
        meetService.disconnect()
    }
}

// MARK: - Compose UI
@Composable
fun MeetingListScreen(
    viewModel: MeetViewModel = viewModel { MeetViewModel(allgramMeetService("your-api-key")) }
) {
    val meetings by viewModel.meetings.collectAsState()
    val isLoading by viewModel.isLoading.collectAsState()

    LazyColumn {
        items(meetings) { meeting ->
            MeetingItem(
                meeting = meeting,
                onClick = { viewModel.joinMeeting(meeting) }
            )
        }
    }

    if (isLoading) {
        CircularProgressIndicator()
    }
}

@Composable
fun MeetingItem(
    meeting: Meeting,
    onClick: () -> Unit
) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp)
            .clickable { onClick() },
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
    ) {
        Column(
            modifier = Modifier.padding(16.dp)
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceBetween,
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text(
                    text = meeting.meetingName,
                    style = MaterialTheme.typography.h6
                )
                if (meeting.isP2P) {
                    Icon(
                        imageVector = Icons.Default.NetworkCheck,
                        contentDescription = "P2P Meeting",
                        tint = Color.Green
                    )
                }
            }

            Text(
                text = meeting.meetingDescription,
                style = MaterialTheme.typography.body2,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
            )

            Text(
                text = "${meeting.participants.size} participants",
                style = MaterialTheme.typography.caption,
                color = MaterialTheme.colors.onSurface.copy(alpha = 0.6f)
            )
        }
    }
}
                                    

Android Development Features

Our Kotlin SDK leverages the latest Android technologies including Jetpack Compose, Coroutines, and modern Android architecture patterns. Built with performance and developer experience in mind, it provides a robust foundation for building scalable video conferencing applications.

  • Jetpack Compose: Modern declarative UI with Material Design 3
  • Coroutines: Asynchronous programming with structured concurrency
  • MVVM Architecture: Clean architecture with Repository pattern
  • WebRTC Integration: Native video communication with P2P support
View Licensing Options

WebRTC & P2P Integration

Leverage WebRTC technology for direct peer-to-peer video communication. Our WebRTC implementation provides low-latency video calls, data channels for real-time collaboration, and seamless integration with the Jitsi Meet SDK for enterprise-grade video conferencing.

  • P2P Communication: Direct peer-to-peer video and audio streaming
  • Data Channels: Real-time file sharing and collaboration tools
  • ICE Servers: STUN/TURN servers for NAT traversal
  • Codec Support: VP8, VP9, H.264 with adaptive quality
Explore Meet Services

// allgram Meet WebRTC P2P Integration Example
class allgramWebRTCClient {
    constructor(meetingId, isP2P = false) {
        this.meetingId = meetingId;
        this.isP2P = isP2P;
        this.peerConnection = null;
        this.localStream = null;
        this.remoteStreams = new Map();
        this.dataChannel = null;

        this.iceServers = [
            { urls: 'stun:stun.l.google.com:19302' },
            { urls: 'stun:stun1.l.google.com:19302' }
        ];

        if (isP2P) {
            this.iceServers.push({
                urls: 'turn:turn.allgram.best:3478',
                username: 'allgram_user',
                credential: 'allgram_password'
            });
        }
    }

    // Initialize WebRTC connection
    async initializeConnection() {
        try {
            // Get user media
            this.localStream = await navigator.mediaDevices.getUserMedia({
                video: {
                    width: { ideal: 1280, max: 1920 },
                    height: { ideal: 720, max: 1080 },
                    frameRate: { ideal: 30, max: 60 }
                },
                audio: {
                    echoCancellation: true,
                    noiseSuppression: true,
                    autoGainControl: true
                }
            });

            // Create peer connection
            this.peerConnection = new RTCPeerConnection({
                iceServers: this.iceServers,
                iceCandidatePoolSize: this.isP2P ? 10 : 0,
                bundlePolicy: 'max-bundle',
                rtcpMuxPolicy: 'require'
            });

            // Add local stream tracks
            this.localStream.getTracks().forEach(track => {
                this.peerConnection.addTrack(track, this.localStream);
            });

            // Handle ICE candidates
            this.peerConnection.onicecandidate = (event) => {
                if (event.candidate) {
                    this.sendIceCandidate(event.candidate);
                }
            };

            // Handle incoming streams
            this.peerConnection.ontrack = (event) => {
                const [stream] = event.streams;
                this.remoteStreams.set(event.track.id, stream);
                this.onRemoteStreamAdded(stream);
            };

            // Handle connection state changes
            this.peerConnection.onconnectionstatechange = () => {
                console.log('Connection state:', this.peerConnection.connectionState);
                this.onConnectionStateChange(this.peerConnection.connectionState);
            };

            // Create data channel for P2P communication
            if (this.isP2P) {
                this.dataChannel = this.peerConnection.createDataChannel('allgram_data', {
                    ordered: true,
                    maxRetransmits: 3
                });

                this.setupDataChannel(this.dataChannel);
            }

            console.log('✅ WebRTC connection initialized');
            return true;
        } catch (error) {
            console.error('❌ Failed to initialize WebRTC:', error);
            throw error;
        }
    }

    // Create and send offer
    async createOffer() {
        try {
            const offer = await this.peerConnection.createOffer({
                offerToReceiveAudio: true,
                offerToReceiveVideo: true
            });

            await this.peerConnection.setLocalDescription(offer);

            // Send offer to signaling server
            this.sendSignalingMessage({
                type: 'offer',
                meetingId: this.meetingId,
                offer: offer,
                isP2P: this.isP2P
            });

            return offer;
        } catch (error) {
            console.error('❌ Failed to create offer:', error);
            throw error;
        }
    }

    // Handle incoming answer
    async handleAnswer(answer) {
        try {
            await this.peerConnection.setRemoteDescription(answer);
            console.log('✅ Answer processed successfully');
        } catch (error) {
            console.error('❌ Failed to process answer:', error);
            throw error;
        }
    }

    // Handle incoming offer
    async handleOffer(offer) {
        try {
            await this.peerConnection.setRemoteDescription(offer);

            const answer = await this.peerConnection.createAnswer();
            await this.peerConnection.setLocalDescription(answer);

            // Send answer back
            this.sendSignalingMessage({
                type: 'answer',
                meetingId: this.meetingId,
                answer: answer
            });

            return answer;
        } catch (error) {
            console.error('❌ Failed to handle offer:', error);
            throw error;
        }
    }

    // Handle ICE candidates
    async handleIceCandidate(candidate) {
        try {
            await this.peerConnection.addIceCandidate(candidate);
            console.log('✅ ICE candidate added');
        } catch (error) {
            console.error('❌ Failed to add ICE candidate:', error);
        }
    }

    // Send ICE candidate to signaling server
    sendIceCandidate(candidate) {
        this.sendSignalingMessage({
            type: 'ice_candidate',
            meetingId: this.meetingId,
            candidate: candidate
        });
    }

    // Setup data channel for P2P communication
    setupDataChannel(channel) {
        channel.onopen = () => {
            console.log('✅ Data channel opened');
            this.onDataChannelOpen(channel);
        };

        channel.onmessage = (event) => {
            const data = JSON.parse(event.data);
            this.onDataChannelMessage(data);
        };

        channel.onclose = () => {
            console.log('🔒 Data channel closed');
            this.onDataChannelClose();
        };

        channel.onerror = (error) => {
            console.error('❌ Data channel error:', error);
        };
    }

    // Send data through data channel
    sendData(data) {
        if (this.dataChannel && this.dataChannel.readyState === 'open') {
            this.dataChannel.send(JSON.stringify(data));
            return true;
        }
        return false;
    }

    // Send signaling message
    sendSignalingMessage(message) {
        // Implementation depends on your signaling server
        // This could be WebSocket, HTTP, or other transport
        console.log('📡 Sending signaling message:', message.type);

        // Example WebSocket implementation
        if (window.meetSignalingSocket) {
            window.meetSignalingSocket.send(JSON.stringify(message));
        }
    }

    // Event handlers (to be implemented by consumer)
    onRemoteStreamAdded(stream) {
        console.log('📹 Remote stream added:', stream.id);
        // Handle new remote stream (e.g., add to UI)
    }

    onConnectionStateChange(state) {
        console.log('🔄 Connection state changed:', state);
        // Handle connection state changes
    }

    onDataChannelOpen(channel) {
        console.log('📡 Data channel ready for communication');
        // Handle data channel ready state
    }

    onDataChannelMessage(data) {
        console.log('📨 Data channel message:', data);
        // Handle incoming data channel messages
    }

    onDataChannelClose() {
        console.log('🔒 Data channel closed');
        // Handle data channel closure
    }

    // Get connection statistics
    async getConnectionStats() {
        if (!this.peerConnection) return null;

        try {
            const stats = await this.peerConnection.getStats();
            const connectionStats = {};

            stats.forEach((report) => {
                if (report.type === 'candidate-pair' && report.state === 'succeeded') {
                    connectionStats.currentRoundTripTime = report.currentRoundTripTime;
                    connectionStats.availableOutgoingBitrate = report.availableOutgoingBitrate;
                }
            });

            return connectionStats;
        } catch (error) {
            console.error('❌ Failed to get connection stats:', error);
            return null;
        }
    }

    // Cleanup resources
    disconnect() {
        if (this.localStream) {
            this.localStream.getTracks().forEach(track => track.stop());
        }

        if (this.dataChannel) {
            this.dataChannel.close();
        }

        if (this.peerConnection) {
            this.peerConnection.close();
        }

        this.localStream = null;
        this.peerConnection = null;
        this.dataChannel = null;
        this.remoteStreams.clear();

        console.log('🧹 WebRTC connection cleaned up');
    }
}

// Usage example
const webrtcClient = new allgramWebRTCClient('meeting_123', true);

// Initialize connection
webrtcClient.initializeConnection()
    .then(() => {
        console.log('WebRTC ready for P2P communication');

        // Create offer for P2P connection
        return webrtcClient.createOffer();
    })
    .then(offer => {
        console.log('Offer created:', offer);
    })
    .catch(error => {
        console.error('Failed to setup WebRTC:', error);
    });

// Handle incoming signaling messages
window.handleSignalingMessage = (message) => {
    switch (message.type) {
        case 'offer':
            webrtcClient.handleOffer(message.offer);
            break;
        case 'answer':
            webrtcClient.handleAnswer(message.answer);
            break;
        case 'ice_candidate':
            webrtcClient.handleIceCandidate(message.candidate);
            break;
    }
};
                                    

WebRTC Features & Benefits

Our WebRTC implementation provides enterprise-grade P2P video communication with advanced features for real-time collaboration and secure data exchange.

  • Low Latency: Direct peer-to-peer communication for minimal delay
  • Data Channels: Real-time file sharing and collaboration tools
  • Adaptive Quality: Automatic quality adjustment based on network conditions
  • Security: Encrypted communication with DTLS-SRTP
View Licensing Options

Calendar Integration & AI Scheduling

Seamlessly integrate video meetings with your calendar system. Our AI-powered scheduling automatically finds optimal meeting times, handles time zones, and coordinates participants across different platforms and devices.

  • AI Scheduling: Intelligent meeting time suggestions based on availability
  • Time Zone Support: Automatic conversion and coordination across regions
  • Calendar Sync: Integration with Google Calendar, Outlook, and more
  • Participant Management: Automated invitations and RSVP tracking
Explore Meet Services

// allgram Meet Calendar Integration & AI Scheduling Example
class allgramCalendarService {
    constructor(apiKey, baseUrl = 'https://api.allgram.best') {
        this.apiKey = apiKey;
        this.baseUrl = baseUrl;
        this.calendars = new Map();
        this.meetings = new Map();
        this.aiScheduler = new AIScheduler();
    }

    // Get user's calendar events
    async getCalendarEvents(calendarId, startDate, endDate) {
        try {
            const response = await fetch(`${this.baseUrl}/calendar/${calendarId}/events`, {
                method: 'GET',
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                },
                params: {
                    start_date: startDate.toISOString(),
                    end_date: endDate.toISOString(),
                    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
                }
            });

            if (response.ok) {
                const events = await response.json();
                this.calendars.set(calendarId, events);
                return events;
            }
        } catch (error) {
            console.error('Failed to fetch calendar events:', error);
            throw error;
        }
    }

    // Create meeting with AI scheduling
    async createMeetingWithAI(meetingData) {
        try {
            const {
                title,
                description,
                participants,
                duration,
                preferredTimes,
                timezone,
                isUrgent = false
            } = meetingData;

            // Get availability for all participants
            const availability = await this.getParticipantAvailability(participants, preferredTimes, timezone);

            // Use AI to find optimal meeting time
            const optimalTime = await this.aiScheduler.findOptimalTime(availability, duration, {
                timezone,
                isUrgent,
                preferredTimes
            });

            // Create meeting at optimal time
            const meeting = await this.createMeeting({
                title,
                description,
                participants,
                startTime: optimalTime.start,
                endTime: optimalTime.end,
                timezone,
                calendarId: optimalTime.calendarId
            });

            // Send invitations to participants
            await this.sendMeetingInvitations(meeting, participants);

            return meeting;
        } catch (error) {
            console.error('Failed to create AI-scheduled meeting:', error);
            throw error;
        }
    }

    // Get participant availability
    async getParticipantAvailability(participants, timeRange, timezone) {
        const availability = {};

        for (const participant of participants) {
            try {
                const participantCalendars = await this.getParticipantCalendars(participant);
                const participantAvailability = this.calculateAvailability(participantCalendars, timeRange, timezone);
                availability[participant] = participantAvailability;
            } catch (error) {
                console.warn(`Could not get availability for ${participant}:`, error);
                // Assume available if calendar access fails
                availability[participant] = this.getDefaultAvailability(timeRange);
            }
        }

        return availability;
    }

    // Calculate availability from calendar events
    calculateAvailability(events, timeRange, timezone) {
        const availability = [];
        const { start, end } = timeRange;

        // Convert to target timezone
        const startTime = new Date(start);
        const endTime = new Date(end);

        // Generate 30-minute time slots
        const timeSlots = [];
        let currentTime = new Date(startTime);

        while (currentTime < endTime) {
            const slotEnd = new Date(currentTime.getTime() + 30 * 60 * 1000);
            timeSlots.push({
                start: new Date(currentTime),
                end: slotEnd,
                available: true
            });
            currentTime = slotEnd;
        }

        // Mark busy times based on calendar events
        events.forEach(event => {
            const eventStart = new Date(event.start.dateTime || event.start.date);
            const eventEnd = new Date(event.end.dateTime || event.end.date);

            timeSlots.forEach(slot => {
                if (this.timesOverlap(slot, { start: eventStart, end: eventEnd })) {
                    slot.available = false;
                    slot.busyReason = event.summary;
                }
            });
        });

        return timeSlots.filter(slot => slot.available);
    }

    // Check if two time ranges overlap
    timesOverlap(range1, range2) {
        return range1.start < range2.end && range1.end > range2.start;
    }

    // Get default availability (assume available during business hours)
    getDefaultAvailability(timeRange) {
        const availability = [];
        const { start, end } = timeRange;
        let currentTime = new Date(start);

        while (currentTime < end) {
            const hour = currentTime.getHours();
            const isBusinessHour = hour >= 9 && hour <= 17;
            const isWeekday = currentTime.getDay() >= 1 && currentTime.getDay() <= 5;

            if (isBusinessHour && isWeekday) {
                const slotEnd = new Date(currentTime.getTime() + 30 * 60 * 1000);
                availability.push({
                    start: new Date(currentTime),
                    end: slotEnd,
                    available: true
                });
            }

            currentTime.setTime(currentTime.getTime() + 30 * 60 * 1000);
        }

        return availability;
    }

    // Create meeting
    async createMeeting(meetingData) {
        try {
            const response = await fetch(`${this.baseUrl}/meetings/create`, {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    meeting_name: meetingData.title,
                    meeting_description: meetingData.description,
                    participants: meetingData.participants,
                    start_datetime: meetingData.startTime.toISOString(),
                    end_datetime: meetingData.endTime.toISOString(),
                    timezone: meetingData.timezone,
                    calendar_id: meetingData.calendarId,
                    is_public: false,
                    max_participants: meetingData.participants.length + 1
                })
            });

            if (response.ok) {
                const meeting = await response.json();
                this.meetings.set(meeting.meeting_id, meeting);
                return meeting;
            }
        } catch (error) {
            console.error('Failed to create meeting:', error);
            throw error;
        }
    }

    // Send meeting invitations
    async sendMeetingInvitations(meeting, participants) {
        for (const participant of participants) {
            try {
                await this.sendInvitation(meeting, participant);
            } catch (error) {
                console.warn(`Failed to send invitation to ${participant}:`, error);
            }
        }
    }

    // Send individual invitation
    async sendInvitation(meeting, participant) {
        const invitation = {
            meeting_id: meeting.meeting_id,
            participant: participant,
            title: meeting.meeting_name,
            description: meeting.meeting_description,
            start_time: meeting.start_datetime,
            end_time: meeting.end_datetime,
            timezone: meeting.timezone,
            join_url: `https://meet.allgram.best/join/${meeting.meeting_id}`
        };

        // Send via email, push notification, or in-app message
        await this.sendNotification(participant, 'meeting_invitation', invitation);
    }

    // Send notification
    async sendNotification(participant, type, data) {
        try {
            const response = await fetch(`${this.baseUrl}/notifications/send`, {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    recipient: participant,
                    type: type,
                    data: data
                })
            });

            if (response.ok) {
                console.log(`✅ Invitation sent to ${participant}`);
            }
        } catch (error) {
            console.error(`Failed to send invitation to ${participant}:`, error);
            throw error;
        }
    }

    // Get participant calendars
    async getParticipantCalendars(participant) {
        try {
            const response = await fetch(`${this.baseUrl}/calendar/${participant}/calendars`, {
                method: 'GET',
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'Content-Type': 'application/json'
                }
            });

            if (response.ok) {
                return await response.json();
            }
        } catch (error) {
            console.error(`Failed to get calendars for ${participant}:`, error);
            return [];
        }
    }
}

// AI Scheduler for optimal meeting times
class AIScheduler {
    constructor() {
        this.preferences = {
            businessHours: { start: 9, end: 17 },
            preferredDays: [1, 2, 3, 4, 5], // Monday to Friday
            bufferTime: 15, // minutes before/after meetings
            urgencyWeight: 0.8
        };
    }

    // Find optimal meeting time
    async findOptimalTime(availability, duration, options) {
        const { timezone, isUrgent, preferredTimes } = options;

        // Score each available time slot
        const scoredSlots = [];

        for (const [participant, slots] of Object.entries(availability)) {
            for (const slot of slots) {
                const score = this.scoreTimeSlot(slot, duration, {
                    isUrgent,
                    preferredTimes,
                    timezone
                });

                scoredSlots.push({
                    participant,
                    slot,
                    score
                });
            }
        }

        // Sort by score and find best overlapping time
        scoredSlots.sort((a, b) => b.score - a.score);

        // Find time that works for most participants
        const bestTime = this.findBestOverlappingTime(scoredSlots, duration);

        return {
            start: bestTime.start,
            end: bestTime.end,
            calendarId: 'primary',
            score: bestTime.score
        };
    }

    // Score a time slot based on various factors
    scoreTimeSlot(slot, duration, options) {
        let score = 100;
        const { isUrgent, preferredTimes, timezone } = options;

        // Check if slot duration is sufficient
        const slotDuration = (slot.end - slot.start) / (1000 * 60); // minutes
        if (slotDuration < duration) {
            score -= 50;
        }

        // Prefer business hours
        const hour = slot.start.getHours();
        if (hour < this.preferences.businessHours.start || hour > this.preferences.businessHours.end) {
            score -= 20;
        }

        // Prefer weekdays
        const day = slot.start.getDay();
        if (!this.preferences.preferredDays.includes(day)) {
            score -= 15;
        }

        // Prefer preferred times if specified
        if (preferredTimes && preferredTimes.length > 0) {
            const isPreferred = preferredTimes.some(prefTime => {
                const prefHour = new Date(prefTime).getHours();
                return Math.abs(hour - prefHour) <= 2;
            });

            if (isPreferred) {
                score += 25;
            }
        }

        // Boost score for urgent meetings
        if (isUrgent) {
            score *= this.preferences.urgencyWeight;
        }

        return Math.max(0, score);
    }

    // Find best overlapping time for multiple participants
    findBestOverlappingTime(scoredSlots, duration) {
        const timeSlots = new Map();

        // Group slots by time
        scoredSlots.forEach(({ participant, slot, score }) => {
            const key = `${slot.start.toISOString()}_${slot.end.toISOString()}`;

            if (!timeSlots.has(key)) {
                timeSlots.set(key, {
                    start: slot.start,
                    end: slot.end,
                    participants: [],
                    totalScore: 0
                });
            }

            const timeSlot = timeSlots.get(key);
            timeSlot.participants.push(participant);
            timeSlot.totalScore += score;
        });

        // Find slot with highest score and most participants
        let bestSlot = null;
        let bestScore = 0;

        for (const [key, slot] of timeSlots) {
            const slotDuration = (slot.end - slot.start) / (1000 * 60);

            if (slotDuration >= duration && slot.totalScore > bestScore) {
                bestSlot = slot;
                bestScore = slot.totalScore;
            }
        }

        return bestSlot || {
            start: new Date(),
            end: new Date(Date.now() + duration * 60 * 1000),
            score: 0
        };
    }
}

// Usage example
const calendarService = new allgramCalendarService('your-api-key');

// Create AI-scheduled meeting
const meetingData = {
    title: 'Team Planning Session',
    description: 'Quarterly planning and strategy discussion',
    participants: ['user1@company.com', 'user2@company.com', 'user3@company.com'],
    duration: 60, // minutes
    preferredTimes: [
        new Date(Date.now() + 24 * 60 * 60 * 1000).setHours(10, 0, 0, 0), // Tomorrow 10 AM
        new Date(Date.now() + 24 * 60 * 60 * 1000).setHours(14, 0, 0, 0)  // Tomorrow 2 PM
    ],
    timezone: 'America/New_York',
    isUrgent: false
};

calendarService.createMeetingWithAI(meetingData)
    .then(meeting => {
        console.log('AI-scheduled meeting created:', meeting);
    })
    .catch(error => {
        console.error('Failed to create AI-scheduled meeting:', error);
    });
                                    

Calendar Features & Benefits

Our calendar integration provides intelligent scheduling with AI-powered optimization, seamless time zone handling, and automated participant coordination.

  • Smart Scheduling: AI algorithms find optimal meeting times for all participants
  • Multi-Platform Sync: Works with Google Calendar, Outlook, Apple Calendar, and more
  • Automated Coordination: Handles invitations, RSVPs, and reminders automatically
  • Time Zone Intelligence: Automatic conversion and coordination across regions
View Licensing Options

Additional Resources & Next Steps

Ready to take your video conferencing integration to the next level? Explore our comprehensive resources and advanced features to build enterprise-grade meeting applications with allgram.

Security & Compliance

Learn about our enterprise security features, GDPR compliance, and FIPS 140-2 certification.

Learn More →

Performance Optimization

Discover advanced techniques for optimizing video performance and scalability.

Learn More →

API Reference

Complete API documentation with examples, error codes, and best practices.

View Docs →

Community Support

Join our developer community for support, updates, and collaboration.

Join Community →