Skip to main content

Manage Rooms

Manage room lifecycle including queries, updates, stream control, and deletion operations for interactive livestreaming.

Querying Rooms

Get Room by ID

Retrieve a single room with real-time updates:
let roomLiveObject = AmityRoomRepository.shared.getRoom(roomId: "room-123")

roomLiveObject.observe { room in
    print("Room: \(room.title)")
    print("Status: \(room.status)")
    print("Participants: \(room.participants.count)")
    print("Live URL: \(room.livePlaybackUrl ?? "Not live")")
}

Query Multiple Rooms

Get rooms with filtering and sorting:
let roomsCollection = AmityRoomRepository.shared.getRooms(
    statuses: [.live, .idle],
    types: [.coHosts],
    isDeleted: false,
    sortBy: .firstCreated
)

roomsCollection.observe { rooms in
    rooms.forEach { room in
        print("Room: \(room.title) - Status: \(room.status)")
    }
}

Query Live Rooms Only

Get currently broadcasting rooms:
let liveRooms = AmityRoomRepository.shared.getRooms(
    statuses: [.live],
    types: nil,
    isDeleted: false,
    sortBy: .lastCreated
)

liveRooms.observe { rooms in
    print("Currently live: \(rooms.count) rooms")
}

Query Parameters

Type: AmityRoomStatus[]
Required: No
Values: idle | live | waitingReconnect | ended | recorded
Filter rooms by their current status. Pass multiple statuses to match any.
Type: AmityRoomType[]
Required: No
Values: coHosts
Filter rooms by type.
Type: boolean
Required: No
Default: false
Include or exclude deleted rooms.
Type: AmityRoomSortOption
Required: No
Values: firstCreated | lastCreated
Default: firstCreated
Sort rooms by creation date.

Updating Rooms

Update room details (creator only):
Task { @MainActor in
    do {
        let updatedRoom = try await AmityRoomRepository.shared.updateRoom(
            roomId: "room-123",
            title: "Updated Room Title",
            description: "New description with updated details",
            thumbnailFileId: "new-thumbnail-file-id",
            metadata: ["category": "updated"],
            channelEnabled: true
        )
        print("Room updated: \(updatedRoom.title)")
    } catch {
        print("Failed to update room: \(error)")
    }
}
Updatable Fields: Only title, description, thumbnailFileId, metadata, and channelEnabled can be updated. Participants and room type cannot be changed after creation.

Stopping a Stream

Stop an active broadcast:
Task { @MainActor in
    do {
        try await AmityRoomRepository.shared.stop(roomId: "room-123")
        print("Stream stopped successfully")
    } catch {
        print("Failed to stop stream: \(error)")
    }
}
Stream Status: Stopping a stream changes the room status to “ended”. The stream cannot be restarted in the same room.

Getting Recorded URLs

Retrieve recorded stream URLs after broadcast ends:
Task { @MainActor in
    do {
        let recordedUrls = try await AmityRoomRepository.shared.getRecordedUrls(
            roomId: "room-123"
        )
        
        if recordedUrls.isEmpty {
            print("No recordings available")
        } else {
            recordedUrls.forEach { url in
                print("Recording URL: \(url)")
            }
        }
    } catch {
        print("Failed to get recorded URLs: \(error)")
    }
}
Recording Availability: Recordings are available after the room status changes to “recorded”. This may take some time after the stream ends.

Common Patterns

Monitor Room Status

Track room status changes in real-time:
let roomLiveObject = AmityRoomRepository.shared.getRoom(roomId: roomId)

roomLiveObject.observe { room in
    switch room.status {
    case .idle:
        showStatus("Room created, ready to start")
        enableStartButton()
        
    case .live:
        showStatus("Broadcasting live")
        updateViewerCount()
        enableStopButton()
        
    case .waitingReconnect:
        showStatus("Reconnecting...")
        showReconnectingUI()
        
    case .ended:
        showStatus("Stream ended")
        disableStreamControls()
        checkForRecording()
        
    case .recorded:
        showStatus("Recording available")
        enablePlaybackButton()
    }
}

Display Live Rooms List

Show currently active broadcasts:
let liveRooms = AmityRoomRepository.shared.getRooms(
    statuses: [.live],
    types: [.coHosts],
    isDeleted: false,
    sortBy: .lastCreated
)

liveRooms.observe { rooms in
    let roomList = rooms.map { room in
        RoomListItem(
            roomId: room.roomId,
            title: room.title,
            thumbnail: room.getThumbnail()?.fileUrl,
            participantCount: room.participants.count,
            playbackUrl: room.livePlaybackUrl,
            channelId: room.channelId
        )
    }
    updateLiveRoomsList(roomList)
}

Stream Lifecycle Management

Complete stream management workflow:
// Start streaming
func startStreaming(roomId: String) async {
    do {
        let broadcasterData = try await AmityRoomRepository.shared.getBroadcastData(
            roomId: roomId
        )
        
        if case .coHosts(let token, let url) = broadcasterData {
            try await initializeLiveKit(url: url, token: token)
        }
        
        try await beginBroadcast()
        print("Streaming started")
    } catch {
        print("Failed to start streaming: \(error)")
    }
}

// Stop streaming
func stopStreaming(roomId: String) async {
    do {
        endBroadcast()
        try await AmityRoomRepository.shared.stop(roomId: roomId)
        print("Streaming stopped")
        
        // Wait for recording
        DispatchQueue.main.asyncAfter(deadline: .now() + 30) {
            Task {
                if let urls = try? await AmityRoomRepository.shared.getRecordedUrls(roomId: roomId),
                   let firstUrl = urls.first {
                    print("Recording available: \(firstUrl)")
                }
            }
        }
    } catch {
        print("Failed to stop streaming: \(error)")
    }
}

Best Practices

Monitor room status for better UX:
  • Subscribe to room updates for real-time status
  • Handle all status transitions appropriately
  • Show appropriate UI for each status
  • Auto-reconnect on temporary disconnections
Implement proper stream controls:
  • Validate room status before starting/stopping
  • Provide clear feedback to users
  • Handle network interruptions gracefully
  • Implement timeout mechanisms
Manage recordings effectively:
  • Poll for recordings after stream ends
  • Store recording URLs for playback
  • Implement retry logic for unavailable recordings
  • Clean up old recordings
Optimize resource usage:
  • Unsubscribe from live collections when not needed
  • Delete ended rooms after recording retrieval
  • Limit concurrent live room queries
  • Cache frequently accessed room data

Permission Checks

Verify permissions before operations:
// Check if user can stop/delete room
let roomLiveObject = AmityRoomRepository.shared.getRoom(roomId: roomId)

roomLiveObject.observe { room in
    let isCreator = room.creatorId == AmityCoreClient.currentUserId
    let isHost = room.participants.first { $0.type == .host && $0.userId == AmityCoreClient.currentUserId } != nil
    let isCoHost = room.participants.first { $0.type == .coHost && $0.userId == AmityCoreClient.currentUserId } != nil
    
    if isCreator || isHost {
        // User can stop or delete the room
        showStreamControls()
    } else if isCoHost {
        // Co-host can leave but not stop/delete
        showCoHostControls()
    } else {
        // User is viewer
        showViewerControls()
    }
}

Error Handling

do {
    try await AmityRoomRepository.shared.stop(roomId: roomId)
} catch AmityError.permissionDenied {
    showError("You don't have permission to stop this stream")
} catch AmityError.notFound {
    showError("Room not found")
} catch AmityError.invalidStatus {
    showError("Stream is not currently active")
} catch {
    showError("Failed to stop stream: \(error.localizedDescription)")
}