Merge pull request #48 from daily-demos/dev-1074-update-recording-examples-demo-with-new
DEV-1074: Additional recording type support
This commit is contained in:
commit
f735bcf250
|
|
@ -6,14 +6,14 @@
|
|||
|
||||
## What does this demo do?
|
||||
|
||||
- Use [startRecording](https://docs.daily.co/reference#%EF%B8%8F-startrecording) to create a video and audio recording of your call. You can read more about Daily call recording (and the different modes and types) [here](https://docs.daily.co/reference#recordings)
|
||||
- Supports both `cloud` and `local` recording modes (specified when creating the room or managed using the Daily dashboard)
|
||||
- Use [startRecording](https://docs.daily.co/reference#%EF%B8%8F-startrecording) to create a video and audio recording of your call. You can read more about Daily call recording (and the different modes and types) [here](https://docs.daily.co/guides/recording-calls-with-the-daily-api)
|
||||
- Supports `cloud`, `cloud-beta`, `local`, and `rtp-tracks` recording modes (specified when creating the room or managed using the Daily dashboard). _Heads up: if recording on mobile devices or Safari, then `cloud-beta` must be the specified mode._
|
||||
- Coming soon: support different recording layouts / composites
|
||||
- Coming soon: use the Daily REST API to retrieve a list of cloud recordings for the currently active room
|
||||
|
||||
**To turn on recording, you need to be on the Scale plan. There is also a per minute recording fee for cloud recording.**
|
||||
|
||||
Please note: this demo is not currently mobile optimised
|
||||
Please note: this demo is not currently mobile optimised.
|
||||
|
||||
### Getting started
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import {
|
|||
RECORDING_RECORDING,
|
||||
RECORDING_SAVED,
|
||||
RECORDING_TYPE_CLOUD,
|
||||
RECORDING_TYPE_CLOUD_BETA,
|
||||
RECORDING_TYPE_RTP_TRACKS,
|
||||
RECORDING_UPLOADING,
|
||||
useRecording,
|
||||
} from '../contexts/RecordingProvider';
|
||||
|
|
@ -92,7 +94,7 @@ export const RecordingModal = () => {
|
|||
{!enableRecording ? (
|
||||
<Well variant="error">
|
||||
Recording is not enabled for this room (or your browser does not
|
||||
support it.) Please enabled recording when creating the room or via
|
||||
support it.) Please enable recording when creating the room or via
|
||||
the Daily dashboard.
|
||||
</Well>
|
||||
) : (
|
||||
|
|
@ -105,7 +107,9 @@ export const RecordingModal = () => {
|
|||
<p>Recording started: {recordingStartedDate.toString()}</p>
|
||||
)}
|
||||
|
||||
{enableRecording === RECORDING_TYPE_CLOUD && (
|
||||
{[RECORDING_TYPE_CLOUD, RECORDING_TYPE_CLOUD_BETA].includes(
|
||||
enableRecording
|
||||
) && (
|
||||
<>
|
||||
<hr />
|
||||
|
||||
|
|
@ -115,6 +119,24 @@ export const RecordingModal = () => {
|
|||
</p>
|
||||
</>
|
||||
)}
|
||||
{enableRecording === RECORDING_TYPE_RTP_TRACKS && (
|
||||
<>
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
rtp-tracks recordings can be accessed via the Daily API. See the{' '}
|
||||
<a
|
||||
href="https://docs.daily.co/guides/recording-calls-with-the-daily-api#retrieve-individual-tracks-from-rtp-tracks-recordings"
|
||||
noreferrer
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Daily recording guide
|
||||
</a>{' '}
|
||||
for details.
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</CardBody>
|
||||
</Modal>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,10 @@ export const RECORDING_COUNTDOWN_3 = 'starting3';
|
|||
export const RECORDING_IDLE = 'idle';
|
||||
|
||||
export const RECORDING_TYPE_CLOUD = 'cloud';
|
||||
export const RECORDING_TYPE_CLOUD_BETA = 'cloud-beta';
|
||||
export const RECORDING_TYPE_LOCAL = 'local';
|
||||
export const RECORDING_TYPE_OUTPUT_BYTE_STREAM = 'output-byte-stream';
|
||||
export const RECORDING_TYPE_RTP_TRACKS = 'rtp-tracks';
|
||||
|
||||
const RecordingContext = createContext({
|
||||
isRecordingLocally: false,
|
||||
|
|
@ -37,8 +40,12 @@ const RecordingContext = createContext({
|
|||
});
|
||||
|
||||
export const RecordingProvider = ({ children }) => {
|
||||
const { callObject, enableRecording, startCloudRecording, state } =
|
||||
useCallState();
|
||||
const {
|
||||
callObject,
|
||||
enableRecording,
|
||||
startCloudRecording,
|
||||
state,
|
||||
} = useCallState();
|
||||
const { participants } = useParticipants();
|
||||
const [recordingStartedDate, setRecordingStartedDate] = useState(null);
|
||||
const [recordingState, setRecordingState] = useState(RECORDING_IDLE);
|
||||
|
|
@ -85,19 +92,27 @@ export const RecordingProvider = ({ children }) => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleRecordingUploadCompleted = () => {
|
||||
setRecordingState(RECORDING_SAVED);
|
||||
// The 'recording-data' event is emitted when an output-byte-stream recording has started
|
||||
// When the event emits, start writing data to the stream created in handleRecordingStarted()
|
||||
const handleRecordingData = async (ev) => {
|
||||
try {
|
||||
console.log('got data', ev);
|
||||
await window.writer.write(ev.data);
|
||||
if (ev.finished) {
|
||||
console.log('closing!');
|
||||
window.writer.close();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
callObject.on('app-message', handleAppMessage);
|
||||
callObject.on('recording-upload-completed', handleRecordingUploadCompleted);
|
||||
callObject.on('recording-data', handleRecordingData);
|
||||
|
||||
return () => {
|
||||
callObject.off('app-message', handleAppMessage);
|
||||
callObject.off(
|
||||
'recording-upload-completed',
|
||||
handleRecordingUploadCompleted
|
||||
);
|
||||
callObject.off('recording-data', handleRecordingData);
|
||||
};
|
||||
}, [callObject, enableRecording]);
|
||||
|
||||
|
|
@ -155,13 +170,26 @@ export const RecordingProvider = ({ children }) => {
|
|||
*/
|
||||
const handleRecordingStarted = useCallback(
|
||||
(event) => {
|
||||
console.log('RECORDING');
|
||||
console.log(event);
|
||||
|
||||
if (recordingState === RECORDING_RECORDING) return;
|
||||
setRecordingState(RECORDING_RECORDING);
|
||||
if (event.local) {
|
||||
// Recording started locally, either through UI or programmatically
|
||||
setIsRecordingLocally(true);
|
||||
if (!recordingStartedDate) setRecordingStartedDate(new Date());
|
||||
// If an output-byte-stream recording has started, create a new data stream that can be piped to a third-party (in this case a file)
|
||||
if (event.type === 'output-byte-stream') {
|
||||
const { readable, writable } = new TransformStream({
|
||||
transform: (chunk, ctrl) => {
|
||||
chunk.arrayBuffer().then((b) => ctrl.enqueue(new Uint8Array(b)));
|
||||
},
|
||||
});
|
||||
window.writer = writable.getWriter();
|
||||
readable.pipeTo(window.streamSaver.createWriteStream('test-vid.mp4'));
|
||||
}
|
||||
}
|
||||
setRecordingState(RECORDING_RECORDING);
|
||||
},
|
||||
[recordingState, recordingStartedDate]
|
||||
);
|
||||
|
|
@ -179,7 +207,8 @@ export const RecordingProvider = ({ children }) => {
|
|||
useEffect(() => {
|
||||
if (!callObject || !enableRecording) return false;
|
||||
|
||||
const handleRecordingStopped = () => {
|
||||
const handleRecordingStopped = (event) => {
|
||||
console.log(event);
|
||||
if (isRecordingLocally) return;
|
||||
setRecordingState(RECORDING_IDLE);
|
||||
setRecordingStartedDate(null);
|
||||
|
|
@ -263,11 +292,15 @@ export const RecordingProvider = ({ children }) => {
|
|||
if (recordingState === RECORDING_RECORDING) {
|
||||
switch (enableRecording) {
|
||||
case RECORDING_TYPE_LOCAL:
|
||||
case RECORDING_TYPE_OUTPUT_BYTE_STREAM:
|
||||
setRecordingState(RECORDING_SAVED);
|
||||
setIsRecordingLocally(false);
|
||||
break;
|
||||
case RECORDING_TYPE_CLOUD:
|
||||
case RECORDING_TYPE_CLOUD_BETA:
|
||||
case RECORDING_TYPE_RTP_TRACKS:
|
||||
setRecordingState(RECORDING_UPLOADING);
|
||||
setRecordingState(RECORDING_SAVED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* ---
|
||||
* Configures the general state of a Daily call, such as which features
|
||||
* to enable, as well as instantiate the 'call machine' hook responsible
|
||||
* fir the overaching call loop (joining, leaving, etc)
|
||||
* for the overaching call loop (joining, leaving, etc)
|
||||
*/
|
||||
import React, {
|
||||
createContext,
|
||||
|
|
@ -60,19 +60,22 @@ export const CallProvider = ({
|
|||
);
|
||||
}
|
||||
const browser = Bowser.parse(window.navigator.userAgent);
|
||||
const recordingType =
|
||||
roomConfig?.tokenConfig?.enable_recording ??
|
||||
roomConfig?.config?.enable_recording;
|
||||
|
||||
// Mobile and Safari recordings are only supported under the 'cloud-beta' type
|
||||
const supportsRecording =
|
||||
browser.platform.type === 'desktop' && browser.engine.name === 'Blink';
|
||||
// recording and screen sharing is hidden in owner_only_broadcast for non-owners
|
||||
((browser.platform.type !== 'desktop' ||
|
||||
browser.engine.name !== 'Blink') &&
|
||||
recordingType === 'cloud-beta') ||
|
||||
(browser.platform.type === 'desktop' &&
|
||||
browser.engine.name === 'Blink');
|
||||
if (supportsRecording) {
|
||||
const recordingType =
|
||||
roomConfig?.tokenConfig?.enable_recording ??
|
||||
roomConfig?.config?.enable_recording;
|
||||
if (['local', 'cloud'].includes(recordingType)) {
|
||||
setEnableRecording(recordingType);
|
||||
setStartCloudRecording(
|
||||
roomConfig?.tokenConfig?.start_cloud_recording ?? false
|
||||
);
|
||||
}
|
||||
setEnableRecording(recordingType);
|
||||
setStartCloudRecording(
|
||||
roomConfig?.tokenConfig?.start_cloud_recording ?? false
|
||||
);
|
||||
}
|
||||
};
|
||||
updateRoomConfigState();
|
||||
|
|
|
|||
Loading…
Reference in New Issue