So what we have to do now is we have to connect to LiveKit so we can create our ingress. So go ahead and visit livekit.io or go ahead and use the link inside of the description. So this is real-time video and audio for developers and it is an open source alternative to Twilio or some other stuff and they include WebRTC and sockets inside. So if you want to you can even self-host this and they have great documentation on how to do that as well. So what I want you to do is go ahead and find the sign in button from here and go ahead and log in.
Once you are inside of your dashboard I'm not sure if you're going to see this exactly perhaps some project will be created for you, but what I'm gonna do is go right here on the bottom and click create new project and I'm gonna give my app a name Game Hub which is our parody name, right? So let's go ahead and create this project here and if you want to you can go ahead and fill in this survey to help them know better about what you are doing. What we have to do now is we have to prepare some environment variables right. So I'm going to go inside of my settings here and in here you should have the keys option and you also have webhooks which we're going to do later. So what I'm going to do is I'm going to click add a new key here and I'm going to call this development and let's go ahead and click generate like this.
And now you're going to get this items right here so keep that open don't close it yet and instead let's go ahead inside of our .environment file and let's go all the way to the bottom right here and let's add the following. So we need livekit underscore API URL, we need livekit underscore API key, and we need livekit underscore API secret. Like this. So let's go ahead and let's fill in the API key from here. So I'm gonna give that here.
Let's use the secret key right here. Let's use that and paste it here like that. And this is the WebSocket URL. I'm not sure if we need this or I think we actually need an API URL. So this is something else.
So just make sure you added the API key and the secret key. And if it happened to you that you accidentally closed this you're probably going to notice that you cannot see it again. The secret key, right? So you can just always click add a new key. It's not a big problem.
So in order to find the LiveKit API URL, we can do that by going inside of the analytics here and in here you can go ahead and copy this from your URL like this. So let's go ahead and put that here and I believe we need to add HTTPS at the beginning like this. And I actually made a mistake previously when I told you that we don't need the WebSocket server we do need that as well. So let's see if we can get that from the settings here. So I have my keys here, this is the development one and in here we have the WebSocket URL.
So let's go ahead and just copy this right here and let's paste that in here as well so no no worries that we cannot see the secret right because we can still see the web socket url so let's add next underscore public underscore like it underscore vs underscore url like this So these three keys will be used privately right because they don't have the next public prefix but this one does meaning that it can be used in the client and it needs to be used in the client to initialize the WebSocket connection but for these two we can just leave them as they are. So make sure that you have the LiveKit API URL which you can get by clicking on the analytics here copying what you see here at the top and I believe it's actually exactly the same as your WebSocket URL as you can see but it does need an HTTPS prefix right here and inside of your settings here you can get by clicking on the development when we open this you have the API key and maybe we can click reveal secret looks like we can right so just make sure that you have both your API key and your secret inside.
After you've done all of that you can go ahead and close this and if you want you can keep this open in your analytics because we're going to come back to it later once we establish the connection so we can see that it was properly established here. So what I want to do here is shut down my terminal and install a couple of packages. So we're going to need lightkit components react So make sure you install that package. Let's wait a second for this to install. So this is going to give us some set of useful client side hooks and components.
Then we're going to need npm install livekit-client. So make sure you have that. And we're going to need npm install livekit-server-sdk like this so make sure you have all of those installed and now let's go ahead and let's go inside of our actions and create a new file ingress.ts like that and mark this as user server because this is a server action And now let's go ahead and let's import everything we need from LiveKit server SDK. So we're going to need the Ingress audio encoding preset, the Ingress input, we're going to need the Ingress client, the ingress video encoding preset and room service client. Then we're also going to need to import track source from LiveKit server SDK.
I believe, can we also import that from here? I believe we can. So we can just add it to this one like that. All right. And now what we have to do is import our database from add slash lib db.
We have to import get self from auth service and we have to import well that should be it for now and now let's go ahead and create our room service so const roomService is going to be new roomServiceClient and now we have to pass in three environment variables inside which we have right here so we're going to work with this three right so let's go ahead and first passing process.environment the API URL like that and then in the other ones for the second one we're going to pass in the API key and for the last one we're gonna pass the API secret like that and you can put exclamation points at the end of each of those to ensure because we know that they exist right. So now what I want to do is I want to create a create ingress action which is going to be an asynchronous function and what it's going to accept is the ingress type so let's go ahead and give this a type of ingress type to be a type of ingress input which we have imported from right here from the live server SDK and now inside of here let's go ahead and let's write const self to be await get self and then let's go ahead and write a little comment here to do resetPreviousIngress like that and now let's go ahead and write const options to be create ingress options and let's go ahead and give some properties here so the name is going to be self.username the room name is going to be self.id So anyone who joins our room is going to join our ID.
That's how we're going to recognize which room the user wants to join. Now let's create a participant name, which is going to be self.username. And let's create the participant identity, which is going to be self.id. Great. And now we have to add some more options depending on whether we use the WIP input or the RTMP input, right?
And let's just see what exactly this error is. It looks like I didn't import this. Let's go ahead and look at this. Create ingress options. Oh, so we have to import type create ingress options from livekit server SDK.
So make sure you have that as well. And then this error should go away. And now let's go ahead and let's write if ingress type is equal to ingress input.wipinput. Let's enable bypass transcoding so options.bypassTranscoding is true else, so if it is the other protocol, we're going to use options.video to be an object which uses the source to be trackSource.camera and present is ingressVideoEncodingPresent. And preset is IngressVideoEncodingPreset.
And now we're gonna go ahead and use H.264 underscore 180p underscore 30fps underscore 3 layers. Like that. And now let's go ahead and let's see what this is going on so track source dot camera is not assignable to this. Let's see what did I do wrong here. I believe that you can import track source from one other place.
Perhaps this was the wrong place to import it or let's go ahead and try it like this. Let's import track source from livekit server SDK slash dist slash proto slash livekit models. Like that. So this is how it looks in one line. So let's try this now and that seems to be working.
So it looks like we have to import track source from that one specifically. In case it changes for you in the future, I'm sure that well it's going to be quite easy for you to look at the documentation to see but if you're still getting errors or if this doesn't exist for you let me show you my package json so you can see what livekit versions I have so my livekit components react are 1.4.2 My LiveKit client is 1.15.4 and my LiveKit server SDK is 1.2.7 like that. So if you want to you can use the exact versions that I have so you ensure that you can import this, right? But if you're not having any errors here, it means that it is working. Great, so we set the options for video and now let's do options.audio here.
So for the source, we're going to use track source.microphone and for the preset we're going to use ingressAudioEncodingPreset.opusStereo96kbps like that. And now let's go ahead outside of this if clause and let's create an ingress. So const ingress is await ingressClient.createIngress. Let's do ingressClient. Do I have this ingressClient imported?
Oh my apologies I forgot to create the Ingress client. Right so go below the room service here and create the Ingress client and that's going to be new Ingress client with a capital I so make sure you have this imported from here so new Ingress client and inside pass process.environment and we're going to use the LiveKit API URL like that and put an exclamation point at the end to get rid of the error. And now we have the IngressClient like this. So let's go ahead and do IngressClient.createIngress. Let's pass in the IngressType as the first argument and let's pass in the options as the second argument.
And then if we don't have an ingress created or if there is no ingress.url or if there is no ingress.stream key, in that case, throw new error, failed to create ingress. And now let's go ahead and do await db.stream.update where we have a matching user ID from our self.id and let's update the following data. Ingress ID is ingress.ingressID. Server URL is ingress.url. And the stream key is ingress.streamkey.
Like that. And now let's do revalidate path slash u slash self dot username slash keys so that fields get updated once we do this and let's return ingress itself. Great, so this is my ingress function. You can always visit the source code to see more information here. And one more thing I want to do is just finish this to reset previous ingresses.
So we can do that now. So let's go ahead and just above the create ingress let's also do export const reset ingress let's set ingress says right and do asynchronous function which accepts the host identity which is a string and all it's going to do is get all ingresses first so ingresses is await ingress client dot list ingress and passing the room name to be the host identity. And now let's get all the rooms so const rooms await room service room service.listrooms and passing the host identity inside. Like this. And then let's do for const roomOfRooms() await roomService.deleteRoom() and passing room.name() Right, so we cannot use forEach() or map() here because await() does not work in those functions so we have to use the plain old for here and let's write another one for const ingress of ingresses let's do if we have ingress.ingressId meaning that it's the proper active ingress in that case await ingressClient.deleteIngress ingress.ingressId like this great and now every time that the user tries to create a new ingress we are going to ensure that we remove all instances so await reset ingresses and pass in self.id So we're going to remove all previous instances of active streams and rooms and ingresses which this user has.
So that's why we have that warning here. When we click on generate connection, you can see that this is a warning which tells you that exactly that is going to happen. Great and what I want to do now that we have this function here which again you can always double check by going directly inside of my github source code is go back inside of our app folder, app folder dashboard, user name, keys, components, connect model here and now what I want to do is I want to go ahead and import a couple of stuff from LiveKit Server SDK here. So let's go ahead and import ingressInput from LiveKit Server SDK like that. And then what I want to do is create the rtmp and wip functions here.
So const rtmp is a string which comes from the ingress input dot rtmp input, rtmp input. And const wip is a string which comes from the ingressInput.whipInput and then let's do type ingressType to be type of rtmp or type of whip, like that. So now we're going to use this to create our functioning set state here. So let's go ahead and do the following. So I'm going to write const ingress type and set ingress type to be used state which you can import from react so just make sure you add that like this and let's go ahead and let's give it the default value of rtmp and let's go ahead and make sure to give it the ingress type here so it can accept both RTMP and WIP protocols like that.
And now what I want to do is go down where we have our select function here and let's change this hard-coded string to now use the actual RTMP string which we stringified from the actual import of LiveKit so we know it's correct and here we do WIP and now let's go ahead and modify this select here to have a value of IngressType and give it an onValue change to get the value and then do set IngressType and passes in that value and as you can see We have no type errors because all of this is supported here. We have all the appropriate types for this. Great! So now what I want to do is I want to import useTransition and I want to import createIngress from actionsIngress. So make sure you added those two and now let's go ahead here and let's add const isPending and startTransition from useTransition like that and now let's create const on submit here which is going to call start transition and it's going to call that create ingress option with the value of ingress type which we have inside of our store here and let's go ahead and wrap this inside of parseInteger like this.
There we go, so no more type errors. Let's create a dot then let's import toast from sonar so make sure you added this toast package here and let's call toast we're gonna call ingress created like that and we're gonna go ahead and use the .catch here to write toast.error, sorry this was supposed to be toast.success and this is an error, something went wrong. Like that and now what we can do is first of all we can go ahead and add a disabled field to the input for isPending and now we can go inside of our generate button and pass this on click to be on submit and give it a property disabled off is pending as well and one more thing I want to do is I want to close this model once that is finished so for that let's go ahead and let's add use ref from react And now let's go in here where our state is and before everything I'm going to add a const closeRef to be useRef with the default value of null. And the type of this ref is going to be element ref which you can import from react so make sure you add this as well and specifically we're going to target a button element like that and Now let's go ahead and assign this to our DialogClose wrapper.
So find the DialogClose with the cancel button inside and give it a ref of CloseRef. Oh and let's also give this asChild property so we don't have any hydration errors for this. And then what I'm going to do is go inside of my function here and I'm gonna extend this .then to be a function like this and after we do the toast message I'm gonna do closeRef.currentClick Like that and if everything is done correctly this should be working So let's go ahead and do npm run dev make sure that you have this Running on your localhost here, and I'm also gonna prepare my Prisma Studio so I'm going to open a new terminal here and I'm going to write npx prisma studio so that's going to open on localhost 5555 and I'm working with Antonio's stream so what I expect that after I click generate the Ingress ID should be populated, the server URL and the stream key. So let's go ahead and try that out. I will refresh here one more time and let's go ahead and click generate connection.
Let's choose RTMP and let's click generate and let's see if we did everything correctly. So it is generating and it says Ingress created and as you can see we have a server URL here and we have our stream key. If I check in my Prisma Studio here you should see the exact same thing. There we go. Ingress ID, server URL and a stream key and maybe we can even find something inside of the live kit.
I believe we cannot because there are no active ingresses right so this will only appear once we actually connect to OBS or some streaming service I think for now we are not seeing any information about this yes but once we connect we are going to see some stuff. Great! So if this is working for you, amazing! You now know how to create an RTMP protocol using LiveKit and now you can use this server URL and this stream key on literally any streaming service, right? So this is not, you are not locked in to any specific software.
This will work with anything. Specifically we're gonna use OBS which is the most popular streaming software and it's completely open source but I believe that all other streaming services work in an exactly the same way. I mean they do have to support this kind of protocols which are the standard for live streaming. Great! So just ensure that you have this working and you can even try and reset this so let's do it again.
Let's go ahead and regenerate this and this should give us a completely different stream key. I think that server URL might actually be the same but the stream key should be different once you click generate connection. Great, so you finished that. What I'm going to show you next is how to use these two items to connect to the OBS software. So I'm going to give you a little crash course on OBS and then we're finally going to be able to see some streaming which we're going to develop in this tab here.
Great, great job.