ไลบรารี Core-Telecom
จะช่วยปรับปรุงกระบวนการผสานรวมแอปพลิเคชันการโทรเข้ากับแพลตฟอร์ม Android ด้วยการจัดเตรียมชุด API ที่มีประสิทธิภาพและสม่ำเสมอ
หากต้องการดูการใช้งานจริง คุณสามารถดูตัวอย่างแอปพลิเคชันบน GitHub ได้ที่
- แอปตัวอย่างขนาดเบา — ตัวอย่างการใช้งาน
Core-Telecom
API ขั้นต่ำ เหมาะสำหรับการทำความเข้าใจแนวคิดพื้นฐานอย่างรวดเร็ว - ตัวอย่างแอปที่ครอบคลุม (พัฒนาโดยทีม Core-Telecom) — แอปพลิเคชันที่มาพร้อมฟีเจอร์มากมายซึ่งแสดงฟังก์ชันการทำงานขั้นสูงและแนวทางปฏิบัติแนะนำของโทรคมนาคม นี่เป็นแหล่งข้อมูลที่ยอดเยี่ยมในการทำความเข้าใจสถานการณ์การผสานรวมที่ซับซ้อน
ตั้งค่า Core-Telecom
เพิ่มการพึ่งพา 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))
จัดการปลายทางเสียงของสายเรียกเข้า
ตรวจสอบและจัดการอุปกรณ์ปลายทางเสียงโดยใช้ Flow
currentCallEndpoint
,
availableEndpoints
และ isMuted
ภายใน 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 ขึ้นไป) เพื่อรองรับการทำงานอยู่เบื้องหน้า
แอปพลิเคชันต้องโพสต์การแจ้งเตือนเพื่อให้ผู้ใช้ทราบว่าแอปพลิเคชันทำงานอยู่เบื้องหน้าตามข้อกำหนดของเบื้องหน้า
สร้างการแจ้งเตือนเมื่อคุณเพิ่มการเรียกใช้กับแพลตฟอร์มเพื่อให้แอปของคุณได้รับสิทธิ์ดำเนินการในเบื้องหน้า ระบบจะนำลำดับความสำคัญในเบื้องหน้าออกเมื่อแอปสิ้นสุดการโทรหรือการแจ้งเตือนของคุณไม่ถูกต้องอีกต่อไป
ดูข้อมูลเพิ่มเติมเกี่ยวกับบริการที่ทำงานอยู่เบื้องหน้า
การสนับสนุน Surface จากระยะไกล
อุปกรณ์ระยะไกล (สมาร์ทวอทช์ ชุดหูฟังบลูทูธ, Android Auto) สามารถจัดการการโทรได้โดยไม่ต้องโต้ตอบกับโทรศัพท์โดยตรง แอปของคุณต้องใช้แลมดาการเรียกกลับ (onAnswerCall
, onSetCallDisconnected
, onSetCallActive
,
onSetCallInactive
) ที่ระบุให้กับ CallsManager.addCall
เพื่อจัดการการดำเนินการที่อุปกรณ์เหล่านี้เริ่ม
เมื่อเกิดการดำเนินการระยะไกล ระบบจะเรียกใช้ Lambda ที่เกี่ยวข้อง
สัญญาณ Lambda เสร็จสมบูรณ์ที่ประมวลผลคําสั่ง หากไม่สามารถปฏิบัติตามคําสั่งได้ Lambda ควรแสดงข้อยกเว้น
การติดตั้งใช้งานอย่างเหมาะสมช่วยให้ควบคุมการโทรในอุปกรณ์ต่างๆ ได้อย่างราบรื่น ทดสอบอย่างละเอียดกับแพลตฟอร์มระยะไกลต่างๆ
ชิ้นงานการโทร
นอกจากการจัดการสถานะการโทรและเส้นทางเสียงของการโทรแล้ว ไลบรารียังรองรับส่วนขยายการโทร ซึ่งเป็นฟีเจอร์ที่ไม่บังคับที่แอปของคุณนำมาใช้เพื่อให้ได้รับประสบการณ์การโทรที่สมบูรณ์ยิ่งขึ้นบนแพลตฟอร์มระยะไกล เช่น Android Auto ฟีเจอร์เหล่านี้ ได้แก่ ห้องประชุม การปิดเสียงการโทร และไอคอนการโทรเพิ่มเติม เมื่อแอปของคุณใช้ส่วนขยาย ข้อมูลที่แอปให้ไว้จะซิงค์กับอุปกรณ์ที่เชื่อมต่อทั้งหมดที่รองรับการแสดงส่วนขยายเหล่านี้ใน UI ด้วย ซึ่งหมายความว่าฟีเจอร์เหล่านี้จะพร้อมใช้งานบนอุปกรณ์ระยะไกลเพื่อให้ผู้ใช้โต้ตอบด้วย
สร้างการโทรด้วยส่วนขยาย
เมื่อสร้างการโทร คุณสามารถใช้ CallManager#addCallWithExtensions แทนการใช้ CallManager#addCall
เพื่อสร้างการโทร ซึ่งจะให้สิทธิ์เข้าถึงขอบเขตอื่นที่เรียกว่า 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)
}
}