Core-Telecom

Core-Telecom লাইব্রেরি, Android প্ল্যাটফর্মের সাথে আপনার কলিং অ্যাপ্লিকেশন ইন্টিগ্রেট করার প্রসেসকে আরও সহজ করে তোলে। এটি API-এর একটি শক্তিশালী এবং সামঞ্জস্যপূর্ণ সেট প্রদান করে

আপনি যদি ব্যবহারিক প্রয়োগ এক্সপ্লোর করতে চান, তাহলে GitHub-এ স্যাম্পেল অ্যাপ্লিকেশন খুঁজে পেতে পারেন:

Core-Telecom সেট-আপ করা

আপনার অ্যাপের build.gradle ফাইলে androidx.core:core-telecom ডিপেন্ডেন্সি যোগ করুন:

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

আপনার AndroidManifest.xml-এ MANAGE_OWN_CALLS অনুমতি ঘোষণা করুন:

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

আপনার অ্যাপ রেজিস্টার করা

সিস্টেমে কল যোগ করা শুরু করতে, CallsManager ব্যবহার করে Android-এর সাথে আপনার কলিং অ্যাপ রেজিস্টার করুন। রেজিস্টার করার সময়, আপনার অ্যাপের ক্ষমতা নির্দিষ্ট করুন (যেমন, অডিও, ভিডিও সাপোর্ট):

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 এবং কলব্যাক ব্যবহার করুন। 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 */ }
}

কল ডিসকানেক্ট করা

DisconnectCause-এর সাথে disconnect() ব্যবহার করে কল ডিসকানেক্ট করা:

disconnect(DisconnectCause(DisconnectCause.LOCAL))

কল অডিও এন্ডপয়েন্ট ম্যানেজ করা

CallControlScope-এর মধ্যে currentCallEndpoint, availableEndpoints ও isMuted Flow ব্যবহার করে অডিও এন্ডপয়েন্ট পর্যবেক্ষণ ও ম্যানেজ করুন। Telecom ব্যবহার করার সময় অডিও রুট ম্যানেজ করতে AudioManager#setCommunicationDevice বা AudioManager#startBluetoothSco API ব্যবহার করবেন না; এটি করলে আপনার কলে অডিও সংক্রান্ত সমস্যা হবে।

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) এবং আপনার AndroidManifest.xml-এ phoneCall ফোরগ্রাউন্ড পরিষেবার ধরন ঘোষণা করুন:

<service
    android:name=".TelecomVoipService"
    android:foregroundServiceType="phoneCall" />

ফোরগ্রাউন্ড সংক্রান্ত প্রয়োজনীয়তার অংশ হিসেবে, আপনার অ্যাপকে অবশ্যই একটি NotificationCompat.CallStyle বিজ্ঞপ্তি পোস্ট করতে হবে যাতে ব্যবহারকারীরা জানতে পারেন যে ফোরগ্রাউন্ডে একটি কল অ্যাক্টিভ আছে। আপনার অ্যাপ যাতে ফোরগ্রাউন্ডে এক্সিকিউশন প্রাধান্য পায় তা নিশ্চিত করতে, প্ল্যাটফর্মে কল যোগ করার startForeground পরে একবার আপনার পরিষেবা ফোরগ্রাউন্ডে প্রমোট করুন:

startForeground(
    notificationId,
    notification,
    ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
)

ফোরগ্রাউন্ড পরিষেবা সম্পর্কে আরও জানুন।

রিমোট Surface সহায়তা

রিমোট ডিভাইস (স্মার্টওয়াচ, ব্লুটুথ হেডসেট, Android Auto) সরাসরি ফোনের সাথে ইন্টার‍্যাক্ট না করেই কল ম্যানেজ করতে পারে। এইসব ডিভাইস দ্বারা শুরু করা অ্যাকশন ম্যানেজ করার জন্য CallsManager.addCall-কে দেওয়া কলব্যাক ল্যাম্বডা (onAnswerCall, onSetCallDisconnected, onSetCallActive, onSetCallInactive) আপনার অ্যাপকে অবশ্যই প্রয়োগ করতে হবে।

কোনও রিমোট অ্যাকশন ঘটলে, সংশ্লিষ্ট ল্যাম্বডা ইনভোক করা হয়।

ল্যাম্বডা সিগন্যাল সফলভাবে সম্পূর্ণ হলে বুঝতে হবে যে কমান্ডটি প্রসেস করা হয়েছে। কমান্ড পালন করা না গেলে, ল্যাম্বডাকে একটি ব্যতিক্রম দেখাতে হবে।

সঠিকভাবে প্রয়োগ করা হলে, বিভিন্ন ডিভাইস জুড়ে নির্বিঘ্নে কল কন্ট্রোল করা যায়। বিভিন্ন রিমোট সারফেসের সাথে পুঙ্খানুপুঙ্খভাবে পরীক্ষা করুন।

কল এক্সটেনশন

আপনার কলের কল স্টেট ও অডিও রুট ম্যানেজ করা ছাড়াও, লাইব্রেরি কল এক্সটেনশন সাপোর্ট করে। এটি ঐচ্ছিক ফিচার যা আপনার অ্যাপ 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 কল যোগ করতে পারবেন, যাতে সেগুলি সিস্টেম ডায়ালারে দেখা যায় এবং ব্যবহারকারীরা সেখান থেকে আবার কল করতে পারেন। আরও বিবরণের জন্য, একত্রিত কল ইতিহাস দেখুন।