Updated openvidu-ionic

This commit is contained in:
Carlos Santos 2023-11-13 19:51:46 +01:00
parent 757fec766e
commit 981b85ce61
8 changed files with 654 additions and 740 deletions

9
openvidu-ionic/Caddyfile Normal file
View File

@ -0,0 +1,9 @@
{$IP_ADDRESS}:5001 {
reverse_proxy http://localhost:5000
@ws {
header Connection *Upgrade*
header Upgrade websocket
}
reverse_proxy @ws http://localhost:7880
}

View File

@ -5,34 +5,16 @@ const config: CapacitorConfig = {
appId: 'io.ionic.starter',
appName: 'openvidu-ionic',
webDir: 'www',
server: {
androidScheme: 'http',
iosScheme: 'http'
},
};
if (environment.externalIp) {
config.server = config.server || {};
config.server.hostname = 'localhost';
config.server.cleartext = true;
// config.includePlugins = config.includePlugins || [];
// '@jcesarmobile/ssl-skip' plugin is needed to allow serve the app over HTTPS
// with a self-signed certificate without installing the certificate in the device
// config.includePlugins.push('@jcesarmobile/ssl-skip', 'cordova-plugin-android-permissions');
// Android configuration
config.android = config.android || {};
config.android.allowMixedContent = true;
config.android.includePlugins = config.android.includePlugins || [];
config.android.includePlugins.push('@jcesarmobile/ssl-skip', 'cordova-plugin-android-permissions');
// iOS configuration
// config.ios = config.ios || {};
// config.ios.includePlugins = config.ios.includePlugins || [];
// config.ios.includePlugins.push('@jcesarmobile/ssl-skip');
}
export default config;

View File

@ -1,32 +0,0 @@
platforms:
android:
versionName: 1.0.0
manifest:
- file: AndroidManifest.xml
target: manifest
merge: |
<manifest>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
</manifest>
- file: AndroidManifest.xml
target: manifest/application/activity
attrs:
android:exported: true
android:networkSecurityConfig: "@xml/network_security_config"
res:
- path: xml
file: network_security_config.xml
text: |
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system"/>
<certificates src="user"/>
</trust-anchors>
</base-config>
</network-security-config>
ios:
version: 1.0.0

View File

@ -1,52 +0,0 @@
events {
worker_connections 512;
}
http {
upstream openvidu-deployment {
server host.docker.internal:4443;
}
upstream server-application {
server host.docker.internal:5000;
}
upstream client-application {
server host.docker.internal:8100;
}
server {
listen 443 ssl;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Proto https;
proxy_headers_hash_bucket_size 512;
proxy_redirect off;
# Websockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# OpenVidu deployment API
location /openvidu/api {
proxy_pass http://openvidu-deployment;
}
# OpenVidu WebSocket
location ~ /openvidu$ {
proxy_pass http://openvidu-deployment;
}
# Server application requests
location /api/ {
proxy_pass http://server-application;
}
# Client application requests
location / {
proxy_pass http://client-application;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -4,14 +4,13 @@
"author": "Ionic Framework",
"homepage": "https://ionicframework.com/",
"scripts": {
"start": "ionic serve",
"build": "ng build",
"start": "npx ionic serve",
"build": "npx ionic build",
"watch": "ng build --watch --configuration development",
"android": "./scripts/mobile_run.sh androidd",
"android": "./scripts/mobile_run.sh android",
"ios": "./scripts/mobile_run.sh ios",
"sync": "npx ionic capacitor sync",
"build:full": "npm run trapeze && npx ionic capacitor sync",
"build:android": "npm run build:full && npx ionic capacitor build android --no-open && cd android && ./gradlew assembleDebug && ./gradlew assembleRelease",
"build:android": "npx ionic capacitor build android --no-open && cd android && ./gradlew assembleDebug && ./gradlew assembleRelease",
"copy:android": "cp ./android/app/build/outputs/apk/debug/app-debug.apk /opt/openvidu/android/openvidu-ionic.apk"
},
"private": true,

View File

@ -17,18 +17,7 @@ case "$os_name" in
"Linux")
# Commands for Linux
LOCAL_IP=$(hostname -I | awk '{print $1}')
if [ -z "$LOCAL_IP" ]; then
echo "Cannot get your local IP address."
exit 1
fi
sed -i "s/\(externalIp:\s*'\)[^']*/\1$LOCAL_IP/" src/environments/environment.ts
echo "Your local ip is $LOCAL_IP"
echo "Setting up your movile environment for developing OpenVidu..."
npx ionic cap run $PLATFORM -l --external --disable-host-check --public-host=$LOCAL_IP --ssl
sed -i "s/\(externalIp:\s*'\)[^']*/\1$LOCAL_IP/" $ENV_FILE
;;
"Darwin")
# Commands for macOS
@ -39,21 +28,37 @@ case "$os_name" in
break
fi
done
if [ -z "$LOCAL_IP" ]; then
echo "Cannot get your local IP address."
exit 1
fi
echo "Your local ip is $LOCAL_IP"
echo "Setting up your movile environment for developing OpenVidu..."
sed -i '' "s/externalIp: .*/externalIp: '$LOCAL_IP'/g" $ENV_FILE
npx ionic capacitor run ios -c development
;;
*)
# Unsupported/Unknown OS
echo "Unsupported operating system: $os_name"
exit 1
# Windows OS
echo "Recognized $os_name as operating system. The ip must be set manually."
read -p "Insert your local ip " ip_address
LOCAL_IP=$ip_address
# Requesting the user to set the ip manually and wait for the user to press enter
echo "Please set your local ip in $ENV_FILE"
echo "Example:"
echo ""
echo "export const environment = {"
echo " production: false,"
echo " externalIp: 'XXX.XXX.X.XX' <--- SET YOUR IP HERE"
echo "};"
read -p "Press Enter to continue..."
;;
esac
if [ -z "$LOCAL_IP" ]; then
echo "Cannot get your local IP address."
exit 1
fi
if [ "$(docker ps -q -f ancestor=caddy)" ]; then
echo "Container caddy is running."
else
echo "Container caddy is not running. Launching it..."
docker run -d --network=host -v $PWD/Caddyfile:/etc/caddy/Caddyfile -e IP_ADDRESS=$LOCAL_IP caddy
fi
echo "Your local ip is $LOCAL_IP"
echo "Setting up your mobile environment for developing OpenVidu..."
npm run build
npx ionic cap run $PLATFORM -c development --external --disable-host-check --public-host=$LOCAL_IP --ssl

View File

@ -6,7 +6,6 @@ import {
RemoteTrackPublication,
Room,
RoomEvent,
TrackPublishOptions,
} from 'livekit-client';
import { HttpClient } from '@angular/common/http';
import { AlertController, Platform } from '@ionic/angular';
@ -21,24 +20,20 @@ import { environment } from 'src/environments/environment';
})
export class HomePage {
APPLICATION_SERVER_URL = 'http://localhost:5000/';
WS_LIVEKIT_URL = 'ws://localhost:7880/';
private IS_DEVICE_DEV_MODE = false;
// OpenVidu objects
room: Room | undefined = undefined;
localPublication: LocalTrackPublication | undefined = undefined;
remotePublications: RemoteTrackPublication[] = [];
// Join form
myRoomName!: string;
myParticipantName!: string;
cameraIcon = 'videocam';
microphoneIcon = 'mic';
private cameras: MediaDeviceInfo[] = [];
private cameraSelected!: MediaDeviceInfo;
private isFrontCamera: boolean = false;
ANDROID_PERMISSIONS = [
this.androidPermissions.PERMISSION.CAMERA,
this.androidPermissions.PERMISSION.RECORD_AUDIO,
@ -52,19 +47,6 @@ export class HomePage {
private androidPermissions: AndroidPermissions
) {
this.generateParticipantInfo();
// WARNING!! To make the mobile development easier, this code allows
// using your local IP address for communicating with the backend.
// For production uses, the server should be accessible from the Internet
if (this.platform.is('hybrid')) {
if (environment.externalIp) {
console.warn('Your local IP address: ', environment.externalIp);
this.APPLICATION_SERVER_URL = this.APPLICATION_SERVER_URL.replace(
'localhost',
environment.externalIp
);
}
}
}
@HostListener('window:beforeunload')
@ -73,6 +55,23 @@ export class HomePage {
this.leaveRoom();
}
ngOnInit() {
/**
* WARNING!! To make the mobile development easier, this code allows
* using your local IP address for communicating with the backend.
* For production uses, the server should be accessible from the Internet
* and the code below should be removed.
*/
if (this.platform.is('hybrid') && environment.externalIp) {
this.IS_DEVICE_DEV_MODE = true;
this.prepareForDeviceDevelopment();
}
console.log('IS_DEVICE_DEV_MODE: ', this.IS_DEVICE_DEV_MODE);
console.log('APPLICATION_SERVER_URL: ', this.APPLICATION_SERVER_URL);
console.log('WS_LIVEKIT_URL: ', this.WS_LIVEKIT_URL);
}
ngOnDestroy() {
// On component destroyed leave room
this.leaveRoom();
@ -114,28 +113,20 @@ export class HomePage {
this.myParticipantName
);
let livekitUrl = this.getLivekitUrlFromMetadata(token);
if (environment.externalIp) {
// WARNING!! To make the mobile development easier, this code allows
// using your local IP address for communicating with the backend.
// For production uses, the server should be accessible from the Internet
livekitUrl = livekitUrl.replace('localhost', environment.externalIp);
if (!this.IS_DEVICE_DEV_MODE) {
// Get the Livekit WebSocket URL from the token metadata if not in device dev mode
this.WS_LIVEKIT_URL = this.getLivekitUrlFromMetadata(token);
}
// First param is the LiveKit server URL. Second param is the access token
await this.room.connect(livekitUrl, token);
await this.room.connect(this.WS_LIVEKIT_URL, token);
// --- 5) Requesting and Checking Android Permissions
if (this.platform.is('hybrid') && this.platform.is('android')) {
await this.checkAndroidPermissions();
}
const publishOptions: TrackPublishOptions = {
stream: 'test',
};
const [audioPublication, videoPublication] = await Promise.all([
this.room.localParticipant.setMicrophoneEnabled(true),
this.room.localParticipant.setCameraEnabled(true),
@ -143,7 +134,10 @@ export class HomePage {
// Set the main video in the page to display our webcam and store our localPublication
this.localPublication = videoPublication;
this.refreshVideos();
videoPublication?.track?.on('elementAttached', (track) => {
this.refreshVideos();
});
await this.initDevices();
} catch (error: any) {
console.log(
@ -154,11 +148,11 @@ export class HomePage {
}
}
leaveRoom() {
async leaveRoom() {
// --- 7) Leave the room by calling 'disconnect' method over the Session object ---
if (this.room) {
this.room.disconnect();
await this.room.disconnect();
}
// Empty all properties...
@ -166,6 +160,8 @@ export class HomePage {
this.localPublication = undefined;
this.room = undefined;
this.generateParticipantInfo();
this.cameraIcon = 'videocam';
this.microphoneIcon = 'mic';
}
// Others methods...
@ -208,11 +204,6 @@ export class HomePage {
async toggleCamera() {
if (this.room) {
const enabled = !this.room.localParticipant.isCameraEnabled;
// const options: VideoCaptureOptions = {};
// const publishOptions: TrackPublishOptions = {
// stream: 'test',
// };
await this.room.localParticipant.setCameraEnabled(enabled);
this.refreshVideos();
this.cameraIcon = enabled ? 'videocam' : 'eye-off';
@ -222,14 +213,7 @@ export class HomePage {
async toggleMicrophone() {
if (this.room) {
const enabled = !this.room.localParticipant.isMicrophoneEnabled;
const publishOptions: TrackPublishOptions = {
stream: 'test',
};
await this.room.localParticipant.setMicrophoneEnabled(
enabled,
undefined,
publishOptions
);
await this.room.localParticipant.setMicrophoneEnabled(enabled);
this.microphoneIcon = enabled ? 'mic' : 'mic-off';
}
}
@ -251,6 +235,10 @@ export class HomePage {
}
}
/**
* This method allows to change the LiveKit websocket URL and the application server URL
* from the application itself. This is useful for development purposes.
*/
async presentSettingsAlert() {
const alert = await this.alertController.create({
header: 'Application server',
@ -262,6 +250,13 @@ export class HomePage {
placeholder: 'URL',
id: 'url-input',
},
{
name: 'websocket',
type: 'text',
value: this.WS_LIVEKIT_URL,
placeholder: 'WS URL',
id: 'ws-input',
},
],
buttons: [
{
@ -275,6 +270,7 @@ export class HomePage {
id: 'ok-btn',
handler: (data) => {
this.APPLICATION_SERVER_URL = data.url;
this.WS_LIVEKIT_URL = data.websocket;
},
},
],
@ -284,17 +280,21 @@ export class HomePage {
}
private refreshVideos() {
// setTimeout(() => {
// console.warn('track restarted: UPDATED DOM');
// const refreshedElement = document.getElementById('refreshed-workaround');
// if (refreshedElement) {
// refreshedElement.remove();
// } else {
// const p = document.createElement('p');
// p.id = 'refreshed-workaround';
// document.getElementById('room')?.appendChild(p);
// }
// }, 200);
if (this.platform.is('hybrid') && this.platform.is('android')) {
// Workaround for Android devices
setTimeout(() => {
const refreshedElement = document.getElementById(
'refreshed-workaround'
);
if (refreshedElement) {
refreshedElement.remove();
} else {
const p = document.createElement('p');
p.id = 'refreshed-workaround';
document.getElementById('room')?.appendChild(p);
}
}, 250);
}
}
private async checkAndroidPermissions(): Promise<void> {
@ -353,6 +353,19 @@ export class HomePage {
}
}
private prepareForDeviceDevelopment() {
/**
* WARNING!! To make the mobile development easier, this code allows
* using your local IP address for communicating with the backend.
* For production uses, the server should be accessible from the Internet
* and the code below should be removed.
*/
console.warn('Your local IP address: ', environment.externalIp);
// Pointing to our proxy server through https/wss and our local IP address
this.APPLICATION_SERVER_URL = `https://${environment.externalIp}:5001/`;
this.WS_LIVEKIT_URL = `wss://${environment.externalIp}:5001/`;
}
/**
* --------------------------------------------
* GETTING A TOKEN FROM YOUR APPLICATION SERVER