diff --git a/example/index.js b/example/index.js index 23a0ec8..9250f39 100644 --- a/example/index.js +++ b/example/index.js @@ -1,8 +1,5 @@ import { AppRegistry } from 'react-native'; -import App from './src/App'; -//import App from './src/Play'; -//import App from './src/Peer'; -//import App from './src/Conference'; import { name as appName } from './app.json'; +import App from './src/App'; AppRegistry.registerComponent(appName, () => App); diff --git a/example/package.json b/example/package.json index d76001c..dfbc0b2 100644 --- a/example/package.json +++ b/example/package.json @@ -17,7 +17,10 @@ "dependencies": { "react": "18.3.1", "react-native": "0.75.2", + "react-native-gesture-handler": "^2.24.0", "react-native-incall-manager": "^4.2.0", + "react-native-safe-area-context": "^5.3.0", + "react-native-screens": "^4.9.1", "react-native-vector-icons": "^10.1.0", "react-native-webrtc": "^124.0.4" }, @@ -29,7 +32,10 @@ "@react-native/eslint-config": "0.75.2", "@react-native/metro-config": "0.75.2", "@react-native/typescript-config": "0.75.2", - "@types/react": "^18.2.6", + "@react-navigation/native": "^7.0.15", + "@react-navigation/stack": "^7.1.2", + "@types/react": "^18.3.18", + "@types/react-native": "^0.73.0", "@types/react-native-vector-icons": "^6.4.18", "@types/react-test-renderer": "^18.0.0", "babel-jest": "^29.6.3", diff --git a/example/src/App.tsx b/example/src/App.tsx index 2d87733..b887a95 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,186 +1,39 @@ -import React, {useCallback, useRef, useState, useEffect} from 'react'; - -import { - StyleSheet, - View, - SafeAreaView, - TouchableOpacity, - Text, -} from 'react-native'; -import {useAntMedia, rtc_view} from '@antmedia/react-native-ant-media'; - -import InCallManager from 'react-native-incall-manager'; - -var publishStreamId:string; - -export default function App() { - var defaultStreamName = 'streamTest1'; - const webSocketUrl = 'ws://test.antmedia.io:5080/WebRTCAppEE/websocket'; - //or webSocketUrl: 'wss://server.com:5443/WebRTCAppEE/websocket', - - const streamNameRef = useRef(defaultStreamName); - const [localMedia, setLocalMedia] = useState(''); - const [isPlaying, setIsPlaying] = useState(false); - const [isWaitingWebsocketInit, setIsWaitingWebsocketInit] = useState(false); - - let localStream: any = useRef(null); - - useEffect(() => { - console.log(' localStream.current ', localStream.current); - }, []); - - const adaptor = useAntMedia({ - url: webSocketUrl, - mediaConstraints: { - audio: true, - video: { - width: 640, - height: 480, - frameRate: 30, - facingMode: 'front', - }, - }, - callback(command: any, data: any) { - switch (command) { - case 'pong': - break; - case 'publish_started': - console.log('publish_started'); - setIsPlaying(true); - break; - case 'publish_finished': - console.log('publish_finished'); - InCallManager.stop(); - setIsPlaying(false); - adaptor.closeWebSocket(); - break; - case 'local_stream_updated': - console.log('local_stream_updated'); - verify(); - break; - case 'websocket_not_initialized': - setIsWaitingWebsocketInit(true); - adaptor.initialiseWebSocket(); - break; - case 'websocket_closed': - console.log('websocket_closed'); - adaptor.stopLocalStream(); - break; - default: - console.log(command); - break; - } - }, - callbackError: (err: any, data: any) => { - console.error('callbackError', err, data); - }, - peer_connection_config: { - iceServers: [ - { - url: 'stun:stun.l.google.com:19302', - }, - ], - }, - debug: true, - }); - - const generateRandomString = (length: number): string => { - const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - let result = ''; - const charactersLength = characters.length; - - for (let i = 0; i < length; i++) { - const randomIndex = Math.floor(Math.random() * charactersLength); - result += characters.charAt(randomIndex); - } - return result; - }; - - const verify = () => { - console.log('in verify'); - if (adaptor.localStream.current && adaptor.localStream.current.toURL()) { - console.log('in verify if adaptor local stream', adaptor.localStream); - if (isWaitingWebsocketInit) { - setIsWaitingWebsocketInit(false); - publishStreamId = generateRandomString(12); - adaptor.publish(publishStreamId); - } - return setLocalMedia(adaptor.localStream.current.toURL()); - } - setTimeout(verify, 5000); - }; - - useEffect(() => { - verify(); - }, [adaptor.localStream]); - - useEffect(() => { - if (localMedia) { - InCallManager.start({media: 'video'}); - } - }, [localMedia]); - - const handlePublish = useCallback(() => { - if (!adaptor) { - return; - } - publishStreamId = generateRandomString(12); - adaptor.publish(publishStreamId); - }, [adaptor]); - - const handleStop = useCallback(() => { - if (!adaptor) { - return; - } - adaptor.stop(publishStreamId); - }, [adaptor]); - +import React from 'react'; +import { NavigationContainer } from '@react-navigation/native'; +import { createStackNavigator } from '@react-navigation/stack'; +import MainScreen from './MainScreen'; +import AppScreen from './App'; + +import Publish from './Publish'; +import Chat from './Chat'; +import Peer from './Peer'; +import Conference from './Conference'; +import Play from './Play'; + +export type RootStackParamList = { + MainScreen: undefined; + AppScreen: undefined; + Play: undefined; + Peer: undefined; + Conference: undefined; +}; + +const Stack = createStackNavigator(); + +const App: React.FC = () => { return ( - - - Ant Media WebRTC Publish - {localMedia ? <>{rtc_view(localMedia, styles.streamPlayer, 'cover')} : <>} - {!isPlaying ? ( - <> - - Start Publishing - - - ) : ( - <> - - Stop Publishing - - - )} - - + + + + + + + + + + + ); -} +}; -const styles = StyleSheet.create({ - container: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - }, - box: { - alignSelf: 'center', - width: '80%', - height: '80%', - }, - streamPlayer: { - width: '100%', - height: '80%', - alignSelf: 'center', - }, - button: { - alignItems: 'center', - backgroundColor: '#DDDDDD', - padding: 10, - marginBottom: 10, - }, - heading: { - alignSelf: 'center', - }, -}); +export default App; diff --git a/example/src/Chat.tsx b/example/src/Chat.tsx index 54a08c0..a952f3e 100644 --- a/example/src/Chat.tsx +++ b/example/src/Chat.tsx @@ -184,11 +184,12 @@ const styles = StyleSheet.create({ }, button: { alignItems: 'center', - backgroundColor: '#DDDDDD', + backgroundColor: '#AAAAAA', padding: 10, marginBottom: 10, }, heading: { alignSelf: 'center', + color: 'black' }, }); diff --git a/example/src/Conference.tsx b/example/src/Conference.tsx index 8a90bef..cc4ae30 100644 --- a/example/src/Conference.tsx +++ b/example/src/Conference.tsx @@ -332,7 +332,7 @@ const styles = StyleSheet.create({ button: { alignItems: 'center', justifyContent: 'center', - backgroundColor: '#DDDDDD', + backgroundColor: '#AAAAAA', padding: 10, width: '100%', marginTop: 20, @@ -341,15 +341,17 @@ const styles = StyleSheet.create({ alignSelf: 'center', marginBottom: 5, padding: 2, + color: 'black' }, heading1: { alignSelf: 'center', marginTop: 20, + color: 'black' }, roundButton: { alignItems: 'center', justifyContent: 'center', - backgroundColor: '#DDDDDD', + backgroundColor: '#AAAAAA', padding: 5, borderRadius: 25, // This will make the button round width: 30, // Diameter of the button diff --git a/example/src/MainScreen.tsx b/example/src/MainScreen.tsx new file mode 100644 index 0000000..cdcebe1 --- /dev/null +++ b/example/src/MainScreen.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; + +type RootStackParamList = { + MainScreen: undefined; + Publish: undefined; + Play: undefined; + Peer: undefined; + Conference: undefined; + Chat: undefined; +}; + +type MainScreenProps = { + navigation: StackNavigationProp; +}; + +const MainScreen: React.FC = ({ navigation }) => { + return ( + + Sample Apps + + navigation.navigate('Publish')}> + Publish + + + navigation.navigate('Play')}> + Play + + + navigation.navigate('Peer')}> + Peer + + + navigation.navigate('Conference')}> + Conference + + + navigation.navigate('Chat')}> + Chat + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#f5f5f5', + }, + title: { + fontSize: 24, + fontWeight: 'bold', + marginBottom: 20, + color: 'black', + }, + box: { + width: 200, + height: 60, + backgroundColor: '#6200ee', + justifyContent: 'center', + alignItems: 'center', + borderRadius: 10, + marginVertical: 10, + }, + text: { + color: 'white', + fontSize: 18, + }, +}); + +export default MainScreen; diff --git a/example/src/Peer.tsx b/example/src/Peer.tsx index a12cf12..f34bae5 100644 --- a/example/src/Peer.tsx +++ b/example/src/Peer.tsx @@ -44,7 +44,7 @@ export default function App() { console.log('leaved!'); setIsPlaying(false); break; - case "newStreamAvailable": + case "newStreamAvailable": if(data.streamId == streamNameRef.current) setRemoteStream(data.stream.toURL()); default: @@ -161,12 +161,13 @@ const styles = StyleSheet.create({ }, button: { alignItems: 'center', - backgroundColor: '#DDDDDD', + backgroundColor: '#AAAAAA', padding: 10, marginBottom: 10, }, heading: { alignSelf: 'center', marginBottom: 10, + color: 'black' }, }); diff --git a/example/src/Play.tsx b/example/src/Play.tsx index 15a9c51..f411c70 100644 --- a/example/src/Play.tsx +++ b/example/src/Play.tsx @@ -115,6 +115,7 @@ const styles = StyleSheet.create({ flex: 1, alignItems: 'center', justifyContent: 'center', + ackgroundColor: '#f5f5f5', }, box: { alignSelf: 'center', @@ -133,11 +134,12 @@ const styles = StyleSheet.create({ }, startButton: { alignItems: 'center', - backgroundColor: '#DDDDDD', + backgroundColor: '#AAAAAA', padding: 10, top: 400, }, heading: { alignSelf: 'center', + color: 'black' }, }); diff --git a/example/src/Publish.tsx b/example/src/Publish.tsx new file mode 100644 index 0000000..8be4b94 --- /dev/null +++ b/example/src/Publish.tsx @@ -0,0 +1,187 @@ +import React, {useCallback, useRef, useState, useEffect} from 'react'; + +import { + StyleSheet, + View, + SafeAreaView, + TouchableOpacity, + Text, +} from 'react-native'; +import {useAntMedia, rtc_view} from '@antmedia/react-native-ant-media'; + +import InCallManager from 'react-native-incall-manager'; + +var publishStreamId:string; + +export default function App() { + var defaultStreamName = 'streamTest1'; + const webSocketUrl = 'ws://test.antmedia.io:5080/WebRTCAppEE/websocket'; + //or webSocketUrl: 'wss://server.com:5443/WebRTCAppEE/websocket', + + const streamNameRef = useRef(defaultStreamName); + const [localMedia, setLocalMedia] = useState(''); + const [isPlaying, setIsPlaying] = useState(false); + const [isWaitingWebsocketInit, setIsWaitingWebsocketInit] = useState(false); + + let localStream: any = useRef(null); + + useEffect(() => { + console.log(' localStream.current ', localStream.current); + }, []); + + const adaptor = useAntMedia({ + url: webSocketUrl, + mediaConstraints: { + audio: true, + video: { + width: 640, + height: 480, + frameRate: 30, + facingMode: 'front', + }, + }, + callback(command: any, data: any) { + switch (command) { + case 'pong': + break; + case 'publish_started': + console.log('publish_started'); + setIsPlaying(true); + break; + case 'publish_finished': + console.log('publish_finished'); + InCallManager.stop(); + setIsPlaying(false); + adaptor.closeWebSocket(); + break; + case 'local_stream_updated': + console.log('local_stream_updated'); + verify(); + break; + case 'websocket_not_initialized': + setIsWaitingWebsocketInit(true); + adaptor.initialiseWebSocket(); + break; + case 'websocket_closed': + console.log('websocket_closed'); + adaptor.stopLocalStream(); + break; + default: + console.log(command); + break; + } + }, + callbackError: (err: any, data: any) => { + console.error('callbackError', err, data); + }, + peer_connection_config: { + iceServers: [ + { + url: 'stun:stun.l.google.com:19302', + }, + ], + }, + debug: true, + }); + + const generateRandomString = (length: number): string => { + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + const charactersLength = characters.length; + + for (let i = 0; i < length; i++) { + const randomIndex = Math.floor(Math.random() * charactersLength); + result += characters.charAt(randomIndex); + } + return result; + }; + + const verify = () => { + console.log('in verify'); + if (adaptor.localStream.current && adaptor.localStream.current.toURL()) { + console.log('in verify if adaptor local stream', adaptor.localStream); + if (isWaitingWebsocketInit) { + setIsWaitingWebsocketInit(false); + publishStreamId = generateRandomString(12); + adaptor.publish(publishStreamId); + } + return setLocalMedia(adaptor.localStream.current.toURL()); + } + setTimeout(verify, 5000); + }; + + useEffect(() => { + verify(); + }, [adaptor.localStream]); + + useEffect(() => { + if (localMedia) { + InCallManager.start({media: 'video'}); + } + }, [localMedia]); + + const handlePublish = useCallback(() => { + if (!adaptor) { + return; + } + publishStreamId = generateRandomString(12); + adaptor.publish(publishStreamId); + }, [adaptor]); + + const handleStop = useCallback(() => { + if (!adaptor) { + return; + } + adaptor.stop(publishStreamId); + }, [adaptor]); + + return ( + + + Ant Media WebRTC Publish + {localMedia ? <>{rtc_view(localMedia, styles.streamPlayer, 'cover')} : <>} + {!isPlaying ? ( + <> + + Start Publishing + + + ) : ( + <> + + Stop Publishing + + + )} + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + }, + box: { + alignSelf: 'center', + width: '80%', + height: '80%', + }, + streamPlayer: { + width: '100%', + height: '80%', + alignSelf: 'center', + }, + button: { + alignItems: 'center', + backgroundColor: '#AAAAAA', + padding: 10, + marginBottom: 10, + }, + heading: { + alignSelf: 'center', + color: 'black' + }, +}); diff --git a/example/src/StyleSheet.js b/example/src/StyleSheet.js new file mode 100644 index 0000000..97240e6 --- /dev/null +++ b/example/src/StyleSheet.js @@ -0,0 +1,29 @@ +import { StyleSheet } from 'react-native'; + +export default StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#f5f5f5', + }, + title: { + fontSize: 24, + fontWeight: 'bold', + marginBottom: 20, + color: 'black', + }, + box: { + width: 200, + height: 60, + backgroundColor: '#6200ee', + justifyContent: 'center', + alignItems: 'center', + borderRadius: 10, + marginVertical: 10, + }, + text: { + color: 'white', // Changed to white for better contrast + fontSize: 18, + }, +}); diff --git a/src/index.tsx b/src/index.tsx index 8241b0e..1eebe81 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -483,7 +483,7 @@ export function useAntMedia(params: Params) { getDevices(); - if (!onlyDataChannel) { + if (!onlyDataChannel && !isPlayMode) { mediaDevices.getUserMedia(mediaConstraints) .then((stream: any) => { // Got stream! @@ -498,7 +498,7 @@ export function useAntMedia(params: Params) { if (debug) console.log('got error', error , mediaConstraints); }); } else { - if (debug) console.log('only data channel'); + if (debug) console.log('only data channel or play only'); } setPingTimer(); };