diff --git a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/CallComposite.java b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/CallComposite.java index 2647165337..6278c06e50 100644 --- a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/CallComposite.java +++ b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/CallComposite.java @@ -22,6 +22,9 @@ import com.azure.android.communication.ui.calling.models.CallCompositeAudioSelectionChangedEvent; import com.azure.android.communication.ui.calling.models.CallCompositeCallStateCode; import com.azure.android.communication.ui.calling.models.CallCompositeCallStateChangedEvent; +/* */ +import com.azure.android.communication.ui.calling.models.CallCompositeCaptionsReceivedEvent; +/* */ import com.azure.android.communication.ui.calling.models.CallCompositeDebugInfo; import com.azure.android.communication.ui.calling.models.CallCompositeDismissedEvent; import com.azure.android.communication.ui.calling.models.CallCompositeErrorEvent; @@ -673,6 +676,40 @@ public void removeOnPictureInPictureChangedEventHandler( configuration.getCallCompositeEventsHandler().removeOnMultitaskingStateChangedEventHandler(eventHandler); } + /* */ + /** + * Add on captions received event handler {@link CallCompositeEventHandler}. + * + *
+     *
+     * // add on captions received event handler
+     * callComposite.addOnCaptionsReceivedEventHandler(event -> {
+     *     // Process captions received event
+     *     System.out.println(event.getSpeakerName());
+     *     System.out.println(event.getCaptionText());
+     *     System.out.println(event.getIsFinal());
+     * });
+     *
+     * 
+ * + * @param handler The {@link CallCompositeEventHandler}. + */ + public void addOnCaptionsReceivedEventHandler( + final CallCompositeEventHandler handler) { + configuration.getCallCompositeEventsHandler().addOnCaptionsReceivedEventHandler(handler); + } + + /** + * Remove on captions received event handler {@link CallCompositeEventHandler}. + * + * @param handler The {@link CallCompositeEventHandler}. + */ + public void removeOnCaptionsReceivedEventHandler( + final CallCompositeEventHandler handler) { + configuration.getCallCompositeEventsHandler().removeOnCaptionsReceivedEventHandler(handler); + } + /*
*/ + /** * Set {@link CallCompositeParticipantViewData}. * diff --git a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/configuration/events/CallCompositeEventsHandler.kt b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/configuration/events/CallCompositeEventsHandler.kt index 144a527b30..af17fe3525 100644 --- a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/configuration/events/CallCompositeEventsHandler.kt +++ b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/configuration/events/CallCompositeEventsHandler.kt @@ -3,17 +3,21 @@ package com.azure.android.communication.ui.calling.configuration.events + import com.azure.android.communication.ui.calling.CallCompositeEventHandler +import com.azure.android.communication.ui.calling.models.CallCompositeAudioSelectionChangedEvent import com.azure.android.communication.ui.calling.models.CallCompositeCallStateChangedEvent -import com.azure.android.communication.ui.calling.models.CallCompositeErrorEvent -import com.azure.android.communication.ui.calling.models.CallCompositePictureInPictureChangedEvent +/* */ +import com.azure.android.communication.ui.calling.models.CallCompositeCaptionsReceivedEvent +/* */ import com.azure.android.communication.ui.calling.models.CallCompositeDismissedEvent -import com.azure.android.communication.ui.calling.models.CallCompositeRemoteParticipantJoinedEvent -import com.azure.android.communication.ui.calling.models.CallCompositeUserReportedIssueEvent -import com.azure.android.communication.ui.calling.models.CallCompositeAudioSelectionChangedEvent +import com.azure.android.communication.ui.calling.models.CallCompositeErrorEvent import com.azure.android.communication.ui.calling.models.CallCompositeIncomingCallCancelledEvent import com.azure.android.communication.ui.calling.models.CallCompositeIncomingCallEvent +import com.azure.android.communication.ui.calling.models.CallCompositePictureInPictureChangedEvent +import com.azure.android.communication.ui.calling.models.CallCompositeRemoteParticipantJoinedEvent import com.azure.android.communication.ui.calling.models.CallCompositeRemoteParticipantLeftEvent +import com.azure.android.communication.ui.calling.models.CallCompositeUserReportedIssueEvent /* */ import java.util.Date /* */ @@ -50,6 +54,10 @@ internal class CallCompositeEventsHandler { mutableSetOf>() /* */ + /* */ + private val onCaptionsReceivedHandlers = mutableSetOf>() + /* */ + fun getOnErrorHandlers() = errorHandlers.asIterable() fun addOnErrorEventHandler(errorHandler: CallCompositeEventHandler) = @@ -145,4 +153,16 @@ internal class CallCompositeEventsHandler { callStartTimeUpdatedEventHandlers.remove(eventHandler) } /* */ + + /* */ + fun addOnCaptionsReceivedEventHandler(handler: CallCompositeEventHandler) { + onCaptionsReceivedHandlers.add(handler) + } + + fun removeOnCaptionsReceivedEventHandler(handler: CallCompositeEventHandler) { + onCaptionsReceivedHandlers.remove(handler) + } + + internal fun getCaptionsReceivedEventHandlers() = onCaptionsReceivedHandlers.asIterable() + /* */ } diff --git a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/di/DependencyInjectionContainerImpl.kt b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/di/DependencyInjectionContainerImpl.kt index 3ddafc0374..6cfebaf4b5 100644 --- a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/di/DependencyInjectionContainerImpl.kt +++ b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/di/DependencyInjectionContainerImpl.kt @@ -94,6 +94,9 @@ internal class DependencyInjectionContainerImpl( override val captionsRttDataManager by lazy { CaptionsRttDataManager( + /* */ + configuration, + /* */ callingService, appStore, avatarViewManager, diff --git a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/models/CallCompositeCaptionsReceivedEvent.java b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/models/CallCompositeCaptionsReceivedEvent.java new file mode 100644 index 0000000000..21d8b4a62c --- /dev/null +++ b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/models/CallCompositeCaptionsReceivedEvent.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +/* */ +package com.azure.android.communication.ui.calling.models; + +/** + * Call composite captions received event. + */ +public class CallCompositeCaptionsReceivedEvent { + private final String speakerName; + private final String speakerRawId; + private final String captionText; + private final String languageCode; + + CallCompositeCaptionsReceivedEvent( + final String speakerName, + final String speakerRawId, + final String captionText, + final String languageCode) { + this.speakerName = speakerName; + this.speakerRawId = speakerRawId; + this.captionText = captionText; + this.languageCode = languageCode; + } + + /** + * Get speaker name. + * @return Speaker name + */ + public String getSpeakerName() { return speakerName; } + + /** + * Get speaker raw id. + * @return Speaker raw id + */ + public String getSpeakerRawId() { return speakerRawId; } + + /** + * Get caption text. + * @return Caption text + */ + public String getCaptionText() { return captionText; } + + /** + * Get language code. + * @return Language code + */ + public String getLanguageCode() { return languageCode; } +} +/* */ diff --git a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/models/CallCompositeExtensions.kt b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/models/CallCompositeExtensions.kt index 83355c0313..5d243f7810 100644 --- a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/models/CallCompositeExtensions.kt +++ b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/models/CallCompositeExtensions.kt @@ -59,3 +59,19 @@ internal fun CallCompositeButtonViewData.setEnabledChangedEventHandler(handler: internal fun CallCompositeButtonViewData.setVisibleChangedEventHandler(handler: CallCompositeEventHandler) { this.visibleChangedEventHandler = handler } + +/* */ +internal fun createCallCompositeCaptionsReceivedEvent( + speakerName: String, + speakerRawId: String, + captionText: String, + languageCode: String, +): CallCompositeCaptionsReceivedEvent { + return CallCompositeCaptionsReceivedEvent( + speakerName, + speakerRawId, + captionText, + languageCode + ) +} +/* */ diff --git a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/presentation/manager/CaptionsRttDataManager.kt b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/presentation/manager/CaptionsRttDataManager.kt index 515fd98648..2999a36720 100644 --- a/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/presentation/manager/CaptionsRttDataManager.kt +++ b/azure-communication-ui/calling/src/main/java/com/azure/android/communication/ui/calling/presentation/manager/CaptionsRttDataManager.kt @@ -5,9 +5,15 @@ package com.azure.android.communication.ui.calling.presentation.manager import android.graphics.Bitmap import com.azure.android.communication.common.CommunicationIdentifier +/* */ +import com.azure.android.communication.ui.calling.configuration.CallCompositeConfiguration +/* */ import com.azure.android.communication.ui.calling.models.CallCompositeCaptionsData import com.azure.android.communication.ui.calling.models.CaptionsResultType import com.azure.android.communication.ui.calling.models.RttMessage +/* */ +import com.azure.android.communication.ui.calling.models.createCallCompositeCaptionsReceivedEvent +/* */ import com.azure.android.communication.ui.calling.presentation.fragment.calling.CallingFragment import com.azure.android.communication.ui.calling.presentation.fragment.calling.captions.CaptionsRttRecord import com.azure.android.communication.ui.calling.presentation.fragment.calling.captions.CaptionsRttType @@ -32,6 +38,9 @@ import java.util.Date import kotlin.math.min internal class CaptionsRttDataManager( + /* */ + private val configuration: CallCompositeConfiguration, + /* */ private val callingService: CallingService, private val appStore: AppStore, private val avatarViewManager: AvatarViewManager, @@ -226,6 +235,9 @@ internal class CaptionsRttDataManager( if (lastCaptionFromSameUser != null && shouldFinalizeLastCaption(lastCaptionFromSameUser, newCaptionsRecord)) { lastCaptionFromSameUser = finalizeLastCaption(lastCaptionFromSameUser) + /* */ + notifyCaptionReceived(lastCaptionFromSameUser) + /* */ } if (lastCaptionFromSameUser?.isFinal == false) { @@ -233,7 +245,29 @@ internal class CaptionsRttDataManager( } else { addNewCaption(newCaptionsRecord) } + + /* */ + if (newCaptionsRecord.isFinal) { + notifyCaptionReceived(newCaptionsRecord) + } + /* */ + } + + /* */ + private fun notifyCaptionReceived(finalizedCaptionsRecord: CaptionsRttRecord) { + val event = createCallCompositeCaptionsReceivedEvent( + finalizedCaptionsRecord.displayName ?: "", + finalizedCaptionsRecord.speakerRawId ?: "", + finalizedCaptionsRecord.displayText, + finalizedCaptionsRecord.languageCode ?: "" + ) + + configuration.callCompositeEventsHandler.getCaptionsReceivedEventHandlers() + .forEach { handler -> + handler.handle(event) + } } + /* */ private fun getLastCaptionFromUser(speakerRawId: String?, type: CaptionsRttType): CaptionsRttRecord? { return captionsAndRttMutableList.lastOrNull { it.type == type && it.speakerRawId == speakerRawId } diff --git a/azure-communication-ui/demo-app/src/calling/java/com/azure/android/communication/ui/callingcompositedemoapp/CallCompositeManager.kt b/azure-communication-ui/demo-app/src/calling/java/com/azure/android/communication/ui/callingcompositedemoapp/CallCompositeManager.kt index 0f406a025c..9deba42a19 100644 --- a/azure-communication-ui/demo-app/src/calling/java/com/azure/android/communication/ui/callingcompositedemoapp/CallCompositeManager.kt +++ b/azure-communication-ui/demo-app/src/calling/java/com/azure/android/communication/ui/callingcompositedemoapp/CallCompositeManager.kt @@ -377,6 +377,15 @@ class CallCompositeManager(private val context: Context) { RemoteParticipantJoinedHandler(callComposite, context) ) } + + /* */ + callComposite.addOnCaptionsReceivedEventHandler { + toast( + context, + "Captions received: speakerName: ${it.speakerName}, speakerRawId: ${it.speakerRawId}, captionText: ${it.captionText}, languageCode: ${it.languageCode}" + ) + } + /* */ } fun dismissCallComposite() {