override fun promoteToPrimaryMeeting()

in amazon-chime-sdk/src/main/java/com/amazonaws/services/chime/sdk/meetings/audiovideo/DefaultAudioVideoController.kt [140:220]


    override fun promoteToPrimaryMeeting(
        credentials: MeetingSessionCredentials,
        observer: PrimaryMeetingPromotionObserver
    ) {
        // We create a pseudo-'Wait Group' to wait for both audio and video to complete,
        // and then merge their statuses
        val audioVideoPromotionsToComplete = AtomicInteger()
        audioVideoPromotionsToComplete.addAndGet(2)

        var audioClientStatus = MeetingSessionStatus(MeetingSessionStatusCode.OK)
        var videoClientStatus = MeetingSessionStatus(MeetingSessionStatusCode.OK)
        val mergeAndReturnPromotionStatuses = fun (
            firstStatus: MeetingSessionStatus,
            secondStatus: MeetingSessionStatus
        ) {
            // We intentionally don't differentiate status sources here
            // as the preferences towards audio vs. video really doesn't matter
            val mergedStatus = when {
                firstStatus.statusCode != MeetingSessionStatusCode.OK -> firstStatus
                secondStatus.statusCode != MeetingSessionStatusCode.OK -> secondStatus
                else -> firstStatus
            }

            CoroutineScope(Dispatchers.Main).launch {
                primaryMeetingPromotionObserver?.onPrimaryMeetingPromotion(mergedStatus)
            }
        }

        primaryMeetingPromotionObserver = observer
        // In these observers we try demoting the other client. Note that the individual controllers
        // do not follow the exact same pattern of calling back on observer (with `MeetingSessionStatusCode.OK` in
        // the case of explicit demotion request so we don't need to worry about any infinite loops
        val audioPrimaryMeetingPromotionObserverAdapter = object : PrimaryMeetingPromotionObserver {
            override fun onPrimaryMeetingPromotion(status: MeetingSessionStatus) {
                audioClientStatus = status
                if (audioVideoPromotionsToComplete.decrementAndGet() == 0) {
                    mergeAndReturnPromotionStatuses(audioClientStatus, videoClientStatus)
                }
            }

            override fun onPrimaryMeetingDemotion(status: MeetingSessionStatus) {
                videoClientController.demoteFromPrimaryMeeting()
                CoroutineScope(Dispatchers.Main).launch {
                    primaryMeetingPromotionObserver?.onPrimaryMeetingDemotion(status)
                }
            }
        }
        val videoPrimaryMeetingPromotionObserverAdapter = object : PrimaryMeetingPromotionObserver {
            override fun onPrimaryMeetingPromotion(status: MeetingSessionStatus) {
                videoClientStatus = status
                if (audioVideoPromotionsToComplete.decrementAndGet() == 0) {
                    mergeAndReturnPromotionStatuses(audioClientStatus, videoClientStatus)
                }
            }

            override fun onPrimaryMeetingDemotion(status: MeetingSessionStatus) {
                audioClientController.demoteFromPrimaryMeeting()
                CoroutineScope(Dispatchers.Main).launch {
                    primaryMeetingPromotionObserver?.onPrimaryMeetingDemotion(status)
                }
            }
        }

        audioClientController.promoteToPrimaryMeeting(credentials, audioPrimaryMeetingPromotionObserverAdapter)
        videoClientController.promoteToPrimaryMeeting(credentials, videoPrimaryMeetingPromotionObserverAdapter)

        // Setup timeout in case those callbacks are never hit for extremely spurious network or server issues
        Timer().schedule(timerTask {
            // Setting to -1 will invalidate any late callbacks
            if (audioVideoPromotionsToComplete.getAndSet(-1) != 0) {
                // Try demoting to clean up separate state but remove existing cached observer to avoid repeated callbacks
                primaryMeetingPromotionObserver = null
                videoClientController.demoteFromPrimaryMeeting()
                audioClientController.demoteFromPrimaryMeeting()
                // Using observer from scope
                CoroutineScope(Dispatchers.Main).launch {
                    observer.onPrimaryMeetingPromotion(MeetingSessionStatus(MeetingSessionStatusCode.AudioInternalServerError))
                }
            }
        }, PRIMARY_MEETING_PROMOTION_TIMEOUT)
    }