Core-Telecom ไลบรารีจะเพิ่มประสิทธิภาพกระบวนการผสานรวมแอปพลิเคชันการโทรกับแพลตฟอร์ม Android โดยการจัดชุด API ที่มีประสิทธิภาพและสอดคล้องกัน
หากต้องการดูการใช้งานจริง คุณสามารถดูตัวอย่าง แอปพลิเคชันได้ใน GitHub
- แอปตัวอย่างแบบเบา - ตัวอย่างที่เรียบง่ายที่สุด
ที่แสดง
Core-Telecomการใช้งาน API เหมาะสำหรับการทำความเข้าใจแนวคิดพื้นฐานอย่างรวดเร็ว - แอปตัวอย่างที่ครอบคลุม (พัฒนาโดยทีม Core-Telecom) - แอปพลิเคชันที่มีฟีเจอร์มากมายซึ่งแสดงฟังก์ชันการทำงานของ 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")
return CallAttributesCompat(
displayName = callerName,
address = addressUri,
direction = CallAttributesCompat.DIRECTION_INCOMING,
callType = if (isVideoCall) {
CallAttributesCompat.CALL_TYPE_VIDEO_CALL
} else {
CallAttributesCompat.CALL_TYPE_AUDIO_CALL
},
callCapabilities = CallAttributesCompat.SUPPORTS_SET_INACTIVE
)
}
เพิ่มการโทร
ใช้ callsManager.addCall กับ CallAttributesCompat และการเรียกกลับเพื่อเพิ่ม
การโทรใหม่ลงในระบบและจัดการการอัปเดต Surface จากระยะไกล 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 อย่าใช้ API AudioManager#setCommunicationDevice หรือ AudioManager#startBluetoothSco เพื่อจัดการเส้นทางเสียงเมื่อใช้ Telecom
การทำเช่นนี้จะทำให้เกิดปัญหาเกี่ยวกับเสียงในการโทร
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) และต่ำกว่า หรือ
ประเภทบริการที่ทำงานอยู่เบื้องหน้าใน Android 14 (ระดับ API 34) ขึ้นไป เพื่อ
รองรับการทำงานเบื้องหน้า
หากต้องการให้การโทรยังคงใช้งานได้เมื่อแอปทำงานในเบื้องหลัง ให้โฮสต์ CallsManager
ภายใน Service ที่ทำงานอยู่เบื้องหน้า (เช่น LifecycleService) และประกาศ
phoneCall ประเภทบริการที่ทำงานอยู่เบื้องหน้าใน AndroidManifest.xml ดังนี้
<service
android:name=".TelecomVoipService"
android:foregroundServiceType="phoneCall" />
แอปของคุณต้องโพสต์การแจ้งเตือน NotificationCompat.CallStyle เพื่อให้ผู้ใช้ทราบว่าการโทรทำงานอยู่เบื้องหน้า
ซึ่งเป็นส่วนหนึ่งของข้อกำหนดเบื้องหน้า หากต้องการให้แอปได้รับลำดับความสำคัญในการดำเนินการที่ทำงานอยู่เบื้องหน้า
ให้เลื่อนระดับบริการไปที่เบื้องหน้าโดยใช้ startForeground once
เมื่อเพิ่มการเรียกใช้กับแพลตฟอร์มแล้ว
startForeground(
notificationId,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
)
ดูข้อมูลเพิ่มเติมเกี่ยวกับบริการที่ทำงานอยู่เบื้องหน้า
การสนับสนุน Surface จากระยะไกล
อุปกรณ์ระยะไกล (สมาร์ทวอทช์ ชุดหูฟังบลูทูธ Android Auto) สามารถ
จัดการการโทรได้โดยไม่ต้องโต้ตอบกับโทรศัพท์โดยตรง แอปของคุณต้องใช้
Lambda ของการเรียกกลับ (onAnswerCall, onSetCallDisconnected, onSetCallActive,
onSetCallInactive) ที่ระบุไว้ใน CallsManager.addCall เพื่อจัดการการดำเนินการ
ที่อุปกรณ์เหล่านี้เริ่มต้น
เมื่อมีการดำเนินการจากระยะไกล ระบบจะเรียกใช้ Lambda ที่เกี่ยวข้อง
การดำเนินการ Lambda เสร็จสมบูรณ์จะส่งสัญญาณว่ามีการประมวลผลคำสั่งแล้ว หากทำตามคำสั่งไม่ได้ Lambda ควรแสดงข้อยกเว้น
การติดตั้งใช้งานที่เหมาะสมจะช่วยให้ควบคุมการโทรได้อย่างราบรื่นในอุปกรณ์ต่างๆ ทดสอบอย่างละเอียดกับพื้นผิวระยะไกลต่างๆ
ส่วนขยายการโทร
นอกเหนือจากการจัดการสถานะการโทรและเส้นทางเสียงของการโทรแล้ว ไลบรารียังรองรับชิ้นงานการโทร ซึ่งเป็นฟีเจอร์ที่ไม่บังคับที่แอปของคุณ สามารถใช้เพื่อประสบการณ์การโทรที่ดียิ่งขึ้นบนอุปกรณ์ระยะไกล เช่น Android Auto ฟีเจอร์เหล่านี้ ได้แก่ ห้องประชุม การปิดเสียงการโทร และไอคอนการโทรเพิ่มเติม เมื่อแอปใช้ส่วนขยาย ข้อมูลที่แอป ระบุจะซิงค์กับอุปกรณ์ที่เชื่อมต่อทั้งหมดซึ่งรองรับ การแสดงส่วนขยายเหล่านี้ใน UI ด้วย ซึ่งหมายความว่าฟีเจอร์เหล่านี้ จะพร้อมใช้งานในอุปกรณ์ระยะไกลเพื่อให้ผู้ใช้โต้ตอบด้วย
สร้างการโทรด้วยส่วนขยาย
เมื่อสร้างการโทร แทนที่จะใช้ CallsManager.addCall เพื่อสร้างการโทร
คุณสามารถใช้ CallsManager.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 ของแอปไปยังบันทึกการโทรของระบบเพื่อให้ปรากฏ ในแป้นโทรของระบบและผู้ใช้สามารถโทรกลับจากที่นั่นได้ ดูรายละเอียดได้ที่ประวัติการโทรแบบรวม