Skip to content

Commit

Permalink
Merge pull request #39 from nethesis/fix_recording_view
Browse files Browse the repository at this point in the history
recording view. show messages before recording
  • Loading branch information
edospadoni authored Feb 23, 2024
2 parents 7c3270a + 755d47d commit 261be4a
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 81 deletions.
52 changes: 52 additions & 0 deletions docs/EVENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ eventDispatch(`<event-name>`, `<data-object>`)
}
}

- `phone-island-audio-input-change` The event to change default audio input device for phone island

```json
{
"deviceId": "756ada2c6b10546e28808c13062982d66cae723eba1e03fe3834f8df79f794ee" // string - The input deviceId obtained by getUserMediaDevices
}
```

- `phone-island-audio-output-change` The event to change default audio output device for phone island

```json
{
"deviceId": "2d331f699ec92b95000f3a656ab1d6ff9f17b3c9502c4a8db1d3f91905b5743f" // string - The output deviceId obtained by getUserMediaDevices
}
```

## Dispatch Phone-Island Events - phone-island-*

- `phone-island-attached` The dispatch of initialize webrtc with phone-island (switch to webrtc device)
Expand All @@ -84,6 +100,16 @@ eventDispatch(`<event-name>`, `<data-object>`)
```json
{}

- `phone-island-audio-input-changed` The dispatch of change default audio input device for phone island

```json
{}

- `phone-island-audio-output-changed` The dispatch of change default audio output device for phone island

```json
{}


## Listen Call Events - phone-island-call-*

Expand Down Expand Up @@ -202,6 +228,22 @@ eventDispatch(`<event-name>`, `<data-object>`)
}
```

- `phone-island-call-audio-input-switch` The event to change audio input device during a call

```json
{
"deviceId": "756ada2c6b10546e28808c13062982d66cae723eba1e03fe3834f8df79f794ee" // string - The input deviceId obtained by getUserMediaDevices
}
```

- `phone-island-call-audio-output-switch` The event to change audio output device during a call

```json
{
"deviceId": "2d331f699ec92b95000f3a656ab1d6ff9f17b3c9502c4a8db1d3f91905b5743f" // string - The output deviceId obtained by getUserMediaDevices
}
```

## Dispatch Call Events - phone-island-call-*

- `phone-island-call-ringing` The dispatch of call ringing
Expand Down Expand Up @@ -313,6 +355,16 @@ eventDispatch(`<event-name>`, `<data-object>`)
```json
{}

- `phone-island-call-audio-input-switched` The dispatch of call input switch

```json
{}

- `phone-island-call-audio-output-switched` The dispatch of call output switch

```json
{}

## Listen Recording Events - phone-island-recording-*

- `phone-island-recording-open` The event to show the recording view.
Expand Down
4 changes: 3 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"Common": {
"Intrude": "Intrude",
"Listen": "Listen"
"Listen": "Listen",
"Start recording message before": "Click the button below to start recording",
"Start recording message after": "You can speak in a moment..."
},
"Tooltip": {
"Hangup": "Hangup",
Expand Down
4 changes: 3 additions & 1 deletion public/locales/it/translation.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"Common": {
"Intrude": "Intromesso",
"Listen": "Ascolto"
"Listen": "Ascolto",
"Start recording message before": "Premi il pulsante qui sotto per registrare",
"Start recording message after": "Puoi parlare tra poco..."
},
"Tooltip": {
"Hangup": "Chiudi",
Expand Down
41 changes: 40 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ import wakeUpWorker from './workers/wake_up'
import loadI18n from './lib/i18n'

import 'react-tooltip/dist/react-tooltip.css'
import { useEventListener, eventDispatch } from './utils'
import { useEventListener, eventDispatch, setJSONItem, getJSONItem } from './utils'
import { detach } from './lib/webrtc/messages'

interface PhoneIslandProps {
dataConfig: string
showAlways?: boolean
}

interface DeviceInputOutputTypes {
deviceId: string
}

export const PhoneIsland: FC<PhoneIslandProps> = ({ dataConfig, showAlways = false }) => {
const CONFIG: string[] = Base64.atob(dataConfig || '').split(':')
const HOST_NAME: string = CONFIG[0]
Expand Down Expand Up @@ -75,7 +79,31 @@ export const PhoneIsland: FC<PhoneIslandProps> = ({ dataConfig, showAlways = fal
eventDispatch('phone-island-detached', {})
})

useEventListener('phone-island-audio-input-change', (data: DeviceInputOutputTypes) => {
setJSONItem('phone-island-audio-input-device', { deviceId: data.deviceId })
eventDispatch('phone-island-audio-input-changed', {})
})
useEventListener('phone-island-audio-output-change', (data: DeviceInputOutputTypes) => {
const remoteAudioElement: any = store.getState().player.remoteAudio
// set audio output
remoteAudioElement?.current
.setSinkId(data.deviceId)
.then(function () {
console.info('Default audio output device change with success!')
// set device to localstorage
setJSONItem('phone-island-audio-output-device', { deviceId: data.deviceId })

// dispatch event
eventDispatch('phone-island-audio-output-changed', {})
})
.catch(function (err) {
console.error('Default audio output device change error:', err)
})
})

const [firstRenderI18n, setFirstRenderI18n] = useState(true)
const [firstAudioOutputInit, setFirstAudioOutputInit] = useState(true)

//initialize i18n
useEffect(() => {
if (firstRenderI18n) {
Expand All @@ -84,6 +112,17 @@ export const PhoneIsland: FC<PhoneIslandProps> = ({ dataConfig, showAlways = fal
}
}, [firstRenderI18n])

const remoteAudioElement: any = store.getState().player.remoteAudio

//initialize i18n
useEffect(() => {
if (firstAudioOutputInit && remoteAudioElement) {
const defaultAudioOutputDevice: any = getJSONItem(`phone-island-audio-output-device`)?.deviceId
eventDispatch('phone-island-audio-output-change', { deviceId: defaultAudioOutputDevice })
setFirstAudioOutputInit(false)
}
}, [firstAudioOutputInit, remoteAudioElement])

return (
<>
<Provider store={store}>
Expand Down
11 changes: 10 additions & 1 deletion src/components/RecorderView/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { dispatchRecordingSave } from '../../events'
import { Tooltip } from 'react-tooltip/dist/react-tooltip.min.cjs'
import { useTranslation } from 'react-i18next'
import { useEventListener, eventDispatch } from '../../utils'
import DropdownContent from '../SwitchInputView/DropdownContent'

export const Actions: FC<{}> = () => {
const dispatch = useDispatch<Dispatch>()
Expand Down Expand Up @@ -126,7 +127,7 @@ export const Actions: FC<{}> = () => {

return (
<div
className={`pi-flex pi-justify-center pi-items-center pi-pt-9 pi-gap-6`}
className={`pi-flex pi-items-center pi-justify-center pi-pt-9 pi-gap-6`}
style={recorded ? { paddingTop: '2rem' } : {}}
>
{recording && (
Expand Down Expand Up @@ -192,6 +193,7 @@ export const Actions: FC<{}> = () => {
style={{ transform: 'scale(1.15)' }}
data-tooltip-id='tooltip'
data-tooltip-content={t('Tooltip.Start recording')}
className='pi-flex pi-justify-center pi-ml-[4.7rem]'
>
{waiting ? (
<FontAwesomeIcon icon={faCircleNotch} className='fa-spin pi-loader' size='lg' />
Expand All @@ -200,6 +202,13 @@ export const Actions: FC<{}> = () => {
)}
</Button>
)}
{!recording && !recorded && (
<div
className='pi-flex-none pi-justify-end pi-ml-11 pi-w-2'
>
<DropdownContent data-stop-propagation={true}></DropdownContent>
</div>
)}
{/* Buttons tooltips */}
<Tooltip className='pi-z-20' id='tooltip' place='bottom' />
</div>
Expand Down
18 changes: 15 additions & 3 deletions src/components/RecorderView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Progress from '../AudioPlayerView/Progress'
import { updateAudioPlayerSource } from '../../lib/phone/audio'
import fixWebmDuration from 'webm-duration-fix'
import Timer from './Timer'
import { useTranslation } from 'react-i18next'

// The number of groups to be created
// ...the minimun to have this effect is 2
Expand All @@ -31,10 +32,11 @@ export const RecorderView: FC<RecorderViewProps> = () => {
const localAudioStream = useSelector((state: RootState) => state.webrtc.localAudioStream)

// Retrieve the local audio stream from recorder state
const { recording, recorded } = useSelector(
const { recording, recorded, waiting } = useSelector(
(state: RootState) => ({
recording: state.recorder.recording,
recorded: state.recorder.recorded,
waiting: state.recorder.waiting,
}),
shallowEqual,
)
Expand Down Expand Up @@ -83,6 +85,8 @@ export const RecorderView: FC<RecorderViewProps> = () => {
}
}, [])

const { t } = useTranslation()

return (
<>
{isOpen ? (
Expand All @@ -95,14 +99,14 @@ export const RecorderView: FC<RecorderViewProps> = () => {
</div>
{/* Bars animation section */}
<div
className={`pi-relative pi-w-full ${
className={`pi-relative pi-w-full pi-justify-center ${
!recorded ? 'pi-h-8' : ''
} pi-overflow-x-hidden pi-flex`}
ref={visibleContainerRef}
>
{recorded ? (
<Progress />
) : (
) : recording && !waiting ? (
// Create a custom numbers of bars groups
Array.from({ length: BAR_GROUPS_COUNT }).map((_, i) => (
<BarsGroup
Expand All @@ -112,6 +116,14 @@ export const RecorderView: FC<RecorderViewProps> = () => {
audioStream={localAudioStream}
/>
))
) : recording && waiting ? (
<div className='pi-sans pi-text-sm pi-w-fit pi-h-fit pi-text-white'>
{t('Common.Start recording message after')}
</div>
) : (
<div className='pi-sans pi-text-sm pi-w-fit pi-h-fit pi-text-white'>
{t('Common.Start recording message before')}
</div>
)}
</div>
{/* Actions section */}
Expand Down
72 changes: 55 additions & 17 deletions src/components/SwitchInputView/DropdownContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,75 @@ import { faCheck, faEllipsis, faMicrophone, faVolumeHigh } from '@fortawesome/fr
import { Menu, Transition } from '@headlessui/react'
import { t } from 'i18next'
import { isWebRTC } from '../../lib/user/default_device'
import { eventDispatch, getJSONItem, setJSONItem, useEventListener } from '../../utils'

const DropdownContent: FC<DropdownContentProps> = ({ username, status }) => {
const { sipcall }: any = useSelector((state: RootState) => state.webrtc)
const remoteAudioElement: any = useSelector((state: RootState) => state.player.remoteAudio)

const [selectedAudioInput, setSelectedAudioInput] = useState<string | null>(null)
const [selectedAudioOutput, setSelectedAudioOutput] = useState<string | null>(null)
const [selectedAudioInput, setSelectedAudioInput] = useState<string | null>(
getJSONItem('phone-island-audio-input-device').deviceId || null,
)
const [selectedAudioOutput, setSelectedAudioOutput] = useState<string | null>(
getJSONItem('phone-island-audio-output-device').deviceId || null,
)

const handleClickAudioInput = (audioInputDevice: string) => {
setSelectedAudioInput(audioInputDevice)

sipcall?.replaceTracks({
tracks: [
{
type: 'audio',
mid: '0', // We assume mid 0 is audio
capture: { deviceId: { exact: audioInputDevice } },
if (sipcall.webrtcStuff.myStream) {
sipcall?.replaceTracks({
tracks: [
{
type: 'audio',
mid: '0', // We assume mid 0 is audio
capture: { deviceId: { exact: audioInputDevice } },
},
],
success: function () {
console.info('Audio input device switch success!')
// set device to localstorage
setJSONItem('phone-island-audio-input-device', { deviceId: audioInputDevice })

// dispatch event
eventDispatch('phone-island-call-audio-input-switched', {})
},
],
error: function (err) {
console.log('Audio input device switch error:', err)
},
})
error: function (err) {
console.error('Audio input device switch error:', err)
},
})
} else {
// set device to localstorage
setJSONItem('phone-island-audio-input-device', { deviceId: audioInputDevice })

// dispatch event
eventDispatch('phone-island-call-audio-input-switched', {})
}
}
useEventListener('phone-island-call-audio-input-switch', (data: DeviceInputOutputTypes) => {
handleClickAudioInput(data.deviceId)
})

const handleClickAudioOutput = (audioOutputDevice: string) => {
setSelectedAudioOutput(audioOutputDevice)

remoteAudioElement?.current
.setSinkId(audioOutputDevice)
.then(function () {})
.then(function () {
console.info('Audio output device switch success!')
// set device to localstorage
setJSONItem('phone-island-audio-output-device', { deviceId: audioOutputDevice })

// dispatch event
eventDispatch('phone-island-call-audio-output-switched', {})
})
.catch(function (err) {
console.log('Audio output device switch error:', err)
console.error('Audio output device switch error:', err)
})
}
useEventListener('phone-island-call-audio-output-switch', (data: DeviceInputOutputTypes) => {
handleClickAudioOutput(data.deviceId)
})

const [actualDevice, setActualDevice]: any = useState([])

Expand Down Expand Up @@ -147,7 +181,7 @@ const DropdownContent: FC<DropdownContentProps> = ({ username, status }) => {
} pi-text-gray-100 pi-mr-1`}
/>
<div className='pi-text-gray-50'>
{audioDevice?.label || `Device ${index + 1}`}
{audioDevice?.label || `Input device ${index + 1}`}
</div>
</div>
)}
Expand Down Expand Up @@ -222,7 +256,7 @@ const DropdownContent: FC<DropdownContentProps> = ({ username, status }) => {
className='pi-text-gray-100 pi-mr-2'
/> */}
<div className='pi-text-gray-50'>
{audioDevice?.label || `Device ${index + 1}`}
{audioDevice?.label || `Output device ${index + 1}`}
</div>
</div>
)}
Expand Down Expand Up @@ -259,4 +293,8 @@ interface DropdownContentProps extends ComponentProps<'div'> {
status?: string
}

interface DeviceInputOutputTypes {
deviceId: string
}

export default DropdownContent
Loading

0 comments on commit 261be4a

Please sign in to comment.