Add Chat Feature to Demo of Amazon Chime SDK React Component Library
Tags: JavaScript, React, AWS, Videoconference

Add Chat Feature to Demo of Amazon Chime SDK React Component Library dannadori Follow Nov 30 · 7 min read

Note:

This article is also available here.(Japanese)

https://cloud.flect.co.jp/entry/2020/11/30/125920

In our last article, we posted a brief introduction to the Amazon Chime SDK React Component Library. At the time of writing, the latest update of this library, ver 1.5.0, added Chat-related components. I’m going to use it to add Chat functionality to an official AWS demo.

Like this.

Note: that this article is a bit complicated, using React coding. If you simply want to run the code, the URL of the repository is given at the end of this article, so you can get the code from there and run it.

At First

This time, we will add Chat functionality based on the demo provided by the official. First, make sure you have a working sample of ver 1.5.0, referring to the previous article.

Approach

Generally, the Amazon Chime SDK React Component Library provides React components as well as hooks and providers (Context APIs) that work behind the components to make it easier to use Amazon Chime’s features.

With the addition of the Chat-related components, I was hoping that they would provide providers or hooks to enable Chat functionality, but unfortunately, they haven’t yet. This issue says that you should implement it yourself with data messages for real-time signaling. Please refer to my previous article on data messages for real-time signaling.

So, I would like to implement a provider that uses data messages for real-time signaling by myself.

RealitimeSubscribeChatStateProvider

We will name the provider we will create as RealtimeSubscribeChatStateProvider. The following is a brief description of the content of the provider, in excerpts that we think are important. The entire source code can be found here.

Call userealitimeSubscribeChatState() of this provider so that you can refer to the Chat features and data.

Definition of State

Define the State (Chat function and data) provided by userealitimeSubscribeChatState(). If you just want to create a simple Chat function, the following two variables should be sufficient.

export interface RealitimeSubscribeChatStateValue {

chatData: RealtimeData[]

sendChatData: (mess: string) => void

}

The RealtimeData used in the interface is the actual data to be sent and received. In this article, we have defined the following data structure.

export type RealtimeData = {

uuid: string

data: any

createdDate: number

senderName: string

//<snip>

}

useRealitimeSubscribeChatState()

The method to provide the above State is as follows: when creating a provider using the Context API, I think it’s almost formulaic, so I won’t describe it.

export const useRealitimeSubscribeChatState = (): RealitimeSubscribeChatStateValue => {

const state = useContext(RealitimeSubscribeChatStateContext)

if (!state) {

// handle exception

}

return state

}

Definition of Provider

Sending and receiving data messages for real-time signaling is done by AudioVideoFacade. You can get a reference to this AudioVideoFacade with useAudioVideo() (1–1), and you can get the username with useAppState() (1–2). The user name can be retrieved with useAppState() (1–2). The Chat text data is managed by this provider using useState. (1–3)

In (2–1), we define a data transmission function using data messages for real-time signaling. We call the method of audioVideo (AudioVideoFacade) to send the data. In this time, we specify “CHAT” because we can specify the topic (2–2). Also, since the sender can’t receive the sent data , you should add the sent data to the Chat text data after sending(2–3).

useEffect registers (and deletes) a function for receiving data messages for real-time signaling (3–1), (3–2). The receive function itself just parses the received data and adds it to the text data of Chat, as shown in (3–3).

export const RealitimeSubscribeChatStateProvider = ({ children }: Props) => {

const audioVideo = useAudioVideo() // <----- (1-1)

const { localUserName } = useAppState() // <----- (1-2)

const [chatData, setChatData] = useState([] as RealtimeData[]) // <----- (1-3)



const sendChatData = (text: string) => { // <----- (2-1)

const mess: RealtimeData = {

uuid: v4(),

data: text,

createdDate: new Date().getTime(),

senderName: localUserName

}

audioVideo!.realtimeSendDataMessage("CHAT" as DataMessageType, JSON.stringify(mess)) // <----- (2-2)

setChatData([...chatData, mess]) // <----- (2-3)

}



const receiveChatData = (mess: DataMessage) => { // <----- (3-3)

const data = JSON.parse(mess.text()) as RealtimeData

setChatData([...chatData, data])

}



useEffect(() => {

audioVideo!.realtimeSubscribeToReceiveDataMessage( // <----- (3-1)

"CHAT" as DataMessageType,

receiveChatData

)

return () => {

audioVideo!.realtimeUnsubscribeFromReceiveDataMessage("CHAT" as DataMessageType) // <----- (3-2)

}

})



const providerValue = {

chatData,

sendChatData,

}

return (

<RealitimeSubscribeChatStateContext.Provider value={providerValue}>

{children}

</RealitimeSubscribeChatStateContext.Provider>

)

}

GUI

Next, I’m going to go over the part that displays the Chat screen. Here is another excerpt of what we think is important.

Adding RealitimeSubscribeStateProvider

Modify the DOM of MeetingView to allow the above created providers to be used in the conference room. Add a real-timeSubscribeStateProvider to the (1) part. This will allow the Chat feature to be used in the subordinate Views.

const MeetingView = () => {

useMeetingEndRedirect();

const { showNavbar, showRoster, showChat } = useNavigation();



return (

<UserActivityProvider>

<StyledLayout showNav={showNavbar} showRoster={showRoster || showChat}>

<RealitimeSubscribeStateProvider> // <--- (1)

<StyledContent>

<MeetingMetrics />

<VideoTileGrid

className="videos"

noRemoteVideoView={<MeetingDetails />}

/>

<MeetingControls />

</StyledContent>

<NavigationControl />

</RealitimeSubscribeStateProvider>

</StyledLayout>

</UserActivityProvider>

);

};

ChatView

In (1), we get the chat data and a reference to the data sending function using the userealitimeSubscribeChatState() we created earlier. In (2–1) and (2–2), we use the Chat component of the Amazon Chime SDK React Component Library to generate the display part (more on this later). (3) calls the send function of the chat data.

const ChatView = () => {

const { localUserName } = useAppState()

const { closeChat } = useNavigation();

const { chatData, sendChatData } = useRealitimeSubscribeChatState() // <---- (1)

const [ chatMessage, setChatMessage] = useState('');



const attendeeItems = []

for (let c of chatData) { // <---- (2-1)

const senderName = c.senderName

const text = c.data

const time = (new Date(c.createdDate)).toLocaleTimeString('ja-JP')

attendeeItems.push(

<ChatBubbleContainer timestamp={time} key={time+senderName}> // <---- (2-2)

<ChatBubble

variant= {localUserName === senderName ? "outgoing" : "incoming"}

senderName={senderName}

content={text}

showTail={true}

css={bubbleStyles}

/>

</ChatBubbleContainer>

)

}



return (



<Roster className="roster">

<RosterHeader title="Chat" onClose={()=>{closeChat}}>

</RosterHeader>

{attendeeItems}

<br/>

<Textarea

//@ts-ignore

onChange={e => setChatMessage(e.target.value)}

value={chatMessage}

placeholder="input your message"

type="text"

label=""

style={{resize:"vertical",}}

/>

<PrimaryButton

label="send"

onClick={e=>{

setChatMessage("")

sendChatData(chatMessage) // <---- (3)

}}

/>

</Roster>

);

}

The rest you have to do is enable this ChatView to be displayed from a navibar. The display from the navibar is not essential in this case, and it contains several minor modifications, so I will not describe it. Please check the changes from the repository’s commit log.

Run

Now, let’s see how it works. If you type a message like this, you’ll see a message on your screen with the other person.

For your own message (which has an outgoing variant attribute), it will be a blue speech bubble. For other messages, it will be a white speech bubble.

You can toggle the display of the balloon’s tail (which, in cartoon terms, indicates where the balloon originates) by using the tail attribute, but you can’t change its direction.

Otherwise, you can omit the time or add action buttons.

Repository

You can find the source code for this one in the “chat_feature” branch of the following repository

You can launch it in the same way as the way we ran the demo in the previous article, so check out how it works.

Finally

This is a look at adding chat functionality to the official Amazon Chime SDK React Component Library demo. Although I had to touch the raw Amazon Chime SDK a bit, I was able to create a chat GUI that was consistent with the other components without too much effort.

In addition to the chat function introduced here, the following repositories provide a version with a whiteboard function. Also, Cognito integration and virtual backgrounds are implemented in the following repositories.

Virtual Background

Whiteboard