Skip to content

New LibSoftphone API (Experimental)

The Instance API has two limitations that can make it difficult to use in modern Android applications: its methods must be called on the main thread, and its static methods are difficult to mock in tests or integrate with dependency injection frameworks.

We are introducing a new Libsoftphone interface to address these limitations. It supports dependency injection, provides thread-safe methods, and exposes types such as Kotlin Flow and PagingSource.

This API is highly experimental and under active development. Some types and methods are not yet documented, and the API may change without notice. We welcome feedback from users trying it out.

The Instance methods are gradually becoming wrappers around Libsoftphone. When you call Instance.loadLibrary(), it creates a Libsoftphone instance and delegates some of its methods to that instance. You can adopt the new API gradually while continuing to use Instance.

Getting started

To use the new API, first create a Libsoftphone instance:

val componentsFactory = LibsoftphoneComponentsFactory()
val libsoftphone = Libsoftphone.createLibsoftphone(context, componentsFactory)

Then replace your call to Instance.loadLibrary() with:

Instance.loadLibraryWithExistingLibsoftphone(libsoftphone)

Note

Call loadLibraryWithExistingLibsoftphone() on the main thread. All other calls to Libsoftphone can be made on any thread.

You can now access the new APIs through your libsoftphone instance.

Components factory

LibsoftphoneComponentsFactory provides default implementations of the library's components. To customize a component, override the corresponding factory method:

val componentsFactory = object : LibsoftphoneComponentsFactory() {
    override fun createTelecomStrategy(context: Context, coroutineScope: CoroutineScope): TelecomStrategy? {
        return MyTelecomStrategy(context, coroutineScope, yourDependencies)
    }
}

Kotlin requirement

The Libsoftphone API requires Kotlin 1.8 or higher.

The API uses coroutines and flows extensively. These can be used from Java, but doing so is cumbersome. If your application is written in Java, we recommend enabling Kotlin in your project to work with the new API.

Lifecycle

Libsoftphone is inexpensive to create and is designed to be initialized early in your application's lifecycle. Create it in your Application class or provide it as a singleton through a dependency injection framework. With Hilt, install the provider module in SingletonComponent.

You can access the Libsoftphone APIs before calling loadLibraryWithExistingLibsoftphone(), so you can connect your dependencies before loading the native library.

Create only one Libsoftphone instance per process. Subsequent calls to Libsoftphone.createLibsoftphone() throw an exception.

Dependency injection with Hilt

The following example provides Libsoftphone and its components through Hilt, then uses the injected instance to initialize the Instance API.

@Module
@InstallIn(SingletonComponent::class)
internal object LibsoftphoneModuleProvides {

    @Provides
    @Singleton
    fun provideLibsoftphoneComponentsFactory(): LibsoftphoneComponentsFactory = LibsoftphoneComponentsFactory()

    @Provides
    @Singleton
    fun provideLibsoftphone(
        @ApplicationContext context: Context,
        componentsFactory: LibsoftphoneComponentsFactory
    ): Libsoftphone = Libsoftphone.createLibsoftphone(context, componentsFactory)

    // Expose individual components so they can be injected directly.

    @Provides
    @Singleton
    fun providePreferences(libsoftphone: Libsoftphone): Libsoftphone.LibsoftphonePreferences =
        libsoftphone.preferences

    @Provides
    @Singleton
    fun provideAccounts(libsoftphone: Libsoftphone): Libsoftphone.LibsoftphoneAccounts =
        libsoftphone.accounts

    // Add providers for other components as needed.
}

// Initialize the Instance API with the injected Libsoftphone instance.
class LibsoftphoneInitializer @Inject constructor(
    private val libsoftphone: Libsoftphone
) {
    fun initialize() {
        Instance.loadLibraryWithExistingLibsoftphone(libsoftphone)
    }
}

Call LibsoftphoneInitializer.initialize() on the main thread.

We plan to publish the full LibsoftphoneModuleProvides Hilt module as a Maven artifact in a future release.