Core-Telecom

ไลบรารี Core-Telecom ช่วยลดความซับซ้อนของกระบวนการผสานรวมแอปพลิเคชันการโทรกับแพลตฟอร์ม Android โดยมีชุด API ที่มีประสิทธิภาพและสอดคล้องกัน

หากต้องการดูการใช้งานจริง คุณสามารถดูแอปพลิเคชันตัวอย่างได้ใน GitHub ดังนี้

  • แอปตัวอย่างแบบเบา — ตัวอย่างที่เล็กที่สุด ซึ่งแสดงการใช้งาน Core-Telecom API เหมาะสำหรับการทำความเข้าใจแนวคิดพื้นฐานอย่างรวดเร็ว
  • แอปตัวอย่างที่ครอบคลุม (พัฒนาโดยทีม Core-Telecom Team) — แอปพลิเคชันที่มีฟีเจอร์หลากหลายมากขึ้นซึ่งแสดง ฟังก์ชันการทำงานขั้นสูงของ Telecom และแนวทางปฏิบัติแนะนำ ซึ่งเป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับการทำความเข้าใจสถานการณ์การผสานรวมที่ซับซ้อน

ตั้งค่า Core-Telecom

เพิ่มทรัพยากร Dependency androidx.core:core-telecom ลงในไฟล์ build.gradle ของแอป

dependencies {
    implementation ("androidx.core:core-telecom:1.0.0")
}

ประกาศสิทธิ์ MANAGE_OWN_CALLS ใน AndroidManifest.xml

<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />

ลงทะเบียนแอปของคุณ

ลงทะเบียนแอปการโทรกับ Android โดยใช้ CallsManager เพื่อเริ่มเพิ่มการโทรลงในระบบ เมื่อลงทะเบียน ให้ระบุความสามารถของแอป (เช่น การรองรับเสียง วิดีโอ)

val callsManager = CallsManager(context)

val capabilities: @CallsManager.Companion.Capability Int =
    (CallsManager.CAPABILITY_BASELINE or
          CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING)

callsManager.registerAppWithTelecom(capabilities)

การจัดการการโทร

ใช้ Core-Telecom API เพื่อสร้างและจัดการวงจรการโทร

สร้างการโทร

ออบเจ็กต์ CallAttributesCompat จะกำหนดพร็อพเพอร์ตี้ของการโทรที่ไม่ซ้ำกัน ซึ่งอาจมีลักษณะดังนี้

  • displayName: ชื่อผู้โทร
  • address: ที่อยู่การโทร (เช่น หมายเลขโทรศัพท์ ลิงก์การประชุม)
  • direction: ขาเข้าหรือขาออก
  • callType: เสียงหรือวิดีโอ
  • callCapabilities: รองรับการโอนสายและการพักสาย

ตัวอย่างวิธีสร้างการโทรขาเข้ามีดังนี้

fun createIncomingCallAttributes(
    callerName: String,
    callerNumber: String,
    isVideoCall: Boolean): CallAttributesCompat {
    val addressUri = Uri.parse("YourAppScheme:$callerNumber")

    // Define capabilities supported by your call.
    val callCapabilities = CallAttributesCompat.CallCapability(
        supportsSetInactive = CallAttributesCompat.SUPPORTS_SET_INACTIVE // Call can be made inactive (implies hold)
    )

    return CallAttributesCompat(
        displayName = callerName,
        address = addressUri,
        direction = CallAttributesCompat.DIRECTION_INCOMING,
        callType = if (isVideoCall) CallAttributesCompat.CALL_TYPE_VIDEO_CALL else CallAttributesCompat.CALL_TYPE_AUDIO_CALL,
        callCapabilitiesCompat = callCapabilities
    )
}

เพิ่มการโทร

ใช้ callsManager.addCall กับ CallAttributesCompat และการเรียกกลับเพื่อเพิ่มการโทรใหม่ลงในระบบและจัดการการอัปเดตพื้นผิวระยะไกล callControlScope ภายในบล็อก addCall ช่วยให้แอปเปลี่ยนสถานะการโทรและรับการอัปเดตเสียงได้เป็นหลัก

try {
    callsManager.addCall(
        INCOMING_CALL_ATTRIBUTES,
        onAnswerCall, // Watch needs to know if it can answer the call.
        onSetCallDisconnected,
        onSetCallActive,
        onSetCallInactive
    ) {
        // The call was successfully added once this scope runs.
        callControlScope = this
    }
}
catch(addCallException: Exception){
   // Handle the addCall failure.
}

รับสาย

รับสายเรียกเข้าภายใน CallControlScope

when (val result = answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
    is CallControlResult.Success -> { /* Call answered */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

ปฏิเสธสาย

ปฏิเสธสายโดยใช้ disconnect() กับ DisconnectCause.REJECTED ภายใน CallControlScope

disconnect(DisconnectCause(DisconnectCause.REJECTED))

ทำให้สายโทรออกใช้งานได้

ตั้งค่าสายโทรออกให้ใช้งานได้เมื่ออีกฝ่ายรับสาย

when (val result = setActive()) {
    is CallControlResult.Success -> { /* Call active */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

พักสาย

ใช้ setInactive() เพื่อพักสาย

when (val result = setInactive()) {
    is CallControlResult.Success -> { /* Call on hold */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

ตัดสาย

ตัดสายโดยใช้ disconnect() กับ DisconnectCause

disconnect(DisconnectCause(DisconnectCause.LOCAL))

จัดการปลายทางเสียงของการโทร

สังเกตและจัดการปลายทางเสียงโดยใช้ currentCallEndpoint, availableEndpoints และ isMuted Flow ภายใน CallControlScope

fun observeAudioStateChanges(callControlScope: CallControlScope) {
    with(callControlScope) {
        launch { currentCallEndpoint.collect { /* Update UI */ } }
        launch { availableEndpoints.collect { /* Update UI */ } }
        launch { isMuted.collect { /* Handle mute state */ } }
    }
}

เปลี่ยนอุปกรณ์เสียงที่ใช้งานอยู่โดยใช้ requestEndpointChange()

coroutineScope.launch {
     callControlScope.requestEndpointChange(callEndpoint)
}

การรองรับการทำงานอยู่เบื้องหน้า

ไลบรารีใช้ ConnectionService (Android 13 ระดับ API 33 ลงไป) หรือ foregroundtypes (Android 14 ระดับ API 34 ขึ้นไป) เพื่อรองรับการทำงานอยู่เบื้องหน้า

แอปพลิเคชันต้องโพสต์การแจ้งเตือนเพื่อให้ผู้ใช้ทราบว่าแอปพลิเคชันกำลังทำงานอยู่เบื้องหน้า ซึ่งเป็นส่วนหนึ่งของข้อกำหนดการทำงานอยู่เบื้องหน้า

สร้างการแจ้งเตือนเมื่อเพิ่มการโทรด้วยแพลตฟอร์มเพื่อให้แอปได้รับการจัดลำดับความสำคัญในการดำเนินการเบื้องหน้า ระบบจะนำการจัดลำดับความสำคัญเบื้องหน้าออกเมื่อแอปสิ้นสุดการโทรหรือการแจ้งเตือนไม่ถูกต้องอีกต่อไป

ดูข้อมูลเพิ่มเติมเกี่ยวกับบริการที่ทำงานอยู่เบื้องหน้า

การรองรับพื้นผิวระยะไกล

อุปกรณ์ระยะไกล (สมาร์ทวอทช์ ชุดหูฟังบลูทูธ, Android Auto) สามารถจัดการการโทรได้โดยไม่ต้องโต้ตอบกับโทรศัพท์โดยตรง แอปของคุณต้องใช้แลมบ์ดาการเรียกกลับ (onAnswerCall, onSetCallDisconnected, onSetCallActive, onSetCallInactive) ที่ให้ไว้กับ CallsManager.addCall เพื่อจัดการการดำเนินการที่อุปกรณ์เหล่านี้เริ่มต้น

เมื่อมีการดำเนินการระยะไกลเกิดขึ้น ระบบจะเรียกใช้แลมบ์ดาที่เกี่ยวข้อง

การดำเนินการแลมบ์ดาเสร็จสมบูรณ์จะส่งสัญญาณว่าระบบประมวลผลคำสั่งแล้ว หากทำตามคำสั่งไม่ได้ แลมบ์ดาควรแสดงข้อยกเว้น

การติดตั้งใช้งานอย่างเหมาะสมจะช่วยให้ควบคุมการโทรได้อย่างราบรื่นในอุปกรณ์ต่างๆ ทดสอบอย่างละเอียดกับพื้นผิวระยะไกลต่างๆ

ส่วนขยายการโทร

นอกเหนือจากการจัดการสถานะการโทรและเส้นทางเสียงของการโทรแล้ว ไลบรารียังรองรับส่วนขยายการโทร ซึ่งเป็นฟีเจอร์ที่ไม่บังคับที่แอปของคุณสามารถติดตั้งใช้งานเพื่อมอบประสบการณ์การโทรที่สมบูรณ์ยิ่งขึ้นในพื้นผิวระยะไกล เช่น Android Auto ฟีเจอร์เหล่านี้ ได้แก่ ห้องประชุม การปิดเสียงการโทร และไอคอนการโทรเพิ่มเติม เมื่อแอปของคุณติดตั้งใช้งานส่วนขยาย ข้อมูลที่แอปให้ไว้จะซิงค์กับอุปกรณ์ที่เชื่อมต่อทั้งหมดซึ่งรองรับการแสดงส่วนขยายเหล่านี้ใน UI ด้วย ซึ่งหมายความว่าฟีเจอร์เหล่านี้จะพร้อมใช้งานในอุปกรณ์ระยะไกลเพื่อให้ผู้ใช้โต้ตอบได้ด้วย

สร้างการโทรด้วยส่วนขยาย

เมื่อสร้างการโทร แทนที่จะใช้ CallManager#addCall เพื่อสร้างการโทร คุณสามารถใช้ CallManager#addCallWithExtensions แทน ซึ่งจะช่วยให้ แอปเข้าถึงขอบเขตอื่นที่เรียกว่า ExtensionInitializationScope ขอบเขตนี้ช่วยให้แอปพลิเคชันเริ่มต้นชุดส่วนขยายที่ไม่บังคับที่รองรับได้ นอกจากนี้ ขอบเขตนี้ยังมีเมธอดเพิ่มเติม onCall ซึ่งจะส่ง CallControlScope กลับไปยังแอปหลังจากที่การแลกเปลี่ยนความสามารถของส่วนขยายและการเริ่มต้นเสร็จสมบูรณ์

scope.launch {
    mCallsManager.addCallWithExtensions(
        attributes,
        onAnswer,
        onDisconnect,
        onSetActive,
        onSetInactive
    ) {
        // Initialize extension-specific code...

        // After the call has been initialized, perform in-call actions
        onCall {
            // Example: process call state updates
            callStateFlow.onEach { newState ->
                // handle call state updates and notify telecom
            }.launchIn(this)

            // Use initialized extensions...
        }
    }
}

รองรับผู้เข้าร่วมการโทร

หากแอปของคุณรองรับผู้เข้าร่วมการโทรสำหรับการประชุมหรือการโทรแบบกลุ่ม ให้ใช้ addParticipantExtension เพื่อประกาศการรองรับส่วนขยายนี้ และใช้ API ที่เกี่ยวข้องเพื่ออัปเดตพื้นผิวระยะไกลเมื่อผู้เข้าร่วมมีการเปลี่ยนแปลง

mCallsManager.addCallWithExtensions(...) {
        // Initialize extensions...

        // Notifies Jetpack that this app supports the participant
        // extension and provides the initial participants state in the call.
        val participantExtension = addParticipantExtension(
            initialParticipants,
            initialActiveParticipant
        )

        // After the call has been initialized, perform in-call control actions
        onCall {
            // other in-call control and extension actions...

            // Example: update remote surfaces when the call participants change
            participantsFlow.onEach { newParticipants ->
                participantExtension.updateParticipants(newParticipants)
            }.launchIn(this)
        }
    }

นอกเหนือจากการแจ้งพื้นผิวระยะไกลว่ามีผู้เข้าร่วมใดบ้างในการโทรแล้ว คุณยังอัปเดตผู้เข้าร่วมที่ใช้งานอยู่ได้โดยใช้ ParticipantExtension#updateActiveParticipant

นอกจากนี้ ยังมีการรองรับการดำเนินการที่ไม่บังคับที่เกี่ยวข้องกับผู้เข้าร่วมการโทรด้วย แอปสามารถใช้ ParticipantExtension#addRaiseHandSupport เพื่อรองรับแนวคิดที่ผู้เข้าร่วมยกมือในการโทร และดูว่ามีผู้เข้าร่วมคนอื่นๆ ยกมือด้วยหรือไม่

mCallsManager.addCallWithExtensions(...) {
        // Initialize extensions...

        // Notifies Jetpack that this app supports the participant
        // extension and provides the initial list of participants in the call.
        val participantExtension = addParticipantExtension(initialParticipants)
        // Notifies Jetpack that this app supports the notion of participants
        // being able to raise and lower their hands.
        val raiseHandState = participantExtension.addRaiseHandSupport(
                initialRaisedHands
            ) { onHandRaisedStateChanged ->
                // handle this user's raised hand state changed updates from
                // remote surfaces.
            }

        // After the call has been initialized, perform in-call control actions
        onCall {
            // other in-call control and extension actions...

            // Example: update remote surfaces when the call participants change
            participantsFlow.onEach { newParticipants ->
                participantExtension.updateParticipants(newParticipants)
            }.launchIn(this)
            // notify remote surfaces of which of the participants have their
            // hands raised
            raisedHandsFlow.onEach { newRaisedHands ->
                raiseHandState.updateRaisedHands(newRaisedHands)
            }.launchIn(this)
        }
    }

รองรับการปิดเสียงการโทร

การปิดเสียงการโทรช่วยให้ผู้ใช้ขอให้แอปปิดเสียงออกของการโทรโดยไม่ต้องปิดเสียงไมโครโฟนของอุปกรณ์จริง ระบบจะจัดการฟีเจอร์นี้ต่อการโทรแต่ละครั้ง ดังนั้น Jetpack จะจัดการความซับซ้อนของการจัดการสถานะการปิดเสียงทั่วโลกของการโทรผ่านมือถือที่กำลังดำเนินการอยู่ขณะที่การโทร VOIP ใช้งานอยู่ ซึ่งจะช่วยลดข้อผิดพลาดในการปิดเสียงออกในสถานการณ์ที่มีการโทรหลายครั้ง และยังช่วยให้มีฟีเจอร์ที่เป็นประโยชน์ เช่น ข้อความบ่งชี้ "คุณกำลังพูดอยู่" เมื่อผู้ใช้กำลังพูดโดยไม่ทราบว่ามีการเปิดใช้การปิดเสียงการโทร

mCallsManager.addCallWithExtensions(...) {
        // Initialize extensions...

        // Add support for locally silencing the call's outgoing audio and
        // register a handler for when the user changes the call silence state
        // from a remote surface.
        val callSilenceExtension = addLocalCallSilenceExtension(
            initialCallSilenceState = false
        ) { newCallSilenceStateRequest ->
            // handle the user's request to enable/disable call silence from
            // a remote surface
        }

        // After the call has been initialized, perform in-call control actions
        onCall {
            // other in-call control and extension actions...

            // When the call's call silence state changes, update remote
            // surfaces of the new state.
            callSilenceState.onEach { isSilenced ->
                callSilenceExtension.updateIsLocallySilenced(isSilenced)
            }.launchIn(this)
        }
    }

รองรับไอคอนการโทร

ไอคอนการโทรช่วยให้แอประบุไอคอนที่กำหนดเองซึ่งแสดงการโทรที่จะแสดงบนพื้นผิวระยะไกลระหว่างการโทรได้ นอกจากนี้ คุณยังอัปเดตไอคอนนี้ได้ตลอดอายุการใช้งานของการโทร

mCallsManager.addCallWithExtensions(...) {
        // Initialize extensions...

        // Add support for a custom call icon to be displayed during the
        // lifetime of the call.
        val callIconExtension = addCallIconExtension(
            initialCallIconUri = initialUri
        )

        // After the call has been initialized, perform in-call control actions
        onCall {
            // other in-call control and extension actions...

            // When the call's icon changes, update remote surfaces by providing
            // the new URI.
            callIconUri.onEach { newIconUri ->
                callIconExtension.updateCallIconUri(newIconUri)
            }.launchIn(this)
        }
    }

เพิ่มลงในบันทึกการโทรของระบบ

คุณสามารถเพิ่มการโทร VoIP ของแอปไปยังบันทึกการโทรของระบบเพื่อให้ปรากฏในแป้นโทรของระบบและผู้ใช้สามารถโทรกลับจากที่นั่นได้ ดูรายละเอียดได้ที่ ประวัติการโทรแบบรวม