কোর-টেলিকম

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)

কল ব্যবস্থাপনা

কল লাইফসাইকেল তৈরি ও পরিচালনা করতে কোর-টেলিকম এপিআই ব্যবহার করুন।

একটি কল তৈরি করুন

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
    )
}

একটি কল যোগ করুন

সিস্টেমে একটি নতুন কল যোগ করতে এবং রিমোট সারফেস আপডেটগুলি পরিচালনা করতে CallAttributesCompat এবং কলব্যাকগুলির সাথে callsManager.addCall ব্যবহার করুন। addCall ব্লকের মধ্যে থাকা callControlScope প্রধানত আপনার অ্যাপকে কলের অবস্থা পরিবর্তন করতে এবং অডিও আপডেট গ্রহণ করতে সাহায্য করে:

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 */ }
}

একটি কল প্রত্যাখ্যান করুন

CallControlScope মধ্যে DisconnectCause.REJECTED সহ disconnect() ব্যবহার করে একটি কল প্রত্যাখ্যান করুন:

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 ব্যবহার করে অডিও এন্ডপয়েন্টগুলো পর্যবেক্ষণ ও পরিচালনা করুন।

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 (অ্যান্ড্রয়েড ১৩ এপিআই লেভেল ৩৩ এবং তার নিচের সংস্করণ) অথবা foregroundtypes (অ্যান্ড্রয়েড ১৪ এপিআই লেভেল ৩৪ এবং তার উপরের সংস্করণ) ব্যবহার করে।

ফোরগ্রাউন্ডে থাকার আবশ্যিক শর্ত হিসেবে, অ্যাপ্লিকেশনটিকে অবশ্যই একটি নোটিফিকেশন পোস্ট করতে হবে, যাতে ব্যবহারকারীরা জানতে পারেন যে অ্যাপ্লিকেশনটি ফোরগ্রাউন্ডে চলছে।

আপনার অ্যাপ যাতে ফোরগ্রাউন্ডে চলার অগ্রাধিকার পায়, তা নিশ্চিত করতে প্ল্যাটফর্মে কলটি যোগ করার পর একটি নোটিফিকেশন তৈরি করুন। আপনার অ্যাপ কলটি বন্ধ করে দিলে বা আপনার নোটিফিকেশনটি আর বৈধ না থাকলে ফোরগ্রাউন্ড অগ্রাধিকার বাতিল হয়ে যায়।

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

রিমোট সারফেস সাপোর্ট

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

যখন কোনো রিমোট অ্যাকশন সংঘটিত হয়, তখন সংশ্লিষ্ট ল্যাম্বডাটি কল করা হয়।

ল্যাম্বডার সফল সমাপ্তি নির্দেশ করে যে কমান্ডটি প্রক্রিয়াজাত করা হয়েছে। যদি কমান্ডটি পালন করা সম্ভব না হয়, তবে ল্যাম্বডা একটি এক্সেপশন থ্রো করবে।

সঠিক বাস্তবায়ন বিভিন্ন ডিভাইসে নির্বিঘ্ন কল নিয়ন্ত্রণ নিশ্চিত করে। বিভিন্ন রিমোট সারফেস ব্যবহার করে পুঙ্খানুপুঙ্খভাবে পরীক্ষা করুন।

কল এক্সটেনশন

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

Support Call Silence

কল সাইলেন্স ব্যবহারকারীকে ডিভাইসের মাইক্রোফোন ফিজিক্যালি মিউট না করেই অ্যাপের মাধ্যমে কলের আউটগোয়িং অডিও সাইলেন্স করার অনুরোধ জানানোর সুযোগ দেয়। এই ফিচারটি প্রতিটি কলের জন্য আলাদাভাবে পরিচালিত হয়, তাই একটি ভিওআইপি (VOIP) কল চালু থাকা অবস্থায় চলমান সেলুলার কলগুলোর গ্লোবাল মিউট অবস্থা পরিচালনার জটিলতা জেটপ্যাকই সামলে নেয়। এর ফলে একাধিক কলের ক্ষেত্রে আউটগোয়িং অডিও সাইলেন্স করার প্রক্রিয়াটি ত্রুটিমুক্ত হয় এবং একই সাথে কিছু সহায়ক ফিচারও পাওয়া যায়, যেমন—ব্যবহারকারী যখন কথা বলার সময় খেয়ালই করেন না যে কল সাইলেন্স চালু আছে, তখন "আপনি কি কথা বলছেন" (are you speaking) ধরনের সংকেত পাওয়া যায়।

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) অ্যাপ্লিকেশন ব্যবহার করে করা বা গ্রহণ করা কলগুলো সিস্টেম ডায়লারের কল হিস্ট্রিতে দেখা যায়, ফলে ব্যবহারকারীরা ডায়লার ব্যবহার করে কলব্যাক শুরু করতে পারেন।

কল লগ ইন্টিগ্রেশন সক্ষম করুন

এই ফিচারটি চালু করতে, আপনার অ্যাপ্লিকেশনটিকে অবশ্যই তার AndroidManifest.xmlTelecomManager.ACTION_CALL_BACK ইন্টেন্টটি হ্যান্ডেল করার জন্য রেজিস্টার করতে হবে এবং কলব্যাকটি প্রসেস করার জন্য একটি Activity প্রদান করতে হবে। উদাহরণস্বরূপ, ধরা যাক VoipCallbackActivity হলো সেই অ্যাক্টিভিটি যা কলব্যাকটি হ্যান্ডেল করে, তাহলে আপনার ম্যানিফেস্টটি দেখতে হবে নিম্নরূপ:

ম্যানিফেস্টে অভিপ্রায়টি নিবন্ধন করুন।

<activity
    android:name=".VoipCallbackActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.telecom.action.CALL_BACK" />
    </intent-filter>
</activity>

কলব্যাক ইন্টেন্টটি পরিচালনা করুন

যখন ব্যবহারকারী সিস্টেম ডায়ালার থেকে একটি কলব্যাক শুরু করেন, তখন আপনার নিবন্ধিত অ্যাক্টিভিটিটি TelecomManager.ACTION_CALL_BACK অ্যাকশন সহ চালু হয়। এই ইন্টেন্টটিতে TelecomManager.EXTRA_UUID থাকে, যা আপনি CallsManager ব্যবহার করে প্রথমবার কলটি যোগ করার সময় আপনার অ্যাপে সরবরাহ করেছিলেন।

CallControlScope মেথড getCallId কলটির জন্য এই অনন্য আইডিটি রিটার্ন করে।

UUID দ্বারা চিহ্নিত কলটি শুরু করার জন্য প্রয়োজনীয় সমস্ত তথ্য (উদাহরণস্বরূপ, গ্রুপ কলের জন্য ফোন নম্বরের তালিকা) আপনার অ্যাপের মধ্যে সংরক্ষণ করা উচিত, যাতে কলব্যাক ট্রিগার হলে আপনি কলটি পুনর্গঠন করে পুনরায় করতে পারেন।

class VoipCallbackActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (intent?.action == TelecomManager.ACTION_CALL_BACK) {
            val uuidString = intent.getStringExtra(TelecomManager.EXTRA_UUID)
            if (uuidString != null) {
                val uuid = UUID.fromString(uuidString)
                
                // Retrieve your persisted call info using the UUID
                val callData = CallRepository.getCallByUuid(uuid)
                
                if (callData != null) {
                    // Place the call again using your app's logic
                    // ...
                }
            }
        }
        finish()
    }
}

কল লগ ইন্টিগ্রেশন থেকে অপ্ট আউট করুন

ডিফল্টরূপে, কলগুলি সিস্টেম কল লগে লগ করা হয়। CallAttributesCompat তৈরি করার সময় isLogged প্যারামিটারটিকে false সেট করে আপনি প্রতিটি কলের জন্য আলাদাভাবে এই বৈশিষ্ট্যটি নিষ্ক্রিয় করতে পারেন।

val callAttributes = CallAttributesCompat(
    displayName = callerName,
    address = addressUri,
    direction = CallAttributesCompat.DIRECTION_OUTGOING,
    isLogExcluded = true // Opt-out of system call logging
)