A software library for embedding enterprise-grade video communication into Android mobile applications
English / Π ΡΡΡΠΊΠΈΠΉ / Deutsch / EspaΓ±ol
- What is TrueConf SDK for Android?
- Getting Access to TrueConf SDK
- Project Structure
- Example 1. Demonstration of Basic TrueConf SDK Features
- Example 2. Working with TrueConf URI links
TrueConf SDK for Android is a software library for embedding enterprise-grade video communication into Android mobile applications. With it, you can add support for video calls, group video conferences with chat, and flexibly manage the interface and user experience in your app.
TrueConf SDK is connected to your project as an external dependency and provides a comprehensive API set for full integration with the TrueConf video conferencing system. It includes:
- user authentication;
- making calls and participating in conferences;
- obtaining and tracking user statuses;
- working with multimedia;
- customizing interfaces and video windows.
TrueConf SDK is suitable for creating:
- corporate messengers with video communication,
- telemedicine solutions,
- mobile workstations,
- industry-specific applications for security, education, manufacturing, and more.
- Connection to the server via the trueconf protocol.
- User account authorization and registration.
- Connection to group conferences.
- Calls to other users.
- In-conference chat.
- Receiving and tracking user statuses.
- Interface and video component customization.
TrueConf SDK is available not only for native platforms but also for cross-platform development:
- .NET (C#)
- React Native (JavaScript)
- Cordova (JavaScript)
- Qt (C++)
The official SDK ensures reliable interaction of mobile applications with other TrueConf products, including:
- TrueConf Server;
- other client applications based on the SDK;
- external systems via the TrueConf Server API.
Tip
Mobile applications created with TrueConf Mobile SDK can connect only to servers where the TrueConf SDK extension is activated.
TrueConf SDK for mobile applications is distributed via a private remote repository. Access is provided upon individual requestβplease contact the sales department using the feedback form on the website or via official contacts.
How to get access:
-
Contact the TrueConf sales department. Specify that you want access to the TrueConf SDK and the private Maven repository for Android.
Contacts: https://trueconf.com/company/contacts.html -
Describe your project. TrueConf representatives may ask about your intended use of the SDK.
-
Receive access credentials. After your request is reviewed, you will receive a login and password to connect to the Maven repository.
-
Configure access to the Maven repository. To download the Android library, you need to set up authorization in Gradle using your login and password. In your
gradle.propertiesfile, add the following lines:trueconfUsername=your_login trueconfPassword=your_password
Warning
Replace your_login and your_password with the credentials provided to you.
Download this repository and open it in Android Studio. All the examples discussed below are included in this project. The project has approximately the following structure:
gradle/
βββ wrapper/
βββ gradle-wrapper.jar
βββ gradle-wrapper.properties
TestApp1/ // ΠΡΠΈΠΌΠ΅Ρ β1
βββ src/
β βββ main/
β β βββ java/
β β β βββ com/example/trueconf/sample/
β β β βββ MainActivity1.java
β β β βββ PlaceholderFragment.java
β β β βββ TestApp1.java
β β βββ res/
β β β βββ drawable/
β β β βββ layout/
β β β βββ values/
β β βββ AndroidManifest.xml
βββ build.gradle
TestApp2/
TestApp3/
TestApp4/
TestApp5/
TestApp6/
TestApp7/
build.gradle
settings.gradle
gradlew
gradlew.bat
gradle.properties
An application where all the main TrueConf SDK functions are implemented:
- SDK initialization and connection to the server;
- user authorization and logout;
- calling a server user by their TrueConf ID;
- the ability to receive incoming audio and video calls.
In the project, open the TestApp1.java file in the TestApp1 module. The TestApp1.java file is the main application class (Application) responsible for initializing TrueConf SDK when the app starts. It supports MultiDex (MultiDexApplication), which allows bypassing the 65,536 method limit and using multiple .dex files. Learn more in the official documentation.
To initialize the SDK, you need to register the application using the registerApp method. Pass this (the main application class, which inherits from Application) as a parameter. This is required to manage SDK resources throughout the application's lifecycle.
To start the SDK, use the start method. You must call it after registerApp() for the SDK to begin working. You can pass the following parameters to start():
serverListβ a comma-separated list of server addresses (String, optional parameter);checkPermissionsβ checks if the app has the necessary permissions, such as access to the camera, microphone, network (Boolean).
Example TestApp1 class:
public class TestApp1 extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
TrueConfSDK.getInstance().registerApp(this);
TrueConfSDK.getInstance().start(true);
}
}Now let's look at the code in MainActivity1.java. The MainActivity1 class is an activity that inherits from AppCompatActivity. It performs basic UI initialization, configures the TrueConf SDK, and manages fragments.
In this class, we override the onCreate() method from AppCompatActivity. This method is called when the activity is created and is responsible for its initialization. The call to super.onCreate(savedInstanceState) ensures proper activity initialization, including theme setup, FragmentManager operation, and restoring state after destruction. This call is required before adding your custom logic.
Next, several important steps must be performed:
-
Ensure proper handling of call exit and prevent the situation where the user stays on a blank screen after a call. For this, use
setFallbackActivity()and pass the desiredActivityclass (in this case,MainActivity1.class). -
Initialize the layout so that something is displayed in the app. Instead of the usual
findViewByIdapproach, we will use the convenientView Bindingtool. Create abindingobject that automatically binds code to UI elements fromres/layout/activity_main.xml:ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
-
Display the screen to the user. Use
setContentView(binding.getRoot()). If this is the first time the screen is launched (savedInstanceState == null), load our interface using the fragment manager (FragmentManager):getSupportFragmentManager() .beginTransaction() .add(binding.container.getId(), new PlaceholderFragment()) .commit();
Example MainActivity1 class:
public class MainActivity1 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("Example 1. Calling a User by TrueConf ID");
TrueConfSDK.getInstance().setFallbackActivity(MainActivity1.class);
ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
if (savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.add(binding.container.getId(), new PlaceholderFragment())
.commit();
}
}
}All the logic for this example is located in the PlaceholderFragment.java file. It defines a class PlaceholderFragment, which is an Android fragment and implements the TrueConfListener.LoginEventsCallback and TrueConfListener.ServerStatusEventsCallback interfaces, allowing you to handle connection and authorization status changes.
Main functions of the PlaceholderFragment class:
- Connecting to the server β entering the video server address (IP or FQDN) and starting the connection.
- Authorization β entering a login and password to sign in.
- Making a call β entering the user ID and initiating a call.
- Logout β handling user logout.
- Updating the interface β managing the visibility of buttons and fields depending on the connection and authorization state.
We won't go through all 200 lines in this file, but will focus on the key points.
Methods annotated with @Override are callback functions that override methods from the parent class, adding extra logic. For example, when the app is destroyed, we also remove the TrueConfListener:
@Override
public void onDestroy() {
super.onDestroy();
TrueConfSDK.getInstance().removeTrueconfListener(this);
}All main app logic is concentrated in the setUpUI() method. It:
-
binds UI elements to variables:
mETLogin = binding.etLogin; mETPass = binding.etPass; ...
-
assigns event handlers for buttons (authorization, connection, call, logout):
binding.btnConnect.setOnClickListener(btn -> afterServerEnter()); mBtnLogin.setOnClickListener(btn -> {...} mBtnCall.setOnClickListener(btn -> {...}
-
manages the visibility of elements depending on states:
mETServer.setVisibility(data == null || data.length == 0 ? View.GONE : View.VISIBLE)
So, if you need to change any logic in Example 1, you need to edit the PlaceholderFragment.java file.
And finally, let's look at the TrueConfSDK methods used:
TrueConfSDK.getInstance().addTrueconfListener(this)β adds a listener;TrueConfSDK.getServerManager().isLoggedIn()β checks if the user is authorized on the server;TrueConfSDK.getInstance().start(server, true)β starts the SDK with a specific server;TrueConfSDK.getServerManager().loginAs(username, password, true, false)β authorizes a specific user on the server;TrueConfSDK.getConferenceManager().callTo(peerId)β calls a specific user;TrueConfSDK.getServerManager().logout()β logs out (de-authorizes) the user;TrueConfSDK.getInstance().removeTrueconfListener(this)β removes the listener.
Let's look at an example where the application allows you to connect to TrueConf Server and initiate a call using the trueconf URI scheme (for example, trueconf:ivanov). This can be a call to a specific user by their TrueConf ID or connecting to a group conference by its identifier. Authorization and connection are performed automaticallyβlogin and server parameters are passed inside the link. The call is handled using the parseProtocolLink method, which takes the call string as a String.
Tip
For more details about the syntax and capabilities of the trueconf URI scheme, read this article.
In MainActivity2.java in the TestApp2 module, there is a class with the same name, which, like TestApp1, inherits from AppCompatActivity. Inside the MainActivity2 class, you will find a static nested class PlaceholderFragment. Its purpose is to demonstrate working with the SDK by entering and parsing links using the trueconf URI scheme. After the application is initialized and the fragment layout is created, the class's onViewCreated() method is called. It implements the following actions:
binding.btnParseLink.setOnClickListener(btn -> {
var link = mETLink.getText().toString().trim();
if (!TextUtils.isEmpty(link)) {
TrueConfSDK.getVisicallManager().parseProtocolLink(link);
}
});- When pressed, it reads the text from the field and trims spaces;
- If the string is not empty, it calls the
parseProtocolLink(...)method ofIVisicallManagerprovided by TrueConf SDK; - This method initializes the connection to the server, authorizes the user, and initiates the callβall through a single link.
binding.btnClear.setOnClickListener(btn -> mETLink.setText(""));Simply clears the input field, resetting its content. For convenience in testing this example, you can paste a link from the code so you don't have to type it every time:
mETLink.setText("trueconf:chester&h=10.110.2.240&login=joe_smith&password=12345678&encrypt=1&force=1");Code snippet from the onViewCreated() method:
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding = FragmentPlaceholderBinding.bind(view);
var mETLink = binding.etLink;
binding.btnParseLink.setOnClickListener(btn -> {
var link = mETLink.getText().toString().trim();
if (!TextUtils.isEmpty(link)) {
TrueConfSDK.getVisicallManager().parseProtocolLink(link);
}
});
binding.btnClear.setOnClickListener(btn -> mETLink.setText(""));
}This example demonstrates connecting to a multi-user video conference using the joinConf(conferenceId) method. Unlike calling a specific user via callTo(userId), here the conference identifier (String confId) is used to join an already created session on the server.
The interface is almost identical to Example 1, except that the joinConf(...) method is used instead of callTo(...).
Currently, only connection to existing conferences is supported.
In the setUpUI() method of the PlaceholderFragment class, here is an example of connecting to a conference when the Call button is pressed:
mBtnCall.setOnClickListener(v1 -> {
var conferenceId = mETConferenceId.getText().toString();
if (!conferenceId.isEmpty()) {
TrueConfSDK.getConferenceManager().joinConf(conferenceId);
}
});If the Conference ID is specified correctly, the app will connect to the corresponding conference:
This example demonstrates how to track user statuses on the server, as well as add a user for subsequent monitoring of their availability.
The implementation consists of two screens: the first connects to the server and authorizes the user, after which the second screen displays a list of users from the address book.
The example shows how to get the current user status using the getUserStatus(user) method, as well as how to handle status changes via the onUserStatusUpdate and onContactListUpdate callbacks.
To view the code, go to TestApp4 β java β com.trueconf.sample. This folder contains a few more files than previous examples, so let's briefly review them:
TestApp4.javaβ Application class. Initializes TrueConf SDK inonCreate(): sets the server, performs authorization, and establishes the connection.MainActivity4.javaβ UI entry point. LoadsContactListFragmentwhen the activity starts.ContactListFragment.javaβ UI fragment. Displays the user list, subscribes to status change events (onUserStatusUpdate,onContactListUpdate), allows adding users by ID. UsesContactsAdapter.ContactsAdapter.javaβ RecyclerView adapter. Displays the user ID and status with emoji. Updates data viaupdateContact, uses a ViewHolder.
π Component structure and interaction:
TestApp4 (Application)
β
βββββΆ TrueConf SDK initialization
β
βΌ
MainActivity4 (Activity)
β
βββββΆ Loads ContactListFragment
β
βββ Connects to TrueConf SDK
βββ Subscribes to user status events
βββ Displays user list (RecyclerView)
βββ Uses:
βΌ
ContactsAdapter (RecyclerView.Adapter)
βββ Stores user list
βββ Displays ID and status (emoji)
βββ Updates data on SDK events
π ContactListFragment.java: subscribing to events and managing the list
The ContactListFragment.java file implements a fragment that displays users with their current connection status. After the fragment is created and its layout is loaded in onViewCreated(), the current class is registered as an SDK event listener:
TrueConfSDK.getInstance().addTrueconfListener(this);This allows you to handle changes via callbacks:
onUserStatusUpdate(String id, PresenceStatus status)β called when a specific user's status changes;onContactListUpdate()β called when the contact list (address book) is updated.
When the add contact button is pressed, the user's status is retrieved by ID:
var peerId = addContactEdit.getText().toString();
var status = TrueConfSDK.getContactsManager().getUserStatus(peerId);The getUserStatus(String id) method returns a PresenceStatus valueβthis can be ONLINE, BUSY, LOGOFF, and other states. After getting the status, it is passed to the adapter:
adapter.updateContact(peerId, status);In onContactListUpdate(), the full address book of subscribers is obtained from the TrueConf server. The getUsers() method returns a list of all users available in the address book:
var peerList = TrueConfSDK.getContactsManager().getUsers();
adapter.contacts.clear();
adapter.contacts.addAll(peerList);
adapter.notifyDataSetChanged();This list is stored in the adapter, and the interface is updated via notifyDataSetChanged() if there are fewer than two items in the current list. This approach is used for initial data loading or restoring the list after a state reset.
Thus, the fragment implements full subscription to TrueConf SDK events and real-time UI updates.
π ContactsAdapter.java: displaying IDs and statuses with emoji
The ContactsAdapter class implements a RecyclerView adapter that displays the user's ID and current status. It works with ContactInfo objects containing the user's identifier and PresenceStatus value. Data formatting for display is implemented in the onBindViewHolder method, where the getStatusEmoji(...) function is called:
var text = peerId + " " + getStatusEmoji(status);
holder.binding.text.setText(text);The getStatusEmoji method maps PresenceStatus values to clear visual indicators, for example:
case ONLINE: return "π’ Online";
case BUSY: return "π Busy";π What do we get as a result?
This example demonstrates a practical implementation of the main mechanisms of TrueConf SDK for Android: subscribing to user status update events, obtaining the current state of subscribers, and loading the full address book from the server using the getUserStatus() and getUsers() methods.
Below are screenshots of the working Example 4 application:
In TrueConf SDK for Android, you can extend the call control panel by adding your own buttons via the IExtraButtonController interface. This allows you to trigger additional actions directly from the conference window, such as opening a fragment or navigating to another Activity.
Custom buttons are added using the setNewExtraButtons() method, which takes a list of TCExtraButton objects. These buttons appear in the conference interface when the user clicks the "more" (β―) button, which is the rightmost element of the call control panel during a call.
The IExtraButtonController is available via the SDK:
TrueConfSDK.getExtraButtonController()Below is a complete example of adding two buttons:
- The first button opens a
Fragment, - The second button launches an
Activity.
ArrayList<TCExtraButton> buttons = new ArrayList<>();
// Handler for the first button: open a Fragment over the conference
View.OnClickListener onClickListener = btn ->
((AppCompatActivity) btn.getContext())
.getSupportFragmentManager()
.beginTransaction()
.add(com.trueconf.sdk.R.id.container_call, new EmptyFragment())
.addToBackStack(null)
.commit();
// Handler for the second button: launch an Activity
View.OnClickListener onClickListener2 = btn -> {
Intent emptyActivity = new Intent (this, FirstActivity.class);
startActivity(emptyActivity);
};
// Create buttons and add to the list
buttons.add(new TCExtraButton("button 1", onClickListener));
buttons.add(new TCExtraButton("button 2", onClickListener2));
// Pass the button list to the SDK
TrueConfSDK.getExtraButtonController().setNewExtraButtons(buttons);The added buttons do not replace standard interface elements. They are displayed only when you click the "more" button (β―) on the bottom call control panel. They appear in the order in which they were added to the buttons list.
If you need to change the default icons (e.g., microphone, camera, speaker, end call button, etc.), you can replace the image resources in the res/drawable folder. The SDK will automatically use your custom versions if the filenames match the standard ones.
Here is the list of supported icon names for replacement:
ic_bluetooth_audio_arrow_off
ic_bluetooth_audio_arrow
ic_bluetooth_audio
ic_call_end
ic_camera_off
ic_camera_on
ic_dyn_arrow_off
ic_dyn_arrow
ic_empty_invoice
ic_headphones_arrow_off
ic_headphones_arrow
ic_headset_mic_arrow_off
ic_headset_mic_arrow
ic_headset_mic
ic_headset
ic_mic_off
ic_mic_on
ic_more_horiz
ic_phone_in_talk_arrow_off
ic_phone_in_talk_arrow
ic_phone_in_talk_off
ic_phone_in_talk
ic_sound_off
ic_sound_on
ic_rotate
ic_minimize_fullscreen
conf_button_back
Just add your versions of these icons with the corresponding names to res/drawable, and they will automatically replace the built-in ones.
Example 5 shows how you can integrate custom actions directly into the conference window with minimal effort, while maintaining the native look and feel of the interface. Thanks to the flexible IExtraButtonController API and the ability to override icons, developers can tailor the behavior and appearance of the panel to their application's needs.
The first button opens a Fragment, and the second opens an Activity.
This example demonstrates the implementation of a text chat, including sending messages with sendChatMessage() and handling incoming events via onChatMessageReceived().
In this section, we will look at how chat is implemented in a mobile app using TrueConf SDK, and show how sending, displaying, and processing of messages works from the application architecture perspective.
The sendChatMessage() method allows you to send a text message to a specified user:
TrueConfSDK.getChatManager().sendChatMessage(receiverId, messageText);Parameters:
toIDβ TrueConf ID of the recipient (in the formatuser@server.name). To send to the group chat of the current conference, you can pass an empty string.textβ message content.
Return value:
trueβ if the message was successfully sent to the server;falseβ if it failed due to loss of connection (in this case, the message is queued and will be sent when the connection is restored).
Tip
TrueConf SDK advantage: if the user is offline, the message will be delivered as soon as they come online.
To handle incoming messages, implement a callback:
@Override
public void onChatMessageReceived(String fromId, String fromName, String text, String toId) {
mAdapter.addNewMessage(fromId, fromName, text, toId, false);
}Parameters:
fromIdβ sender's ID;fromNameβ sender's name;textβ message text;toIdβ recipient's ID (your ID or conference).
In ChatPageFragment, inside the onViewCreated() method, the send button is handled:
view.findViewById(R.id.chat_action_button).setOnClickListener(v -> {
var receiverId = binding.toolbar.etTo.getText().toString();
var messageText = binding.toolbar.etChatMessage.getText().toString();
TrueConfSDK.getChatManager().sendChatMessage(receiverId, messageText);
mAdapter.addNewMessage(TrueConfSDK.getContactsManager().getMyId(), TrueConfSDK.getContactsManager().getMyName(),
messageText, receiverId, true);
});What happens:
- Get recipient ID and message text.
- Send the message via SDK.
- Add the message to the list (locally, for display in
RecyclerView).
All message display is handled via a RecyclerView and the ChatPageMsgsRecyclerAdapter:
mAdapter = new ChatPageMsgsRecyclerAdapter();
messagesRecycler.setAdapter(mAdapter);Each message is added using the method:
public void addNewMessage(String fromId, String fromName, String text, String outId, boolean isOut) {
messages.add(new ChatModel(fromId, fromName, text, outId, isOut));
notifyItemInserted(messages.size() - 1);
}Here, a ChatModel object is created with parameters:
fromIdandfromNameβ sender identification,textβ message text,outIdβ recipient ID,isOutgoingβ whether the message is from the current user.
The adapter's onBindViewHolder method handles the display of messages:
if (outgoing) {
tvMsgOutgoing.setText(msgText);
tvMsgOutgoing.setVisibility(View.VISIBLE);
tvMsgIncoming.setVisibility(View.GONE);
tvMsgIncomingSender.setVisibility(View.GONE);
} else {
tvMsgIncoming.setText(msgText);
tvMsgIncoming.setVisibility(View.VISIBLE);
tvMsgOutgoing.setVisibility(View.GONE);
tvMsgIncomingSender.setText(senderName);
}-
If the message is outgoing (
isOutgoing == true) β it is displayed on the right. -
Incoming messages are on the left, with the sender's name shown.
π‘ Things to consider:
- Use the full TrueConf ID (
user@server) β this increases delivery reliability. - You can use
sendChatMessage("", "text")to send to the group chat of the current conference. - All events and messages can be logged for debugging or analytics.
- The UI can be easily extended: add emoji, attachments, delivery/read indicators, etc.
In this example, we explore advanced customization capabilities of the video conference interface using TrueConf SDK for Android. Here, we demonstrate how a developer can completely override the behavior of standard conference windows and implement a custom UI with precise control over video windows and audio devices.
This example implements the following features:
- Replacing the standard incoming and outgoing call windows with custom
Fragmentimplementations. - Connecting a custom conference interface based on
ConferenceFragment. - Managing microphone, camera, and speaker via the SDK.
- Flexible adjustment of participant video window sizes and positions.
- Manual selection of audio devices during a call.
To override SDK windows, the following classes are replaced:
| Window Purpose | SDK Base Class | Custom Class from Example |
|---|---|---|
| Incoming call | IncomingCallFragment |
IncomingCallFragmentCast |
| Outgoing call | PlaceCallFragment |
PlaceCallFragmentCast |
| Conference window | ConferenceFragment |
ConferenceFragmentCast |
Custom window initialization is performed using the setCallCastFragments() method in MainActivity7:
TrueConfSDK.getCallScreenController().setPlaceCallFragment(new PlaceCallFragmentCast(...));
TrueConfSDK.getCallScreenController().setReceiveCallFragment(new IncomingCallFragmentCast(...));
TrueConfSDK.getCallScreenController().setConferenceFragment(new ConferenceFragmentCast(...));In the ConferenceFragmentCast.java file, manual control elements are added:
btnMic,btnCam,btnSpeakerβ toggle microphone, camera, and select audio device.btnFlip,btnCloseβ switch camera and end call.
Events are handled via SDK methods, for example:
btnMic.setOnClickListener(view -> onSwitchMic());
btnSpeaker.setOnClickListener(view -> {
TrueConfSDK.getAudioDeviceController().requestAudioState();
showDialog = true;
});The speaker button invokes an audio device selection dialog via the changeAudioDeviceDialog() method. This implementation allows the user to manually select the active audio device or completely mute sound:
TrueConfSDK.getAudioDeviceController().setDefaultAudioDevice(selectedDevice);The setCallLayoutParams() method allows you to set the call window size and position:
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.width = MATCH_PARENT;
params.height = 400dp;
params.gravity = Gravity.BOTTOM;
TrueConfSDK.getCallWindowController().setCallLayoutParams(params);This example supports manual placement of participant windows. Coordinates are set in a HashMap<String, Rect> forcedCells:
forcedCells.put("user1@trueconf.name", new Rect(0, 0, 400, 200));
forcedCells.put("user2@trueconf.name", new Rect(30, 310, 400, 510));To apply these values, uncomment the code in the onCalculateCustomLayouts() method:
var customGfxLayout = GfxLayout.NewInstance("just description");
customGfxLayout.SetManualMode(true);
customGfxLayout.SetUserCell(peerId, cell);
...
TrueConfSDK.getParticipantLayoutController().setCustomLayout(customGfxLayout);This gives the developer full control over the position and size of participant video windows on the screen.
The SDK provides convenient methods for enabling/disabling microphone and camera by default:
TrueConfSDK.getAudioDeviceController().setDefaultMicEnabled(true);
TrueConfSDK.getVideoDeviceController().setDefaultCameraEnabled(true);The current device status can be displayed in the UI via listeners:
@Override
public void onAudioDeviceUpdate(boolean playerMute, boolean recorderMute, AudioDeviceInfo pair) {
setupMic(recorderMute);
setupSpeaker(playerMute, pair);
}Status display is implemented by changing button icons depending on state:
btnMic.setImageResource(muteRecorder ? R.drawable.ic_mic_off : R.drawable.ic_mic);














