Code Monkey home page Code Monkey logo

daily-react's People

Contributors

aconchillo avatar harshithpabbati avatar kompfner avatar lewiswolfgang avatar markbackman avatar mattieruth avatar nienkedekker avatar rajneeshksoni avatar regaddi avatar vipyne avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

daily-react's Issues

Allow nested RecoilRoot structure

Feature request

Using daily-react inside an application that uses Recoil will lose its ability to access its state values of the nearest ancestor RecoilRoot.

Why you need this

We have application set up with Recoil as its dependency. Since daily-react uses Recoil internally, it is nearly impossible share states between nested RecoilRoot.

Alternatives you've considered

We have tried moving DailyProvider further up in the application structure. We don't think this approach is scalable, since daily-react Recoil does not accept any properties for its internal RecoilRoot implementation.

Wrap exported components with `React.forwardRef()`

Feature request

It would be useful to wrap DailyAudio, DailyAudioTrack, and DailyVideo in React.forwardRef().

Why you need this

I’d love to use <DailyAudioTrack />, but it’s useful to have a reference to the DOM node for HTMLMediaElements. For instance, it’s not possible to set volume under the current implementation, since you’d need access to audioEl.current.volume.

Alternatives you've considered

I think it’s most useful to simply accept a ref and join it to the internal ref with something like useMergeRefs1. That way, the user can use the ref however they need.

But if that’s not to your taste, you could also define specific methods with useImperativeHandle.

It could also be nice to accept declarative props (like volume) and handle all of the effects internally, but it’s less flexible and more work on your end.

Additional context

I also think it would be useful to accept arbitrary props and spread them onto the returned element, like so:

export default React.forwardRefs(function DailyAudioTrack ({
  onPlayFailed,
  sessionId,
  type = 'audio',
  ...rest,
}, externalRef) {
  const audioEl = useRef(null);

  // ...

  const ref = useMergedRef(audioEl, externalRef);
  return (
    <audio
      autoPlay
      data-session-id={sessionId}
      data-audio-type={type}
      playsInline
      ref={ref}
      { ...rest }
    />
  );
});

That way, you can pass in arbitrary properties like muted.


Footnotes

  1. Reference implementation:

    // Takes multiple refs and merges them into a single ref so you can attach
    // multiple refs to the same element.
    export function useMergedRef(refs) {
      const filteredRefs = refs.filter(Boolean);
      const mergedRef = useCallback(el => {
        filteredRefs.forEach(ref => {
          if (typeof ref === 'function') {
            ref(el);
          } else {
            ref.current = el;
          }
        });
      }, filteredRefs);
      return mergedRef;
    }
    

[FEATURE-REQUEST] React 18

Feature request

Please add React 18 support

Why you need this

Some other packages requires React 18, so its not possible to it with daily-react

Allow returning user IDs from `useParticipantIds`

Hi again! Since my last feature request sparked some good discussion, I’m adding another idea.

Feature request

Add an idType param to useParticipantIds to allow returning user IDs, instead of the default behaviour which returns session IDs.

useParticipantIds({ idType: 'user' });

Why you need this

My application stores user data in a map keyed by participant user IDs. It would be really helpful to get a list of user IDs directly from this hook, rather than needing to store them in a separate callState object as shown here.

Alternatives you've considered

This could go into its own hook called useUserIds or useParticipantUserIds, but that feels a bit heavy vs. the above proposal.

Additional context

I can make a quick draft PR if this sounds useful.

Unable to get working in a Remix application

Description

Unable to initiate a call and pass it to DailyProvider in a Remix application. Since the error starts in DailyProvider I'm gonna post the issue here for now. I've tried running the same code in Vite and NextJS without any issues. When I try to use it in Remix I get errors:

react-dom.development.js:22839 Uncaught TypeError: Cannot read properties of undefined (reading 'call')
    at i2.value (daily-iframe-esm.js:1:121213)
    at DailyProvider.tsx:135:22
    at useDailyEvent.ts:47:5
    at commitHookEffectListMount (react-dom.development.js:23150:26)
    at commitPassiveMountOnFiber (react-dom.development.js:24926:13)
    at commitPassiveMountEffects_complete (react-dom.development.js:24891:9)
    at commitPassiveMountEffects_begin (react-dom.development.js:24878:7)
    at commitPassiveMountEffects (react-dom.development.js:24866:3)
    at flushPassiveEffectsImpl (react-dom.development.js:27039:3)

Details

"@daily-co/daily-js": "^0.40.0",
"@daily-co/daily-react": "^0.7.2",

Looking through the stack trace it appears to have something to do with using hydrateRoot in React 18. Very far from obvious what the specific issue is beyond that to me at least.

Reproduction

Here's a reproduction: https://stackblitz.com/edit/remix-daily-co?file=app/routes/index.tsx
And here's the same code in a regular react template working: https://stackblitz.com/edit/react-ts-2rur5u?file=App.tsx

DailyProvider does not cleanup the inner callObject state

Expected behavior

DailyProvider should cleanup its own internal callObject state when going from passed callObject to passed null.

Describe the bug (unexpected behavior)

I want my application behind DailyProvider to be able to know that the callObject has been destroyed. Currently when passing a callObject everything is fine, but when that callObject is set to null afterwards, DailyProvider still hold the previous reference.

Steps to reproduce

1 - Pass a callObject to DailyProvider from a setState hook.
2 - Set that hook to null
3 - The previous callObject still remains inside of DailyProvider

Screenshots

System information

  • Device: MacBook Pro
  • OS, version: lastest
  • Browser, version: Chrome latest

Additional context

<3
I love your product.

`camState` and `micState` from `useDevices()` are set to `"granted"` before permissions are requested

Expected behavior

useDevices().camState and useDevices().micState should be set to "pending" or "unknown" until device access is requested and granted.

Describe the bug (unexpected behavior)

When a call is created with startAudioOff and startVideoOff set to true, then joined, useDevices().camState and useDevices().micState return "granted" even before device access is requested with callObject.updateParticipant('local', { setVideo: true, setAudio: true }).

Steps to reproduce

Initialize the call with startAudioOff and startVideoOff set to true:

const callObject = DailyIframe.createCallObject({
	startAudioOff: true,
	startVideoOff: true,
	// ...
});

Join the call:

await callObject.join({ url: dailyRoomUrl, token: dailyMeetingToken, userName: name });

Later (but before calling callObject.updateParticipant), run the following:

const { camState, micState } = useDevices();
console.log(camState, micState); // > granted granted

System information

  • Device: Macbook Pro M1 Max, 2021
  • OS, version: MacOS Ventura 13.1
  • Browser, version: 109.0b2 (64-bit)

Additional context

I’m currently using the following as a workaround:

const { cameras, microphones } = useDevices();
const isMediaAccessGranted =
	cameras.some(c => c.selected && c.state === 'granted') &&
	microphones.some(m => m.selected && m.state === 'granted');

callobject is destroyed at some point after startCamera() since 0.17.0

In my custom react app we use createCallObject and manually manage the callObject lifecycle instead of the newly introduced useCallObject hook.

I can confirm that at 0.16.0 our app works, but at 0.17.0 the callObject gets destroyed at some point after startCamera.

I'd be happy to try and isolate some code and create a repeatable example if this is not enough info.

Our code that sets up the callObject looks like this:

import DailyIframe, {
  DailyEventObjectParticipant,
  DailyEventObjectParticipantLeft,
  DailyEventObjectActiveSpeakerChange,
} from "@daily-co/daily-js";
import getToken from "../../lib/requests/getToken";

export const setupCallObject = async (
  hashedInvitationID: string,
  roomName: string,
  clientID: string,
  userName: string,
  onParticipantJoined: (event?: DailyEventObjectParticipant) => void,
  onParticipantLeft: (event?: DailyEventObjectParticipantLeft) => void,
  onActiveSpeakerChange: (event?: DailyEventObjectActiveSpeakerChange) => void
) => {
  console.log("[session-ui]: Setting up call object");
  const dailyTokenResponse = await getToken(hashedInvitationID, clientID);
  const url = `https://xxxxx.daily.co/${roomName}`;

  let callObject = DailyIframe.getCallInstance();

  if (callObject) {
    console.log("[session-ui]: Daily iframe already exists, leaving meeting.");
    await callObject.leave();
  }

  if (!callObject) {
    callObject = DailyIframe.createCallObject({ strictMode: true });
  }

  callObject.on("participant-joined", onParticipantJoined);
  callObject.on("participant-left", onParticipantLeft);
  callObject.on("active-speaker-change", onActiveSpeakerChange);

  callObject.on("call-instance-destroyed", (e) => {
    console.error("callInstanceDestroyed Event", e);
  });

  callObject.on("error", (e) => {
    console.error("callObjectError Event", e);
  });

  await callObject.startCamera({
    token: dailyTokenResponse.token,
    userName: userName.toString() || "",
    url: url,
    dailyConfig: {
      v2CamAndMic: true,
    },
  });

  await callObject.startLocalAudioLevelObserver(100);
  await callObject.startRemoteParticipantsAudioLevelObserver(100);

  return callObject;
};

Another part of our app then calls callObject.join triggered by the button in our prejoin/haircheck component.

We render the app with the DailyProvider, and initially callObject can be undefined. I thought maybe there is something going on where DailyProvider is doing the destroying, so I also tried not having DailyProvider in the component tree until the callObject is ready to be used, but that didn't seem to do anything.

        {callObject && (
          <DailyProvider callObject={callObject}>
            <ThemeProvider theme={getThemeByName("default")}>{children}</ThemeProvider>
          </DailyProvider>
        )}
        {!callObject && <ThemeProvider theme={getThemeByName("default")}>{children}</ThemeProvider>}

`useCallFrame` creates an iframe directly inside `<body>` ignoring the component structure

Please tell me if I'm doing something wrong. Here's my simplified code:

function Call({ roomUrl, meetingToken }: { roomUrl: string; meetingToken: string | undefined }) {
  const callRef = useRef<HTMLDivElement>(null);
  const callFrame = useCallFrame({
    parentEl: callRef.current,
    options: CALL_OPTIONS,
    shouldCreateInstance: useCallback(() => Boolean(callRef.current), []),
  });

  useEffect(() => {
    if (!callFrame) {
      return;
    }

    void callFrame.join({ url: roomUrl, token: meetingToken });

    callFrame.on("left-meeting", () => {
      void callFrame.destroy();
    });
  }, [callFrame, meetingToken, roomUrl]);

  return (
    <DailyProvider callObject={callFrame}>
      <div ref={callRef} className="h-full w-full" />
    </DailyProvider>
  );
}

Deleting shouldCreateInstance or the <div> which callRef is passed into doesn't make a difference; they're basically ignored.

Package versions:

"@daily-co/daily-js": "0.57.4",
"@daily-co/daily-react": "^0.17.1"

`DailyProvider` should handle `null` call object

Currently, DailyProvider takes callObject: DailyCall as a prop. Both useCallFrame and useCallObject return DailyCall | null. I'm not sure if this is intentional but I expected it to handle the null case on its own.

It's not a big deal since a simple if (!callObject) return; can fix this but I think this can be a quality of life improvement.

Edit: The documentation doesn't know about this issue.

BUG - isRecording value is not correct after leaving the room and joining again

Expected behavior

I'm experiencing an issue similar to what I saw here:
#9

This time the issue is with the isRecording value returned by the useRecording hook. I expect the isRecording value to accurately reflect whether or not there is a recording in progress for the current room.

Describe the bug (unexpected behavior)

When a user joins a room and starts a recording, the isRecording value is true. If that user then stops the recording and leaves the room, the isRecording value remains true. If the user rejoins the room, the isRecording value is still true even though there is no recording in progress.

During the above process, if there is another user in the room the isRecording value changes from true to false as expected.

Steps to reproduce

I have a modified version of our last code sandbox here:
https://codesandbox.io/s/angry-driscoll-h0ouu6?file=/src/SessionIDDisplay.js

To reproduce:

  1. Open code sandbox in 2 separate windows
  2. In both windows, join the call
  3. In window A, click "start recording"
  4. After delay note that "is recording" is showing true for both users
  5. In window A, click "leave call"
  6. Note that "is recording" is showing true in window A and false in window B
  7. In window A, click "join call"
  8. Note that "is recording" is still showing true in window A and false in window B

Error with React 18 in development mode

Expected behavior

Daily works in development mode: The DailyProvider manages creating and destroying the callObject correctly.

Describe the bug (unexpected behavior)

With react 18 running in development mode, it throws the error Duplicate DailyIframe instances are not allowed, essentially breaking the app in dev mode.
This is due to react 18 rendering the app twice in development mode.

Maybe the call object is not cleaned up correctly on unmount?

Steps to reproduce

  1. Create a react app npx create-react-app my-app
  2. Replace App.js with the following:
    import { DailyProvider } from '@daily-co/daily-react';
    import './App.css';
    
    function App() {
    	return <DailyProvider>Hello World</DailyProvider>;
    }
    
    export default App;
  3. Run the development server npm start
  4. It now throws the error Duplicate DailyIframe instances are not allowed

System information

  • Device:
  • OS, version:
  • Browser, version:

Additional context

Daily versions:

		"@daily-co/daily-js": "0.45.0",
		"@daily-co/daily-react": "^0.8.0",

Remote screen share track state stuck on "loading" v0.11.0

Expected behavior

Upon receiving a screen share track, it's video should be visible.

Describe the bug (unexpected behavior)

A subscribed screen share track is received, but never leaves "loading" state.

Steps to reproduce

  1. User A share screen
  2. User B receives
  3. User B does not see video due to "loading" state

System information

  • Device: MacBook Air M2
  • OS, version: Sonoma (bug exists on other OSs)
  • Browser, version: Arc 1.1.1 (bug exists on other browsers)

Additional context

This issue is not present in v0.10.0. Perhaps a regression with Recoil changes around participants?

Typescript Bug with daily-react-hooks

Expected behavior

When utilizing the DailyProvider component in a Next.js typescript app, I should be able to pass children as props to the component, as outlined in the docs.

Describe the bug (unexpected behavior)

When utilizing the DailyProvider component and passing children, I am receiving this error on DailyProvider:

Type '{ children: never[]; url: string; }' is not assignable to type 'IntrinsicAttributes & Props'.
  Property 'children' does not exist on type 'IntrinsicAttributes & Props'.

Steps to reproduce

  1. Install @daily-co/daily-react-hooks to a Next.js typescript project utilizing Next ^12.1.5.
  2. Add DailyProvider to a page component.
  3. Pass a url and children to the provider.
  4. See error.

Screenshots

System information

  • Device: Macbook Pro
  • OS, version: Monterey, 12.3.1
  • Browser, version: Chrome, Version 101.0.4951.54

Additional context

BUG - useLocalSessionId does not update after leaving the room then calling daily.preAuth

Expected behavior

After calling daily.preAuth I see that the useLocalSessionId hook correctly returns the session ID of the local user. I can then call daily.join() to the join the room with that session ID, and then call daily.leave() to leave the room with that session ID.

At this point the useLocalSessionId hook returns undefined, and I expect that calling preAuth again will issue a new local session ID that can be accessed by the useLocalSessionId hook.

Describe the bug (unexpected behavior)

In the above scenario, if I call preAuth again after leaving the room I see a participant-updated event fire with a new session ID for the local user but the return value of useLocalSessionId as well as useLocalParticipant remains undefined. I would expect those values to reflect the new local session ID, unless I am misunderstanding how this works?

Steps to reproduce

  1. Call daily.preAuth() passing in url and token as options
  2. Notice participant-updated event fires with new session ID, which is correctly returned by useLocalSessionId and useLocalParticipant hooks
  3. Call daily.join() to join room
  4. Call daily.leave() to leave room
  5. Call daily.preAuth again, passing in same url and token options
  6. Notice participant-updated event fires with new session ID, however useLocalSessionId and useLocalParticipant hooks returns undefined

Additional context

Room I am testing in:
https://tastemade-staging.daily.co/zPmtkqdArvkU4a53DdzC

`camState` becomes "idle" when muted

Expected behavior

In 671300e, a new "idle" state was added to represent devices that had not been asked for access permission yet. As soon as permissions are requested, the state should become "pending", then either "granted" or some other error state.

Describe the bug (unexpected behavior)

When a camera is muted through Daily, it returns to the "idle" state.

Steps to reproduce

Add this snippet somewhere in your demo code:

const { camState, micState } = useDevices();
console.log(`Camera state is "${camState}"   \tMicrophone state is "${micState}"`);

Once you’ve granted camera and microphone access, you should see the following log:

Camera state is "granted" Microphone state is "granted"

Mute your mic and you’ll see the same thing:

Camera state is "granted" Microphone state is "granted"

Mute your camera and you’ll see:

Camera state is "idle" Microphone state is "granted"

System information

  • Device: Macbook Pro M1 Max, 2021
  • OS, version: MacOS Ventura 13.1
  • Browser, version: 109.0b2 (64-bit)

Additional context

Mute state is already tracked on dailyVideo.track.muted. Keeping mute state decoupled from media state is important.

Error: Failed to execute 'postMessage' on 'DOMWindow'

Using useCallFrame, I get this error in the console:

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://xxx.daily.co') does not match the recipient window's origin ('http://localhost:xxx').

Using an error boundary, the call frame doesn't render. But without it, everything works just fine. I'm not sure what the issue can be.

I'm wrapping my call with <DailyProvider> and passing the call frame object as callObject.

Retrieve a recording?

A user of mine started a recording but forgot to stop it. It's recording id cdb45f18-63b5-42f2-89e8-0fe111451fa1 - is there any way to retrieve this?

[FEATURE-REQUEST] Prerecorded audio track

I'd like to be able to pipe a pre-recorded audio track from the server to everyone in the call simultaneously. Ideally, I'd also be able to have the host pause and play it.

Is this possible using the Daily API, either in REST or JS? I think the DailyAudioTrack can do this, but I can't quite tell.

[FEATURE-REQUEST] Record just audio

How do I record just audio and not the video too? The docs (https://docs.daily.co/reference/daily-js/instance-methods/start-recording) show the following command that records video as well. I do not want to turn off the displayed video, just not record it.

call.startRecording({
  width: 1280,
  height: 720,
  fps: 25,
  backgroundColor: '#FF1F2D3D',
  layout: {
    preset: 'default',
    max_cam_streams: 5,
  },
});

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.