ABOUT THE PROJECT
During the start of the COVID-19 pandemic the New Jersey Courts were seeking an immediate solution for streaming court services throughout the state. Within a week our team created a working prototype that has been constantly updated and restructured to meet the ever-growing demands of our users. It was integrated into Zoom and allowed for unlimited scaling of viewers throughout the state.
STREAMING SERVER
We hosted our original Zoomtube application on an EC2 instance using NGINX to host an RTMP server that transcoded streams from Zoom into an HLS feed. Due to the high bandwidth we switched to a Graviton Server which greatly reduced overall cost of the project. After creating this HLS stream, it allowed us the ability to use any client-side front end media player to broadcast the stream to users. We ended up settling on VideoJS which comes with a ton of features for customizing, including skinning, overlays, quality level controls, and various other plugins. We also utilized a single dynamic page that would take in various parameters in order to display a stream. This dramatically decreased the amount of code and reduced the amount of time it would take to deploy code fixes (single page, not 50+ for each stream).
SERVICES
Previously, the EC2 server utilized a Node.js server that performed an array of tasks which included:
- Reading the m3u8 files that were stored on the local file system and parsing the Zoom Meeting ID from the filename.
- The script would then utilize the ZoomAPI to query that Meeting information using a JWT token that was generated for authentication. It would then store that information into memory, and periodically check the memory vs the file system for any changes.
- The service also had two end points which served JSON responses.
- Get Live - This would serve all current meetings from memory as a JSON response.
- Get All Meetings - This would serve all meetings that existed, since it was so big, we saved the file to a static JSON file.
In order to avoid viewer limitations, we completely removed the Node.js server from the Graviton box and moved everything into Lambda functions. Why? This allows for complete scalability of the application and allows us to easily load balance for multiple boxes by making the stream servers stateless. The Graviton box now only utilizes a simple python script which looks at the m3u8 files, parses the meeting ids, and uses the Zoomtube API call to retrieve information. However, after this information is retrieved it is posted (sent) to an API Gateway Endpoint which is responsible for sending it to our Lambda functions. This API Gateway Endpoint utilizes an API key for authorization and uses origin headers to restrict access from only our NJCourts domains, making it very secure.
The meeting information is then forwarded to our NJCourtsDynamoDB lambda function, which then utilizes the Dyanamo API to save the information into our NOSQL database. After a meeting ends, the python script will then send a put (update) response to our API Gateway, which then calls another Lambda function which performs an update on the current record in the DynamoDB. This allows us to have real time data, unlike our original solution which would have nightly data dumps.
We also moved the meetings live functionality out of the Graviton server completely. It now is served from an API Gateway Endpoint which points to a NJCourtsDyanamoDBGetMeetings Lambda function. We utilized a proxy pass through so that we were able to retrieve all header information and not just the body payload. This allowed us to introduce date filtering when making the get request for meetings. For example, we can now pass in request such as:
Which can now be tied into calendar filters, so we no longer need to query the entire database, removing slow load times. For the new streaming page (page that displays all available streams that are active), we now are able to pass in an active parameter, which will only show meetings that currently do not have an end time (active).
https://0w13nkotj6.execute-api.us-east-2.amazonaws.com/default/getmeetings?active=true
We also introduced safeguards in case the server ever goes down. If that happened there could potentially be meetings that do not have an end time. To fix this the python script will send a post request to custom Lambda function and will end all current meetings on server startup. This meeting would already be disconnected from the stream so it would not change anything.
ZOOM APP / STREAM APPENDER
We also created a Zoom App that sends events when a meeting is created or edited. Zoom sends these events to an API Gateway Endpoint, which then calls a Lambda function. The Lambda function will then take the response from the event and append the required information to the meeting for the stream to work. The user will never have to enter in any information and can just hit the stream button because all information will be prefilled.
FEATURES
- RTMP Server using NGINX
- Custom AWS Lambda Functions / API Gateways
- Data stored in DynamoDB for active and expired meetings.
- Zoom App integration with stream information appending on meeting creation
- Dynamic active stream page with VideoJS integration.
- Python scripts for generating requests
- Automatic stream detection for court recess
- Google antalyics integration and custom page for view statictics by location, judge, and time
MADE FOR
Court Services