all files / src/core/ Config.js

48.89% Statements 22/45
33.33% Branches 9/27
52.94% Functions 9/17
50% Lines 21/42
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180                                                                                                                                                            20×               10×                                                                                                                                                    
import media from './util/Media';
import * as DataSync from './util/DataSync';
import * as Log from './util/Log';
import cache from './util/cache';
 
const _flattenServers = servers => {
	const _expand = servers.map(server => {
		const {username, credential, urls, url} = server;
		const uris = urls || url;
		if(typeof uris !== 'string' ) {
			return uris.map(uri => ({username, credential, urls: uri}));
		}
		return [server];
	});
	return [].concat(..._expand);
};
 
/**
 * The Reach configuration object
 * @class Config
 */
export default class Config {
	/**
	 * Create configuration
	 * @access protected
	 * @param obj
	 */
	constructor(obj) {
		/**
		 * The default media constraints. These can be overridden when subscribing to a stream.
		 * @type {MediaStreamConstraints}
		 */
		this.constraints = null;
 
		/**
		 * The id/element dom element that will hold the local video/audio element
		 * @type {string|Element}
		 */
		this.localStreamContainer = null;
		/**
		 * The id/element dom element that will hold the remote video/audio element
		 * @type {string|Element}
		 */
		this.remoteStreamContainer = null;
 
		/**
		 * The preferred video Codec. Takes a RegExp matching the codec name and sample rate.
		 * Predefined values can be found in {@link Codec/video}
		 * @type {RegExp}
		 * @example <caption>Prefer VP9</caption>
		 * var myReach = new Reach('https://io.datasync.orange.com/base/<my_namespace>', {
		 *  preferredVideoCodec: Reach.codecs.video.VP9
		 * });
		 */
		this.preferredVideoCodec = null;
 
		/**
		 * The preferred audio Codec. Takes a RegExp matching the codec name and sample rate.
		 * Predefined values can be found in {@link Codec/audio}
		 * @type {RegExp}
		 * @example <caption>Prefer opus</caption>
		 * var myReach = new Reach('https://io.datasync.orange.com/base/<my_namespace>', {
		 *  preferredAudioCodec: Reach.codecs.audio.OPUS
		 * });
		 */
		this.preferredAudioCodec = null;
 
		// Populate with default values
		this.reset();
 
		// Populate with data
		this.assign(obj);
 
		// Read ICE servers from server
		DataSync.get('_/ice').then(snapData => {
			Eif(snapData) {
				this.iceServers = snapData.val();
				Log.i('ICEServers', this.iceServers.length > 0 ? this.iceServers : 'None');
			}
		}, e => Log.d('ICEServers', e));
 
		// TODO #Feat: Add boolean prop to request permission on start, sdpEditor (for user defined SDP modifications)
	}
 
	/**
	 * Assign new conf values
	 * @access protected
	 * @param {object} obj the new conf values
	 */
	assign(obj) {
		Object.keys(obj || {}).forEach(key => {this[key] = obj[key];});
	}
 
	/**
	 * The log level (DEBUG, INFO, WARN, ERROR)
	 * @type {string}
	 */
	set logLevel(level) {
		cache.logLevel = level;
	}
 
	/**
	 * The log level (DEBUG, INFO, WARN, ERROR)
	 * @returns {string}
	 */
	get logLevel() {
		return cache.logLevel;
	}
 
	/**
	 * List of TURN/STUN servers to use for ICE. This list will be merged with the ICE servers declared in the namespace (**_/ice**).
	 * @type {ICEServer[]}
	 */
	set iceServers(servers) {
		Log.d('Config~set~iceServers', servers);
		Eif(servers) {
			Eif (!this._iceServers) {
				/**
				 * @ignore
				 */
				this._iceServers = [].concat(servers || []);
			} else {
				// flatten existing
				const _currentServers = _flattenServers(this._iceServers);
				// flatten new
				const _newServers = _flattenServers(servers);
				// Add only the missing servers
				_newServers.forEach(newServer => {
					if(!_currentServers.some(server =>
							server.urls === newServer.urls &&
							server.username === newServer.username &&
							server.credential === newServer.credential)) {
						_currentServers.push(newServer);
					}
				});
				// Re-group by username/credential
				this._iceServers = _currentServers.reduce((previous, current) => {
					const {username, credential, urls} = current;
					const idx = previous.findIndex(s => s.username === username && s.credential === credential);
					if(idx >= 0) {
						previous[idx].urls.push(urls);
					} else {
						previous.push({username, credential, urls: [urls]});
					}
					return previous;
				}, []);
			}
		}
	}
 
	/**
	 * List of TURN/STUN servers to use for ICE. This list will be merged with the ICE servers declared in the namespace (**_/ice**).
	 * @type {ICEServer[]}
	 */
	get iceServers() {
		return this._iceServers || [
			{
				username: 'admin',
				credential: 'webcom1234',
				urls: [
					'turns:turn1.webcom.orange.com:443',
					'turn:turn1.webcom.orange.com:443?transport=tcp',
					'turn:turn1.webcom.orange.com:3478?transport=tcp'
				]
			}
		];
	}
 
	/**
	 * Resets configuration to default values
	 * @protected
	 */
	reset () {
		this.assign({
			constraints: media.constraints(),
			logLevel: 'ERROR'
		});
	}
}