mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-02-13 13:40:44 +00:00
Merge branch 'master' into v1.6
This commit is contained in:
commit
d38d065f51
@ -533,7 +533,7 @@ libs/libzrtp/libzrtp.a:
|
||||
cd libs/libzrtp && $(MAKE)
|
||||
|
||||
libs/libvpx/Makefile:
|
||||
cd libs/libvpx && sh ./configure --enable-pic --disable-docs --disable-examples --disable-install-bins --disable-install-srcs --disable-unit-tests --extra-cflags="-fvisibility=hidden"
|
||||
cd libs/libvpx && CC=$(CC) CXX=$(CXX) CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" ./configure --enable-pic --disable-docs --disable-examples --disable-install-bins --disable-install-srcs --disable-unit-tests --extra-cflags="-fvisibility=hidden"
|
||||
|
||||
libs/libvpx/libvpx.a: libs/libvpx/Makefile
|
||||
@cd libs/libvpx && $(MAKE)
|
||||
|
@ -1,8 +1,8 @@
|
||||
<configuration name="httapi.conf" description="HT-TAPI Hypertext Telephony API">
|
||||
<settings>
|
||||
<!-- print xml on the consol -->
|
||||
<!-- print xml on the console -->
|
||||
<param name="debug" value="true"/>
|
||||
<!-- time to keep audio files when discoverd they were deleted from the http server -->
|
||||
<!-- time to keep audio files when discovered they were deleted from the http server -->
|
||||
<param name="file-not-found-expires" value="300"/>
|
||||
<!-- how often to re-check the server to make sure the remote file has not changed -->
|
||||
<param name="file-cache-ttl" value="300"/>
|
||||
|
4
debian/freeswitch.postinst
vendored
4
debian/freeswitch.postinst
vendored
@ -31,7 +31,9 @@ case "$1" in
|
||||
done
|
||||
if [ ! -d "/etc/freeswitch" ]; then
|
||||
mkdir -p /etc/freeswitch/
|
||||
cp -a /usr/share/freeswitch/conf/vanilla/* /etc/freeswitch/
|
||||
if [ -e /usr/share/freeswitch/conf/vanilla/freeswitch.xml ]; then
|
||||
cp -a /usr/share/freeswitch/conf/vanilla/* /etc/freeswitch/
|
||||
fi
|
||||
fi
|
||||
if [ ! -d "/etc/freeswitch/tls" ]; then
|
||||
mkdir -p /etc/freeswitch/tls/
|
||||
|
@ -103,7 +103,7 @@
|
||||
|
||||
if (moz) {
|
||||
this.constraints = {
|
||||
offerToReceiveAudio: true,
|
||||
offerToReceiveAudio: this.options.useSpeak === "none" ? false : true,
|
||||
offerToReceiveVideo: this.options.useVideo ? true : false,
|
||||
};
|
||||
} else {
|
||||
@ -111,7 +111,7 @@
|
||||
optional: [{
|
||||
'DtlsSrtpKeyAgreement': 'true'
|
||||
}],mandatory: {
|
||||
OfferToReceiveAudio: true,
|
||||
OfferToReceiveAudio: this.options.useSpeak === "none" ? false : true,
|
||||
OfferToReceiveVideo: this.options.useVideo ? true : false,
|
||||
}
|
||||
};
|
||||
|
@ -1308,11 +1308,15 @@
|
||||
this.modCommand("vid-write-png", null, file);
|
||||
};
|
||||
|
||||
$.verto.conf.prototype.setVideoLayout = function(layout) {
|
||||
$.verto.conf.prototype.setVideoLayout = function(layout, canvasID) {
|
||||
if (!this.params.hasVid) {
|
||||
throw 'Conference has no video';
|
||||
}
|
||||
this.modCommand("vid-layout", null, layout);
|
||||
if (canvasID) {
|
||||
this.modCommand("vid-layout", null, [layout, canvasID]);
|
||||
} else {
|
||||
this.modCommand("vid-layout", null, layout);
|
||||
}
|
||||
};
|
||||
|
||||
$.verto.conf.prototype.kick = function(memberID) {
|
||||
@ -1439,7 +1443,7 @@
|
||||
|
||||
var vlhtml = "<div id='" + vlayout_id + "'><br>" +
|
||||
"<b>Video Layout Canvas " + (j+1) +
|
||||
"</b> <select onChange='$.verto.modfuncs.change_video_layout(\"" + vlayout_id + "\", \"" + j + "\")' id='" + vlselect_id + "'></select> " +
|
||||
"</b> <select onChange='$.verto.modfuncs.change_video_layout(\"" + vlayout_id + "\", \"" + (j+1) + "\")' id='" + vlselect_id + "'></select> " +
|
||||
"<br><br></div>";
|
||||
jq.append(vlhtml);
|
||||
}
|
||||
@ -2154,7 +2158,7 @@
|
||||
var speaker = dialog.useSpeak;
|
||||
console.info("Using Speaker: ", speaker);
|
||||
|
||||
if (speaker && speaker !== "any") {
|
||||
if (speaker && speaker !== "any" && speaker !== "none") {
|
||||
setTimeout(function() {
|
||||
dialog.setAudioPlaybackDevice(speaker);
|
||||
}, 500);
|
||||
|
@ -120,6 +120,7 @@ module.exports = function (grunt) {
|
||||
'<%= config.app %>/**/*.html',
|
||||
'.tmp/styles/{,*/}*.css',
|
||||
'<%= config.app %>/images/{,*/}*',
|
||||
'<%= config.app %>/locales/{,*/}*',
|
||||
'.tmp/**/*.js',
|
||||
'<%= config.app %>/**/*.js'
|
||||
],
|
||||
@ -150,6 +151,7 @@ module.exports = function (grunt) {
|
||||
],
|
||||
routes: {
|
||||
'/partials': 'src/partials',
|
||||
'/locales': 'src/locales',
|
||||
'/config.json': 'src/config.json',
|
||||
'/contributors.txt': 'src/contributors.txt',
|
||||
'/bower_components': './bower_components',
|
||||
@ -309,7 +311,8 @@ module.exports = function (grunt) {
|
||||
'img/*.png',
|
||||
'images/{,*/}*.{webp}',
|
||||
'css/fonts/{,*/}*.*',
|
||||
'sounds/*.*'
|
||||
'sounds/*.*',
|
||||
'locales/*.*'
|
||||
]
|
||||
}, {
|
||||
expand: true,
|
||||
|
@ -43,7 +43,9 @@
|
||||
"jquery-json": "~2.5.1",
|
||||
"datatables": "~1.10.8",
|
||||
"angular-bootstrap": "~0.14.3",
|
||||
"bootstrap-material-design": "~0.3.0"
|
||||
"bootstrap-material-design": "~0.3.0",
|
||||
"angular-translate": "~2.10.0",
|
||||
"angular-translate-loader-static-files": "~2.10.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"angular": "~1.3.15",
|
||||
|
@ -2,6 +2,7 @@
|
||||
"Jonatas Oliveira <jonatas@evolux.net.br>",
|
||||
"Ítalo Rossi <italo@evolux.net.br>",
|
||||
"Stefan Yohansson <stefan@evolux.net.br>",
|
||||
"Victor Torres <victor@evolux.net.br>",
|
||||
"João Mesquita <jmesquita@indicium.com.ar>",
|
||||
"Ken Rice <krice@freeswitch.org>",
|
||||
"Brian West <brian@freeswitch.org>"
|
||||
|
@ -143,7 +143,7 @@ button.btn i {
|
||||
-webkit-animation: rotator 1.4s linear infinite;
|
||||
animation: rotator 1.4s linear infinite;
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -35px;
|
||||
zoom: 2;
|
||||
@ -503,17 +503,17 @@ body .modal-body .btn-group .btn.active {
|
||||
}*/
|
||||
|
||||
#incall .video-call {
|
||||
width: 81vw;
|
||||
height: 82vw;
|
||||
max-height: calc(100% - 1vw);
|
||||
max-width: 146.78vh;
|
||||
margin: auto;
|
||||
margin: 7px auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-top: auto;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
#incall .avatar {
|
||||
@ -764,7 +764,7 @@ body .modal-body .btn-group .btn.active {
|
||||
}
|
||||
|
||||
#sidebar-wrapper {
|
||||
z-index: 1000;
|
||||
z-index: 8;
|
||||
position: fixed;
|
||||
width: 0;
|
||||
height: calc(100% - 60px);
|
||||
@ -1686,3 +1686,53 @@ body:-webkit-full-screen #incall .video-footer {
|
||||
from { max-height:2000px;}
|
||||
to { max-height:0px;}
|
||||
}
|
||||
|
||||
#settings {
|
||||
z-index: 9;
|
||||
position: fixed;
|
||||
background: rgba(10, 56, 127, 0.9);
|
||||
width: 100%;
|
||||
transition: .4s ease-out;
|
||||
color: white;
|
||||
max-height: 80%;
|
||||
overflow: auto;
|
||||
top: -100%;
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
#settings select {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#settings option {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#settings .content {
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#settings.toggled {
|
||||
top: 67px;
|
||||
}
|
||||
|
||||
#settings .form-group .form-control:focus {
|
||||
background-image: linear-gradient(#d2d2d2, #d2d2d2), linear-gradient(#d2d2d2, #d2d2d2)
|
||||
}
|
||||
|
||||
#settings .checkbox input[type=checkbox]:checked + .checkbox-material .check,
|
||||
#settings .checkbox input[type=checkbox]:checked + .checkbox-material .check:before,
|
||||
#settings .checkbox-default input[type=checkbox]:checked + .checkbox-material .check:before {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#settings .checkbox .checkbox-material .check {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#settings .btn {
|
||||
color: rgba(0, 10, 66, 0.84);
|
||||
background-color: #E8E8E8;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@
|
||||
<body>
|
||||
|
||||
<div ng-include="'partials/menu.html'"></div>
|
||||
<div ng-include="'partials/settings.html'"></div>
|
||||
|
||||
<div id="wrapper" class="toggled">
|
||||
<!-- Sidebar -->
|
||||
@ -96,6 +97,8 @@
|
||||
<script src="bower_components/datatables/media/js/jquery.dataTables.js"></script>
|
||||
<script src="bower_components/bootstrap-material-design/dist/js/material.js"></script>
|
||||
<script src="bower_components/bootstrap-material-design/dist/js/ripples.js"></script>
|
||||
<script src="bower_components/angular-translate/angular-translate.js"></script>
|
||||
<script src="bower_components/angular-translate-loader-static-files/angular-translate-loader-static-files.js"></script>
|
||||
<!-- endbower -->
|
||||
<!-- endbuild -->
|
||||
|
||||
@ -125,7 +128,7 @@
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalDialpadController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalWsReconnectController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalLoginInformationController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalSettingsController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/SettingsController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/PreviewController.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/vertoDirectives/vertoDirectives.module.js"></script>
|
||||
|
151
html5/verto/verto_communicator/src/locales/locale-de.json
Normal file
151
html5/verto/verto_communicator/src/locales/locale-de.json
Normal file
@ -0,0 +1,151 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Oops, actives Gespräch in Bearbeitung.",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "Es wärst du bereits in einer Konversation. Konversation beenden?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "Es scheint als warst du in einer Konversation bevor die Sitzung beendet wurde. Diese Konversation fortsetzen?",
|
||||
"TITLE_INCOMING_CALL": "Eingehender Anruf",
|
||||
"MESSAGE_INCOMING_CALL": "Von ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "Es gibt keine Gespräche die beendet werden können.",
|
||||
"MESSAGE_ENTER_FILENAME": "Bitte, Dateinamen eingeben",
|
||||
"TITLE_ENABLE_VIDEO": "Video für dieses Gespräch aktivieren?",
|
||||
"MESSAGE_ENABLE_VIDEO": "Video wird für die nächsten Gespräche aktiviert werden.",
|
||||
"TITLE_INSERT_BANNER": "Bitte Banner text eingeben",
|
||||
"TITLE_INSERT_CANVAS_ID": "Bitte Canvas ID eingeben",
|
||||
"TITLE_INSERT_LAYER": "Please insert the Layer",
|
||||
"TITLE_TRANSFER": "Gespräch weiterleiten?",
|
||||
"MESSAGE_TRANSFER": "Welches Ziel soll die Weiterleitung haben?",
|
||||
"LABEL_TRANSFER": "Ziel",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "Die Vorschau Einstellungen können während eines Gesprächs nicht angezeigt werden",
|
||||
"BUTTON_END_CALL": "Anruf beenden",
|
||||
"BUTTON_CLOSE": "Schließen",
|
||||
"MESSAGE_PLAY": "Wiedergabe",
|
||||
"MESSAGE_STOP": "Stoppen",
|
||||
"MESSAGE_RECORD": "Aufnahme",
|
||||
"MESSAGE_STOP_RECORD": "Aufnahme beenden",
|
||||
"MESSAGE_SNAPSHOT": "Snapshot",
|
||||
"MESSAGE_VIDEO_MODE": "Video Modus",
|
||||
"MESSAGE_MUTE_MIC": "Mikrofon ein/ausschalten",
|
||||
"MESSAGE_MUTE_VIDEO": "Video ein/ausschalten",
|
||||
"MESSAGE_FULLSCREEN": "Vollbildmodus ein/ausschalten",
|
||||
"MESSAGE_SCREENSHARE": "Bildschirm teilen",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Chat öffnen/schließen",
|
||||
"MESSAGE_SPEAKER": "Lautsprecher",
|
||||
"MESSAGE_POPUP": "Popup",
|
||||
"CHAT_TITLE_MEMBERS": "Teilnehmer",
|
||||
"CHAT_TITLE": "Chat",
|
||||
"CHAT_NO_MEMBERS": "Es gibt keine Mitglieder zum anzeigen.",
|
||||
"CHAT_GENERAL": "Generell",
|
||||
"CHAT_TITLE_KICK": "Kick",
|
||||
"CHAT_KICK": "Kick",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Video Floor",
|
||||
"CHAT_FLOOR": "Floor",
|
||||
"CHAT_TITLE_TRANSFER": "Weiterleiten",
|
||||
"CHAT_TRANSFER": "Weiterleiten",
|
||||
"CHAT_BANNER": "Banner",
|
||||
"CHAT_TITLE_SET": "Set",
|
||||
"CHAT_SET": "Set",
|
||||
"CHAT_TITLE_RESET": "Resetieren",
|
||||
"CHAT_RESET": "Resetieren",
|
||||
"CHAT_CANVAS": "Canvas",
|
||||
"CHAT_CANVAS_IN": "Canvas In",
|
||||
"CHAT_CANVAS_OUT": "Canvas Out",
|
||||
"CHAT_PREV": "Zurück",
|
||||
"CHAT_NEXT": "Weiter",
|
||||
"CHAT_LAYER": "Layer",
|
||||
"CHAT_AUDIO_VIDEO": "Audio/Video",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Mikrofon ein/ausschalten",
|
||||
"CHAT_MUTE_MIC": "stumm schalten",
|
||||
"CHAT_UNMUTE_MIC": "stummschaltung deaktivieren",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_VIDEO": "Stummschaltung ein/ausschalten",
|
||||
"CHAT_NO_MESSAGES": "Es gibt keine Nachrichten zum anzeigen.",
|
||||
"CHAT_SEND_MESSAGE": "Absenden",
|
||||
"CHAT_TYPE_MESSAGE": "Nachricht kann hier eingegeben werden...",
|
||||
"TITLE_CONTRIBUTORS": "Mitwirkende",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "Die Verbindung ist ungesichert.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Navigation umschalten",
|
||||
"BANDWIDTH_INFO": "Info Bandbreite",
|
||||
"BANDWIDTH_INFO_INCOMING": "Eingehend:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "Ausgehend:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Video Auflösung:",
|
||||
"IN_CALL": "Im Gespräch:",
|
||||
"LAST_CALL": "Letzter Anruf:",
|
||||
"OPEN_NEW_WINDOW": "Neues Fenster öffnen",
|
||||
"CHANGE_LOGIN_INFO": "Anmeldedaten verändern",
|
||||
"LOGOUT": "Abmelden",
|
||||
"ABOUT": "Über",
|
||||
"HELP": "Hilfe",
|
||||
"CONTRIBUTORS": "Mitwirkende",
|
||||
"TITLE_PREVIEW_SETTINGS": "Kamera und Mikrofon Einstellungen",
|
||||
"CAMERA_SETTINGS": "Kamera:",
|
||||
"MIC_SETTINGS": "Mikrofon:",
|
||||
"SAVE": "Speichern",
|
||||
"LOADING": "Ladend",
|
||||
"ERRORS" : "Fehler",
|
||||
"CALLING_TO": "Gesprächsaufbau zu ",
|
||||
"CANCELLING": "Abbrechen...",
|
||||
"DETERMINING_SPEED": "Geschwindigkeit wird analysiert...",
|
||||
"CALL_HISTORY": "Gesprächsverlauf",
|
||||
"CLEAR_CALL_HISTORY": "Gesprächsverlauf löschen",
|
||||
"NO_CALL_HISTORY": "Kein Gesprächsverlauf vorhanden.",
|
||||
"ENTER_EXTENSION": "Nummer eingeben",
|
||||
"CALL_EXTENSION": "Nummer anrufen",
|
||||
"LOGIN": "Anmelden",
|
||||
"LOGIN_INFORMATION": "Anmeldeinformationen",
|
||||
"SAVE_LOGIN_INFORMATION": "Anmeldeinformationen speichern",
|
||||
"INVALID_LOGIN_FIELDS": "Bitte die unteren Felder kontrollieren und erneut versuchen.",
|
||||
"NAME": "Name",
|
||||
"YOUR_NAME": "Dein Name",
|
||||
"EMAIL": "E-Mail",
|
||||
"YOUR_EMAIL": "Deine E-Mail",
|
||||
"USER": "Benutzer",
|
||||
"PASSWORD": "Passwort",
|
||||
"CALLER_ID": "Anrufer ID",
|
||||
"HOSTNAME": "Hostname",
|
||||
"WEBSOCKET_URL": "Websocket URL",
|
||||
"SETTINGS": "Einstellungen",
|
||||
"DEVICE_SETTINGS": "Geräte Einstellungen",
|
||||
"SHARE_DEVICE": "Gerät teilen",
|
||||
"SPEAKER": "Lautsprecher:",
|
||||
"SPEAKER_FEATURE": "Dein browser scheint diese Funktion nicht zu unterstützen",
|
||||
"PREVIEW_SETTINGS": "Vorschau Einstellungen",
|
||||
"REFRESH_DEVICE_LIST": "Aktualisieren Geräteliste",
|
||||
"GENERAL_SETTINGS": "Generelle Einstellungen:",
|
||||
"USE_VIDEO": "Video aktivieren",
|
||||
"USE_STEREO_AUDIO": "Stereo Audio",
|
||||
"USE_STUN": "STUN benützen",
|
||||
"SCALE_VIDEO": "Entfernte Kamera skalieren damit die Auflösung zusammenpasst",
|
||||
"ASK_BEFORE_RECOVER": "Nachfrage bevor das Gespräch wiederhergestellt wird",
|
||||
"BEST_FRAME_RATE": "Beste frame rate:",
|
||||
"AUDIO_SETTINGS": "Audio Einstellungen:",
|
||||
"ECHO_CANCEL": "Echo Cancellation",
|
||||
"NOISE_SUPPRESSION": "Noise Suppression",
|
||||
"HIGHPASS_FILTER": "Highpass Filter",
|
||||
"VIDEO_SETTINGS": "Video Einstellungen:",
|
||||
"REMOTE_ENCODER": "Dedicated Remote Encoder enabled.",
|
||||
"AUTO_SPEED_RES": "Automatisch geschwindigkeit messen und Auflösung einstellen",
|
||||
"RECHECK_BANDWIDTH": "Recheck bandwidth before each outgoing call",
|
||||
"CHECK_NETWORK_SPEED": "Netzwerk Geschwindigkeit messen",
|
||||
"VIDEO_QUALITY": "Video Qualität:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Max eingehnde Bandbreite:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Max ausgehende Bandbreite:",
|
||||
"FACTORY_RESET": "Werkseinstellungen",
|
||||
"SAVE_DEVICE_SETTINGS": "Geräteeinstellungen speichern",
|
||||
"BROWSER_COMPATIBILITY": "Browserkompatibilität prüfen.",
|
||||
"REFRESH_MEDIA_DEVICES": "Aktualisiern Medien Geräte.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Fehler: Browser unterstützt kein WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Medien berechtigungen prüfen",
|
||||
"CHECK_PROVISIONING_CONF": "Provisioning Konfiguration.",
|
||||
"CHECK_LOGIN": "Anmeldung verifizieren.",
|
||||
"CHECK_CONNECTION_SPEED": "Verbindungsgeschwindikeit prüfen.",
|
||||
"ERROR_PERMISSION_MEDIA": "Fehler: Medien Berechtigung fehlgeschlagen",
|
||||
"ERROR_PROVISIONING_CONF": "Fehler: Provisioning fehlgeschlagen.",
|
||||
"PLEASE_WAIT": "Bitte warten...",
|
||||
"CANCEL": "Abbrechen",
|
||||
"CHAT_TITLE_VOL_MINUS": "Lautstärke -",
|
||||
"CHAT_TITLE_VOL_PLUS": "Lautstärke +",
|
||||
"CHAT_TITLE_GAIN_MINUS": "Gain -",
|
||||
"CHAT_TITLE_GAIN_PLUS": "Gain +",
|
||||
"CHAT_VOL_MINUS": "Lautstärke -",
|
||||
"CHAT_VOL_PLUS": "Lautstärke +",
|
||||
"CHAT_GAIN_MINUS": "Gain -",
|
||||
"CHAT_GAIN_PLUS": "Gain +"
|
||||
}
|
151
html5/verto/verto_communicator/src/locales/locale-en.json
Normal file
151
html5/verto/verto_communicator/src/locales/locale-en.json
Normal file
@ -0,0 +1,151 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Oops, Active Call in Course.",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "It seems that you are in a call. Do you want to hang up?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "It seems you were in a call before leaving the last time. Wanna go back to that?",
|
||||
"TITLE_INCOMING_CALL": "Incoming Call",
|
||||
"MESSAGE_INCOMING_CALL": "from ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "There is no call to hangup.",
|
||||
"MESSAGE_ENTER_FILENAME": "Please, enter filename",
|
||||
"TITLE_ENABLE_VIDEO": "Would you like to activate video for this call?",
|
||||
"MESSAGE_ENABLE_VIDEO": "Video will be active during the next calls.",
|
||||
"TITLE_INSERT_BANNER": "Please insert the banner text",
|
||||
"TITLE_INSERT_CANVAS_ID": "Please insert the Canvas Id",
|
||||
"TITLE_INSERT_LAYER": "Please insert the Layer",
|
||||
"TITLE_TRANSFER": "Transfer party?",
|
||||
"MESSAGE_TRANSFER": "To what destination would you like to transfer this call?",
|
||||
"LABEL_TRANSFER": "Destination",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "Can't display preview settings during a call",
|
||||
"BUTTON_END_CALL": "End Call",
|
||||
"BUTTON_CLOSE": "Close",
|
||||
"MESSAGE_PLAY": "Play",
|
||||
"MESSAGE_STOP": "Stop",
|
||||
"MESSAGE_RECORD": "Record",
|
||||
"MESSAGE_STOP_RECORD": "Stop Record",
|
||||
"MESSAGE_SNAPSHOT": "Snapshot",
|
||||
"MESSAGE_VIDEO_MODE": "Video Mode",
|
||||
"MESSAGE_MUTE_MIC": "(un)Mute Mic",
|
||||
"MESSAGE_MUTE_VIDEO": "(un)Mute Video",
|
||||
"MESSAGE_FULLSCREEN": "Toggle Fullscreen Mode",
|
||||
"MESSAGE_SCREENSHARE": "Screenshare",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Open/Close Chat",
|
||||
"MESSAGE_SPEAKER": "Speaker",
|
||||
"MESSAGE_POPUP": "Popup",
|
||||
"CHAT_TITLE_MEMBERS": "Members",
|
||||
"CHAT_TITLE": "Chat",
|
||||
"CHAT_NO_MEMBERS": "There are no members to show.",
|
||||
"CHAT_GENERAL": "General",
|
||||
"CHAT_TITLE_KICK": "Kick",
|
||||
"CHAT_KICK": "Kick",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Video Floor",
|
||||
"CHAT_FLOOR": "Floor",
|
||||
"CHAT_TITLE_TRANSFER": "Transfer",
|
||||
"CHAT_TRANSFER": "Transfer",
|
||||
"CHAT_BANNER": "Banner",
|
||||
"CHAT_TITLE_SET": "Set",
|
||||
"CHAT_SET": "Set",
|
||||
"CHAT_TITLE_RESET": "Reset",
|
||||
"CHAT_RESET": "Reset",
|
||||
"CHAT_CANVAS": "Canvas",
|
||||
"CHAT_CANVAS_IN": "Canvas In",
|
||||
"CHAT_CANVAS_OUT": "Canvas Out",
|
||||
"CHAT_PREV": "Prev",
|
||||
"CHAT_NEXT": "Next",
|
||||
"CHAT_LAYER": "Layer",
|
||||
"CHAT_AUDIO_VIDEO": "Audio/Video",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Mute/Unmute Mic",
|
||||
"CHAT_MUTE_MIC": "Mute",
|
||||
"CHAT_UNMUTE_MIC": "Unmute",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_VIDEO": "Mute/Unmute Video",
|
||||
"CHAT_NO_MESSAGES": "There are no messages to show.",
|
||||
"CHAT_SEND_MESSAGE": "Send",
|
||||
"CHAT_TYPE_MESSAGE": "Type your message here...",
|
||||
"TITLE_CONTRIBUTORS": "Contributors",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "This Connection is Untrusted.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Toggle navigation",
|
||||
"BANDWIDTH_INFO": "Bandwidth Info",
|
||||
"BANDWIDTH_INFO_INCOMING": "Incoming:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "Outgoing:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Video Resolution:",
|
||||
"IN_CALL": "In Call:",
|
||||
"LAST_CALL": "Last Call:",
|
||||
"OPEN_NEW_WINDOW": "Open New Window",
|
||||
"CHANGE_LOGIN_INFO": "Change Login Information",
|
||||
"LOGOUT": "Logout",
|
||||
"ABOUT": "About",
|
||||
"HELP": "Help",
|
||||
"CONTRIBUTORS": "Contributors",
|
||||
"TITLE_PREVIEW_SETTINGS": "Setup your camera and microphone settings",
|
||||
"CAMERA_SETTINGS": "Camera:",
|
||||
"MIC_SETTINGS": "Microphone:",
|
||||
"SAVE": "Save",
|
||||
"LOADING": "Loading",
|
||||
"ERRORS" : "Errors",
|
||||
"CALLING_TO": "Calling to ",
|
||||
"CANCELLING": "Cancelling...",
|
||||
"DETERMINING_SPEED": "Determining your speed...",
|
||||
"CALL_HISTORY": "Call History",
|
||||
"CLEAR_CALL_HISTORY": "Clear History",
|
||||
"NO_CALL_HISTORY": "No history calls.",
|
||||
"ENTER_EXTENSION": "Enter an extension",
|
||||
"CALL_EXTENSION": "Call Extension",
|
||||
"LOGIN": "Login",
|
||||
"LOGIN_INFORMATION": "Login Information",
|
||||
"SAVE_LOGIN_INFORMATION": "Save Login Information",
|
||||
"INVALID_LOGIN_FIELDS": "Verify the fields below and try again.",
|
||||
"NAME": "Name",
|
||||
"YOUR_NAME": "Your name",
|
||||
"EMAIL": "Email",
|
||||
"YOUR_EMAIL": "Your email",
|
||||
"USER": "User",
|
||||
"PASSWORD": "Password",
|
||||
"CALLER_ID": "Caller ID",
|
||||
"HOSTNAME": "Hostname",
|
||||
"WEBSOCKET_URL": "Websocket URL",
|
||||
"SETTINGS": "Settings",
|
||||
"DEVICE_SETTINGS": "Device Settings",
|
||||
"SHARE_DEVICE": "Share device",
|
||||
"SPEAKER": "Speaker:",
|
||||
"SPEAKER_FEATURE": "Your browser doesn't seem to support this feature",
|
||||
"PREVIEW_SETTINGS": "Preview Settings",
|
||||
"REFRESH_DEVICE_LIST": "Refresh device list",
|
||||
"GENERAL_SETTINGS": "General settings:",
|
||||
"USE_VIDEO": "Use Video",
|
||||
"USE_STEREO_AUDIO": "Stereo Audio",
|
||||
"USE_STUN": "Use STUN",
|
||||
"SCALE_VIDEO": "Scale Remote Video To Match Camera Resolution",
|
||||
"ASK_BEFORE_RECOVER": "Ask before recovering call",
|
||||
"BEST_FRAME_RATE": "Best frame rate:",
|
||||
"AUDIO_SETTINGS": "Audio settings:",
|
||||
"ECHO_CANCEL": "Echo Cancellation",
|
||||
"NOISE_SUPPRESSION": "Noise Suppression",
|
||||
"HIGHPASS_FILTER": "Highpass Filter",
|
||||
"VIDEO_SETTINGS": "Video settings:",
|
||||
"REMOTE_ENCODER": "Dedicated Remote Encoder enabled.",
|
||||
"AUTO_SPEED_RES": "Automatically determine speed and resolution settings",
|
||||
"RECHECK_BANDWIDTH": "Recheck bandwidth before each outgoing call",
|
||||
"CHECK_NETWORK_SPEED": "Check Network Speed",
|
||||
"VIDEO_QUALITY": "Video quality:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Max incoming bandwidth:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Max outgoing bandwidth:",
|
||||
"FACTORY_RESET": "Factory reset",
|
||||
"SAVE_DEVICE_SETTINGS": "Save Device Settings",
|
||||
"BROWSER_COMPATIBILITY": "Checking browser compatibility.",
|
||||
"REFRESH_MEDIA_DEVICES": "Refresh Media Devices.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Error: browser doesn't support WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Checking media permissions",
|
||||
"CHECK_PROVISIONING_CONF": "Provisioning configuration.",
|
||||
"CHECK_LOGIN": "Checking login.",
|
||||
"CHECK_CONNECTION_SPEED": "Check Connection Speed.",
|
||||
"ERROR_PERMISSION_MEDIA": "Error: Media Permission Denied",
|
||||
"ERROR_PROVISIONING_CONF": "Error: Provision failed.",
|
||||
"PLEASE_WAIT": "Please wait...",
|
||||
"CANCEL": "Cancel",
|
||||
"CHAT_TITLE_VOL_MINUS": "Volume -",
|
||||
"CHAT_TITLE_VOL_PLUS": "Volume +",
|
||||
"CHAT_TITLE_GAIN_MINUS": "Gain -",
|
||||
"CHAT_TITLE_GAIN_PLUS": "Gain +",
|
||||
"CHAT_VOL_MINUS": "Vol -",
|
||||
"CHAT_VOL_PLUS": "Vol +",
|
||||
"CHAT_GAIN_MINUS": "Gain -",
|
||||
"CHAT_GAIN_PLUS": "Gain +"
|
||||
}
|
142
html5/verto/verto_communicator/src/locales/locale-es.json
Normal file
142
html5/verto/verto_communicator/src/locales/locale-es.json
Normal file
@ -0,0 +1,142 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Uy, llamada activa en curso.",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "Parece que estas en una llamada, Desea colgar?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "Parece que estabas en una llamada la ultima vez, quieres regresar a eso?",
|
||||
"TITLE_INCOMING_CALL": "Llamada entrante",
|
||||
"MESSAGE_INCOMING_CALL": "Desde ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "No hay ninguna llamada que colgar.",
|
||||
"MESSAGE_ENTER_FILENAME": "Por favor, indique el nombre del archivo.",
|
||||
"TITLE_ENABLE_VIDEO": "¿Quieres activar el video para esta convocatoria?",
|
||||
"MESSAGE_ENABLE_VIDEO": "Video estará activo durante las siguientes llamadas.",
|
||||
"TITLE_INSERT_BANNER": "Por favor introduzca el texto del estandarte ",
|
||||
"TITLE_INSERT_CANVAS_ID": "Por favor, Introduzca el Id de lona",
|
||||
"TITLE_INSERT_LAYER": "Por favor inserte la capa",
|
||||
"TITLE_TRANSFER": "¿Transferencia de partido?",
|
||||
"MESSAGE_TRANSFER": "¿A qué destino quieres transferir esta llamada?",
|
||||
"LABEL_TRANSFER": "Destino",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "No se puede mostrar la configuración durante una llamada",
|
||||
"BUTTON_END_CALL": "Finalizar llamada",
|
||||
"BUTTON_CLOSE": "Cerrar",
|
||||
"MESSAGE_PLAY": " Reproducir",
|
||||
"MESSAGE_STOP": "Parar",
|
||||
"MESSAGE_RECORD": "Grabar",
|
||||
"MESSAGE_STOP_RECORD": "Parar de grabar",
|
||||
"MESSAGE_SNAPSHOT": "Foto instantánea",
|
||||
"MESSAGE_VIDEO_MODE": "Modo de vídeo",
|
||||
"MESSAGE_MUTE_MIC": "(des) silenciar el micrófono",
|
||||
"MESSAGE_MUTE_VIDEO": "(des) silenciar el Video",
|
||||
"MESSAGE_FULLSCREEN": "Cambiar el modo de pantalla completa",
|
||||
"MESSAGE_SCREENSHARE": "Compartir la pantalla",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Abrir/cerrar Chat",
|
||||
"MESSAGE_SPEAKER": "Altavoz",
|
||||
"MESSAGE_POPUP": "Emergente",
|
||||
"CHAT_TITLE_MEMBERS": "Miembros",
|
||||
"CHAT_TITLE": "Chat",
|
||||
"CHAT_NO_MEMBERS": "No hay miembros para mostrar.",
|
||||
"CHAT_GENERAL": "General",
|
||||
"CHAT_TITLE_KICK": "Patear",
|
||||
"CHAT_KICK": "Patear",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Piso Video",
|
||||
"CHAT_FLOOR": "Piso",
|
||||
"CHAT_TITLE_TRANSFER": "Transferir",
|
||||
"CHAT_TRANSFER": "Transferir",
|
||||
"CHAT_BANNER": "Estandarte",
|
||||
"CHAT_TITLE_SET": "Poner",
|
||||
"CHAT_SET": "Poner",
|
||||
"CHAT_TITLE_RESET": "Reajustar",
|
||||
"CHAT_RESET": "Reajustar ",
|
||||
"CHAT_CANVAS": "Lona",
|
||||
"CHAT_CANVAS_IN": "Lona dentro",
|
||||
"CHAT_CANVAS_OUT": "Lona afuera",
|
||||
"CHAT_PREV": "Prev",
|
||||
"CHAT_NEXT": "Proximo",
|
||||
"CHAT_LAYER": "Capa",
|
||||
"CHAT_AUDIO_VIDEO": "Audio/Video",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Silenciar/Des Silenciar Microfono",
|
||||
"CHAT_MUTE_MIC": "Silenciar ",
|
||||
"CHAT_UNMUTE_MIC": "Des Silenciar",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Silenciar/Des Silenciar Video",
|
||||
"CHAT_NO_MESSAGES": "No hay mensajes para mostrar.",
|
||||
"CHAT_SEND_MESSAGE": "Enviar",
|
||||
"CHAT_TYPE_MESSAGE": "Escriba su mensaje aquí...",
|
||||
"TITLE_CONTRIBUTORS": "Contribuyente",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "Esta conexión no es de confianza.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Alternar la navegación",
|
||||
"BANDWIDTH_INFO": "Información de la amplitud de banda",
|
||||
"BANDWIDTH_INFO_INCOMING": "Entrante:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "Saliente:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Resolución de vídeo:",
|
||||
"IN_CALL": "En llamada:",
|
||||
"LAST_CALL": " Última llamada:",
|
||||
"OPEN_NEW_WINDOW": "Abrir nueva Ventana",
|
||||
"CHANGE_LOGIN_INFO": "Cambiar la información de inicio de sesión",
|
||||
"LOGOUT": "Salir de sesión",
|
||||
"ABOUT": "Sobre",
|
||||
"HELP": "Ayuda",
|
||||
"CONTRIBUTORS": "Contribuyente",
|
||||
"TITLE_PREVIEW_SETTINGS": "Configuración de la Cámara y el Micrófono",
|
||||
"CAMERA_SETTINGS": "Cámara:",
|
||||
"MIC_SETTINGS": "Micrófono:",
|
||||
"SAVE": "Salvar",
|
||||
"LOADING": "Cargando",
|
||||
"ERRORS" : "Errores",
|
||||
"CALLING_TO": "Llamar a ",
|
||||
"CANCELLING": "Cancelando...",
|
||||
"DETERMINING_SPEED": "Determinación de la velocidad...",
|
||||
"CALL_HISTORY": "Historial de llamadas",
|
||||
"CLEAR_CALL_HISTORY": "Borrar Historial",
|
||||
"NO_CALL_HISTORY": "No Historial de llamadas.",
|
||||
"ENTER_EXTENSION": "Entre en una extensión",
|
||||
"CALL_EXTENSION": " Llamar extensión",
|
||||
"LOGIN": "Inicio de Sesión",
|
||||
"LOGIN_INFORMATION": "Información de Inicio de Sesión",
|
||||
"SAVE_LOGIN_INFORMATION": "Salvar Información de Inicio de Sesión",
|
||||
"INVALID_LOGIN_FIELDS": "Verifique los campos abajo e intente otra vez.",
|
||||
"NAME": "Nombre",
|
||||
"YOUR_NAME": "Su Nombre",
|
||||
"EMAIL": " El Correo Electrónico",
|
||||
"YOUR_EMAIL": "Su Correo Electrónico",
|
||||
"USER": "Usuario",
|
||||
"PASSWORD": "Contraseña",
|
||||
"CALLER_ID": "Identificador de llamadas",
|
||||
"HOSTNAME": "Hostname",
|
||||
"WEBSOCKET_URL": "Websocket URL",
|
||||
"SETTINGS": "Configuraciónes",
|
||||
"DEVICE_SETTINGS": "La configuración de usuario",
|
||||
"SHARE_DEVICE": "Compartir dispositivo",
|
||||
"SPEAKER": "Altavoz:",
|
||||
"SPEAKER_FEATURE": "Su navegador no parece apoyar esta función",
|
||||
"PREVIEW_SETTINGS": "Configuración de vista anticipada",
|
||||
"REFRESH_DEVICE_LIST": "Actualizar la lista de dispositivos",
|
||||
"GENERAL_SETTINGS": "Configuración general:",
|
||||
"USE_VIDEO": "Utilizar vídeo",
|
||||
"USE_STEREO_AUDIO": "Audio Estéreo",
|
||||
"USE_STUN": "Utilizar STUN",
|
||||
"SCALE_VIDEO": "Escala de vídeo remoto para que coincida con la resolución de la cámara",
|
||||
"ASK_BEFORE_RECOVER": "Preguntar antes de recuperar la llamada",
|
||||
"BEST_FRAME_RATE": "Mejor velocidad:",
|
||||
"AUDIO_SETTINGS": "Configuración de audio:",
|
||||
"ECHO_CANCEL": "Cancelación de eco",
|
||||
"NOISE_SUPPRESSION": "Supresión de Ruido",
|
||||
"HIGHPASS_FILTER": "Filtro de paso alto",
|
||||
"VIDEO_SETTINGS": "Configuración de vídeo:",
|
||||
"REMOTE_ENCODER": "Codificador Remoto dedicado permitido.",
|
||||
"AUTO_SPEED_RES": "Determinar automáticamente la configuración de velocidad y resolución",
|
||||
"RECHECK_BANDWIDTH": "Compruebe de nuevo la amplitud de banda antes de cada llamada saliente",
|
||||
"CHECK_NETWORK_SPEED": "Compruebe la velocidad de la red",
|
||||
"VIDEO_QUALITY": "Calidad de video:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Máxima amplitude banda entrante:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Máxima amplitude banda saliente:",
|
||||
"FACTORY_RESET": "Restablecimiento de fábrica",
|
||||
"SAVE_DEVICE_SETTINGS": "Guardar la Configuración del dispositivo ",
|
||||
"BROWSER_COMPATIBILITY": "Comprobar Compatibilidad de navegadores.",
|
||||
"REFRESH_MEDIA_DEVICES": "Actualizar dispositivos de medios.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Error: el navegador no soporta WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Comprobación de permisos de los medios de comunicación",
|
||||
"CHECK_PROVISIONING_CONF": "Aprovisionamiento de configuración.",
|
||||
"CHECK_LOGIN": "Verifiicar inicio de sesión.",
|
||||
"CHECK_CONNECTION_SPEED": " Verificar la velocidad de conexión.",
|
||||
"ERROR_PERMISSION_MEDIA": "Error: permiso de medios negado",
|
||||
"ERROR_PROVISIONING_CONF": "Error: Provisión falló.",
|
||||
"PLEASE_WAIT": "Por favor espere..."
|
||||
}
|
143
html5/verto/verto_communicator/src/locales/locale-fr.json
Normal file
143
html5/verto/verto_communicator/src/locales/locale-fr.json
Normal file
@ -0,0 +1,143 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Oups, appel actif déjà en cours",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "Il semble que vous êtes déjà en communication. Voulez vous raccrocher ?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "Il semblre que vous étiez déjà en appel avant de quitter la dernière fois, Voulez-vous retourner à cet appel ?",
|
||||
"TITLE_INCOMING_CALL": "Appel entrant",
|
||||
"MESSAGE_INCOMING_CALL": "De ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "Il n'y as pas d'appels à raccrocher.",
|
||||
"MESSAGE_ENTER_FILENAME": "Veuillez entrer le nom de fichier",
|
||||
"TITLE_ENABLE_VIDEO": "Voulez vous activer la video pour cet appel?",
|
||||
"MESSAGE_ENABLE_VIDEO": "La vidéo sera activée pour les prochains appels.",
|
||||
"TITLE_INSERT_BANNER": "Merci d'insérer le texte de bannière",
|
||||
"TITLE_INSERT_CANVAS_ID": "Merci d'insérer l'ID du Canvas",
|
||||
"TITLE_INSERT_LAYER": "Merci d'insérer la couche",
|
||||
"TITLE_TRANSFER": "Transferer le correspondant ?",
|
||||
"MESSAGE_TRANSFER": "Vers quelle destination voulez vous transférer cet appel ?",
|
||||
"LABEL_TRANSFER": "Destination",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "Nous ne pouvons afficher les paramêtres de prévisualisation pendant un appel",
|
||||
"BUTTON_END_CALL": "Terminer l'appel",
|
||||
"BUTTON_CLOSE": "Fermer",
|
||||
"MESSAGE_PLAY": "Jouer",
|
||||
"MESSAGE_STOP": "Stop",
|
||||
"MESSAGE_RECORD": "Enregistrer",
|
||||
"MESSAGE_STOP_RECORD": "Arrêter l'enregistrement",
|
||||
"MESSAGE_SNAPSHOT": "Capture d'écran",
|
||||
"MESSAGE_VIDEO_MODE": "Mode Video",
|
||||
"MESSAGE_MUTE_MIC": "(des)activer Micro",
|
||||
"MESSAGE_MUTE_VIDEO": "(des)activer Video",
|
||||
"MESSAGE_FULLSCREEN": "Basculer en mode plein écran",
|
||||
"MESSAGE_SCREENSHARE": "Partage d'écran",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Ouvrir/Fermer le chat",
|
||||
"MESSAGE_SPEAKER": "Orateur",
|
||||
"MESSAGE_POPUP": "Popup",
|
||||
"CHAT_TITLE_MEMBERS": "Membres",
|
||||
"CHAT_TITLE": "Chat",
|
||||
"CHAT_NO_MEMBERS": "Il n'y as pas de membres actuellement.",
|
||||
"CHAT_GENERAL": "General",
|
||||
"CHAT_TITLE_KICK": "Ejecter",
|
||||
"CHAT_KICK": "Ejecter",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Video Floor",
|
||||
"CHAT_FLOOR": "Floor",
|
||||
"CHAT_TITLE_TRANSFER": "Transferer",
|
||||
"CHAT_TRANSFER": "Transferer",
|
||||
"CHAT_BANNER": "Bannière",
|
||||
"CHAT_TITLE_SET": "Set",
|
||||
"CHAT_SET": "Set",
|
||||
"CHAT_TITLE_RESET": "Reset",
|
||||
"CHAT_RESET": "Reset",
|
||||
"CHAT_CANVAS": "Canvas",
|
||||
"CHAT_CANVAS_IN": "Canvas In",
|
||||
"CHAT_CANVAS_OUT": "Canvas Out",
|
||||
"CHAT_PREV": "Précédent",
|
||||
"CHAT_NEXT": "Suivant",
|
||||
"CHAT_LAYER": "Couche",
|
||||
"CHAT_AUDIO_VIDEO": "Audio/Video",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Activer/Désactiver micro",
|
||||
"CHAT_MUTE_MIC": "Désactiver le micro",
|
||||
"CHAT_UNMUTE_MIC": "Activer le micro",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_VIDEO": "Activer/Désactiver video",
|
||||
"CHAT_NO_MESSAGES": "il n'y as pas de messages à afficher",
|
||||
"CHAT_SEND_MESSAGE": "Envoyer",
|
||||
"CHAT_TYPE_MESSAGE": "Saisir votre message ici...",
|
||||
"TITLE_CONTRIBUTORS": "Contributeurs",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "Cette connection n'est pas certifiée sûre.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Basculer la navigation",
|
||||
"BANDWIDTH_INFO": "Information de bande passante",
|
||||
"BANDWIDTH_INFO_INCOMING": "Entrant:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "Sortant:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Résolution vidéo:",
|
||||
"IN_CALL": "Appel en cours:",
|
||||
"LAST_CALL": "Dernier appel:",
|
||||
"OPEN_NEW_WINDOW": "Ouvrir une nouvelle fenêtre",
|
||||
"CHANGE_LOGIN_INFO": "Changer les informations utilisateur",
|
||||
"LOGOUT": "Deconnection",
|
||||
"ABOUT": "A propos",
|
||||
"HELP": "Aide",
|
||||
"CONTRIBUTORS": "Contributeurs",
|
||||
"TITLE_PREVIEW_SETTINGS": "Paramêtrer votre micro et caméra",
|
||||
"CAMERA_SETTINGS": "Camera:",
|
||||
"MIC_SETTINGS": "Microphone:",
|
||||
"SAVE": "Sauvegarder",
|
||||
"LOADING": "Chargement",
|
||||
"ERRORS" : "Erreurs",
|
||||
"CALLING_TO": "Appel sortant vers ",
|
||||
"CANCELLING": "Annulation en cours...",
|
||||
"DETERMINING_SPEED": "En train de déterminer votre bande passante...",
|
||||
"CALL_HISTORY": "Historique d'appel",
|
||||
"CLEAR_CALL_HISTORY": "Effacer l'historique",
|
||||
"NO_CALL_HISTORY": "Pas d'historique d'appel",
|
||||
"ENTER_EXTENSION": "Saisir une extension",
|
||||
"CALL_EXTENSION": "Appeler une extension",
|
||||
"LOGIN": "Nom d'utilisateur:",
|
||||
"LOGIN_INFORMATION": "Information utilisateur",
|
||||
"SAVE_LOGIN_INFORMATION": "Sauvegarder les informations utilisateurs",
|
||||
"INVALID_LOGIN_FIELDS": "Vérifiez les champs ci dessous et rééssayez.",
|
||||
"NAME": "Nom",
|
||||
"YOUR_NAME": "Votre nom",
|
||||
"EMAIL": "Email",
|
||||
"YOUR_EMAIL": "Votre email",
|
||||
"USER": "Utilisateur",
|
||||
"PASSWORD": "mot de passe",
|
||||
"CALLER_ID": "Numéro Appelant",
|
||||
"HOSTNAME": "Nom de domaine",
|
||||
"WEBSOCKET_URL": "URL Websocket",
|
||||
"SETTINGS": "Paramêtres",
|
||||
"DEVICE_SETTINGS": "Paramêtres de l'appareil",
|
||||
"SHARE_DEVICE": "Partager le périphérique",
|
||||
"SPEAKER": "Orateur:",
|
||||
"SPEAKER_FEATURE": "Votre navigateur ne semble pas supporter cette fonctionnalité",
|
||||
"PREVIEW_SETTINGS": "Paramêtres de prévisualisation",
|
||||
"REFRESH_DEVICE_LIST": "Rafraichir la liste des périphériques",
|
||||
"GENERAL_SETTINGS": "Paramêtres généraux:",
|
||||
"USE_VIDEO": "Utiliser la vidéo",
|
||||
"USE_STEREO_AUDIO": "Audio stereo",
|
||||
"USE_STUN": "Utiliser STUN",
|
||||
"SCALE_VIDEO": "Ajuster la résolution de la vidéo distante pour correspondre à la résolution de la caméra",
|
||||
"ASK_BEFORE_RECOVER": "Demander avant de récupérer un appel",
|
||||
"BEST_FRAME_RATE": "Meilleur taux de rafraichissement:",
|
||||
"AUDIO_SETTINGS": "Paramêtres audio:",
|
||||
"ECHO_CANCEL": "Anti-echo",
|
||||
"NOISE_SUPPRESSION": "Suppression du bruit",
|
||||
"HIGHPASS_FILTER": "Filtre passe-haut:",
|
||||
"VIDEO_SETTINGS": "Paramêtres vidéo:",
|
||||
"REMOTE_ENCODER": "Encodeur distant dédié activé",
|
||||
"AUTO_SPEED_RES": "Détecter automatiquement les paramêtres de bande passante et de résolution vidéo",
|
||||
"RECHECK_BANDWIDTH": "Revérifier la bande passante avant chaque appel",
|
||||
"CHECK_NETWORK_SPEED": "Verification de la vitesse de connection.",
|
||||
"VIDEO_QUALITY": "Qualité vidéo:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Bande passante entrante maximale:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Bande passante sortante maximale:",
|
||||
"FACTORY_RESET": "Remise aux paramêtres par défaut",
|
||||
"SAVE_DEVICE_SETTINGS": "Sauvegarder les paramêtres de l'appareil.",
|
||||
"BROWSER_COMPATIBILITY": "Vérification de la compatibilité du navigateur.",
|
||||
"REFRESH_MEDIA_DEVICES": "Rafraichir les périphériques multimédias.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Erreur: votre navigateur ne supporte pas WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Vérification des permissions multimédias",
|
||||
"CHECK_PROVISIONING_CONF": "Vérification de la configuration.",
|
||||
"CHECK_LOGIN": "Vérification du nom d'utilisateur",
|
||||
"CHECK_CONNECTION_SPEED": "Vérifiez votre vitesse de connection à Internet.",
|
||||
"ERROR_PERMISSION_MEDIA": "Erreur: La permission d'accéder aux périphériques multimedia as été refusée",
|
||||
"ERROR_PROVISIONING_CONF": "Erreur: La configuration as échouée.",
|
||||
"PLEASE_WAIT": "Merci de patienter...",
|
||||
"CANCEL": "Annuler"
|
||||
}
|
143
html5/verto/verto_communicator/src/locales/locale-id.json
Normal file
143
html5/verto/verto_communicator/src/locales/locale-id.json
Normal file
@ -0,0 +1,143 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Waduh, Panggilan sedang berlangsung .",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "Tampaknya kamu sedang dalam percakapan. Mau diputus?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "Sebelum ini, Tampaknya kamu sedang dalam percakapan. Mau disambungkan lagi?",
|
||||
"TITLE_INCOMING_CALL": "Panggilan masuk",
|
||||
"MESSAGE_INCOMING_CALL": "dari ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "Tidak ada panggilan yang perlu diputus.",
|
||||
"MESSAGE_ENTER_FILENAME": "Silahkan masukan nama file",
|
||||
"TITLE_ENABLE_VIDEO": "Apakah anda ingin mengaktifkan Video di panggilan ini?",
|
||||
"MESSAGE_ENABLE_VIDEO": "Video akan diaktifkan di panggilan berikutnya.",
|
||||
"TITLE_INSERT_BANNER": "Silahkan isi dengan teks banner",
|
||||
"TITLE_INSERT_CANVAS_ID": "Silahkan isi dengan id canvas",
|
||||
"TITLE_INSERT_LAYER": "Silahkan isi dengan layer",
|
||||
"TITLE_TRANSFER": "Panggilan dialihkan?",
|
||||
"MESSAGE_TRANSFER": "Kemana panggilan anda ingin dialihkan?",
|
||||
"LABEL_TRANSFER": "Tujuan",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "Tidak dapat mereview setelan, selama dalam panggilan",
|
||||
"BUTTON_END_CALL": "Mengakhiri Panggilan",
|
||||
"BUTTON_CLOSE": "Tutup",
|
||||
"MESSAGE_PLAY": "Mainkan",
|
||||
"MESSAGE_STOP": "Hentikan",
|
||||
"MESSAGE_RECORD": "Catat",
|
||||
"MESSAGE_STOP_RECORD": "Hentikan Pencatatan",
|
||||
"MESSAGE_SNAPSHOT": "Jepret",
|
||||
"MESSAGE_VIDEO_MODE": "Mode Video",
|
||||
"MESSAGE_MUTE_MIC": "(tidak)Aktifkan Mic",
|
||||
"MESSAGE_MUTE_VIDEO": "(tidak)Aktifkan Video",
|
||||
"MESSAGE_FULLSCREEN": "Pilihan Mode Layar Penuh",
|
||||
"MESSAGE_SCREENSHARE": "Berbagi Layar",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Buka/Tutup Obrolan",
|
||||
"MESSAGE_SPEAKER": "Speaker",
|
||||
"MESSAGE_POPUP": "Muncul",
|
||||
"CHAT_TITLE_MEMBERS": "Anggota",
|
||||
"CHAT_TITLE": "Obrolan",
|
||||
"CHAT_NO_MEMBERS": "Tidak ada anggota untuk ditampilkan.",
|
||||
"CHAT_GENERAL": "Umum",
|
||||
"CHAT_TITLE_KICK": "Tendang",
|
||||
"CHAT_KICK": "Tendang",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Video Latar",
|
||||
"CHAT_FLOOR": "Latar",
|
||||
"CHAT_TITLE_TRANSFER": "Alihkan",
|
||||
"CHAT_TRANSFER": "Alihkan",
|
||||
"CHAT_BANNER": "Banner",
|
||||
"CHAT_TITLE_SET": "Setelan",
|
||||
"CHAT_SET": "Setelan",
|
||||
"CHAT_TITLE_RESET": "Atur Ulang",
|
||||
"CHAT_RESET": "Atur Ulang",
|
||||
"CHAT_CANVAS": "Canvas",
|
||||
"CHAT_CANVAS_IN": "Canvas Masuk",
|
||||
"CHAT_CANVAS_OUT": "Canvas Keluar",
|
||||
"CHAT_PREV": "Sebelumnya",
|
||||
"CHAT_NEXT": "Berikutnya",
|
||||
"CHAT_LAYER": "Layer",
|
||||
"CHAT_AUDIO_VIDEO": "Suara/Video",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Matikan/Aktifkan Mic",
|
||||
"CHAT_MUTE_MIC": "Matikan",
|
||||
"CHAT_UNMUTE_MIC": "Aktifkan",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Matikan/Aktifkan Video",
|
||||
"CHAT_NO_MESSAGES": "Tidak ada pesan yang perlu ditampilkan.",
|
||||
"CHAT_SEND_MESSAGE": "Kirim",
|
||||
"CHAT_TYPE_MESSAGE": "Ketik pesan kamu disini...",
|
||||
"TITLE_CONTRIBUTORS": "Penyumbang",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "Sambungan ini tidak bisa dipercaya.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Pilihan navigasi",
|
||||
"BANDWIDTH_INFO": "Info Bandwith",
|
||||
"BANDWIDTH_INFO_INCOMING": "Panggilan Masuk:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "Panggilan Keluar:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Resolusi Video:",
|
||||
"IN_CALL": "Dalam Panggilan:",
|
||||
"LAST_CALL": "Panggilan Terakhir:",
|
||||
"OPEN_NEW_WINDOW": "Buka Tampilan Baru",
|
||||
"CHANGE_LOGIN_INFO": "Ganti Informasi Login",
|
||||
"LOGOUT": "Keluar",
|
||||
"ABOUT": "Tentang",
|
||||
"HELP": "Bantuan",
|
||||
"CONTRIBUTORS": "Penyumbang",
|
||||
"TITLE_PREVIEW_SETTINGS": "Setel Kamera dan Mikrophone kamu",
|
||||
"CAMERA_SETTINGS": "Kamera:",
|
||||
"MIC_SETTINGS": "Mikrophone:",
|
||||
"SAVE": "Simpan",
|
||||
"LOADING": "Sedang di muat",
|
||||
"ERRORS" : "Kesalahan",
|
||||
"CALLING_TO": "Panggilan ke ",
|
||||
"CANCELLING": "Membatalkan...",
|
||||
"DETERMINING_SPEED": "Mengukur kecepatan kamu...",
|
||||
"CALL_HISTORY": "Riwayat Panggilan",
|
||||
"CLEAR_CALL_HISTORY": "Hapus Riwayat",
|
||||
"NO_CALL_HISTORY": "Tidak ada Riwayat Panggilan.",
|
||||
"ENTER_EXTENSION": "Ketikkan Nomer Ekstensi",
|
||||
"CALL_EXTENSION": "Panggilan Ke Nomer Ekstensi",
|
||||
"LOGIN": "Login",
|
||||
"LOGIN_INFORMATION": "Informasi Login",
|
||||
"SAVE_LOGIN_INFORMATION": "Simpan Informasi Login",
|
||||
"INVALID_LOGIN_FIELDS": "Periksa isian dibawah ini dan periksa lagi.",
|
||||
"NAME": "Nama",
|
||||
"YOUR_NAME": "Nama kamu",
|
||||
"EMAIL": "Email",
|
||||
"YOUR_EMAIL": "Email kamu",
|
||||
"USER": "User",
|
||||
"PASSWORD": "Password",
|
||||
"CALLER_ID": "ID Pemanggil",
|
||||
"HOSTNAME": "Hostname",
|
||||
"WEBSOCKET_URL": "Websocket URL",
|
||||
"SETTINGS": "Setelan",
|
||||
"DEVICE_SETTINGS": "Setelan Perangkat",
|
||||
"SHARE_DEVICE": "Berbagi Perangkat",
|
||||
"SPEAKER": "Speaker:",
|
||||
"SPEAKER_FEATURE": "Tampaknya browser kamu tidak mendukung feature ini",
|
||||
"PREVIEW_SETTINGS": "Mereview Setelan",
|
||||
"REFRESH_DEVICE_LIST": "Data ulang daftar perangkat",
|
||||
"GENERAL_SETTINGS": "Setelan Umum:",
|
||||
"USE_VIDEO": "Menggunakan Video",
|
||||
"USE_STEREO_AUDIO": "Suara Stereo",
|
||||
"USE_STUN": "Menggunakan STUN",
|
||||
"SCALE_VIDEO": "Menyesuaikan skala video sisi jauh dengan resolusi kamera",
|
||||
"ASK_BEFORE_RECOVER": "Bertanya sebelum memulihkan panggilan",
|
||||
"BEST_FRAME_RATE": "Kecepatan frame terbaik:",
|
||||
"AUDIO_SETTINGS": "Setelan Suara:",
|
||||
"ECHO_CANCEL": "Membuang Gema",
|
||||
"NOISE_SUPPRESSION": "Meminimalkan Gangguan",
|
||||
"HIGHPASS_FILTER": "Highpass Filter",
|
||||
"VIDEO_SETTINGS": "Setelan Video:",
|
||||
"REMOTE_ENCODER": "Encoder sisi jauh diaktifkan.",
|
||||
"AUTO_SPEED_RES": "Menentukan setelan kecepatan dan resolusi secara otomatis",
|
||||
"RECHECK_BANDWIDTH": "Memastikan bandwidth sebelum setiap panggilan keluar",
|
||||
"CHECK_NETWORK_SPEED": "Memastikan kecepatan Jaringan",
|
||||
"VIDEO_QUALITY": "Kualitas Video:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Maksimum bandwith masuk:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Maksimum bandwith keluar:",
|
||||
"FACTORY_RESET": "Kembali ke Setelan Pabrik",
|
||||
"SAVE_DEVICE_SETTINGS": "Simpan Setelan Perngkat",
|
||||
"BROWSER_COMPATIBILITY": "Memastikan kecocokan browser.",
|
||||
"REFRESH_MEDIA_DEVICES": "Mendata ulang perangkat media.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Salah: browser tidak mendukung WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Memastikan izin dari perangkat",
|
||||
"CHECK_PROVISIONING_CONF": "Konfigurasi Provisioning.",
|
||||
"CHECK_LOGIN": "Memastikan login.",
|
||||
"CHECK_CONNECTION_SPEED": "Memastikan kecepatan koneksi.",
|
||||
"ERROR_PERMISSION_MEDIA": "Salah: Izin media ditolak",
|
||||
"ERROR_PROVISIONING_CONF": "Salah: Provision gagal.",
|
||||
"PLEASE_WAIT": "Tunggu..."
|
||||
}
|
||||
|
153
html5/verto/verto_communicator/src/locales/locale-it.json
Normal file
153
html5/verto/verto_communicator/src/locales/locale-it.json
Normal file
@ -0,0 +1,153 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Oops, Chiamata in corso.",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "Sembra che tu sia in conversazione. Vuoi chiudere la chiamata?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "Sembra che eri in conversazione prima di abbandonare la sessione l'ultima volta. Vuoi tornare in quella conversazione?",
|
||||
"TITLE_INCOMING_CALL": "Chiamata in arrivo",
|
||||
"MESSAGE_INCOMING_CALL": "da ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "Non ci sono chiamate da chiudere.",
|
||||
"MESSAGE_ENTER_FILENAME": "Per favore, inserisci il nome del file",
|
||||
"TITLE_ENABLE_VIDEO": "Vuoi attivare il video per questa chiamata?",
|
||||
"MESSAGE_ENABLE_VIDEO": "Il video verrà attivato a partire dalla prossima chiamata.",
|
||||
"TITLE_INSERT_BANNER": "Per favore inserisci il testo del banner",
|
||||
"TITLE_INSERT_CANVAS_ID": "Please insert the Canvas Id",
|
||||
"TITLE_INSERT_LAYER": "Please insert the Layer",
|
||||
"TITLE_TRANSFER": "Transfer party?",
|
||||
"MESSAGE_TRANSFER": "To what destination would you like to transfer this call?",
|
||||
"LABEL_TRANSFER": "Destinazione",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "Non è possibile mostrare le configurazioni video durante una chiamata",
|
||||
"BUTTON_END_CALL": "Termina la chiamata",
|
||||
"BUTTON_CLOSE": "Chiudi",
|
||||
"MESSAGE_PLAY": "Riproduci",
|
||||
"MESSAGE_STOP": "Ferma",
|
||||
"MESSAGE_RECORD": "Registra",
|
||||
"MESSAGE_STOP_RECORD": "Ferma la registrazione",
|
||||
"MESSAGE_SNAPSHOT": "Snapshot",
|
||||
"MESSAGE_VIDEO_MODE": "Video Mode",
|
||||
"MESSAGE_MUTE_MIC": "(un)Mute Mic",
|
||||
"MESSAGE_MUTE_VIDEO": "(un)Mute Video",
|
||||
"MESSAGE_FULLSCREEN": "Abilita/Disabilita schermo intero",
|
||||
"MESSAGE_SCREENSHARE": "Condividi lo schermo",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Apri/Chiudi Chat",
|
||||
"MESSAGE_SPEAKER": "Speaker",
|
||||
"MESSAGE_POPUP": "Popup",
|
||||
"CHAT_TITLE_MEMBERS": "Membri",
|
||||
"CHAT_TITLE": "Chat",
|
||||
"CHAT_NO_MEMBERS": "Non ci sono membri da mostrare.",
|
||||
"CHAT_GENERAL": "Generale",
|
||||
"CHAT_TITLE_KICK": "Kick",
|
||||
"CHAT_KICK": "Kick",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Video Floor",
|
||||
"CHAT_FLOOR": "Floor",
|
||||
"CHAT_TITLE_TRASFER": "Transfer",
|
||||
"CHAT_TRANSFER": "Transfer",
|
||||
"CHAT_BANNER": "Banner",
|
||||
"CHAT_TITLE_SET": "Set",
|
||||
"CHAT_SET": "Set",
|
||||
"CHAT_TITLE_RESET": "Reset",
|
||||
"CHAT_RESET": "Reset",
|
||||
"CHAT_RESET": "Reset",
|
||||
"CHAT_CANVAS": "Canvas",
|
||||
"CHAT_CANVAS_IN": "Canvas In",
|
||||
"CHAT_CANVAS_OUT": "Canvas Out",
|
||||
"CHAT_PREV": "Precedente",
|
||||
"CHAT_NEXT": "Successivo",
|
||||
"CHAT_LAYER": "Layer",
|
||||
"CHAT_AUDIO_VIDEO": "Audio/Video",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Mute/Unmute Mic",
|
||||
"CHAT_MUTE_MIC": "Mute",
|
||||
"CHAT_UNMUTE_MIC": "Unmute",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_VIDEO": "Mute/Unmute Video",
|
||||
"CHAT_NO_MESSAGES": "Non ci sono messaggi da mostrare.",
|
||||
"CHAT_SEND_MESSAGE": "Invia",
|
||||
"CHAT_TYPE_MESSAGE": "Scrivi il tuo messaggio qui...",
|
||||
"TITLE_CONTRIBUTORS": "Contributori",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "Questa connessione non è sicura.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Abilita/Disabilita navigazione",
|
||||
"BANDWIDTH_INFO": "Informazioni sulla larghezza di banda",
|
||||
"BANDWIDTH_INFO_INCOMING": "Ingresso:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "Uscita:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Risoluzione Video:",
|
||||
"IN_CALL": "In chiamata: ",
|
||||
"LAST_CALL": "Ultima chiamata: ",
|
||||
"OPEN_NEW_WINDOW": "Apri Una Nuova Finestra",
|
||||
"CHANGE_LOGIN_INFO": "Cambia le informazioni di login",
|
||||
"LOGOUT": "Logout",
|
||||
"ABOUT": "About",
|
||||
"HELP": "Aiuto",
|
||||
"CONTRIBUTORS": "Contributori",
|
||||
"TITLE_PREVIEW_SETTINGS": "Configura le impostazioni della tua video camera e del tuo microfono",
|
||||
"CAMERA_SETTINGS": "Video Camera:",
|
||||
"MIC_SETTINGS": "Microfono:",
|
||||
"SAVE": "Salva",
|
||||
"LOADING": "Caricamento",
|
||||
"ERRORS" : "Errori",
|
||||
"CALLING_TO": "Chiamata verso ",
|
||||
"CANCELLING": "In annullamento",
|
||||
"DETERMINING_SPEED": "Calcolo della tua velocità...",
|
||||
"CALL_HISTORY": "Cronologia Chiamate",
|
||||
"CLEAR_CALL_HISTORY": "Rimuovi la cronologia",
|
||||
"NO_CALL_HISTORY": "Nessuna chiamata nella cronologia.",
|
||||
"ENTER_EXTENSION": "Inserisci un numero",
|
||||
"CALL_EXTENSION": "Chiama il numero",
|
||||
"LOGIN": "Login",
|
||||
"LOGIN_INFORMATION": "Informazioni di login",
|
||||
"SAVE_LOGIN_INFORMATION": "Salva le informazioni di login",
|
||||
"INVALID_LOGIN_FIELDS": "Verifica i campi e prova di nuovo.",
|
||||
"NAME": "Nome",
|
||||
"YOUR_NAME": "Il tuo nome",
|
||||
"EMAIL": "Email",
|
||||
"YOUR_EMAIL": "Il tuo indirizzo email",
|
||||
"USER": "Utente",
|
||||
"PASSWORD": "Password",
|
||||
"CALLER_ID": "Caller ID",
|
||||
"HOSTNAME": "Hostname",
|
||||
"WEBSOCKET_URL": "Websocket URL",
|
||||
"SETTINGS": "Impostazioni",
|
||||
"DEVICE_SETTINGS": "Configurazione dei dispositivi",
|
||||
"SHARE_DEVICE": "Dispositivo in condivisione",
|
||||
"SPEAKER": "Altoparlante:",
|
||||
"SPEAKER_FEATURE": "Il tuo browser sembra non supportare questa funzionalità",
|
||||
"PREVIEW_SETTINGS": "Anteprima delle configurazioni",
|
||||
"REFRESH_DEVICE_LIST": "Aggiorna la lista dei dispositivi",
|
||||
"GENERAL_SETTINGS": "Configurazioni generali:",
|
||||
"USE_VIDEO": "Abilita Video",
|
||||
"USE_STEREO_AUDIO": "Abilita Audio Stereo",
|
||||
"USE_STUN": "Abilita STUN",
|
||||
"SCALE_VIDEO": "Scala il video remoto con la risoluzione della video camera",
|
||||
"ASK_BEFORE_RECOVER": "Chiedi prima di recuperare una chiamata",
|
||||
"BEST_FRAME_RATE": "Miglior frame rate:",
|
||||
"AUDIO_SETTINGS": "Impostazioni audio:",
|
||||
"ECHO_CANCEL": "Cancellatore d'eco",
|
||||
"NOISE_SUPPRESSION": "Soppressione del rumore",
|
||||
"HIGHPASS_FILTER": "Highpass Filter",
|
||||
"VIDEO_SETTINGS": "Impostazioni video:",
|
||||
"REMOTE_ENCODER": "Abilita codificatore remoto dedicato.",
|
||||
"AUTO_SPEED_RES": "Rileva in modo automatico la velocità e le impostazioni",
|
||||
"RECHECK_BANDWIDTH": "Controlla la larghezza di banda per ogni chiamata in uscita",
|
||||
"CHECK_NETWORK_SPEED": "Controllo della velocità di rete",
|
||||
"VIDEO_QUALITY": "Qualità video:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Massima larghezza di banda in ingresso:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Massima larghezza di banda in uscita:",
|
||||
"FACTORY_RESET": "Reset ai valori di default",
|
||||
"SAVE_DEVICE_SETTINGS": "Salva le impostazioni dei dispositivi",
|
||||
"BROWSER_COMPATIBILITY": "Verifica compatibilità browser.",
|
||||
"REFRESH_MEDIA_DEVICES": "Aggiornamento dei dispositivi.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Errore: il browser non supporta WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Verifica permessi dispositivi",
|
||||
"CHECK_PROVISIONING_CONF": "Recupero della configurazione.",
|
||||
"CHECK_LOGIN": "Verifica del login.",
|
||||
"CHECK_CONNECTION_SPEED": "Verifica velocità connessione.",
|
||||
"ERROR_PERMISSION_MEDIA": "Errore: permesso sui dispositivi negato",
|
||||
"ERROR_PROVISIONING_CONF": "Errore: Recupero configurazione fallito.",
|
||||
"PLEASE_WAIT": "Attendere prego...",
|
||||
"CANCEL": "Cancella",
|
||||
"CHAT_TITLE_VOL_MINUS": "Volume -",
|
||||
"CHAT_TITLE_VOL_PLUS": "Volume +",
|
||||
"CHAT_TITLE_GAIN_MINUS": "Guadagno -",
|
||||
"CHAT_TITLE_GAIN_PLUS": "Guadagno +",
|
||||
"CHAT_VOL_MINUS": "Vol -",
|
||||
"CHAT_VOL_PLUS": "Vol +",
|
||||
"CHAT_GAIN_MINUS": "Guadagno -",
|
||||
"CHAT_GAIN_PLUS": "Guadagno +"
|
||||
|
||||
}
|
BIN
html5/verto/verto_communicator/src/locales/locale-pl.json
Normal file
BIN
html5/verto/verto_communicator/src/locales/locale-pl.json
Normal file
Binary file not shown.
151
html5/verto/verto_communicator/src/locales/locale-pt.json
Normal file
151
html5/verto/verto_communicator/src/locales/locale-pt.json
Normal file
@ -0,0 +1,151 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Ops, já existe uma chamada ativa.",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "Parece que você está em uma chamada. Você quer desligar?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "Parece que você estava em uma chamada antes de sair pela última vez. Quer voltar pra ela?",
|
||||
"TITLE_INCOMING_CALL": "Nova Chamada",
|
||||
"MESSAGE_INCOMING_CALL": "de ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "Não há chamada para desligar.",
|
||||
"MESSAGE_ENTER_FILENAME": "Por favor, insira o nome do arquivo",
|
||||
"TITLE_ENABLE_VIDEO": "Deseja ativar o vídeo para esta chamada?",
|
||||
"MESSAGE_ENABLE_VIDEO": "O vídeo será ativado para as próximas chamadas.",
|
||||
"TITLE_INSERT_BANNER": "Por favor, insira o texto do banner",
|
||||
"TITLE_INSERT_CANVAS_ID": "Por favor, insira o ID do Canvas",
|
||||
"TITLE_INSERT_LAYER": "Por favor, insira o Layer",
|
||||
"TITLE_TRANSFER": "Transferir?",
|
||||
"MESSAGE_TRANSFER": "Para qual destino você deseja transferir esta chamada?",
|
||||
"LABEL_TRANSFER": "Destino",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "Não é possível mostrar a pré-visualização das configurações durante uma chamda",
|
||||
"BUTTON_END_CALL": "Finalizar Chamada",
|
||||
"BUTTON_CLOSE": "Fechar",
|
||||
"MESSAGE_PLAY": "Reproduzir",
|
||||
"MESSAGE_STOP": "Parar",
|
||||
"MESSAGE_RECORD": "Gravar",
|
||||
"MESSAGE_STOP_RECORD": "Parar Gravação",
|
||||
"MESSAGE_SNAPSHOT": "Snapshot",
|
||||
"MESSAGE_VIDEO_MODE": "Modo de Vídeo",
|
||||
"MESSAGE_MUTE_MIC": "Ativar/Desativar Mudo do Microfone",
|
||||
"MESSAGE_MUTE_VIDEO": "Ativar/Desativar Mudo do Vídeo",
|
||||
"MESSAGE_FULLSCREEN": "Ativar/Desativar Modo Tela Cheia",
|
||||
"MESSAGE_SCREENSHARE": "Compartilhar Tela",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Abrir/Fechar Chat",
|
||||
"MESSAGE_SPEAKER": "Alto-falante",
|
||||
"MESSAGE_POPUP": "Popup",
|
||||
"CHAT_TITLE_MEMBERS": "Membros",
|
||||
"CHAT_TITLE": "Chat",
|
||||
"CHAT_NO_MEMBERS": "Não há membros para mostrar.",
|
||||
"CHAT_GENERAL": "Geral",
|
||||
"CHAT_TITLE_KICK": "Chutar",
|
||||
"CHAT_KICK": "Chutar",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Floor do Vídeo",
|
||||
"CHAT_FLOOR": "Floor",
|
||||
"CHAT_TITLE_TRANSFER": "Transferência",
|
||||
"CHAT_TRANSFER": "Transferir",
|
||||
"CHAT_BANNER": "Banner",
|
||||
"CHAT_TITLE_SET": "Definir",
|
||||
"CHAT_SET": "Definir",
|
||||
"CHAT_TITLE_RESET": "Redefinir",
|
||||
"CHAT_RESET": "Redefinir",
|
||||
"CHAT_CANVAS": "Canvas",
|
||||
"CHAT_CANVAS_IN": "Colocar no Canvas",
|
||||
"CHAT_CANVAS_OUT": "Remover do Canvas",
|
||||
"CHAT_PREV": "Anterior",
|
||||
"CHAT_NEXT": "Seguinte",
|
||||
"CHAT_LAYER": "Layer",
|
||||
"CHAT_AUDIO_VIDEO": "Áudio/Vídeo",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Ativar/Desativar Microfone",
|
||||
"CHAT_MUTE_MIC": "Ativar Mudo",
|
||||
"CHAT_UNMUTE_MIC": "Desativar Mudo",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_VIDEO": "Ativar/Desativar Vídeo",
|
||||
"CHAT_NO_MESSAGES": "Não há mensagens para mostrar.",
|
||||
"CHAT_SEND_MESSAGE": "Enviar",
|
||||
"CHAT_TYPE_MESSAGE": "Escreva sua mensagem aqui...",
|
||||
"TITLE_CONTRIBUTORS": "Contribuidores",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "Esta conexão não é confiável.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Ativar/Desativar Navegação",
|
||||
"BANDWIDTH_INFO": "Informações sobre largura de banda",
|
||||
"BANDWIDTH_INFO_INCOMING": "Entrada:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "Saída:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Resolução de vídeo:",
|
||||
"IN_CALL": "Em chamada:",
|
||||
"LAST_CALL": "Última chamada:",
|
||||
"OPEN_NEW_WINDOW": "Abrir nova janela",
|
||||
"CHANGE_LOGIN_INFO": "Mudar informações de login",
|
||||
"LOGOUT": "Sair",
|
||||
"ABOUT": "Sobre",
|
||||
"HELP": "Ajuda",
|
||||
"CONTRIBUTORS": "Contribuidores",
|
||||
"TITLE_PREVIEW_SETTINGS": "Defina suas configurações de câmera e microfone",
|
||||
"CAMERA_SETTINGS": "Câmera:",
|
||||
"MIC_SETTINGS": "Microfone:",
|
||||
"SAVE": "Salvar",
|
||||
"LOADING": "Carregando",
|
||||
"ERRORS" : "Erros",
|
||||
"CALLING_TO": "Ligando para ",
|
||||
"CANCELLING": "Cancelando...",
|
||||
"DETERMINING_SPEED": "Determinando sua velocidade...",
|
||||
"CALL_HISTORY": "Histórico de Chamadas",
|
||||
"CLEAR_CALL_HISTORY": "Limpar Histórico",
|
||||
"NO_CALL_HISTORY": "Não há chamadas no histórico.",
|
||||
"ENTER_EXTENSION": "Insira um número",
|
||||
"CALL_EXTENSION": "Ligar para número",
|
||||
"LOGIN": "Login",
|
||||
"LOGIN_INFORMATION": "Informações de login",
|
||||
"SAVE_LOGIN_INFORMATION": "Salvar informações de login",
|
||||
"INVALID_LOGIN_FIELDS": "Verifique os campos abaixo e tente novamente.",
|
||||
"NAME": "Nome",
|
||||
"YOUR_NAME": "Seu nome",
|
||||
"EMAIL": "E-mail",
|
||||
"YOUR_EMAIL": "Seu e-mail",
|
||||
"USER": "Usuário",
|
||||
"PASSWORD": "Senha",
|
||||
"CALLER_ID": "Identificação de chamada",
|
||||
"HOSTNAME": "Servidor",
|
||||
"WEBSOCKET_URL": "Endereço do websocket",
|
||||
"SETTINGS": "Configurações",
|
||||
"DEVICE_SETTINGS": "Configurações de dispositivos",
|
||||
"SHARE_DEVICE": "Dispositivo de compartilhamento",
|
||||
"SPEAKER": "Alto-falante:",
|
||||
"SPEAKER_FEATURE": "Seu navegador parece não oferecer suporte a esta funcionalidade",
|
||||
"PREVIEW_SETTINGS": "Pré-visualizar configurações",
|
||||
"REFRESH_DEVICE_LIST": "Atualizar lista de dispositivos",
|
||||
"GENERAL_SETTINGS": "Configurações gerais:",
|
||||
"USE_VIDEO": "Habilitar Vídeo",
|
||||
"USE_STEREO_AUDIO": "Áudio Estéreo",
|
||||
"USE_STUN": "Habilitar STUN",
|
||||
"SCALE_VIDEO": "Redimensionar o vídeo remoto para bater com a resolução da câmera",
|
||||
"ASK_BEFORE_RECOVER": "Perguntar antes de recuperar uma chamada",
|
||||
"BEST_FRAME_RATE": "Melhor frame rate:",
|
||||
"AUDIO_SETTINGS": "Configurações de áudio:",
|
||||
"ECHO_CANCEL": "Cancelamento de eco",
|
||||
"NOISE_SUPPRESSION": "Supressão de ruído",
|
||||
"HIGHPASS_FILTER": "Filtro passa-alta",
|
||||
"VIDEO_SETTINGS": "Configurações de vídeo:",
|
||||
"REMOTE_ENCODER": "Encoder Remoto Dedicado habilitado.",
|
||||
"AUTO_SPEED_RES": "Determinar automaticamente velocidade e configurações de resolução",
|
||||
"RECHECK_BANDWIDTH": "Verificar novamente largura de banda antes de realizar cada chamada",
|
||||
"CHECK_NETWORK_SPEED": "Verificar velocidade da rede",
|
||||
"VIDEO_QUALITY": "Qualidade do vídeo:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Largura de banda de entrada máxima:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Largura de banda de saída máxima:",
|
||||
"FACTORY_RESET": "Restaurar padrões de fábrica",
|
||||
"SAVE_DEVICE_SETTINGS": "Salvar configurações de dispositivos",
|
||||
"BROWSER_COMPATIBILITY": "Verificando compatibilidade do browser.",
|
||||
"REFRESH_MEDIA_DEVICES": "Atualizando dispositivos de mídia.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Erro: navegador não oferece suporte ao WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Verificando permissões de mídia",
|
||||
"CHECK_PROVISIONING_CONF": "Provisionando configurações.",
|
||||
"CHECK_LOGIN": "Verificando login.",
|
||||
"CHECK_CONNECTION_SPEED": "Verificando velocidade de conexão.",
|
||||
"ERROR_PERMISSION_MEDIA": "Erro: permissão de mídia negada.",
|
||||
"ERROR_PROVISIONING_CONF": "Erro: provisionamento falhou.",
|
||||
"PLEASE_WAIT": "Por favor, aguarde...",
|
||||
"CANCEL": "Cancelar",
|
||||
"CHAT_TITLE_VOL_MINUS": "Volume -",
|
||||
"CHAT_TITLE_VOL_PLUS": "Volume +",
|
||||
"CHAT_TITLE_GAIN_MINUS": "Ganho -",
|
||||
"CHAT_TITLE_GAIN_PLUS": "Ganho +",
|
||||
"CHAT_VOL_MINUS": "Vol -",
|
||||
"CHAT_VOL_PLUS": "Vol +",
|
||||
"CHAT_GAIN_MINUS": "Ganho -",
|
||||
"CHAT_GAIN_PLUS": "Ganho +"
|
||||
}
|
151
html5/verto/verto_communicator/src/locales/locale-ru.json
Normal file
151
html5/verto/verto_communicator/src/locales/locale-ru.json
Normal file
@ -0,0 +1,151 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Упс, Уже имеется активный вызов.",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "Такое впечатление, что вы уже разговариваете. Хоитите ли Вы положить трубку?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "Такое впечатление что Вы разговаривали когда отключились в прошлый раз. Хотите ли Вы вернутся к предыдущему собеседнику?",
|
||||
"TITLE_INCOMING_CALL": "Входящий вызов",
|
||||
"MESSAGE_INCOMING_CALL": "от ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "Отсутствуют вызовы которые можно завершить.",
|
||||
"MESSAGE_ENTER_FILENAME": "Пожалуйста, укажите имя файла",
|
||||
"TITLE_ENABLE_VIDEO": "Хотите ли Вы начать передачу видео для этого звонка?",
|
||||
"MESSAGE_ENABLE_VIDEO": "Для следующего звонка включена передача видео.",
|
||||
"TITLE_INSERT_BANNER": "Пожалуйста укажите текст заголовка",
|
||||
"TITLE_INSERT_CANVAS_ID": "Пожалуйста укажите идентификатор канвы",
|
||||
"TITLE_INSERT_LAYER": "Пожалуйста укажите слой",
|
||||
"TITLE_TRANSFER": "Перевести вызов?",
|
||||
"MESSAGE_TRANSFER": "На какой номер Вы хотите перевести этот вызов?",
|
||||
"LABEL_TRANSFER": "Вызываемый номер",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "Не могу отобразить параметры предпросмотра во время вызова",
|
||||
"BUTTON_END_CALL": "Завершить вызов",
|
||||
"BUTTON_CLOSE": "Закрыть",
|
||||
"MESSAGE_PLAY": "Проиграть",
|
||||
"MESSAGE_STOP": "Остановить",
|
||||
"MESSAGE_RECORD": "Записать",
|
||||
"MESSAGE_STOP_RECORD": "Остановить запись",
|
||||
"MESSAGE_SNAPSHOT": "Снимок экрана",
|
||||
"MESSAGE_VIDEO_MODE": "Видеорежим",
|
||||
"MESSAGE_MUTE_MIC": "вкл./выкл. Микрофон",
|
||||
"MESSAGE_MUTE_VIDEO": "вкл./выкл. Камеру",
|
||||
"MESSAGE_FULLSCREEN": "Переключить полноэкранный режим",
|
||||
"MESSAGE_SCREENSHARE": "Дать доступ к рабочему столу",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Открыть/Закрыть чат",
|
||||
"MESSAGE_SPEAKER": "Динамик",
|
||||
"MESSAGE_POPUP": "Всплывающее сообщение",
|
||||
"CHAT_TITLE_MEMBERS": "Участники",
|
||||
"CHAT_TITLE": "Чат",
|
||||
"CHAT_NO_MEMBERS": "Нет участников.",
|
||||
"CHAT_GENERAL": "Общая",
|
||||
"CHAT_TITLE_KICK": "Выкинуть",
|
||||
"CHAT_KICK": "Выкинуть",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Видео мин.уровень",
|
||||
"CHAT_FLOOR": "Мин.уровень",
|
||||
"CHAT_TITLE_TRANSFER": "Перевести",
|
||||
"CHAT_TRANSFER": "Перевести",
|
||||
"CHAT_BANNER": "Заголовок",
|
||||
"CHAT_TITLE_SET": "Установить",
|
||||
"CHAT_SET": "Установить",
|
||||
"CHAT_TITLE_RESET": "Сбросить",
|
||||
"CHAT_RESET": "Сбросить",
|
||||
"CHAT_CANVAS": "Канва",
|
||||
"CHAT_CANVAS_IN": "Канва при входе",
|
||||
"CHAT_CANVAS_OUT": "Канва при выходе",
|
||||
"CHAT_PREV": "Предыдущий",
|
||||
"CHAT_NEXT": "Следующий",
|
||||
"CHAT_LAYER": "Слой",
|
||||
"CHAT_AUDIO_VIDEO": "Аудио/Видео",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Вкл./Выкл. мик.",
|
||||
"CHAT_MUTE_MIC": "Выкл.",
|
||||
"CHAT_UNMUTE_MIC": "Вкл.",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Вкл./Выкл. видео",
|
||||
"CHAT_NO_MESSAGES": "Нет сообщений для отображения.",
|
||||
"CHAT_SEND_MESSAGE": "Отправить",
|
||||
"CHAT_TYPE_MESSAGE": "Наберите ваше сообщение тут...",
|
||||
"TITLE_CONTRIBUTORS": "Помощники",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "Данное соединение не доверенное.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Переключить навигацию",
|
||||
"BANDWIDTH_INFO": "Информация о полосе пропускания",
|
||||
"BANDWIDTH_INFO_INCOMING": "На прием:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "При передаче:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Видео разрешение:",
|
||||
"IN_CALL": "Разговор с:",
|
||||
"LAST_CALL": "Предыдущий вызов:",
|
||||
"OPEN_NEW_WINDOW": "Открыть новое окно",
|
||||
"CHANGE_LOGIN_INFO": "Изменить информацию о логине",
|
||||
"LOGOUT": "Выйти",
|
||||
"ABOUT": "О программе",
|
||||
"HELP": "Помощь",
|
||||
"CONTRIBUTORS": "Помощники",
|
||||
"TITLE_PREVIEW_SETTINGS": "Настройте камеру и параметры микрофона",
|
||||
"CAMERA_SETTINGS": "Камера:",
|
||||
"MIC_SETTINGS": "Микрофон:",
|
||||
"SAVE": "Сохранить",
|
||||
"LOADING": "Загружаю",
|
||||
"ERRORS" : "Ошибки",
|
||||
"CALLING_TO": "Вызываю ",
|
||||
"CANCELLING": "Завершаю...",
|
||||
"DETERMINING_SPEED": "Определяю скорость подключения ...",
|
||||
"CALL_HISTORY": "История вызовов",
|
||||
"CLEAR_CALL_HISTORY": "Очистить историю",
|
||||
"NO_CALL_HISTORY": "История вызов пуста.",
|
||||
"ENTER_EXTENSION": "Укажите вызываемый номер",
|
||||
"CALL_EXTENSION": "Набрать внутрений номер",
|
||||
"LOGIN": "Логин",
|
||||
"LOGIN_INFORMATION": "Информация о логине",
|
||||
"SAVE_LOGIN_INFORMATION": "Сохранить информацию о логине",
|
||||
"INVALID_LOGIN_FIELDS": "Проверьте поля указанные ниже и повторите снова.",
|
||||
"NAME": "Имя",
|
||||
"YOUR_NAME": "Ваше имя",
|
||||
"EMAIL": "Почта",
|
||||
"YOUR_EMAIL": "Ваша почта",
|
||||
"USER": "Пользователь",
|
||||
"PASSWORD": "Пароль",
|
||||
"CALLER_ID": "АОН",
|
||||
"HOSTNAME": "Имя хоста",
|
||||
"WEBSOCKET_URL": "URL вебсокета",
|
||||
"SETTINGS": "Параметры",
|
||||
"DEVICE_SETTINGS": "Параметры устройства",
|
||||
"SHARE_DEVICE": "Дать доступ к устройству",
|
||||
"SPEAKER": "Динамик:",
|
||||
"SPEAKER_FEATURE": "Вероятно Ваш браузер не поддерживают это функцию",
|
||||
"PREVIEW_SETTINGS": "Параметры предпросмотра",
|
||||
"REFRESH_DEVICE_LIST": "Обновить список устройств",
|
||||
"GENERAL_SETTINGS": "Основные параметры:",
|
||||
"USE_VIDEO": "Использовать видео",
|
||||
"USE_STEREO_AUDIO": "Стереозвук",
|
||||
"USE_STUN": "Использовать STUN",
|
||||
"SCALE_VIDEO": "Маштабировать удаленное видео так чтобы соответствовать разрешению камеры",
|
||||
"ASK_BEFORE_RECOVER": "Спросить перед востановлением вызова",
|
||||
"BEST_FRAME_RATE": "Оптимальная частота кадров:",
|
||||
"AUDIO_SETTINGS": "Параметры звука:",
|
||||
"ECHO_CANCEL": "Эхо компенсация",
|
||||
"NOISE_SUPPRESSION": "Шумоподавление",
|
||||
"HIGHPASS_FILTER": "Высокочастотный фильтр",
|
||||
"VIDEO_SETTINGS": "Параметры видео:",
|
||||
"REMOTE_ENCODER": "Включен специализированный удаленный энкодер.",
|
||||
"AUTO_SPEED_RES": "Автоматически определять скорость подключения и параметры разрешения",
|
||||
"RECHECK_BANDWIDTH": "Определять полосу пропускания перед каждым исходящим вызовом",
|
||||
"CHECK_NETWORK_SPEED": "Проверить скорость сети",
|
||||
"VIDEO_QUALITY": "Качество видео:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Макс. полоса пропускания на вход:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Макс. полоса пропускания на выход:",
|
||||
"FACTORY_RESET": "Сброс к заводским настройкам",
|
||||
"SAVE_DEVICE_SETTINGS": "Сохранить параметры устройства",
|
||||
"BROWSER_COMPATIBILITY": "Проверяю возможности браузера.",
|
||||
"REFRESH_MEDIA_DEVICES": "Обновить список медиа-устройств.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Ошибка: браузер не поддерживает WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Проверю разрешения доступа к медиа",
|
||||
"CHECK_PROVISIONING_CONF": "Подготовка конфигурации.",
|
||||
"CHECK_LOGIN": "Проверка логина.",
|
||||
"CHECK_CONNECTION_SPEED": "Проверка скорости подключения.",
|
||||
"ERROR_PERMISSION_MEDIA": "Ошибка: Отказано в доступе к медиа-устройствам",
|
||||
"ERROR_PROVISIONING_CONF": "Ошибка: Подготовить неудалось.",
|
||||
"PLEASE_WAIT": "Пожалуйста подождите...",
|
||||
"CANCEL": "Завершить",
|
||||
"CHAT_TITLE_VOL_MINUS": "Громкость -",
|
||||
"CHAT_TITLE_VOL_PLUS": "Громкость +",
|
||||
"CHAT_TITLE_GAIN_MINUS": "Усиление -",
|
||||
"CHAT_TITLE_GAIN_PLUS": "Усиление +",
|
||||
"CHAT_VOL_MINUS": "Гром. -",
|
||||
"CHAT_VOL_PLUS": "Гром. +",
|
||||
"CHAT_GAIN_MINUS": "Усил. -",
|
||||
"CHAT_GAIN_PLUS": "Усил. +"
|
||||
}
|
151
html5/verto/verto_communicator/src/locales/locale-sv.json
Normal file
151
html5/verto/verto_communicator/src/locales/locale-sv.json
Normal file
@ -0,0 +1,151 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "Hoppsan, Aktivt samtal pågår.",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "Det verkar som du är i ett samtal. Vill du lägga på?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "Det verkar som du var i ett samtal innan du lämnade senast, vill du gå tillbaka till det?",
|
||||
"TITLE_INCOMING_CALL": "Inkommande Samtal",
|
||||
"MESSAGE_INCOMING_CALL": "från ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "Det finns inget samtal att avsluta.",
|
||||
"MESSAGE_ENTER_FILENAME": "Ange filnamn",
|
||||
"TITLE_ENABLE_VIDEO": "Vill du aktivera video i pågående samtal?",
|
||||
"MESSAGE_ENABLE_VIDEO": "Video kommer aktiveras i efterföljande samtal.",
|
||||
"TITLE_INSERT_BANNER": "Lägg till banner text",
|
||||
"TITLE_INSERT_CANVAS_ID": "Lägg till Canvas Id",
|
||||
"TITLE_INSERT_LAYER": "Lägg till Lager",
|
||||
"TITLE_TRANSFER": "Koppla samtal?",
|
||||
"MESSAGE_TRANSFER": "Vilken destination vill du koppla samtalet till?",
|
||||
"LABEL_TRANSFER": "Destination",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "Kan inte förhandsvisa inställningar under samtal",
|
||||
"BUTTON_END_CALL": "Avsluta samtal",
|
||||
"BUTTON_CLOSE": "Stäng",
|
||||
"MESSAGE_PLAY": "Spela upp",
|
||||
"MESSAGE_STOP": "Stoppa",
|
||||
"MESSAGE_RECORD": "Spela in",
|
||||
"MESSAGE_STOP_RECORD": "Avsluta inspelning",
|
||||
"MESSAGE_SNAPSHOT": "Snapshot",
|
||||
"MESSAGE_VIDEO_MODE": "Videoläge",
|
||||
"MESSAGE_MUTE_MIC": "(av)Aktivera Mikrofon",
|
||||
"MESSAGE_MUTE_VIDEO": "(av)Aktivera Video",
|
||||
"MESSAGE_FULLSCREEN": "Växla fullskärmsläge",
|
||||
"MESSAGE_SCREENSHARE": "Skärmdelning",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "Öppna/stäng chatt",
|
||||
"MESSAGE_SPEAKER": "Högtalare",
|
||||
"MESSAGE_POPUP": "Popup",
|
||||
"CHAT_TITLE_MEMBERS": "Medlemmar",
|
||||
"CHAT_TITLE": "Chatt",
|
||||
"CHAT_NO_MEMBERS": "Det finns inga medlemmar att visa.",
|
||||
"CHAT_GENERAL": "Allmänt",
|
||||
"CHAT_TITLE_KICK": "Sparka ut",
|
||||
"CHAT_KICK": "Sparka ut",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "Video Floor",
|
||||
"CHAT_FLOOR": "Floor",
|
||||
"CHAT_TITLE_TRANSFER": "Koppla",
|
||||
"CHAT_TRANSFER": "Koppla",
|
||||
"CHAT_BANNER": "Banner",
|
||||
"CHAT_TITLE_SET": "Sätt",
|
||||
"CHAT_SET": "Sätt",
|
||||
"CHAT_TITLE_RESET": "Reset",
|
||||
"CHAT_RESET": "Reset",
|
||||
"CHAT_CANVAS": "Canvas",
|
||||
"CHAT_CANVAS_IN": "Canvas In",
|
||||
"CHAT_CANVAS_OUT": "Canvas Ut",
|
||||
"CHAT_PREV": "Föregående",
|
||||
"CHAT_NEXT": "Nästa",
|
||||
"CHAT_LAYER": "Lager",
|
||||
"CHAT_AUDIO_VIDEO": "Ljud/Video",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "Aktivera/Inaktivera Mikrofon",
|
||||
"CHAT_MUTE_MIC": "Inaktivera",
|
||||
"CHAT_UNMUTE_MIC": "Aktivera",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_VIDEO": "Aktivera/Inaktivera Video",
|
||||
"CHAT_NO_MESSAGES": "Det finns inga meddelanden att visa.",
|
||||
"CHAT_SEND_MESSAGE": "Skicka",
|
||||
"CHAT_TYPE_MESSAGE": "Skriv ditt meddelande här...",
|
||||
"TITLE_CONTRIBUTORS": "Contributors",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "Denna anslutning är opålitlig.",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "Toggla navigation",
|
||||
"BANDWIDTH_INFO": "Bandbreddsinformation",
|
||||
"BANDWIDTH_INFO_INCOMING": "Inkommande:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "Utgående:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "Videoupplösning:",
|
||||
"IN_CALL": "I Samtal:",
|
||||
"LAST_CALL": "Senaste Samtal:",
|
||||
"OPEN_NEW_WINDOW": "Öppna nytt fönster",
|
||||
"CHANGE_LOGIN_INFO": "Ändra inloggningsinformation",
|
||||
"LOGOUT": "Logga ut",
|
||||
"ABOUT": "Om",
|
||||
"HELP": "Hjälp",
|
||||
"CONTRIBUTORS": "Contributors",
|
||||
"TITLE_PREVIEW_SETTINGS": "Inställningar för kamera och mikrofon",
|
||||
"CAMERA_SETTINGS": "Kamera:",
|
||||
"MIC_SETTINGS": "Mikrofon:",
|
||||
"SAVE": "Spara",
|
||||
"LOADING": "Laddar",
|
||||
"ERRORS" : "Fel",
|
||||
"CALLING_TO": "Ringer till ",
|
||||
"CANCELLING": "Avbryter...",
|
||||
"DETERMINING_SPEED": "Avgör din hastighet...",
|
||||
"CALL_HISTORY": "Samtalshistorik",
|
||||
"CLEAR_CALL_HISTORY": "Rensa Historik",
|
||||
"NO_CALL_HISTORY": "Ingen samtalshistorik.",
|
||||
"ENTER_EXTENSION": "Ange anknytning",
|
||||
"CALL_EXTENSION": "Ring Anknytning",
|
||||
"LOGIN": "Inloggning",
|
||||
"LOGIN_INFORMATION": "Inloggningsinformation",
|
||||
"SAVE_LOGIN_INFORMATION": "Spara inloggningsinformation",
|
||||
"INVALID_LOGIN_FIELDS": "Verifiera nedanstående fält och försök igen.",
|
||||
"NAME": "Namn",
|
||||
"YOUR_NAME": "Ditt namn",
|
||||
"EMAIL": "Epost",
|
||||
"YOUR_EMAIL": "Din epost",
|
||||
"USER": "Användare",
|
||||
"PASSWORD": "Lösenord",
|
||||
"CALLER_ID": "Utringande ID",
|
||||
"HOSTNAME": "Servernamn",
|
||||
"WEBSOCKET_URL": "Websocket URL",
|
||||
"SETTINGS": "Inställningar",
|
||||
"DEVICE_SETTINGS": "Enhetsinställningar",
|
||||
"SHARE_DEVICE": "Dela enhet",
|
||||
"SPEAKER": "Högtalare:",
|
||||
"SPEAKER_FEATURE": "Din browser verkar inte stödja denna funktion",
|
||||
"PREVIEW_SETTINGS": "Förhandsgranska inställningar",
|
||||
"REFRESH_DEVICE_LIST": "Uppdatera enhetslista",
|
||||
"GENERAL_SETTINGS": "Generella inställningar:",
|
||||
"USE_VIDEO": "Använd Video",
|
||||
"USE_STEREO_AUDIO": "Stereoljud",
|
||||
"USE_STUN": "Använd STUN",
|
||||
"SCALE_VIDEO": "Skala fjärrvideo för att matcha kameraupplösning",
|
||||
"ASK_BEFORE_RECOVER": "Fråga före återhämtning av samtal",
|
||||
"BEST_FRAME_RATE": "Bästa framerate:",
|
||||
"AUDIO_SETTINGS": "Ljudinställningar:",
|
||||
"ECHO_CANCEL": "Echo Cancellation",
|
||||
"NOISE_SUPPRESSION": "Brusreducering",
|
||||
"HIGHPASS_FILTER": "Högpassfilter",
|
||||
"VIDEO_SETTINGS": "Videoinställningar:",
|
||||
"REMOTE_ENCODER": "Dedikerad Remote Encoder aktiverad.",
|
||||
"AUTO_SPEED_RES": "Automatiska inställningar för hastighet och upplösning",
|
||||
"RECHECK_BANDWIDTH": "Kontrollera bandbredd före varje utgående samtal",
|
||||
"CHECK_NETWORK_SPEED": "Kontrollera nätverkshastighet",
|
||||
"VIDEO_QUALITY": "Videokvalitet:",
|
||||
"MAX_INCOMING_BANDWIDTH": "Max inkommande bandbredd:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "Max utgående bandbredd:",
|
||||
"FACTORY_RESET": "Fabriksåterställning",
|
||||
"SAVE_DEVICE_SETTINGS": "Spara inställningar",
|
||||
"BROWSER_COMPATIBILITY": "Kontrollerar browserkompatibilitet.",
|
||||
"REFRESH_MEDIA_DEVICES": "Uppdatera mediaenheter.",
|
||||
"BROWSER_WITHOUT_WEBRTC": "Fel: browsern saknar stöd för WebRTC.",
|
||||
"CHECK_PERMISSION_MEDIA": "Kontrollerar mediarättigheter",
|
||||
"CHECK_PROVISIONING_CONF": "Provisioneringskonfiguration.",
|
||||
"CHECK_LOGIN": "Kontrollerar inloggning.",
|
||||
"CHECK_CONNECTION_SPEED": "Kontrollera anslutningshastighet.",
|
||||
"ERROR_PERMISSION_MEDIA": "Fel: Mediaåtkomst nekad",
|
||||
"ERROR_PROVISIONING_CONF": "Fel: Provisionering misslyckades.",
|
||||
"PLEASE_WAIT": "Vänligen vänta...",
|
||||
"CANCEL": "Avbryt",
|
||||
"CHAT_TITLE_VOL_MINUS": "Volym -",
|
||||
"CHAT_TITLE_VOL_PLUS": "Volym +",
|
||||
"CHAT_TITLE_GAIN_MINUS": "Förstärkning -",
|
||||
"CHAT_TITLE_GAIN_PLUS": "Förstärkning +",
|
||||
"CHAT_VOL_MINUS": "Vol -",
|
||||
"CHAT_VOL_PLUS": "Vol +",
|
||||
"CHAT_GAIN_MINUS": "Förstärkning -",
|
||||
"CHAT_GAIN_PLUS": "Förstärkning +"
|
||||
}
|
151
html5/verto/verto_communicator/src/locales/locale-zh.json
Normal file
151
html5/verto/verto_communicator/src/locales/locale-zh.json
Normal file
@ -0,0 +1,151 @@
|
||||
{
|
||||
"TITLE_ACTIVE_CALL": "囧,正在通话中",
|
||||
"MESSAGE_ACTIVE_CALL_HANGUP": "好像正在通话中,你想挂断吗?",
|
||||
"MESSAGE_ACTIVE_CALL_BACK": "好像上次还有个电话没有挂断?你想恢复上次的通话吗?",
|
||||
"TITLE_INCOMING_CALL": "新来电",
|
||||
"MESSAGE_INCOMING_CALL": "来自 ",
|
||||
"MESSAGE_NO_HANGUP_CALL": "没有可挂断的电话",
|
||||
"MESSAGE_ENTER_FILENAME": "请输入文件名",
|
||||
"TITLE_ENABLE_VIDEO": "你想为当前通话开启视频吗?",
|
||||
"MESSAGE_ENABLE_VIDEO": "开启视频将在下次通话生效",
|
||||
"TITLE_INSERT_BANNER": "请输入标题文本",
|
||||
"TITLE_INSERT_CANVAS_ID": "请选择一个画布ID",
|
||||
"TITLE_INSERT_LAYER": "请输入一个层",
|
||||
"TITLE_TRANSFER": "转移方?",
|
||||
"MESSAGE_TRANSFER": "你想把该电话转移到什么号码?",
|
||||
"LABEL_TRANSFER": "目的地",
|
||||
"MESSAGE_DISPLAY_SETTINGS": "通话中不能预览",
|
||||
"BUTTON_END_CALL": "挂断",
|
||||
"BUTTON_CLOSE": "关闭",
|
||||
"MESSAGE_PLAY": "播放",
|
||||
"MESSAGE_STOP": "停止",
|
||||
"MESSAGE_RECORD": "录音/录像",
|
||||
"MESSAGE_STOP_RECORD": "停止录音/录像",
|
||||
"MESSAGE_SNAPSHOT": "抓拍",
|
||||
"MESSAGE_VIDEO_MODE": "停止发送视频",
|
||||
"MESSAGE_MUTE_MIC": "静音/恢复",
|
||||
"MESSAGE_MUTE_VIDEO": "停止视频/恢复",
|
||||
"MESSAGE_FULLSCREEN": "全屏",
|
||||
"MESSAGE_SCREENSHARE": "屏幕共享",
|
||||
"MESSAGE_OPEN_CLOSE_CHAT": "打开/关闭聊天",
|
||||
"MESSAGE_SPEAKER": "喇叭",
|
||||
"MESSAGE_POPUP": "弹出",
|
||||
"CHAT_TITLE_MEMBERS": "成员",
|
||||
"CHAT_TITLE": "聊天",
|
||||
"CHAT_NO_MEMBERS": "没有成员",
|
||||
"CHAT_GENERAL": "一般",
|
||||
"CHAT_TITLE_KICK": "踢出",
|
||||
"CHAT_KICK": "踢出",
|
||||
"CHAT_TITLE_VIDEO_FLOOR": "视频Floor",
|
||||
"CHAT_FLOOR": "Floor",
|
||||
"CHAT_TITLE_TRANSFER": "转移",
|
||||
"CHAT_TRANSFER": "转移",
|
||||
"CHAT_BANNER": "标题",
|
||||
"CHAT_TITLE_SET": "设置",
|
||||
"CHAT_SET": "设置",
|
||||
"CHAT_TITLE_RESET": "重置",
|
||||
"CHAT_RESET": "重置",
|
||||
"CHAT_CANVAS": "画布",
|
||||
"CHAT_CANVAS_IN": "入画布",
|
||||
"CHAT_CANVAS_OUT": "出画布",
|
||||
"CHAT_PREV": "上一个",
|
||||
"CHAT_NEXT": "下一个",
|
||||
"CHAT_LAYER": "层",
|
||||
"CHAT_AUDIO_VIDEO": "音频/视频",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "静音/恢复",
|
||||
"CHAT_MUTE_MIC": "静音",
|
||||
"CHAT_UNMUTE_MIC": "恢复",
|
||||
"CHAT_TITLE_MUTE_UNMUTE_MIC": "停止/恢复视频",
|
||||
"CHAT_NO_MESSAGES": "没有可显示的消息",
|
||||
"CHAT_SEND_MESSAGE": "发送",
|
||||
"CHAT_TYPE_MESSAGE": "请在此输入消息",
|
||||
"TITLE_CONTRIBUTORS": "贡献者",
|
||||
"MESSAGE_CONNECTION_UNTRUSTED": "本连接不是可信的连接",
|
||||
"MESSAGE_TOGGLE_NAVIGATION": "导航",
|
||||
"BANDWIDTH_INFO": "带宽信息",
|
||||
"BANDWIDTH_INFO_INCOMING": "接收:",
|
||||
"BANDWIDTH_INFO_OUTGOING": "发送:",
|
||||
"BANDWIDTH_INFO_VIDEO_RES": "视频分辨率:",
|
||||
"IN_CALL": "通话中:",
|
||||
"LAST_CALL": "最近通话:",
|
||||
"OPEN_NEW_WINDOW": "打开新窗口",
|
||||
"CHANGE_LOGIN_INFO": "修改登录信息",
|
||||
"LOGOUT": "退出登录",
|
||||
"ABOUT": "关于",
|
||||
"HELP": "帮助",
|
||||
"CONTRIBUTORS": "贡献者",
|
||||
"TITLE_PREVIEW_SETTINGS": "设置摄像头和麦克风",
|
||||
"CAMERA_SETTINGS": "摄像头:",
|
||||
"MIC_SETTINGS": "麦克风",
|
||||
"SAVE": "保存",
|
||||
"LOADING": "加载中",
|
||||
"ERRORS" : "错误",
|
||||
"CALLING_TO": "正在呼叫 ",
|
||||
"CANCELLING": "正在取消",
|
||||
"DETERMINING_SPEED": "检查网速...",
|
||||
"CALL_HISTORY": "通话历史",
|
||||
"CLEAR_CALL_HISTORY": "清除历史记录",
|
||||
"NO_CALL_HISTORY": "尚无任何通话",
|
||||
"ENTER_EXTENSION": "输入号码",
|
||||
"CALL_EXTENSION": "呼叫",
|
||||
"LOGIN": "登录",
|
||||
"LOGIN_INFORMATION": "登录信息",
|
||||
"SAVE_LOGIN_INFORMATION": "保存登录信息",
|
||||
"INVALID_LOGIN_FIELDS": "请检查下面的项目并重试",
|
||||
"NAME": "姓名",
|
||||
"YOUR_NAME": "你的姓名",
|
||||
"EMAIL": "电子邮件",
|
||||
"YOUR_EMAIL": "你的电子邮件",
|
||||
"USER": "用户名",
|
||||
"PASSWORD": "密码",
|
||||
"CALLER_ID": "主叫号码",
|
||||
"HOSTNAME": "主机名",
|
||||
"WEBSOCKET_URL": "Websocket URL",
|
||||
"SETTINGS": "设置",
|
||||
"DEVICE_SETTINGS": "设备设置",
|
||||
"SHARE_DEVICE": "共享设备",
|
||||
"SPEAKER": "喇叭:",
|
||||
"SPEAKER_FEATURE": "你的浏览器好像不支持该设置",
|
||||
"PREVIEW_SETTINGS": "预览设置",
|
||||
"REFRESH_DEVICE_LIST": "刷新设备列表",
|
||||
"GENERAL_SETTINGS": "通话设置:",
|
||||
"USE_VIDEO": "启用视频",
|
||||
"USE_STEREO_AUDIO": "立体声",
|
||||
"USE_STUN": "启用STUN",
|
||||
"SCALE_VIDEO": "自动缩放远端视频到本地摄像头分辨率",
|
||||
"ASK_BEFORE_RECOVER": "在恢复上一次通话前询问",
|
||||
"BEST_FRAME_RATE": "最佳帧率:",
|
||||
"AUDIO_SETTINGS": "音频设置:",
|
||||
"ECHO_CANCEL": "回声消除",
|
||||
"NOISE_SUPPRESSION": "噪声抑制",
|
||||
"HIGHPASS_FILTER": "高通滤波",
|
||||
"VIDEO_SETTINGS": "视频设置:",
|
||||
"REMOTE_ENCODER": "已启用专用远端编码器",
|
||||
"AUTO_SPEED_RES": "根据网速自动选择最佳分辨率",
|
||||
"RECHECK_BANDWIDTH": "每次通话前重新检查网速",
|
||||
"CHECK_NETWORK_SPEED": "检查网速",
|
||||
"VIDEO_QUALITY": "视频质量:",
|
||||
"MAX_INCOMING_BANDWIDTH": "最大接收带宽:",
|
||||
"MAX_OUTGOING_BANDWIDTH": "最大发送带宽:",
|
||||
"FACTORY_RESET": "恢复出厂设置",
|
||||
"SAVE_DEVICE_SETTINGS": "保存设备设置",
|
||||
"BROWSER_COMPATIBILITY": "检查浏览器兼容性",
|
||||
"REFRESH_MEDIA_DEVICES": "检查媒体设备",
|
||||
"BROWSER_WITHOUT_WEBRTC": "错误:浏览器不支持WebRTC",
|
||||
"CHECK_PERMISSION_MEDIA": "检查媒体使用权限",
|
||||
"CHECK_PROVISIONING_CONF": "自在自动配置",
|
||||
"CHECK_LOGIN": "正在检查登录信息",
|
||||
"CHECK_CONNECTION_SPEED": "检查网速",
|
||||
"ERROR_PERMISSION_MEDIA": "错误:未授权使用麦克风或摄像头",
|
||||
"ERROR_PROVISIONING_CONF": "错误:自动配置失败",
|
||||
"PLEASE_WAIT": "请稍候...",
|
||||
"CANCEL": "取消",
|
||||
"CHAT_TITLE_VOL_MINUS": "音量-",
|
||||
"CHAT_TITLE_VOL_PLUS": "音量+",
|
||||
"CHAT_TITLE_GAIN_MINUS": "增益-",
|
||||
"CHAT_TITLE_GAIN_PLUS": "增益+",
|
||||
"CHAT_VOL_MINUS": "音量-",
|
||||
"CHAT_VOL_PLUS": "音量+",
|
||||
"CHAT_GAIN_MINUS": "增益-",
|
||||
"CHAT_GAIN_PLUS": "增益+"
|
||||
}
|
@ -2,19 +2,19 @@
|
||||
<ul class="nav nav-tabs" role="tablist" ng-init="activePane = 'members'">
|
||||
<li role="presentation" ng-class="{'active': activePane == 'members'}">
|
||||
<a ng-click="activePane = 'members'" href="">
|
||||
Members
|
||||
{{ 'CHAT_TITLE_MEMBERS' | translate}}
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" ng-class="{'active': activePane == 'chat'}">
|
||||
<a ng-click="activePane = 'chat'" href="">
|
||||
Chat
|
||||
{{ 'CHAT_TITLE' | translate }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="chat-members" ng-show="activePane == 'members'">
|
||||
<div ng-show="!members.length">
|
||||
<p class="text-center text-muted">There are no members to show.</p>
|
||||
<p class="text-center text-muted">{{ 'CHAT_NO_MEMBERS' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="member in members" class="chat-member-item" ng-class="{ opened: $index == openId }">
|
||||
@ -56,33 +56,33 @@
|
||||
<div class="admin-controls" ng-if="verto.data.confRole == 'moderator'" ng-show="$index == $parent.openId">
|
||||
<div>
|
||||
<div class="col-md-6 ctrl-section">
|
||||
<h3>General</h3>
|
||||
<h3>{{ 'CHAT_GENERAL' | translate }}</h3>
|
||||
<div class="group btn-group-justified">
|
||||
<a href="" class="btn btn-xs" ng-click="confKick(member.id)" title="Kick">
|
||||
<a href="" class="btn btn-xs" ng-click="confKick(member.id)" title="{{ 'CHAT_TITLE_KICK' | translate }}">
|
||||
<i class="mdi-fw mdi-av-not-interested"></i>
|
||||
Kick
|
||||
{{ 'CHAT_KICK' | translate }}
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confVideoFloor(member.id)" title="Video Floor">
|
||||
<a href="" class="btn btn-xs" ng-click="confVideoFloor(member.id)" title="{{ 'CHAT_TITLE_VIDEO_FLOOR' | translate }}">
|
||||
<i class="mdi-fw mdi-action-aspect-ratio"></i>
|
||||
Floor
|
||||
{{ 'CHAT_FLOOR' | translate }}
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confTransfer(member.id)" title="Transfer">
|
||||
<a href="" class="btn btn-xs" ng-click="confTransfer(member.id)" title="{{ 'CHAT_TITLE_TRANSFER' | translate }}">
|
||||
<i class="mdi-fw mdi-communication-call-made"></i>
|
||||
<span style="margin-left: -9px">Transfer</span>
|
||||
<span style="margin-left: -9px">{{ 'CHAT_TRANSFER' | translate }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 ctrl-section">
|
||||
<h3>Banner</h3>
|
||||
<h3>{{ 'CHAT_BANNER' | translate }}</h3>
|
||||
<div class="group btn-group-justified">
|
||||
<a href="" class="btn btn-xs" ng-click="confBanner(member.id)" title="Set">
|
||||
<a href="" class="btn btn-xs" ng-click="confBanner(member.id)" title="{{ 'CHAT_TITLE_SET' | translate }}">
|
||||
<i class="mdi-fw mdi-toggle-radio-button-on"></i>
|
||||
Set
|
||||
{{ 'CHAT_SET' | translate }}
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confResetBanner(member.id)" title="Reset">
|
||||
<a href="" class="btn btn-xs" ng-click="confResetBanner(member.id)" title="{{ 'CHAT_TITLE_RESET' | translate }}">
|
||||
<i class="mdi-fw mdi-content-clear"></i>
|
||||
Reset
|
||||
{{ 'CHAT_RESET' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -90,81 +90,81 @@
|
||||
|
||||
<div>
|
||||
<div class="col-md-6 ctrl-section" ng-if="conf.canvasCount > 1">
|
||||
<h3>Canvas</h3>
|
||||
<h3>{{ 'CHAT_CANVAS' | translate }}</h3>
|
||||
<div class="group btn-group-justified">
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasIn(member.id, 'prev')" title="Canvas In">
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasIn(member.id, 'prev')" title="{{ 'CHAT_CANVAS_IN' | translate }}">
|
||||
<i class="mdi-fw mdi-action-open-in-browser"></i>
|
||||
Prev
|
||||
{{ 'CHAT_PREV' | translate }}
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasIn(member.id)" title="Canvas In">
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasIn(member.id)" title="{{ 'CHAT_CANVAS_IN' | translate }}">
|
||||
<i class="mdi-fw mdi-action-open-in-browser"></i>
|
||||
Id
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasIn(member.id, 'next')" title="Canvas In">
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasIn(member.id, 'next')" title="{{ 'CHAT_CANVAS_IN' | translate }}">
|
||||
<i class="mdi-fw mdi-action-open-in-browser"></i>
|
||||
Next
|
||||
{{ 'CHAT_NEXT' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="group btn-group-justified">
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasOut(member.id, 'prev')" title="Canvas Out">
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasOut(member.id, 'prev')" title="{{ 'CHAT_CANVAS_OUT' | translate }}">
|
||||
<i class="mdi-fw mdi-fw mdi-action-system-update-tv"></i>
|
||||
Prev
|
||||
{{ 'CHAT_PREV' | translate }}
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasOut(member.id)" title="Canvas Out">
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasOut(member.id)" title="{{ 'CHAT_CANVAS_OUT' | translate }}">
|
||||
<i class="mdi-fw mdi-fw mdi-action-system-update-tv"></i>
|
||||
Id
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasOut(member.id, 'next')" title="Canvas Out">
|
||||
<a href="" class="btn btn-xs" ng-click="confCanvasOut(member.id, 'next')" title="{{ 'CHAT_CANVAS_OUT' | translate }}">
|
||||
<i class="mdi-fw mdi-fw mdi-action-system-update-tv"></i>
|
||||
Next
|
||||
{{ 'CHAT_NEXT' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="group btn-group-justified">
|
||||
<a href="" class="btn btn-xs" ng-click="confLayer(member.id, 'prev')" title="Layer">
|
||||
<a href="" class="btn btn-xs" ng-click="confLayer(member.id, 'prev')" title="{{ 'CHAT_LAYER' | translate }}">
|
||||
<i class="mdi-fw mdi-action-view-carousel"></i>
|
||||
Prev
|
||||
{{ 'CHAT_PREV' | translate }}
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confLayer(member.id)" title="Layer">
|
||||
<a href="" class="btn btn-xs" ng-click="confLayer(member.id)" title="{{ 'CHAT_LAYER' | translate }}">
|
||||
<i class="mdi-fw mdi-action-view-carousel"></i>
|
||||
Id
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confLayer(member.id, 'next')" title="Layer">
|
||||
<a href="" class="btn btn-xs" ng-click="confLayer(member.id, 'next')" title="{{ 'CHAT_LAYER' | translate }}">
|
||||
<i class="mdi-fw mdi-action-view-carousel"></i>
|
||||
Next
|
||||
{{ 'CHAT_NEXT' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 ctrl-section">
|
||||
<h3>Audio/Video</h3>
|
||||
<h3>{{ 'CHAT_AUDIO_VIDEO' | translate }}</h3>
|
||||
<div class="group btn-group-justified">
|
||||
<a href="" class="btn btn-xs" ng-click="confMuteMic(member.id)" title="Mute/Unmute Mic">
|
||||
<a href="" class="btn btn-xs" ng-click="confMuteMic(member.id)" title="{{ 'CHAT_TITLE_MUTE_UNMUTE_MIC' | translate }}">
|
||||
<i class="mdi-fw" ng-class="member.status.audio.muted ? 'mdi-av-mic-off' : 'mdi-av-mic'"></i>
|
||||
{{ member.status.audio.muted ? 'Unmute' : 'Mute' }}
|
||||
{{ member.status.audio.muted ? 'CHAT_UNMUTE_MIC' : 'CHAT_MUTE_MIC' | translate }}
|
||||
</a>
|
||||
<a href="" ng-class="{ 'disabled': !member.status.video }" class="btn btn-xs" ng-click="confMuteVideo(member.id)" title="Mute/Unmute Video">
|
||||
<a href="" ng-class="{ 'disabled': !member.status.video }" class="btn btn-xs" ng-click="confMuteVideo(member.id)" title="{{ 'CHAT_TITLE_MUTE_UNMUTE_VIDEO' | translate }}">
|
||||
<i class="mdi-fw" ng-class="member.status.video.muted ? 'mdi-av-videocam-off' : 'mdi-av-videocam'"></i>
|
||||
{{ member.status.video.muted ? 'Unmute' : 'Mute' }}
|
||||
{{ member.status.video.muted ? 'CHAT_UNMUTE_MIC' : 'CHAT_MUTE_MIC' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="group btn-group-justified">
|
||||
<a href="" class="btn btn-xs" ng-click="confVolumeDown(member.id)" title="Vol –">
|
||||
<a href="" class="btn btn-xs" ng-click="confVolumeDown(member.id)" title="{{ 'CHAT_TITLE_VOL_MINUS' | translate }}">
|
||||
<i class="mdi-fw mdi-av-volume-down"></i>
|
||||
Vol –
|
||||
{{ 'CHAT_VOL_MINUS' | translate }}
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confVolumeUp(member.id)" title="Vol +">
|
||||
<a href="" class="btn btn-xs" ng-click="confVolumeUp(member.id)" title="{{ 'CHAT_TITLE_VOL_MINUS' | translate }}">
|
||||
<i class="mdi-fw mdi-av-volume-up"></i>
|
||||
Vol +
|
||||
{{ 'CHAT_VOL_PLUS' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="group btn-group-justified">
|
||||
<a href="" class="btn btn-xs" ng-click="confGainDown(member.id)" title="Gain –">
|
||||
<a href="" class="btn btn-xs" ng-click="confGainDown(member.id)" title="{{ 'CHAT_TITLE_VOL_MINUS' | translate }}">
|
||||
<i class="mdi-fw mdi-av-volume-down"></i>
|
||||
Gain –
|
||||
{{ 'CHAT_GAIN_MINUS' | translate }}
|
||||
</a>
|
||||
<a href="" class="btn btn-xs" ng-click="confGainUp(member.id)" title="Gain +">
|
||||
<a href="" class="btn btn-xs" ng-click="confGainUp(member.id)" title="{{ 'CHAT_TITLE_VOL_MINUS' | translate }}">
|
||||
<i class="mdi-fw mdi-av-volume-up"></i>
|
||||
Gain +
|
||||
{{ 'CHAT_GAIN_PLUS' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -176,7 +176,7 @@
|
||||
<div class="chat-history" ng-show="activePane == 'chat'">
|
||||
<div class="chat-messages">
|
||||
<div class="chat-message" ng-show="!messages.length">
|
||||
<p class="text-center text-muted">There are no messages to show.</p>
|
||||
<p class="text-center text-muted">{{ 'CHAT_NO_MESSAGES' | translate }}</p>
|
||||
</div>
|
||||
<div class="chat-message" ng-repeat="message in messages" title="Sent at {{ message.created_at|date }}.">
|
||||
<div class="chat-message-metadata">{{ message.from }}:</div>
|
||||
@ -188,9 +188,9 @@
|
||||
<div class="chat-message-input">
|
||||
<form ng-submit="send()" >
|
||||
<div class="chat-message-input-group">
|
||||
<textarea ng-model="message" ng-keydown="($event.keyCode == 13 && $event.shiftKey !== true) && send($event)" required="required" class="form-control input-sm" placeholder="Type your message here..."></textarea>
|
||||
<textarea ng-model="message" ng-keydown="($event.keyCode == 13 && $event.shiftKey !== true) && send($event)" required="required" class="form-control input-sm" placeholder="{{ 'CHAT_TYPE_MESSAGE' | translate }}"></textarea>
|
||||
<button class="btn btn-success btn-sm" type="submit">
|
||||
Send
|
||||
{{ 'CHAT_SEND_MESSAGE' | translate }}
|
||||
<span class="mdi-navigation-arrow-forward chat-message-input-group-icon-button"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Contributors</h3>
|
||||
<h3 class="modal-title">{{ 'TITLE_CONTRIBUTORS' | translate}}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul class="contributors">
|
||||
|
@ -1,6 +1,15 @@
|
||||
<div ng-show="loading">
|
||||
<h3 style="margin-top: 4%;" class="text-center">Calling to {{ dialpadNumber }}...</h3>
|
||||
<svg class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<h2 ng-show="cancelled" style="margin-top: 4%;" class="text-center">{{ 'CANCELLING' | translate}}</h2>
|
||||
<span ng-show="!cancelled">
|
||||
<h2 style="margin-top: 4%;" class="text-center">{{ 'DETERMINING_SPEED' | translate}}</h2>
|
||||
<h4 style="margin-top: 4%;" class="text-center">
|
||||
{{ 'CALLING_TO' | translate}} {{ dialpadNumber }}...
|
||||
<a class="btn btn-sm btn-raised btn-warning" ng-click="cancel()">
|
||||
Cancel<div class="ripple-container"></div>
|
||||
</a>
|
||||
</h4>
|
||||
</span>
|
||||
<svg class="spinner" width="35px" height="35px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle class="path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
@ -10,7 +19,7 @@
|
||||
<div class="panel-heading">
|
||||
<div class="panel-title">
|
||||
<i class="mdi-navigation-arrow-back back-icon" ng-click="viewCallsList()" ng-if="call_list"></i>
|
||||
<span ng-if="!call_list">Call History</span>
|
||||
<span ng-if="!call_list">{{ 'CALL_HISTORY' | translate}}</span>
|
||||
<span ng-if="call_list">{{ call_list[0].number }}</span>
|
||||
|
||||
<span class="pull-right pull-right-margin dropdown">
|
||||
@ -18,14 +27,14 @@
|
||||
<i class="mdi-navigation-more-vert"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="" ng-click="clearCallHistory()">Clear History</a></li>
|
||||
<li><a href="" ng-click="clearCallHistory()">{{ 'CLEAR_CALL_HISTORY' | translate}}</a></li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="call-history">
|
||||
<div ng-if="!has_history">
|
||||
<p class="text-center text-muted">No history calls.</p>
|
||||
<p class="text-center text-muted">{{ 'NO_CALL_HISTORY' | translate}}</p>
|
||||
</div>
|
||||
|
||||
<li ng-repeat="number in history_control track by number" ng-if="!call_list">
|
||||
@ -63,7 +72,7 @@
|
||||
<i class="mdi-action-settings-phone"></i>
|
||||
</a>
|
||||
</span>
|
||||
<input name="dialpadnumber" type="text" class="form-control text-center" placeholder="Enter an extension" ng-model="dialpadNumber" autofocus/>
|
||||
<input name="dialpadnumber" type="text" class="form-control text-center" placeholder="{{ 'ENTER_EXTENSION' | translate}}" ng-model="dialpadNumber" autofocus/>
|
||||
<span class="input-group-btn">
|
||||
<a href="" ng-click="backspace()">
|
||||
<i class="mdi-content-backspace"></i>
|
||||
@ -154,7 +163,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<button type="submit" class="btn btn-success btn-fab" ng-click="call(dialpadNumber)" title="Call Extension">
|
||||
<button type="submit" class="btn btn-success btn-fab" ng-click="call(dialpadNumber)" title="{{ 'CALL_EXTENSION' | translate}}">
|
||||
<i class="mdi-communication-call"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -2,59 +2,59 @@
|
||||
<div class="col-md-4 col-xs-12 col-sm-12 centered-block">
|
||||
<div class="panel panel-default shadow-z-2">
|
||||
<div class="panel-body">
|
||||
<h3>Login</h3>
|
||||
<h3>{{ 'LOGIN' | translate}}</h3>
|
||||
|
||||
|
||||
<div ng-show="form.$submitted && form.$invalid" class="alert alert-danger">
|
||||
<p>Verify the fields bellow and try again.</p>
|
||||
<p>{{ 'INVALID_LOGIN_FIELDS' | translate }}</p>
|
||||
</div>
|
||||
|
||||
<form name="form" class="css-form" novalidate ng-init="advanced = false">
|
||||
<div class="form-group {{ (((!form.name.$pristine || form.$submitted) && !form.name.$valid) ? 'has-error': '') }}">
|
||||
<label class="control-label" for="login-name">Name</label>
|
||||
<input type="text" name="name" class="form-control" id="login-name" placeholder="Your name" required="" ng-model="verto.data.name" autofocus>
|
||||
<label class="control-label" for="login-name">{{ 'NAME' | translate}}</label>
|
||||
<input type="text" name="name" class="form-control" id="login-name" placeholder="{{ 'YOUR_NAME' | translate}}" required="" ng-model="verto.data.name" autofocus>
|
||||
</div>
|
||||
<div class="form-group {{ (((!form.email.$pristine || form.$submitted) && !form.email.$valid) ? 'has-error': '') }}">
|
||||
<label class="control-label" for="login-email">Email</label>
|
||||
<input type="email" name="email" class="form-control" id="login-email" placeholder="Your email" required="" ng-model="verto.data.email" ng-model-options="{debounce: 250}">
|
||||
<label class="control-label" for="login-email">{{ 'EMAIL' | translate }}</label>
|
||||
<input type="email" name="email" class="form-control" id="login-email" placeholder="{{ 'YOUR_EMAIL' | translate}}" required="" ng-model="verto.data.email" ng-model-options="{debounce: 250}">
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-user">User</label>
|
||||
<input type="text" class="form-control" id="login-user" placeholder="User" ng-model="verto.data.login">
|
||||
<label class="control-label" for="login-user">{{ 'USER' | translate}}</label>
|
||||
<input type="text" class="form-control" id="login-user" placeholder="{{ 'USER' | translate}}" ng-model="verto.data.login">
|
||||
</div>
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-password">Password</label>
|
||||
<input type="password" class="form-control" id="login-password" placeholder="Password" ng-model="verto.data.password">
|
||||
<label class="control-label" for="login-password">{{ 'PASSWORD' | translate}}</label>
|
||||
<input type="password" class="form-control" id="login-password" placeholder={{ 'PASSWORD' | translate}} ng-model="verto.data.password">
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-callerid">Caller ID</label>
|
||||
<input type="text" class="form-control" id="login-callerid" placeholder="Caller ID" ng-model="verto.data.callerid">
|
||||
<label class="control-label" for="login-callerid">{{ 'CALLER_ID' | translate}}</label>
|
||||
<input type="text" class="form-control" id="login-callerid" placeholder="{{ 'CALLER_ID' | translate}}" ng-model="verto.data.callerid">
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-hostname">Hostname</label>
|
||||
<input type="text" class="form-control" id="login-hostname" placeholder="Hostname" ng-model="verto.data.hostname">
|
||||
<label class="control-label" for="login-hostname">{{ 'HOSTNAME' | translate}}</label>
|
||||
<input type="text" class="form-control" id="login-hostname" placeholder="{{ 'HOSTNAME' | translate}}" ng-model="verto.data.hostname">
|
||||
</div>
|
||||
<div class="form-group" ng-hide="!advanced">
|
||||
<label class="control-label" for="login-wsurl">Websocket URL</label>
|
||||
<input type="text" class="form-control" id="login-wsurl" placeholder="Websocket URL" ng-model="verto.data.wsURL">
|
||||
<label class="control-label" for="login-wsurl">{{ 'WEBSOCKET_URL' | translate}}</label>
|
||||
<input type="text" class="form-control" id="login-wsurl" placeholder="{{ 'WEBSOCKET_URL' | translate}}" ng-model="verto.data.wsURL">
|
||||
</div>
|
||||
|
||||
<div class="form-group hide">
|
||||
<label for="login-login">Login</label>
|
||||
<input type="text" class="form-control" id="login-login" placeholder="Login" ng-model="verto.data.login">
|
||||
<label for="login-login">{{ 'LOGIN' | translate}}</label>
|
||||
<input type="text" class="form-control" id="login-login" placeholder="{{ 'LOGIN' | translate}}" ng-model="verto.data.login">
|
||||
</div>
|
||||
<div class="form-group hide">
|
||||
<label for="login-password">Password</label>
|
||||
<input type="text" class="form-control" id="login-password" placeholder="Password" ng-model="verto.data.password">
|
||||
<input type="text" class="form-control" id="login-password" placeholder="{{ 'PASSWORD' | translate}}" ng-model="verto.data.password">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group text-right">
|
||||
<div><a style="margin-top: 13px;" href="" ng-click="advanced = !advanced" class="pull-left">Settings</a></div>
|
||||
<div><button type="submit" class="btn btn-success" ng-click="(form.$valid && login())">Login</button></div>
|
||||
<div><a style="margin-top: 13px;" href="" ng-click="advanced = !advanced" class="pull-left">{{ 'SETTINGS' | translate}}</a></div>
|
||||
<div><button type="submit" class="btn btn-success" ng-click="(form.$valid && login())">{{ 'LOGIN' | translate}}</button></div>
|
||||
<div ng-if="googlelogin" class="googlelogin">
|
||||
<google-plus-signin clientid="{{src/partials/login.html}}" class="center">
|
||||
</google-plus-signin>
|
||||
|
@ -2,13 +2,13 @@
|
||||
<div class="container-fluid">
|
||||
<div class="https-untrusted navbar-center" ng-show="!safeProtocol">
|
||||
<div class="https-message">
|
||||
This Connection is Untrusted.
|
||||
{{ 'MESSAGE_CONNECTION_UNTRUSTED' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="sr-only">{{ 'MESSAGE_TOGGLE_NAVIGATION' | translate }}</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
@ -25,10 +25,10 @@
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu drop-net-info" role="menu" ng-click="$event.stopPropagation()">
|
||||
<li><a class="title">Bandwidth Info</a></li>
|
||||
<li><a>Outgoing: {{bandUp}} Kbps</a></li>
|
||||
<li><a>Incoming: {{bandDown}} Kbps</a></li>
|
||||
<li><a>Video Resolution: {{vidRes}}</a></li>
|
||||
<li><a class="title">{{ 'BANDWIDTH_INFO' | translate }}</a></li>
|
||||
<li><a>{{ 'BANDWIDTH_INFO_OUTGOING' | translate }} {{bandUp}} Kbps</a></li>
|
||||
<li><a>{{ 'BANDWIDTH_INFO_INCOMING' | translate }} {{bandDown}} Kbps</a></li>
|
||||
<li><a>{{ 'BANDWIDTH_INFO_VIDEO_RES' | translate }} {{vidRes}}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
@ -38,11 +38,11 @@
|
||||
</li>
|
||||
<li>
|
||||
<a href="" class="incall-number" ng-show="storage.data.called_number">
|
||||
{{ storage.data.called_number && storage.data.userStatus == 'connecting' ? 'Last Call: ' : 'In Call: ' }} {{ storage.data.called_number }}
|
||||
{{ storage.data.called_number && storage.data.userStatus != 'connected' ? 'LAST_CALL' : 'IN_CALL' | translate }} {{ storage.data.called_number }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="navbar-item-icon" ng-show="verto.data.connected">
|
||||
<a href="" ng-click="openModal('partials/modal_settings.html', 'ModalSettingsController')">
|
||||
<a href="" ng-click="toggleSettings()">
|
||||
<i class="mdi-action-settings"></i>
|
||||
</a>
|
||||
</li>
|
||||
@ -63,10 +63,10 @@
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="#/?sessid=random" target="_blank">Open New Window</a></li>
|
||||
<li><a href="" ng-click="openModal('partials/modal_logininfo.html', 'ModalLoginInformationController')">Change Login Information</a></li>
|
||||
<li><a href="#/?sessid=random" target="_blank">{{ 'OPEN_NEW_WINDOW' | translate}}</a></li>
|
||||
<li><a href="" ng-click="openModal('partials/modal_logininfo.html', 'ModalLoginInformationController')">{{ 'CHANGE_LOGIN_INFO' | translate}}</a></li>
|
||||
<!--<li><a href="#">View Device Settings</a></li>-->
|
||||
<li><a href="" ng-click="logout()">Logout</a></li>
|
||||
<li><a href="" ng-click="logout()">{{ 'LOGOUT' | translate}}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="navbar-item-icon">
|
||||
@ -75,9 +75,9 @@
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="" ng-click="showAbout()">About</a></li>
|
||||
<li><a href="" ng-click="showContributors()">Contributors</a></li>
|
||||
<li><a href="https://freeswitch.org/confluence/x/MQCT" target="_blank">Help</a></li>
|
||||
<li><a href="" ng-click="showAbout()">{{ 'ABOUT' | translate}}</a></li>
|
||||
<li><a href="" ng-click="showContributors()">{{ 'CONTRIBUTORS' | translate}}</a></li>
|
||||
<li><a href="https://freeswitch.org/confluence/x/MQCT" target="_blank">{{ 'HELP' | translate}}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
@ -1,35 +1,35 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Login Information</h3>
|
||||
<h3 class="modal-title">{{ 'LOGIN_INFORMATION' | translate}}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Name:</label>
|
||||
<label for="name">{{ 'NAME' | translate}}</label>
|
||||
<input type="text" name="name" class="form-control" ng-model="storage.data.name" ng-value="storage.data.name"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email:</label>
|
||||
<label for="email">{{ 'EMAIL' | translate}}</label>
|
||||
<input type="text" name="email" class="form-control" ng-model="storage.data.email" ng-value="storage.data.email"/>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="user">User</label>
|
||||
<label class="control-label" for="user">{{ 'USER' | translate}}</label>
|
||||
<input type="text" class="form-control" id="user" placeholder="User" ng-model="storage.data.login">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="password">Password</label>
|
||||
<label class="control-label" for="password">{{ 'PASSWORD' | translate}}</label>
|
||||
<input type="password" class="form-control" id="password" placeholder="Password" ng-model="verto.data.password">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="callerid">Caller ID</label>
|
||||
<label class="control-label" for="callerid">{{ 'CALLER_ID' | translate}}</label>
|
||||
<input type="text" class="form-control" id="callerid" placeholder="Caller ID" ng-model="verto.data.callerid">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<!-- <button class="btn btn-primary" ng-click="cancel()">Cancel</button> -->
|
||||
<button class="btn btn-primary" ng-click="ok()">Save Login Information</button>
|
||||
<button class="btn btn-primary" ng-click="ok()">{{ 'SAVE_LOGIN_INFORMATION' | translate}}</button>
|
||||
</div>
|
||||
|
@ -1,159 +0,0 @@
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Device Settings</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group" ng-show="mydata.useVideo">
|
||||
<label for="settings-camera">Camera:</label>
|
||||
<select name="camera" id="settings-camera" class="form-control"
|
||||
ng-model="mydata.selectedVideo" ng-options="item.id as item.label for item in verto.data.videoDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-show="mydata.useVideo">
|
||||
<label for="settings-share-device">Share device:</label>
|
||||
<select name="share-device" id="settings-share-device" class="form-control"
|
||||
ng-model="mydata.selectedShare" ng-options="item.id as item.label for item in verto.data.shareDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">Microphone:</label>
|
||||
<select name="microphone" id="settings-microphone" class="form-control"
|
||||
ng-model="mydata.selectedAudio" ng-options="item.id as item.label for item in verto.data.audioDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">
|
||||
Speaker:
|
||||
<span ng-show="!speakerFeature" class="unsupported">
|
||||
Your browser doesn't seem to support this feature
|
||||
</span>
|
||||
</label>
|
||||
<select name="microphone" id="settings-microphone" class="form-control" ng-disabled="!speakerFeature"
|
||||
ng-model="mydata.selectedSpeaker" ng-options="item.id as item.label for item in verto.data.speakerDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<a class="btn btn-primary" href="#/preview" ng-click="ok()">Preview Settings</a>
|
||||
<a class="btn btn-primary" href="" ng-click="refreshDeviceList()">Refresh device list</a>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">General settings:</label>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_video" value="mydata.useVideo" ng-model="mydata.useVideo">
|
||||
Use Video
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_stereo_audio" ng-value="mydata.useStereo" ng-model="mydata.useStereo">
|
||||
Stereo Audio
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_stun" ng-value="mydata.useSTUN" ng-model="mydata.useSTUN">
|
||||
Use STUN
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="mirror_input" ng-value="mydata.mirrorInput" ng-model="mydata.mirrorInput">
|
||||
Scale Remote Video To Match Camera Resolution
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="ask_recover_call" ng-value="mydata.askRecoverCall" ng-model="mydata.askRecoverCall">
|
||||
Ask before recovering call
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-framerate">Best frame rate:</label>
|
||||
<select name="settings-framerate" id="settings-framerate" class="form-control"
|
||||
ng-model="mydata.bestFrameRate"
|
||||
ng-options="item.id as item.label for item in verto.framerate"></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">Audio settings:</label>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="googEchoCancellation" value="mydata.googEchoCancellation" ng-model="mydata.googEchoCancellation">
|
||||
Echo Cancellation
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="googNoiseSuppression" value="mydata.googNoiseSuppression" ng-model="mydata.googNoiseSuppression">
|
||||
Noise Suppression
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="googHighpassFilter" value="mydata.googHighpassFilter" ng-model="mydata.googHighpassFilter">
|
||||
Highpass Filter
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Video settings:</label> <br>
|
||||
<input type="hidden" name="use_dedenc" ng-value="mydata.useDedenc" ng-model="mydata.useDedenc">
|
||||
|
||||
|
||||
<div ng-show="mydata.useDedenc" class="dedicated_encoder">
|
||||
<p>Dedicated Remote Encoder enabled.</b>
|
||||
</div>
|
||||
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="mydata.autoBand" ng-change="checkAutoBand(mydata.autoBand)">
|
||||
Automatically determine speed and resolution settings
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox" ng-show="mydata.autoBand">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="mydata.testSpeedJoin">
|
||||
Recheck bandwidth before each outgoing call
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<a ng-show="mydata.autoBand" class="btn btn-primary" href="" ng-click="testSpeed()">Check Network Speed</a> <span ng-bind="speedMsg"></span>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="video-quality">Video quality:</label>
|
||||
<select name="video_quality" id="video-quality" class="form-control"
|
||||
ng-disabled="mydata.autoBand"
|
||||
ng-model="mydata.vidQual"
|
||||
ng-change="checkVideoQuality(mydata.vidQual)"
|
||||
ng-options="item.id as item.label for item in verto.videoQuality"></select>
|
||||
</div>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="incoming-bandwidth">Max incoming bandwidth:</label>
|
||||
<select name="incoming_bandwidth" id="incoming-bandwidth" class="form-control"
|
||||
ng-model="mydata.incomingBandwidth"
|
||||
ng-change="checkUseDedRemoteEncoder(mydata.incomingBandwidth)"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="outgoing-bandwidth">Max outgoing bandwidth:</label>
|
||||
<select name="outgoing_bandwidth" id="outgoing-bandwidth" class="form-control"
|
||||
ng-model="mydata.outgoingBandwidth"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-danger pull-left btn-pull-left" ng-click="resetSettings()">Factory reset</button>
|
||||
<!-- <button class="btn btn-primary" ng-click="cancel()">Cancel</button> -->
|
||||
<button class="btn btn-primary" ng-click="ok()">Save Device Settings</button>
|
||||
</div>
|
@ -2,7 +2,7 @@
|
||||
<div class="col-md-4 col-sm-12 col-xs-12 centered-block">
|
||||
<div class="panel panel-material-blue-900 shadow-z-2 ">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title text-center">Setup your camera and microphone settings</h3>
|
||||
<h3 class="panel-title text-center">{{ 'TITLE_PREVIEW_SETTINGS' | translate }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="preview-wrapper">
|
||||
@ -20,13 +20,13 @@
|
||||
</div>
|
||||
<form name="form">
|
||||
<div class="form-group col-md-5 col-sm-12 col-xs-12" ng-show="true">
|
||||
<label for="settings-camera">Camera:</label>
|
||||
<label for="settings-camera">{{ 'CAMERA_SETTINGS' | translate }}</label>
|
||||
<select name="camera" id="settings-camera" class="form-control" ng-model="storage.data.selectedVideo"
|
||||
ng-options="item.id as item.label for item in verto.data.videoDevices" ng-change="localVideo()" >
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-5 col-sm-12 col-xs-12" ng-show="true">
|
||||
<label for="settings-microphone">Microphone:</label>
|
||||
<label for="settings-microphone">{{ 'MIC_SETTINGS' | translate }}</label>
|
||||
<select name="microphone" id="settings-microphone" class="form-control" ng-model="storage.data.selectedAudio"
|
||||
ng-options="item.id as item.label for item in verto.data.audioDevices" ng-change="localVideo()">
|
||||
</select>
|
||||
@ -36,8 +36,8 @@
|
||||
</a>
|
||||
|
||||
<div class="form-group text-center">
|
||||
<button type="submit" class="btn btn-success" ng-click="endPreview()" title="Save">
|
||||
Save
|
||||
<button type="submit" class="btn btn-success" ng-click="endPreview()" title="{{ 'SAVE' | translate }}">
|
||||
{{ 'SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
159
html5/verto/verto_communicator/src/partials/settings.html
Normal file
159
html5/verto/verto_communicator/src/partials/settings.html
Normal file
@ -0,0 +1,159 @@
|
||||
<div id="settings" ng-controller="SettingsController">
|
||||
<div class="content">
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="form-group" ng-show="mydata.useVideo">
|
||||
<label for="settings-camera">{{ 'CAMERA_SETTINGS' | translate }}</label>
|
||||
<select name="camera" id="settings-camera" class="form-control"
|
||||
ng-model="mydata.selectedVideo" ng-options="item.id as item.label for item in verto.data.videoDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-show="mydata.useVideo">
|
||||
<label for="settings-share-device">{{ 'SHARE_DEVICE' | translate }}</label>
|
||||
<select name="share-device" id="settings-share-device" class="form-control"
|
||||
ng-model="mydata.selectedShare" ng-options="item.id as item.label for item in verto.data.shareDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">{{ 'MIC_SETTINGS' | translate}}</label>
|
||||
<select name="microphone" id="settings-microphone" class="form-control"
|
||||
ng-model="mydata.selectedAudio" ng-options="item.id as item.label for item in verto.data.audioDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">
|
||||
{{ 'SPEAKER' | translate }}
|
||||
<span ng-show="!speakerFeature" class="unsupported">
|
||||
{{ 'SPEAKER_FEATURE' | translate }}
|
||||
</span>
|
||||
</label>
|
||||
<select name="microphone" id="settings-microphone" class="form-control" ng-disabled="!speakerFeature"
|
||||
ng-model="mydata.selectedSpeaker" ng-options="item.id as item.label for item in verto.data.speakerDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-framerate">{{ 'BEST_FRAME_RATE' | translate }}</label>
|
||||
<select name="settings-framerate" id="settings-framerate" class="form-control"
|
||||
ng-model="mydata.bestFrameRate"
|
||||
ng-options="item.id as item.label for item in verto.framerate"></select>
|
||||
</div>
|
||||
|
||||
<a class="btn btn-primary" href="" ng-click="showPreview()">{{ 'PREVIEW_SETTINGS' | translate }}</a>
|
||||
<a class="btn btn-primary" href="" ng-click="refreshDeviceList()">{{ 'REFRESH_DEVICE_LIST' | translate }}</a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">{{ 'GENERAL_SETTINGS' | translate }}</label>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_video" value="mydata.useVideo" ng-model="mydata.useVideo">
|
||||
<span ng-bind="'USE_VIDEO' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_stereo_audio" ng-value="mydata.useStereo" ng-model="mydata.useStereo">
|
||||
<span ng-bind="'USE_STEREO_AUDIO' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="use_stun" ng-value="mydata.useSTUN" ng-model="mydata.useSTUN">
|
||||
<span ng-bind="'USE_STUN' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="mirror_input" ng-value="mydata.mirrorInput" ng-model="mydata.mirrorInput">
|
||||
<span ng-bind="'SCALE_VIDEO' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="ask_recover_call" ng-value="mydata.askRecoverCall" ng-model="mydata.askRecoverCall">
|
||||
<span ng-bind="'ASK_BEFORE_RECOVER' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">{{ 'AUDIO_SETTINGS' | translate }}</label>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="googEchoCancellation" value="mydata.googEchoCancellation" ng-model="mydata.googEchoCancellation">
|
||||
<span ng-bind="'ECHO_CANCEL' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="googNoiseSuppression" value="mydata.googNoiseSuppression" ng-model="mydata.googNoiseSuppression">
|
||||
<span ng-bind="'NOISE_SUPPRESSION' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="googHighpassFilter" value="mydata.googHighpassFilter" ng-model="mydata.googHighpassFilter">
|
||||
<span ng-bind="'HIGHPASS_FILTER' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{ 'VIDEO_SETTINGS' | translate }}</label> <br>
|
||||
<input type="hidden" name="use_dedenc" ng-value="mydata.useDedenc" ng-model="mydata.useDedenc">
|
||||
|
||||
|
||||
<div ng-show="mydata.useDedenc" class="dedicated_encoder">
|
||||
<p>{{ 'REMOTE_ENCODER' | translate }}</b>
|
||||
</div>
|
||||
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="mydata.autoBand" ng-change="checkAutoBand(mydata.autoBand)">
|
||||
<span ng-bind="'AUTO_SPEED_RES' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="checkbox" ng-show="mydata.autoBand">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="mydata.testSpeedJoin">
|
||||
<span ng-bind="'RECHECK_BANDWIDTH' | translate"></span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<a ng-show="mydata.autoBand" class="btn btn-primary" href="" ng-click="testSpeed()">{{ 'CHECK_NETWORK_SPEED' | translate }}</a> <span ng-bind="speedMsg"></span>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="video-quality">{{ 'VIDEO_QUALITY' | translate }}</label>
|
||||
<select name="video_quality" id="video-quality" class="form-control"
|
||||
ng-disabled="mydata.autoBand"
|
||||
ng-model="mydata.vidQual"
|
||||
ng-change="checkVideoQuality(mydata.vidQual)"
|
||||
ng-options="item.id as item.label for item in verto.videoQuality"></select>
|
||||
</div>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="incoming-bandwidth">{{ 'MAX_INCOMING_BANDWIDTH' | translate }}</label>
|
||||
<select name="incoming_bandwidth" id="incoming-bandwidth" class="form-control"
|
||||
ng-model="mydata.incomingBandwidth"
|
||||
ng-change="checkUseDedRemoteEncoder(mydata.incomingBandwidth)"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="outgoing-bandwidth">{{ 'MAX_OUTGOING_BANDWIDTH' | translate }}</label>
|
||||
<select name="outgoing_bandwidth" id="outgoing-bandwidth" class="form-control"
|
||||
ng-model="mydata.outgoingBandwidth"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -2,14 +2,14 @@
|
||||
<div class="col-md-6 centered-block">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h2>Loading</h2>
|
||||
<h2>{{ 'LOADING' | translate }}</h2>
|
||||
<div class="progress progress-striped active">
|
||||
<div class="progress-bar" ng-class="{'progress-bar-danger': interrupt_next}" style="width: {{ progress_percentage }}%"></div>
|
||||
</div>
|
||||
<div ng-bind="message"></div>
|
||||
|
||||
<div class="splash-errors" ng-if="errors.length">
|
||||
<h4>Errors</h4>
|
||||
<h4>{{ 'ERRORS' | translate }}</h4>
|
||||
<ul ng-repeat="error in errors">
|
||||
<li>{{ ::error }}</li>
|
||||
</ul>
|
||||
|
@ -2,28 +2,28 @@
|
||||
<div class="video-wrapper">
|
||||
<div class="video-hover-buttons" ng-show="verto.data.callState == 'active' && !watcher">
|
||||
<div id="moderator-tools" ng-show="verto.data.confRole == 'moderator'">
|
||||
<button tooltip-placement="bottom" tooltip-title="Play" uib-tooltip="Play"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_PLAY' | translate}}" uib-tooltip="{{'MESSAGE_PLAY' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="play()">
|
||||
<i class="mdi-av-play-circle-outline"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Stop" uib-tooltip="Stop"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_STOP' | translate}}" uib-tooltip="{{'MESSAGE_STOP' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="stop()">
|
||||
<i class="mdi-av-stop"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Record" uib-tooltip="Record"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_RECORD' | translate}}" uib-tooltip="{{'MESSAGE_RECORD' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="record()">
|
||||
<i class="mdi-toggle-radio-button-on"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Stop Record" uib-tooltip="Stop Record"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_STOP_RECORD' | translate}}" uib-tooltip="{{'MESSAGE_STOP_RECORD' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="stopRecord()">
|
||||
<i class="mdi-image-switch-camera"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Snapshot" uib-tooltip="Snapshot"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_SNAPSHOT' | translate}}" uib-tooltip="{{'MESSAGE_SNAPSHOT' | translate}}"
|
||||
tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="snapshot()">
|
||||
<i class="mdi-image-photo-camera"></i>
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button tooltip-placement="bottom" tooltip-title="Video Mode" uib-tooltip="Video Mode"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_VIDEO_MODE' | translate}}" uib-tooltip="{{'MESSAGE_VIDEO_MODE' | translate}}"
|
||||
type="button" class="btn btn-material-blue-900 dropdown-toggle"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="mdi-action-view-module"></i>
|
||||
@ -37,28 +37,28 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-tools">
|
||||
<button tooltip-placement="bottom" tooltip-title="(un)Mute Mic" uib-tooltip="(un)Mute Mic"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_MUTE_MIC' | translate}}" uib-tooltip="{{'MESSAGE_MUTE_MIC' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="muteMic(cbMuteMic)">
|
||||
<i class="" ng-class="{'mdi-av-mic': !verto.data.mutedMic, 'mdi-av-mic-off': verto.data.mutedMic}"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="(un)Mute Video" uib-tooltip="(un)Mute Video"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_MUTE_VIDEO' | translate}}" uib-tooltip="{{'MESSAGE_MUTE_VIDEO' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="muteVideo(cbMuteVideo)" ng-if="verto.data.canVideo">
|
||||
<i class="" ng-class="{'mdi-av-videocam': !verto.data.mutedVideo, 'mdi-av-videocam-off': verto.data.mutedVideo}"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Toggle Fullscreen Mode" uib-tooltip="Toggle Fullscreen Mode"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_FULLSCREEN' | translate}}" uib-tooltip="{{'MESSAGE_FULLSCREEN' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="goFullscreen()">
|
||||
<i class="" ng-class="{'mdi-navigation-fullscreen': !fullscreenEnabled, 'mdi-navigation-fullscreen-exit': fullscreenEnabled}"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Screenshare" uib-tooltip="Screenshare"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_SCREENSHARE' | translate}}" uib-tooltip="{{'MESSAGE_SCREENSHARE' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="screenshare()">
|
||||
<i class="mdi-hardware-desktop-windows"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Open/Close Chat" uib-tooltip="Open/Close Chat"
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_OPEN_CLOSE_CHAT' | translate}}" uib-tooltip="{{'MESSAGE_OPEN_CLOSE_CHAT' | translate}}"
|
||||
class="btn btn-material-blue-900" ng-click="toggleChat()" ng-show="fullscreenEnabled">
|
||||
<i class="mdi-communication-chat"></i>
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button tooltip-placement="bottom" tooltip-title="Speaker" uib-tooltips="Speaker" type="button" class="btn btn-material-blue-900 dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_SPEAKER' | translate}}" uib-tooltips="{{'MESSAGE_SPEAKER' | translate}}" type="button" class="btn btn-material-blue-900 dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="mdi-hardware-headset"></i>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
@ -69,7 +69,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="btn-group" ng-show="conf.canvasCount > 1">
|
||||
<button tooltip-placement="bottom" tooltip-title="Popup" uib-tooltips="Popup" type="button" class="btn btn-material-blue-900 dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<button tooltip-placement="bottom" tooltip-title="{{'MESSAGE_POPUP' | translate}}" uib-tooltips="{{'MESSAGE_POPUP' | translate}}" type="button" class="btn btn-material-blue-900 dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="mdi-image-filter-none"></i>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
@ -96,9 +96,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-xs-6 text-right">
|
||||
<button class="btn btn-danger" ng-click="hangup()">
|
||||
<button class="btn btn-danger" ng-click="hangup()" translate>
|
||||
<i class="mdi-communication-call-end"></i>
|
||||
{{ watcher ? 'Close' : 'End Call' }}
|
||||
{{ watcher ? 'BUTTON_CLOSE' : 'BUTTON_END_CALL' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
angular
|
||||
.module('storageService')
|
||||
.service('splashscreen', ['$rootScope', '$q', 'storage', 'config', 'verto',
|
||||
function($rootScope, $q, storage, config, verto) {
|
||||
.service('splashscreen', ['$rootScope', '$q', 'storage', 'config', 'verto', '$translate',
|
||||
function($rootScope, $q, storage, config, verto, $translate) {
|
||||
|
||||
var checkBrowser = function() {
|
||||
return $q(function(resolve, reject) {
|
||||
@ -12,16 +12,15 @@
|
||||
'activity': activity,
|
||||
'soft': false,
|
||||
'status': 'success',
|
||||
'message': 'Checking browser compability.'
|
||||
'message': $translate.instant('BROWSER_COMPATIBILITY')
|
||||
};
|
||||
|
||||
navigator.getUserMedia = navigator.getUserMedia ||
|
||||
navigator.webkitGetUserMedia ||
|
||||
navigator.mozGetUserMedia;
|
||||
|
||||
if (!navigator.getUserMedia) {
|
||||
result['status'] = 'error';
|
||||
result['message'] = 'Error: browser doesn\'t support WebRTC.';
|
||||
result['message'] = $translate.instant('BROWSER_WITHOUT_WEBRTC');
|
||||
reject(result);
|
||||
}
|
||||
|
||||
@ -37,13 +36,13 @@
|
||||
'activity': activity,
|
||||
'soft': false,
|
||||
'status': 'success',
|
||||
'message': 'Checking media permissions'
|
||||
'message': $translate.instant('CHECK_PERMISSION_MEDIA')
|
||||
};
|
||||
|
||||
verto.mediaPerm(function(status) {
|
||||
if(!status) {
|
||||
result['status'] = 'error';
|
||||
result['message'] = 'Error: Media Permission Denied';
|
||||
result['message'] = $translate.instant('ERROR_PERMISSION_MEDIA');
|
||||
verto.data.mediaPerm = false;
|
||||
reject(result);
|
||||
}
|
||||
@ -60,7 +59,7 @@
|
||||
'status': 'success',
|
||||
'soft': true,
|
||||
'activity': activity,
|
||||
'message': 'Refresh Media Devices.'
|
||||
'message': $translate.instant('REFRESH_MEDIA_DEVICES')
|
||||
};
|
||||
|
||||
verto.refreshDevices(function(status) {
|
||||
@ -79,7 +78,7 @@
|
||||
'status': 'success',
|
||||
'soft': true,
|
||||
'activity': activity,
|
||||
'message': 'Check Connection Speed.'
|
||||
'message': $translate.instant('CHECK_CONNECTION_SPEED')
|
||||
};
|
||||
|
||||
if (storage.data.autoBand && verto.data.instance) {
|
||||
@ -101,7 +100,7 @@
|
||||
'status': 'promise',
|
||||
'soft': true,
|
||||
'activity': activity,
|
||||
'message': 'Provisioning configuration.'
|
||||
'message': $translate.instant('CHECK_PROVISIONING_CONF')
|
||||
};
|
||||
|
||||
var configResponse = config.configure();
|
||||
@ -116,7 +115,7 @@
|
||||
return result;
|
||||
} else {
|
||||
result['status'] = 'error';
|
||||
result['message'] = 'Error: Provision failed.';
|
||||
result['message'] = $translate.instant('ERROR_PROVISIONING_CONF');
|
||||
return result;
|
||||
}
|
||||
});
|
||||
@ -134,7 +133,7 @@
|
||||
'status': 'success',
|
||||
'soft': true,
|
||||
'activity': activity,
|
||||
'message': 'Checking login.'
|
||||
'message': $translate.instant('CHECK_LOGIN'),
|
||||
};
|
||||
|
||||
if(verto.data.connecting || verto.data.connected) {
|
||||
@ -179,19 +178,19 @@
|
||||
];
|
||||
|
||||
var progress_message = [
|
||||
'Checking browser compability.',
|
||||
'Checking media permissions',
|
||||
'Refresh Media Devices.',
|
||||
'Provisioning configuration.',
|
||||
'Checking login.',
|
||||
'Check Connection Speed.'
|
||||
$translate.instant('BROWSER_COMPATIBILITY'),
|
||||
$translate.instant('CHECK_PERMISSION_MEDIA'),
|
||||
$translate.instant('REFRESH_MEDIA_DEVICES'),
|
||||
$translate.instant('CHECK_PROVISIONING_CONF'),
|
||||
$translate.instant('CHECK_LOGIN'),
|
||||
$translate.instant('CHECK_CONNECTION_SPEED'),
|
||||
];
|
||||
|
||||
var getProgressMessage = function(current_progress) {
|
||||
if(progress_message[current_progress] != undefined) {
|
||||
return progress_message[current_progress];
|
||||
} else {
|
||||
return 'Please wait...';
|
||||
return $translate.instant('PLEASE_WAIT');
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -17,10 +17,11 @@
|
||||
'ui.gravatar',
|
||||
'ui.bootstrap',
|
||||
'directive.g+signin',
|
||||
'pascalprecht.translate',
|
||||
]);
|
||||
|
||||
vertoApp.config(['$routeProvider', 'gravatarServiceProvider',
|
||||
function($routeProvider, gravatarServiceProvider) {
|
||||
vertoApp.config(['$routeProvider', 'gravatarServiceProvider', '$translateProvider',
|
||||
function($routeProvider, gravatarServiceProvider, $translateProvider) {
|
||||
$routeProvider.
|
||||
when('/', {
|
||||
title: 'Loading',
|
||||
@ -59,6 +60,47 @@
|
||||
gravatarServiceProvider.defaults = {
|
||||
default: 'mm' // Mystery man as default for missing avatars
|
||||
};
|
||||
|
||||
|
||||
$translateProvider
|
||||
.useStaticFilesLoader({
|
||||
prefix: 'locales/locale-',
|
||||
suffix: '.json'
|
||||
})
|
||||
.registerAvailableLanguageKeys(['en', 'it', 'pt', 'fr', 'de', 'es', 'pl', 'ru', 'sv', 'id', 'zh'], {
|
||||
'en': 'en',
|
||||
'en_GB': 'en',
|
||||
'en_US': 'en',
|
||||
'it': 'it',
|
||||
'it_IT': 'it',
|
||||
'fr': 'fr',
|
||||
'fr_FR': 'fr',
|
||||
'fr_CA': 'fr',
|
||||
'pt': 'pt',
|
||||
'pt_BR': 'pt',
|
||||
'pt_PT': 'pt',
|
||||
'de': 'de',
|
||||
'de_DE': 'de',
|
||||
'es': 'es',
|
||||
'es_ES': 'es',
|
||||
'pl': 'pl',
|
||||
'pl_PL': 'pl',
|
||||
'ru': 'ru',
|
||||
'ru_RU': 'ru',
|
||||
'sv': 'sv',
|
||||
'sv_SV': 'sv',
|
||||
'sv_FI': 'sv',
|
||||
'id': 'id',
|
||||
'id_ID': 'id',
|
||||
'zh': 'zh',
|
||||
'zh_CN': 'zh',
|
||||
'zh_TW': 'zh',
|
||||
'zh_HK': 'zh'
|
||||
})
|
||||
.preferredLanguage('en')
|
||||
.determinePreferredLanguage()
|
||||
.fallbackLanguage('en')
|
||||
.useSanitizeValueStrategy(null);
|
||||
}
|
||||
]);
|
||||
|
||||
|
@ -5,9 +5,9 @@
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('ChatController', ['$scope', '$rootScope', '$http',
|
||||
'$location', '$anchorScroll', '$timeout', 'verto', 'prompt',
|
||||
'$location', '$anchorScroll', '$timeout', 'verto', 'prompt', '$translate',
|
||||
function($scope, $rootScope, $http, $location, $anchorScroll, $timeout,
|
||||
verto, prompt) {
|
||||
verto, prompt, $translate) {
|
||||
console.debug('Executing ChatController.');
|
||||
|
||||
function scrollToChatBottom() {
|
||||
@ -246,7 +246,7 @@
|
||||
console.log('$scope.confBanner');
|
||||
|
||||
prompt({
|
||||
title: 'Please insert the banner text',
|
||||
title: $translate.instant('TITLE_INSERT_BANNER'),
|
||||
input: true,
|
||||
label: '',
|
||||
value: '',
|
||||
@ -263,7 +263,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
shortPrompt('Please insert the Canvas Id', function(canvasID) {
|
||||
shortPrompt($translate.instant('TITLE_INSERT_CANVAS_ID'), function(canvasID) {
|
||||
console.log(memberID, canvasID);
|
||||
verto.setCanvasIn(memberID, canvasID);
|
||||
});
|
||||
@ -276,7 +276,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
shortPrompt('Please insert the Canvas Id', function(canvasID) {
|
||||
shortPrompt($translate.instant('TITLE_INSERT_CANVAS_ID'), function(canvasID) {
|
||||
verto.setCanvasOut(memberID, canvasID);
|
||||
});
|
||||
};
|
||||
@ -287,7 +287,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
shortPrompt('Please insert the Layer', function(canvasID) {
|
||||
shortPrompt($translate.instant('TITLE_INSERT_LAYER'), function(canvasID) {
|
||||
verto.setLayer(memberID, canvasID);
|
||||
});
|
||||
};
|
||||
@ -321,10 +321,10 @@
|
||||
$scope.confTransfer = function(memberID) {
|
||||
console.log('$scope.confTransfer');
|
||||
prompt({
|
||||
title: 'Transfer party?',
|
||||
message: 'To what destination would you like to transfer this call?',
|
||||
title: $translate.instant('TITLE_TRANSFER'),
|
||||
message: $translate.instant('MESSAGE_TRANSFER'),
|
||||
input: true,
|
||||
label: 'Destination',
|
||||
label: $translate.instant('LABEL_TRANSFER'),
|
||||
value: '',
|
||||
}).then(function(exten) {
|
||||
if (exten) {
|
||||
|
@ -89,7 +89,17 @@
|
||||
|
||||
if (extension.indexOf('-canvas-') != -1) {
|
||||
$rootScope.watcher = true;
|
||||
verto.call($rootScope.dialpadNumber, null, { useCamera: false, useMic: false, caller_id_name: null, userVariables: {}, caller_id_number: null, mirrorInput: false });
|
||||
verto.call($rootScope.dialpadNumber, null,
|
||||
{
|
||||
useCamera: "none",
|
||||
useMic: "none",
|
||||
useSpeak: "none",
|
||||
caller_id_name: null,
|
||||
userVariables: {},
|
||||
caller_id_number: null,
|
||||
mirrorInput: false
|
||||
}
|
||||
);
|
||||
$location.path('/incall');
|
||||
return;
|
||||
}
|
||||
@ -109,6 +119,7 @@
|
||||
* Call to the number in the $rootScope.dialpadNumber.
|
||||
*/
|
||||
$scope.loading = false;
|
||||
$scope.cancelled = false;
|
||||
$rootScope.call = function(extension) {
|
||||
if (!storage.data.testSpeedJoin || !$rootScope.dialpadNumber) {
|
||||
return call(extension);
|
||||
@ -116,10 +127,19 @@
|
||||
$scope.loading = true;
|
||||
|
||||
verto.testSpeed(function() {
|
||||
$scope.loading = false;
|
||||
call(extension);
|
||||
if ($scope.cancelled) {
|
||||
$scope.cancelled = false;
|
||||
$scope.loading = false;
|
||||
return;
|
||||
} else {
|
||||
call(extension);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$rootScope.cancel = function() {
|
||||
$scope.cancelled = true;
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('InCallController', ['$rootScope', '$scope',
|
||||
'$http', '$location', '$modal', '$timeout', 'toastr', 'verto', 'storage', 'prompt', 'Fullscreen',
|
||||
'$http', '$location', '$modal', '$timeout', 'toastr', 'verto', 'storage', 'prompt', 'Fullscreen', '$translate',
|
||||
function($rootScope, $scope, $http, $location, $modal, $timeout, toastr,
|
||||
verto, storage, prompt, Fullscreen) {
|
||||
verto, storage, prompt, Fullscreen, $translate) {
|
||||
|
||||
console.debug('Executing InCallController.');
|
||||
$scope.layout = null;
|
||||
@ -55,8 +55,8 @@
|
||||
*/
|
||||
$scope.videoCall = function() {
|
||||
prompt({
|
||||
title: 'Would you like to activate video for this call?',
|
||||
message: 'Video will be active during the next calls.'
|
||||
title: $translate.instant('TITLE_ENABLE_VIDEO'),
|
||||
message: $translate.instant('MESSAGE_ENABLE_VIDEO')
|
||||
}).then(function() {
|
||||
storage.data.videoCall = true;
|
||||
$scope.callTemplate = 'partials/video_call.html';
|
||||
|
@ -4,7 +4,7 @@
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('MainController',
|
||||
function($scope, $rootScope, $location, $modal, $timeout, $q, verto, storage, CallHistory, toastr, Fullscreen, prompt, eventQueue) {
|
||||
function($scope, $rootScope, $location, $modal, $timeout, $q, verto, storage, CallHistory, toastr, Fullscreen, prompt, eventQueue, $translate) {
|
||||
|
||||
console.debug('Executing MainController.');
|
||||
|
||||
@ -123,8 +123,8 @@
|
||||
|
||||
if (verto.data.call) {
|
||||
prompt({
|
||||
title: 'Oops, Active Call in Course.',
|
||||
message: 'It seems that you are in a call. Do you want to hang up?'
|
||||
title: $translate.instant('TITLE_ACTIVE_CALL'),
|
||||
message: $translate.instant('MESSAGE_ACTIVE_CALL_HANGUP')
|
||||
}).then(function() {
|
||||
disconnect();
|
||||
});
|
||||
@ -278,6 +278,12 @@
|
||||
angular.element('#wrapper').addClass('toggled');
|
||||
};
|
||||
|
||||
$scope.toggleSettings = function() {
|
||||
var settingsEl = angular.element(document.querySelector('#settings'));
|
||||
settingsEl.toggleClass('toggled');
|
||||
$rootScope.$emit('toggledSettings', settingsEl.hasClass('toggled'));
|
||||
};
|
||||
|
||||
$scope.goFullscreen = function() {
|
||||
if (storage.data.userStatus !== 'connected') {
|
||||
return;
|
||||
@ -320,8 +326,8 @@
|
||||
return $q(function(resolve, reject) {
|
||||
if (storage.data.askRecoverCall) {
|
||||
prompt({
|
||||
title: 'Oops, Active Call in Course.',
|
||||
message: 'It seems you were in a call before leaving the last time. Wanna go back to that?'
|
||||
title: $translate.instant('TITLE_ACTIVE_CALL'),
|
||||
message: $translate.instant('MESSAGE_ACTIVE_CALL_BACK')
|
||||
}).then(function() {
|
||||
console.log('redirect to incall page');
|
||||
$location.path('/incall');
|
||||
@ -417,8 +423,8 @@
|
||||
storage.data.mutedMic = false;
|
||||
|
||||
prompt({
|
||||
title: 'Incoming Call',
|
||||
message: 'from ' + data
|
||||
title: $translate.instant('TITLE_INCOMING_CALL'),
|
||||
message: $translate.instant('MESSAGE_INCOMING_CALL') + data
|
||||
}).then(function() {
|
||||
var call_start = new Date(storage.data.call_start);
|
||||
$rootScope.start_time = call_start;
|
||||
@ -444,7 +450,7 @@
|
||||
*/
|
||||
$scope.hangup = function() {
|
||||
if (!verto.data.call) {
|
||||
toastr.warning('There is no call to hangup.');
|
||||
toastr.warning($translate.instant('MESSAGE_NO_HANGUP_CALL'));
|
||||
$location.path('/dialpad');
|
||||
return;
|
||||
}
|
||||
@ -495,7 +501,7 @@
|
||||
};
|
||||
|
||||
$scope.play = function() {
|
||||
var file = $scope.promptInput('Please, enter filename', '', 'File',
|
||||
var file = $scope.promptInput($translate.instant('MESSAGE_ENTER_FILENAME'), '', 'File',
|
||||
function(file) {
|
||||
verto.data.conf.play(file);
|
||||
console.log('play file :', file);
|
||||
@ -508,7 +514,7 @@
|
||||
};
|
||||
|
||||
$scope.record = function() {
|
||||
var file = $scope.promptInput('Please, enter filename', '', 'File',
|
||||
var file = $scope.promptInput($translate.instant('MESSAGE_ENTER_FILENAME'), '', 'File',
|
||||
function(file) {
|
||||
verto.data.conf.record(file);
|
||||
console.log('recording file :', file);
|
||||
@ -520,7 +526,7 @@
|
||||
};
|
||||
|
||||
$scope.snapshot = function() {
|
||||
var file = $scope.promptInput('Please, enter filename', '', 'File',
|
||||
var file = $scope.promptInput($translate.instant('MESSAGE_ENTER_FILENAME'), '', 'File',
|
||||
function(file) {
|
||||
verto.data.conf.snapshot(file);
|
||||
console.log('snapshot file :', file);
|
||||
|
@ -4,9 +4,9 @@
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('PreviewController', ['$rootScope', '$scope',
|
||||
'$http', '$location', '$modal', '$timeout', 'toastr', 'verto', 'storage', 'prompt', 'Fullscreen',
|
||||
'$http', '$location', '$modal', '$timeout', 'toastr', 'verto', 'storage', 'prompt', 'Fullscreen', '$translate',
|
||||
function($rootScope, $scope, $http, $location, $modal, $timeout, toastr,
|
||||
verto, storage, prompt, Fullscreen) {
|
||||
verto, storage, prompt, Fullscreen, $translate) {
|
||||
|
||||
$scope.storage = storage;
|
||||
console.debug('Executing PreviewController.');
|
||||
@ -87,8 +87,8 @@
|
||||
|
||||
$scope.videoCall = function() {
|
||||
prompt({
|
||||
title: 'Would you like to activate video for this call?',
|
||||
message: 'Video will be active during the next calls.'
|
||||
title: $translate.instant('TITLE_ENABLE_VIDEO'),
|
||||
message: $translate.instant('MESSAGE_ENABLE_VIDEO')
|
||||
}).then(function() {
|
||||
storage.data.videoCall = true;
|
||||
$scope.callTemplate = 'partials/video_call.html';
|
||||
|
@ -3,16 +3,25 @@
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('ModalSettingsController', ['$scope', '$http',
|
||||
'$location', '$modalInstance', '$rootScope', 'storage', 'verto',
|
||||
function($scope, $http, $location, $modalInstance, $rootScope, storage, verto) {
|
||||
.controller('SettingsController', ['$scope', '$http',
|
||||
'$location', '$rootScope', 'storage', 'verto', '$translate', 'toastr',
|
||||
function($scope, $http, $location, $rootScope, storage, verto, $translate, toastr) {
|
||||
console.debug('Executing ModalSettingsController.');
|
||||
|
||||
$.material.init();
|
||||
|
||||
$scope.speakerFeature = typeof document.getElementById('webcam').sinkId !== 'undefined';
|
||||
$scope.storage = storage;
|
||||
$scope.verto = verto;
|
||||
$scope.mydata = angular.copy(storage.data);
|
||||
|
||||
$scope.speakerFeature = typeof document.getElementById('webcam').sinkId !== 'undefined';
|
||||
$rootScope.$on('toggledSettings', function(e, status) {
|
||||
if (status) {
|
||||
$scope.mydata = angular.copy(storage.data);
|
||||
} else {
|
||||
$scope.ok();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.ok = function() {
|
||||
if ($scope.mydata.selectedSpeaker != storage.data.selectedSpeaker) {
|
||||
@ -24,17 +33,24 @@
|
||||
if (storage.data.autoBand) {
|
||||
$scope.testSpeed();
|
||||
}
|
||||
$modalInstance.close('Ok.');
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
$scope.refreshDeviceList = function() {
|
||||
return verto.refreshDevices();
|
||||
};
|
||||
|
||||
$scope.showPreview = function() {
|
||||
var settingsEl = angular.element(document.querySelector('#settings'));
|
||||
settingsEl.toggleClass('toggled');
|
||||
if (!verto.data.call) {
|
||||
$location.path('/preview');
|
||||
return;
|
||||
}
|
||||
else {
|
||||
toastr.warning($translate.instant('MESSAGE_DISPLAY_SETTINGS'));
|
||||
}
|
||||
};
|
||||
|
||||
$scope.testSpeed = function() {
|
||||
return verto.testSpeed(cb);
|
||||
|
||||
@ -49,7 +65,6 @@
|
||||
if (confirm('Factory Reset Settings?')) {
|
||||
storage.factoryReset();
|
||||
$scope.logout();
|
||||
$modalInstance.close('Ok.');
|
||||
window.location.reload();
|
||||
};
|
||||
};
|
10
html5/verto/video_demo/js/verto-min.js
vendored
10
html5/verto/video_demo/js/verto-min.js
vendored
@ -6,7 +6,7 @@ function getCodecPayloadType(sdpLine){var pattern=new RegExp('a=rtpmap:(\\d+) \\
|
||||
function setDefaultCodec(mLine,payload){var elements=mLine.split(' ');var newLine=[];var index=0;for(var i=0;i<elements.length;i++){if(index===3){newLine[index++]=payload;}
|
||||
if(elements[i]!==payload)newLine[index++]=elements[i];}
|
||||
return newLine.join(' ');}
|
||||
$.FSRTC=function(options){this.options=$.extend({useVideo:null,useStereo:false,userData:null,localVideo:null,screenShare:false,useCamera:"any",iceServers:false,videoParams:{},audioParams:{},callbacks:{onICEComplete:function(){},onICE:function(){},onOfferSDP:function(){}},},options);this.audioEnabled=true;this.videoEnabled=true;this.mediaData={SDP:null,profile:{},candidateList:[]};if(moz){this.constraints={offerToReceiveAudio:true,offerToReceiveVideo:this.options.useVideo?true:false,};}else{this.constraints={optional:[{'DtlsSrtpKeyAgreement':'true'}],mandatory:{OfferToReceiveAudio:true,OfferToReceiveVideo:this.options.useVideo?true:false,}};}
|
||||
$.FSRTC=function(options){this.options=$.extend({useVideo:null,useStereo:false,userData:null,localVideo:null,screenShare:false,useCamera:"any",iceServers:false,videoParams:{},audioParams:{},callbacks:{onICEComplete:function(){},onICE:function(){},onOfferSDP:function(){}},},options);this.audioEnabled=true;this.videoEnabled=true;this.mediaData={SDP:null,profile:{},candidateList:[]};if(moz){this.constraints={offerToReceiveAudio:this.options.useSpeak==="none"?false:true,offerToReceiveVideo:this.options.useVideo?true:false,};}else{this.constraints={optional:[{'DtlsSrtpKeyAgreement':'true'}],mandatory:{OfferToReceiveAudio:this.options.useSpeak==="none"?false:true,OfferToReceiveVideo:this.options.useVideo?true:false,}};}
|
||||
if(self.options.useVideo){self.options.useVideo.style.display='none';}
|
||||
setCompat();checkCompat();};$.FSRTC.validRes=[];$.FSRTC.prototype.useVideo=function(obj,local){var self=this;if(obj){self.options.useVideo=obj;self.options.localVideo=local;if(moz){self.constraints.offerToReceiveVideo=true;}else{self.constraints.mandatory.OfferToReceiveVideo=true;}}else{self.options.useVideo=null;self.options.localVideo=null;if(moz){self.constraints.offerToReceiveVideo=false;}else{self.constraints.mandatory.OfferToReceiveVideo=false;}}
|
||||
if(self.options.useVideo){self.options.useVideo.style.display='none';}};$.FSRTC.prototype.useStereo=function(on){var self=this;self.options.useStereo=on;};$.FSRTC.prototype.stereoHack=function(sdp){var self=this;if(!self.options.useStereo){return sdp;}
|
||||
@ -218,14 +218,14 @@ dt.fnAdjustColumnSizing();break;case"modify":if(!args.data){return;}
|
||||
dt.fnUpdate(genRow(args.data),index);dt.fnAdjustColumnSizing();break;case"del":dt.fnDeleteRow(index);dt.fnAdjustColumnSizing();break;case"clear":dt.fnClearTable();break;case"reorder":dt.fnClearTable();dt.fnAddData(genArray(obj));break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;}
|
||||
if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}};la.onChange(la,{action:"init"});};var CONFMAN_SERNO=1;$.verto.conf=function(verto,params){var conf=this;conf.params=$.extend({dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);conf.verto=verto;conf.serno=CONFMAN_SERNO++;createMainModeratorMethods();verto.subscribe(conf.params.laData.modChannel,{handler:function(v,e){if(conf.params.onBroadcast){conf.params.onBroadcast(verto,conf,e.data);}}});verto.subscribe(conf.params.laData.chatChannel,{handler:function(v,e){if(typeof(conf.params.chatCallback)==="function"){conf.params.chatCallback(v,e);}}});};$.verto.conf.prototype.modCommand=function(cmd,id,value){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.conf.prototype.destroy=function(){var conf=this;conf.destroyed=true;conf.params.onBroadcast(conf.verto,conf,'destroy');if(conf.params.laData.modChannel){conf.verto.unsubscribe(conf.params.laData.modChannel);}
|
||||
if(conf.params.laData.chatChannel){conf.verto.unsubscribe(conf.params.laData.chatChannel);}};function createMainModeratorMethods(){$.verto.conf.prototype.listVideoLayouts=function(){this.modCommand("list-videoLayouts",null,null);};$.verto.conf.prototype.play=function(file){this.modCommand("play",null,file);};$.verto.conf.prototype.stop=function(){this.modCommand("stop",null,"all");};$.verto.conf.prototype.record=function(file){this.modCommand("recording",null,["start",file]);};$.verto.conf.prototype.stopRecord=function(){this.modCommand("recording",null,["stop","all"]);};$.verto.conf.prototype.snapshot=function(file){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
this.modCommand("vid-write-png",null,file);};$.verto.conf.prototype.setVideoLayout=function(layout){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
this.modCommand("vid-layout",null,layout);};$.verto.conf.prototype.kick=function(memberID){this.modCommand("kick",parseInt(memberID));};$.verto.conf.prototype.muteMic=function(memberID){this.modCommand("tmute",parseInt(memberID));};$.verto.conf.prototype.muteVideo=function(memberID){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
this.modCommand("vid-write-png",null,file);};$.verto.conf.prototype.setVideoLayout=function(layout,canvasID){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
if(canvasID){this.modCommand("vid-layout",null,[layout,canvasID]);}else{this.modCommand("vid-layout",null,layout);}};$.verto.conf.prototype.kick=function(memberID){this.modCommand("kick",parseInt(memberID));};$.verto.conf.prototype.muteMic=function(memberID){this.modCommand("tmute",parseInt(memberID));};$.verto.conf.prototype.muteVideo=function(memberID){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
this.modCommand("tvmute",parseInt(memberID));};$.verto.conf.prototype.presenter=function(memberID){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
this.modCommand("vid-res-id",parseInt(memberID),"presenter");};$.verto.conf.prototype.videoFloor=function(memberID){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
this.modCommand("vid-floor",parseInt(memberID),"force");};$.verto.conf.prototype.banner=function(memberID,text){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
this.modCommand("vid-banner",parseInt(memberID),escape(text));};$.verto.conf.prototype.volumeDown=function(memberID){this.modCommand("volume_out",parseInt(memberID),"down");};$.verto.conf.prototype.volumeUp=function(memberID){this.modCommand("volume_out",parseInt(memberID),"up");};$.verto.conf.prototype.gainDown=function(memberID){this.modCommand("volume_in",parseInt(memberID),"down");};$.verto.conf.prototype.gainUp=function(memberID){this.modCommand("volume_in",parseInt(memberID),"up");};$.verto.conf.prototype.transfer=function(memberID,exten){this.modCommand("transfer",parseInt(memberID),exten);};$.verto.conf.prototype.sendChat=function(message,type){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.chatChannel,"data":{"action":"send","message":message,"type":type}});};}
|
||||
$.verto.modfuncs={};$.verto.confMan=function(verto,params){var confMan=this;confMan.params=$.extend({tableID:null,statusID:null,mainModID:null,dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);confMan.verto=verto;confMan.serno=CONFMAN_SERNO++;confMan.canvasCount=confMan.params.laData.canvasCount;function genMainMod(jq){var play_id="play_"+confMan.serno;var stop_id="stop_"+confMan.serno;var recording_id="recording_"+confMan.serno;var snapshot_id="snapshot_"+confMan.serno;var rec_stop_id="recording_stop"+confMan.serno;var div_id="confman_"+confMan.serno;var html="<div id='"+div_id+"'><br>"+"<button class='ctlbtn' id='"+play_id+"'>Play</button>"+"<button class='ctlbtn' id='"+stop_id+"'>Stop</button>"+"<button class='ctlbtn' id='"+recording_id+"'>Record</button>"+"<button class='ctlbtn' id='"+rec_stop_id+"'>Record Stop</button>"+
|
||||
(confMan.params.hasVid?"<button class='ctlbtn' id='"+snapshot_id+"'>PNG Snapshot</button>":"")+"<br><br></div>";jq.html(html);$.verto.modfuncs.change_video_layout=function(id,canvas_id){var val=$("#"+id+" option:selected").text();if(val!=="none"){confMan.modCommand("vid-layout",null,[val,canvas_id]);}};if(confMan.params.hasVid){for(var j=0;j<confMan.canvasCount;j++){var vlayout_id="confman_vid_layout_"+j+"_"+confMan.serno;var vlselect_id="confman_vl_select_"+j+"_"+confMan.serno;var vlhtml="<div id='"+vlayout_id+"'><br>"+"<b>Video Layout Canvas "+(j+1)+"</b> <select onChange='$.verto.modfuncs.change_video_layout(\""+vlayout_id+"\", \""+j+"\")' id='"+vlselect_id+"'></select> "+"<br><br></div>";jq.append(vlhtml);}
|
||||
(confMan.params.hasVid?"<button class='ctlbtn' id='"+snapshot_id+"'>PNG Snapshot</button>":"")+"<br><br></div>";jq.html(html);$.verto.modfuncs.change_video_layout=function(id,canvas_id){var val=$("#"+id+" option:selected").text();if(val!=="none"){confMan.modCommand("vid-layout",null,[val,canvas_id]);}};if(confMan.params.hasVid){for(var j=0;j<confMan.canvasCount;j++){var vlayout_id="confman_vid_layout_"+j+"_"+confMan.serno;var vlselect_id="confman_vl_select_"+j+"_"+confMan.serno;var vlhtml="<div id='"+vlayout_id+"'><br>"+"<b>Video Layout Canvas "+(j+1)+"</b> <select onChange='$.verto.modfuncs.change_video_layout(\""+vlayout_id+"\", \""+(j+1)+"\")' id='"+vlselect_id+"'></select> "+"<br><br></div>";jq.append(vlhtml);}
|
||||
$("#"+snapshot_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("vid-write-png",null,file);}});}
|
||||
$("#"+play_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("play",null,file);}});$("#"+stop_id).click(function(){confMan.modCommand("stop",null,"all");});$("#"+recording_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("recording",null,["start",file]);}});$("#"+rec_stop_id).click(function(){confMan.modCommand("recording",null,["stop","all"]);});}
|
||||
function genControls(jq,rowid){var x=parseInt(rowid);var kick_id="kick_"+x;var canvas_in_next_id="canvas_in_next_"+x;var canvas_in_prev_id="canvas_in_prev_"+x;var canvas_out_next_id="canvas_out_next_"+x;var canvas_out_prev_id="canvas_out_prev_"+x;var canvas_in_set_id="canvas_in_set_"+x;var canvas_out_set_id="canvas_out_set_"+x;var layer_set_id="layer_set_"+x;var layer_next_id="layer_next_"+x;var layer_prev_id="layer_prev_"+x;var tmute_id="tmute_"+x;var tvmute_id="tvmute_"+x;var vbanner_id="vbanner_"+x;var tvpresenter_id="tvpresenter_"+x;var tvfloor_id="tvfloor_"+x;var box_id="box_"+x;var gainup_id="gain_in_up"+x;var gaindn_id="gain_in_dn"+x;var volup_id="vol_in_up"+x;var voldn_id="vol_in_dn"+x;var transfer_id="transfer"+x;var html="<div id='"+box_id+"'>";html+="<b>General Controls</b><hr noshade>";html+="<button class='ctlbtn' id='"+kick_id+"'>Kick</button>"+"<button class='ctlbtn' id='"+tmute_id+"'>Mute</button>"+"<button class='ctlbtn' id='"+gainup_id+"'>Gain -</button>"+"<button class='ctlbtn' id='"+gaindn_id+"'>Gain +</button>"+"<button class='ctlbtn' id='"+voldn_id+"'>Vol -</button>"+"<button class='ctlbtn' id='"+volup_id+"'>Vol +</button>"+"<button class='ctlbtn' id='"+transfer_id+"'>Transfer</button>";if(confMan.params.hasVid){html+="<br><br><b>Video Controls</b><hr noshade>";html+="<button class='ctlbtn' id='"+tvmute_id+"'>VMute</button>"+"<button class='ctlbtn' id='"+tvpresenter_id+"'>Presenter</button>"+"<button class='ctlbtn' id='"+tvfloor_id+"'>Vid Floor</button>"+"<button class='ctlbtn' id='"+vbanner_id+"'>Banner</button>";if(confMan.canvasCount>1){html+="<br><br><b>Canvas Controls</b><hr noshade>"+"<button class='ctlbtn' id='"+canvas_in_set_id+"'>Set Input Canvas</button>"+"<button class='ctlbtn' id='"+canvas_in_prev_id+"'>Prev Input Canvas</button>"+"<button class='ctlbtn' id='"+canvas_in_next_id+"'>Next Input Canvas</button>"+"<br>"+"<button class='ctlbtn' id='"+canvas_out_set_id+"'>Set Watching Canvas</button>"+"<button class='ctlbtn' id='"+canvas_out_prev_id+"'>Prev Watching Canvas</button>"+"<button class='ctlbtn' id='"+canvas_out_next_id+"'>Next Watching Canvas</button>";}
|
||||
@ -266,7 +266,7 @@ if(dialog.state==state||!checkStateChange(dialog.state,state)){console.error("Di
|
||||
console.log("Dialog "+dialog.callID+": state change from "+dialog.state.name+" to "+state.name);dialog.lastState=dialog.state;dialog.state=state;if(!dialog.causeCode){dialog.causeCode=16;}
|
||||
if(!dialog.cause){dialog.cause="NORMAL CLEARING";}
|
||||
if(dialog.callbacks.onDialogState){dialog.callbacks.onDialogState(this);}
|
||||
switch(dialog.state){case $.verto.enum.state.early:case $.verto.enum.state.active:var speaker=dialog.useSpeak;console.info("Using Speaker: ",speaker);if(speaker&&speaker!=="any"){setTimeout(function(){dialog.setAudioPlaybackDevice(speaker);},500);}
|
||||
switch(dialog.state){case $.verto.enum.state.early:case $.verto.enum.state.active:var speaker=dialog.useSpeak;console.info("Using Speaker: ",speaker);if(speaker&&speaker!=="any"&&speaker!=="none"){setTimeout(function(){dialog.setAudioPlaybackDevice(speaker);},500);}
|
||||
break;case $.verto.enum.state.trying:setTimeout(function(){if(dialog.state==$.verto.enum.state.trying){dialog.setState($.verto.enum.state.hangup);}},30000);break;case $.verto.enum.state.purge:dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.hangup:if(dialog.lastState.val>$.verto.enum.state.requesting.val&&dialog.lastState.val<$.verto.enum.state.hangup.val){dialog.sendMethod("verto.bye",{});}
|
||||
dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.destroy:delete dialog.verto.dialogs[dialog.callID];if(dialog.params.screenShare){dialog.rtc.stopPeer();}else{dialog.rtc.stop();}
|
||||
break;}
|
||||
|
@ -799,6 +799,7 @@ function docall() {
|
||||
|
||||
check_vid_res();
|
||||
console.error(outgoingBandwidth, incomingBandwidth);
|
||||
|
||||
cur_call = vertoHandle.newCall({
|
||||
destination_number: $("#ext").val(),
|
||||
caller_id_name: $("#cidname").val(),
|
||||
@ -807,9 +808,9 @@ function docall() {
|
||||
incomingBandwidth: incomingBandwidth,
|
||||
useVideo: check_vid(),
|
||||
useStereo: $("#use_stereo").is(':checked'),
|
||||
useCamera: sessid ? "none" : $("#usecamera").find(":selected").val(),
|
||||
useMic: $("#usemic").find(":selected").val(),
|
||||
useSpeak: $("#usespeak").find(":selected").val(),
|
||||
useCamera: (sessid || canvas_id) ? "none" : $("#usecamera").find(":selected").val(),
|
||||
useMic: (sessid || canvas_id) ? "none" : $("#usemic").find(":selected").val(),
|
||||
useSpeak: (sessid || canvas_id) ? "none" : $("#usespeak").find(":selected").val(),
|
||||
dedEnc: $("#use_dedenc").is(':checked'),
|
||||
mirrorInput: $("#mirror_input").is(':checked'),
|
||||
userVariables: {
|
||||
|
@ -1242,18 +1242,7 @@ static ftdm_status_t state_advance(ftdm_channel_t *chan)
|
||||
pri_hangup(isdn_data->spri.pri, call, caller_data->hangup_cause);
|
||||
|
||||
if (chan_priv->peerhangup) {
|
||||
/* Call is inbound and hangup has been initiated by peer */
|
||||
if (!ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
|
||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
|
||||
} else if (caller_data->hangup_cause == PRI_CAUSE_NO_USER_RESPONSE) {
|
||||
/* Can happen when we have a DL link expire or some timer expired */
|
||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
|
||||
} else if (caller_data->hangup_cause == PRI_CAUSE_DESTINATION_OUT_OF_ORDER) {
|
||||
/* Can happen when we have a DL link expire or some timer expired */
|
||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
|
||||
} else if (caller_data->hangup_cause == PRI_CAUSE_INVALID_NUMBER_FORMAT) {
|
||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
|
||||
}
|
||||
ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
scripts/dialog-installer.sh → scripts/FreeSWITCH-debian-raspbian-installer.sh
Normal file → Executable file
33
scripts/dialog-installer.sh → scripts/FreeSWITCH-debian-raspbian-installer.sh
Normal file → Executable file
@ -4,7 +4,6 @@
|
||||
#
|
||||
########################################################
|
||||
# TODO: FreeSWITCH AutoStart
|
||||
# TODO: Install on Raspbian
|
||||
# TODO: Allow Selection of Source or Package Install on Debian
|
||||
|
||||
DIALOG=${DIALOG=dialog}
|
||||
@ -17,7 +16,18 @@ install_prereqs() {
|
||||
#install the prereqs
|
||||
echo "Making sure we have the prereqs for this script to run. Please Stand by..."
|
||||
apt-get update 2>&1 >/dev/null
|
||||
apt-get install -y curl dialog git 2>&1 >/dev/null
|
||||
apt-get install -y curl dialog git ntpdate 2>&1 >/dev/null
|
||||
|
||||
# See if ntpd is running if it is, stop it set the current time as rpi has no RTC and this is needed
|
||||
# for SSL to function properly
|
||||
|
||||
if pgrep "ntpd" >/dev/null ; then
|
||||
/etc/init.d/ntp stop
|
||||
ntpdate pool.ntp.org
|
||||
/etc/init.d/ntp start
|
||||
else
|
||||
ntpdate pool.ntp.org
|
||||
fi
|
||||
}
|
||||
|
||||
welcome_screen() {
|
||||
@ -101,7 +111,7 @@ is_private_ip() {
|
||||
}
|
||||
|
||||
verify_ip_fqdn() {
|
||||
DNSIP=`dig +noall +answer @4.2.2.2 $FQDN | cut -d' ' -f3`
|
||||
DNSIP=`dig +noall +answer @4.2.2.2 $FQDN | awk '{print $5}'`
|
||||
|
||||
dialog --title "NO DNS For this FQDN" --clear \
|
||||
--menu "The FQDN and IP Address do not match what is available in Public DNS Servers." 15 60 5 \
|
||||
@ -132,13 +142,14 @@ config_fs_repos() {
|
||||
}
|
||||
|
||||
get_fs_source() {
|
||||
echo "REPO = $REPO"
|
||||
if [ ! -d /usr/src/freeswitch.git ]; then
|
||||
cd /usr/src
|
||||
git clone $REPO freeswitch.git
|
||||
else
|
||||
cd /usr/src/freeswitch.git
|
||||
git clean -fdx
|
||||
git reset -hard origin/$FS_REV
|
||||
git reset --hard origin/$FS_REV
|
||||
git pull
|
||||
fi
|
||||
}
|
||||
@ -164,7 +175,7 @@ install_certs() {
|
||||
NEED_CERTS_INSTALL=0
|
||||
else
|
||||
echo "Renewing LetsEncrypt Certs as they will expire in the next 30 days."
|
||||
./letsencrypt-auto renew
|
||||
./letsencrypt-auto renew --manual-public-ip-logging-ok
|
||||
fi
|
||||
else
|
||||
echo "Setting up LetsEncrypt and getting you some nice new Certs for this Server."
|
||||
@ -192,7 +203,9 @@ build_fs() {
|
||||
rm -rf /usr/local/freeswitch/{bin,mod,lib}/*
|
||||
fi
|
||||
cd /usr/src/freeswitch.git
|
||||
./bootstrap.sh -j
|
||||
if [ ! -d /usr/src/freeswitch.git/configure ]; then
|
||||
./bootstrap.sh -j
|
||||
fi
|
||||
./configure -C
|
||||
make -j$JLIMIT install
|
||||
make uhd-sounds-install
|
||||
@ -238,6 +251,7 @@ freeswitch_raspbian_source() {
|
||||
libtiff5-dev libperl-dev libgdbm-dev libdb-dev gettext libssl-dev libcurl4-openssl-dev libpcre3-dev libspeex-dev \
|
||||
libspeexdsp-dev libsqlite3-dev libedit-dev libldns-dev libpq-dev libsndfile-dev libopus-dev liblua5.1-0-dev 2>&1 | \
|
||||
awk -W interactive '/Progress/ { print }'| sed -u 's/[^0-9]//g' | dialog --gauge "Please wait.\n Installing Build Requirements..." 10 70 0
|
||||
build_fs
|
||||
|
||||
}
|
||||
|
||||
@ -247,11 +261,12 @@ fs_ver_select
|
||||
get_network_settings
|
||||
|
||||
if [ "$ID" = "debian" ]; then
|
||||
## These only work on Jessie at this time
|
||||
config_fs_repos
|
||||
freeswitch_debian_source
|
||||
elif [ "$ID" = "raspbian" ]; then
|
||||
#freeswitch_raspbiani123
|
||||
JLIMIT="3"
|
||||
freeswitch_raspbian_source
|
||||
fi
|
||||
|
||||
install_vc
|
||||
@ -264,10 +279,10 @@ if [ "x$PRIVIP" != "x$IPADDR" ]; then
|
||||
elif [ $VIPFQDN -eq 1 ]; then
|
||||
echo "Skipping LetsEncrypt\n"
|
||||
else
|
||||
get_dletsencrypt
|
||||
get_letsencrypt
|
||||
install_certs
|
||||
fi
|
||||
else
|
||||
echo "Skipping LetsEncrypt. Since we are on Private IP Space";
|
||||
echo "Skipping LetsEncrypt. Since we are on a Private IP Address";
|
||||
fi
|
||||
|
@ -42,6 +42,7 @@ SWITCH_BEGIN_EXTERN_C
|
||||
#define SWITCH_NO_CRYPTO_TAG -1
|
||||
|
||||
typedef enum {
|
||||
DTMF_AUTO,
|
||||
DTMF_2833,
|
||||
DTMF_INFO,
|
||||
DTMF_NONE
|
||||
|
@ -368,6 +368,19 @@ SWITCH_DECLARE(switch_image_t *) switch_img_write_text_img(int w, int h, switch_
|
||||
SWITCH_DECLARE(switch_image_t *) switch_img_read_file(const char* file_name);
|
||||
SWITCH_DECLARE(switch_status_t) switch_img_letterbox(switch_image_t *img, switch_image_t **imgP, int width, int height, const char *color);
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_has_video(void);
|
||||
|
||||
/*!\brief I420 to I420 Copy*/
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_I420_copy(const uint8_t* src_y, int src_stride_y,
|
||||
const uint8_t* src_u, int src_stride_u,
|
||||
const uint8_t* src_v, int src_stride_v,
|
||||
uint8_t* dst_y, int dst_stride_y,
|
||||
uint8_t* dst_u, int dst_stride_u,
|
||||
uint8_t* dst_v, int dst_stride_v,
|
||||
int width, int height);
|
||||
SWITCH_DECLARE(switch_status_t) switch_I420_copy2(uint8_t *src_planes[], int src_stride[],
|
||||
uint8_t *dst_planes[], int dst_stride[],
|
||||
int width, int height);
|
||||
/** @} */
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
@ -600,6 +600,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_3p_media(const char *uuid, switch_med
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_nomedia(const char *uuid, switch_media_flag_t flags);
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_3p_nomedia(const char *uuid, switch_media_flag_t flags);
|
||||
|
||||
SWITCH_DECLARE(void) switch_ivr_bg_media(const char *uuid, switch_media_flag_t flags, switch_bool_t on, switch_bool_t is3p, uint32_t delay);
|
||||
|
||||
/*!
|
||||
\brief Signal the session with a protocol specific hold message.
|
||||
\param uuid the uuid of the session to hold
|
||||
|
@ -326,6 +326,7 @@ typedef struct switch_mm_s {
|
||||
int vbuf;
|
||||
switch_video_profile_t vprofile;
|
||||
switch_video_encode_speed_t vencspd;
|
||||
uint8_t try_hardware_encoder;
|
||||
} switch_mm_t;
|
||||
|
||||
/*! an abstract representation of a file handle (some parameters based on compat with libsndfile) */
|
||||
@ -393,6 +394,10 @@ struct switch_file_handle {
|
||||
char *modname;
|
||||
switch_mm_t mm;
|
||||
switch_mutex_t *flag_mutex;
|
||||
/*! total video duration, or total page in pdf*/
|
||||
int64_t duration;
|
||||
/*! current video position, or current page in pdf */
|
||||
int64_t vpos;
|
||||
};
|
||||
|
||||
/*! \brief Abstract interface to an asr module */
|
||||
@ -633,6 +638,7 @@ struct switch_video_codec_settings {
|
||||
uint32_t bandwidth;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
uint8_t try_hardware_encoder;
|
||||
};
|
||||
|
||||
union switch_codec_settings {
|
||||
|
@ -2551,7 +2551,8 @@ typedef enum {
|
||||
SWITCH_MEDIA_FLOW_SENDRECV = 0,
|
||||
SWITCH_MEDIA_FLOW_SENDONLY,
|
||||
SWITCH_MEDIA_FLOW_RECVONLY,
|
||||
SWITCH_MEDIA_FLOW_INACTIVE
|
||||
SWITCH_MEDIA_FLOW_INACTIVE,
|
||||
SWITCH_MEDIA_FLOW_DISABLED
|
||||
} switch_media_flow_t;
|
||||
|
||||
typedef enum {
|
||||
@ -2599,7 +2600,8 @@ typedef enum {
|
||||
} switch_vid_spy_fmt_t;
|
||||
|
||||
typedef enum {
|
||||
SCFC_FLUSH_AUDIO
|
||||
SCFC_FLUSH_AUDIO,
|
||||
SCFC_PAUSE_READ
|
||||
} switch_file_command_t;
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
|
@ -27,7 +27,7 @@
|
||||
* Anthony Minessale <anthm@freeswitch.org>
|
||||
* Emmanuel Schmidbauer <eschmidbauer@gmail.com>
|
||||
*
|
||||
* mod_avcodec -- Codec with libav.org
|
||||
* mod_avcodec -- Codec with libav.org and ffmpeg
|
||||
*
|
||||
*/
|
||||
|
||||
@ -91,7 +91,11 @@ static const uint8_t *fs_avc_find_startcode_internal(const uint8_t *p, const uin
|
||||
|
||||
const uint8_t *fs_avc_find_startcode(const uint8_t *p, const uint8_t *end){
|
||||
const uint8_t *out= fs_avc_find_startcode_internal(p, end);
|
||||
if(p<out && out<end && !out[-1]) out--;
|
||||
|
||||
if (p < out && out < end && !out[-1]) {
|
||||
out--;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@ -150,8 +154,7 @@ typedef struct h263_state_s {
|
||||
int quant;
|
||||
} h263_state_t;
|
||||
|
||||
typedef struct our_h264_nalu_s
|
||||
{
|
||||
typedef struct our_h264_nalu_s {
|
||||
const uint8_t *start;
|
||||
const uint8_t *eat;
|
||||
uint32_t len;
|
||||
@ -181,9 +184,11 @@ typedef struct h264_codec_context_s {
|
||||
AVCodecContext *encoder_ctx;
|
||||
AVFrame *encoder_avframe;
|
||||
AVPacket encoder_avpacket;
|
||||
AVFrame *decoder_avframe;
|
||||
our_h264_nalu_t nalus[MAX_NALUS];
|
||||
enum AVCodecID av_codec_id;
|
||||
uint16_t last_seq; // last received frame->seq
|
||||
int hw_encoder;
|
||||
} h264_codec_context_t;
|
||||
|
||||
static uint8_t ff_input_buffer_padding[FF_INPUT_BUFFER_PADDING_SIZE] = { 0 };
|
||||
@ -420,9 +425,12 @@ static switch_status_t buffer_h263_rfc4629_packets(h264_codec_context_t *context
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef H263_MODE_B
|
||||
/* this function is depracated from ffmpeg 3.0 and
|
||||
https://lists.libav.org/pipermail/libav-devel/2015-October/072782.html
|
||||
*/
|
||||
void rtp_callback(struct AVCodecContext *avctx, void *data, int size, int mb_nb)
|
||||
{
|
||||
#ifndef H263_MODE_B
|
||||
uint8_t *d = data;
|
||||
uint32_t code = (ntohl(*(uint32_t *)data) & 0xFFFFFC00) >> 10;
|
||||
h264_codec_context_t *context = (h264_codec_context_t *)avctx->opaque;
|
||||
@ -449,8 +457,8 @@ void rtp_callback(struct AVCodecContext *avctx, void *data, int size, int mb_nb)
|
||||
size > 1500 ? "===============Exceedding MTU===============" : "");
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
const uint8_t *fs_h263_find_resync_marker_reverse(const uint8_t *restrict start,
|
||||
const uint8_t *restrict end)
|
||||
@ -728,81 +736,103 @@ static switch_status_t consume_h263p_bitstream(h264_codec_context_t *context, sw
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "len: %d, mark:%d %02x %02x %02x %02x\n", frame->datalen, frame->m, *p, *(p+1), *(p+2), *(p+3));
|
||||
}
|
||||
|
||||
if (frame->m) av_free_packet(&context->encoder_avpacket);
|
||||
if (frame->m) {
|
||||
av_packet_unref(&context->encoder_avpacket);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return frame->m ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_MORE_DATA;
|
||||
return SWITCH_STATUS_MORE_DATA;
|
||||
}
|
||||
|
||||
static switch_status_t consume_h264_bitstream(h264_codec_context_t *context, switch_frame_t *frame)
|
||||
{
|
||||
AVPacket *pkt = &context->encoder_avpacket;
|
||||
our_h264_nalu_t *nalu = &context->nalus[context->nalu_current_index];
|
||||
uint8_t nalu_hdr = *(uint8_t *)(nalu->start);
|
||||
uint8_t nalu_type = nalu_hdr & 0x1f;
|
||||
uint8_t nri = nalu_hdr & 0x60;
|
||||
int left = nalu->len - (nalu->eat - nalu->start);
|
||||
uint8_t *p = frame->data;
|
||||
uint8_t start = nalu->start == nalu->eat ? 0x80 : 0;
|
||||
|
||||
if (nalu->len <= SLICE_SIZE) {
|
||||
memcpy(frame->data, nalu->start, nalu->len);
|
||||
frame->datalen = nalu->len;
|
||||
context->nalu_current_index++;
|
||||
|
||||
if (nalu_type == 6 || nalu_type == 7 || nalu_type == 8 || context->nalus[context->nalu_current_index].len) {
|
||||
frame->m = 0;
|
||||
return SWITCH_STATUS_MORE_DATA;
|
||||
}
|
||||
|
||||
if (pkt->size > 0) av_packet_unref(pkt);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (left <= (SLICE_SIZE - 2)) {
|
||||
p[0] = nri | 28; // FU-A
|
||||
p[1] = 0x40 | nalu_type;
|
||||
memcpy(p+2, nalu->eat, left);
|
||||
nalu->eat += left;
|
||||
frame->datalen = left + 2;
|
||||
frame->m = 1;
|
||||
context->nalu_current_index++;
|
||||
if (pkt->size > 0) av_packet_unref(pkt);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
p[0] = nri | 28; // FU-A
|
||||
p[1] = start | nalu_type;
|
||||
if (start) nalu->eat++;
|
||||
memcpy(p+2, nalu->eat, SLICE_SIZE - 2);
|
||||
nalu->eat += (SLICE_SIZE - 2);
|
||||
frame->datalen = SLICE_SIZE;
|
||||
return SWITCH_STATUS_MORE_DATA;
|
||||
}
|
||||
|
||||
static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_t *frame)
|
||||
{
|
||||
AVPacket *pkt = &context->encoder_avpacket;
|
||||
our_h264_nalu_t *nalu = &context->nalus[context->nalu_current_index];
|
||||
|
||||
if (!nalu->len) {
|
||||
frame->datalen = 0;
|
||||
frame->m = 0;
|
||||
if (context->encoder_avpacket.size > 0) av_free_packet(&context->encoder_avpacket);
|
||||
// if (context->encoder_avframe->data[0]) av_freep(&context->encoder_avframe->data[0]);
|
||||
if (pkt->size > 0) av_packet_unref(pkt);
|
||||
context->nalu_current_index = 0;
|
||||
return SWITCH_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
if (context->av_codec_id == AV_CODEC_ID_H263) {
|
||||
return consume_h263_bitstream(context, frame);
|
||||
} else if (context->av_codec_id == AV_CODEC_ID_H263P) {
|
||||
}
|
||||
|
||||
if (context->av_codec_id == AV_CODEC_ID_H263P) {
|
||||
return consume_h263p_bitstream(context, frame);
|
||||
}
|
||||
|
||||
assert(nalu->len);
|
||||
|
||||
if (nalu->len <= SLICE_SIZE) {
|
||||
uint8_t nalu_hdr = *(uint8_t *)(nalu->start);
|
||||
uint8_t nalu_type = nalu_hdr & 0x1f;
|
||||
|
||||
memcpy(frame->data, nalu->start, nalu->len);
|
||||
frame->datalen = nalu->len;
|
||||
context->nalu_current_index++;
|
||||
if (nalu_type == 6 || nalu_type == 7 || nalu_type == 8) {
|
||||
frame->m = 0;
|
||||
return SWITCH_STATUS_MORE_DATA;
|
||||
}
|
||||
|
||||
frame->m = context->nalus[context->nalu_current_index].len ? 0 : 1;
|
||||
return frame->m ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_MORE_DATA;
|
||||
} else {
|
||||
uint8_t nalu_hdr = *(uint8_t *)(nalu->start);
|
||||
uint8_t nri = nalu_hdr & 0x60;
|
||||
uint8_t nalu_type = nalu_hdr & 0x1f;
|
||||
int left = nalu->len - (nalu->eat - nalu->start);
|
||||
uint8_t *p = frame->data;
|
||||
|
||||
if (left <= (SLICE_SIZE - 2)) {
|
||||
p[0] = nri | 28; // FU-A
|
||||
p[1] = 0x40 | nalu_type;
|
||||
memcpy(p+2, nalu->eat, left);
|
||||
nalu->eat += left;
|
||||
frame->datalen = left + 2;
|
||||
frame->m = 1;
|
||||
context->nalu_current_index++;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
uint8_t start = nalu->start == nalu->eat ? 0x80 : 0;
|
||||
|
||||
p[0] = nri | 28; // FU-A
|
||||
p[1] = start | nalu_type;
|
||||
if (start) nalu->eat++;
|
||||
memcpy(p+2, nalu->eat, SLICE_SIZE - 2);
|
||||
nalu->eat += (SLICE_SIZE - 2);
|
||||
frame->datalen = SLICE_SIZE;
|
||||
return SWITCH_STATUS_MORE_DATA;
|
||||
}
|
||||
}
|
||||
return consume_h264_bitstream(context, frame);
|
||||
}
|
||||
|
||||
static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t width, uint32_t height)
|
||||
{
|
||||
int sane = 0;
|
||||
|
||||
if (!context->encoder) context->encoder = avcodec_find_encoder(context->av_codec_id);
|
||||
if (!context->encoder) {
|
||||
if (context->av_codec_id == AV_CODEC_ID_H264) {
|
||||
if (context->codec_settings.video.try_hardware_encoder && (context->encoder = avcodec_find_encoder_by_name("nvenc_h264"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "NVENC HW CODEC ENABLED\n");
|
||||
context->hw_encoder = 1;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NVENC HW CODEC NOT PRESENT\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!context->encoder) {
|
||||
context->encoder = avcodec_find_encoder(context->av_codec_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!context->encoder) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find encoder id: %d\n", context->av_codec_id);
|
||||
@ -868,50 +898,60 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt
|
||||
context->encoder_ctx->bit_rate = context->bandwidth * 1024;
|
||||
context->encoder_ctx->rc_max_rate = context->bandwidth * 1024;
|
||||
context->encoder_ctx->rc_buffer_size = context->bandwidth * 1024 * 4;
|
||||
context->encoder_ctx->rtp_payload_size = SLICE_SIZE;
|
||||
|
||||
if (context->av_codec_id == AV_CODEC_ID_H263 || context->av_codec_id == AV_CODEC_ID_H263P) {
|
||||
#ifndef H263_MODE_B
|
||||
# if defined(__ICL) || defined (__INTEL_COMPILER)
|
||||
# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478))
|
||||
# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop))
|
||||
# elif defined(_MSC_VER)
|
||||
# define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:4996))
|
||||
# define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop))
|
||||
# else
|
||||
# define FF_DISABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
# define FF_ENABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"")
|
||||
# endif
|
||||
FF_DISABLE_DEPRECATION_WARNINGS
|
||||
context->encoder_ctx->rtp_callback = rtp_callback;
|
||||
FF_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
context->encoder_ctx->rc_min_rate = context->encoder_ctx->rc_max_rate;
|
||||
context->encoder_ctx->opaque = context;
|
||||
av_opt_set_int(context->encoder_ctx->priv_data, "mb_info", SLICE_SIZE - 8, 0);
|
||||
} else if (context->av_codec_id == AV_CODEC_ID_H264) {
|
||||
context->encoder_ctx->profile = FF_PROFILE_H264_BASELINE;
|
||||
context->encoder_ctx->level = 41;
|
||||
av_opt_set(context->encoder_ctx->priv_data, "preset", "veryfast", 0);
|
||||
av_opt_set(context->encoder_ctx->priv_data, "tune", "zerolatency", 0);
|
||||
av_opt_set(context->encoder_ctx->priv_data, "profile", "baseline", 0);
|
||||
//av_opt_set_int(context->encoder_ctx->priv_data, "slice-max-size", SLICE_SIZE, 0);
|
||||
|
||||
// libx264-medium.ffpreset preset
|
||||
if (context->hw_encoder) {
|
||||
av_opt_set(context->encoder_ctx->priv_data, "preset", "llhp", 0);
|
||||
av_opt_set_int(context->encoder_ctx->priv_data, "2pass", 1, 0);
|
||||
} else {
|
||||
av_opt_set(context->encoder_ctx->priv_data, "preset", "veryfast", 0);
|
||||
av_opt_set(context->encoder_ctx->priv_data, "tune", "zerolatency", 0);
|
||||
av_opt_set(context->encoder_ctx->priv_data, "profile", "baseline", 0);
|
||||
av_opt_set_int(context->encoder_ctx->priv_data, "slice-max-size", SLICE_SIZE, 0);
|
||||
av_opt_set_int(context->encoder_ctx->priv_data, "sc_threshold", 40, 0);
|
||||
av_opt_set_int(context->encoder_ctx->priv_data, "b_strategy", 1, 0);
|
||||
av_opt_set_int(context->encoder_ctx->priv_data, "crf", 18, 0);
|
||||
|
||||
context->encoder_ctx->coder_type = 1; // coder = 1
|
||||
context->encoder_ctx->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop
|
||||
context->encoder_ctx->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1
|
||||
context->encoder_ctx->me_method=ME_HEX; // me_method=hex
|
||||
//context->encoder_ctx->me_subpel_quality = 7; // subq=7
|
||||
// libx264-medium.ffpreset preset
|
||||
|
||||
context->encoder_ctx->me_range = 16; // me_range=16
|
||||
context->encoder_ctx->max_b_frames = 3; // bf=3
|
||||
|
||||
//context->encoder_ctx->refs = 3; // refs=3
|
||||
|
||||
//context->encoder_ctx->trellis = 1; // trellis=1
|
||||
|
||||
context->encoder_ctx->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop
|
||||
context->encoder_ctx->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1
|
||||
context->encoder_ctx->me_range = 21; // me_range=16
|
||||
context->encoder_ctx->max_b_frames = 3; // bf=3
|
||||
//context->encoder_ctx->refs = 3; // refs=3
|
||||
context->encoder_ctx->gop_size = 250; // g=250
|
||||
context->encoder_ctx->keyint_min = 25; // keyint_min=25
|
||||
context->encoder_ctx->i_quant_factor = 0.71; // i_qfactor=0.71
|
||||
context->encoder_ctx->b_quant_factor = 0.76923078; // Qscale difference between P-frames and B-frames.
|
||||
context->encoder_ctx->qcompress = 0.6; // qcomp=0.6
|
||||
context->encoder_ctx->qmin = 10; // qmin=10
|
||||
context->encoder_ctx->qmax = 51; // qmax=51
|
||||
context->encoder_ctx->max_qdiff = 4; // qdiff=4
|
||||
}
|
||||
}
|
||||
|
||||
// libx264-medium.ffpreset preset
|
||||
context->encoder_ctx->gop_size = 250; // g=250
|
||||
context->encoder_ctx->keyint_min = 25; // keyint_min=25
|
||||
context->encoder_ctx->scenechange_threshold = 40; // sc_threshold=40
|
||||
context->encoder_ctx->i_quant_factor = 0.71; // i_qfactor=0.71
|
||||
context->encoder_ctx->b_frame_strategy = 1; // b_strategy=1
|
||||
context->encoder_ctx->qcompress = 0.6; // qcomp=0.6
|
||||
context->encoder_ctx->qmin = 10; // qmin=10
|
||||
context->encoder_ctx->qmax = 51; // qmax=51
|
||||
context->encoder_ctx->max_qdiff = 4; // qdiff=4
|
||||
|
||||
|
||||
if (avcodec_open2(context->encoder_ctx, context->encoder, NULL) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open codec\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@ -923,66 +963,62 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt
|
||||
static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
|
||||
{
|
||||
int encoding, decoding;
|
||||
h264_codec_context_t *context = NULL;
|
||||
|
||||
encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
|
||||
decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
|
||||
|
||||
if (!(encoding || decoding)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
} else {
|
||||
h264_codec_context_t *context = NULL;
|
||||
if (codec->fmtp_in) {
|
||||
codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
|
||||
}
|
||||
|
||||
context = switch_core_alloc(codec->memory_pool, sizeof(h264_codec_context_t));
|
||||
switch_assert(context);
|
||||
memset(context, 0, sizeof(*context));
|
||||
|
||||
if (codec_settings) {
|
||||
context->codec_settings = *codec_settings;
|
||||
}
|
||||
|
||||
if (!strcmp(codec->implementation->iananame, "H263")) {
|
||||
context->av_codec_id = AV_CODEC_ID_H263;
|
||||
} else if (!strcmp(codec->implementation->iananame, "H263-1998")) {
|
||||
context->av_codec_id = AV_CODEC_ID_H263P;
|
||||
} else {
|
||||
context->av_codec_id = AV_CODEC_ID_H264;
|
||||
}
|
||||
|
||||
if (decoding) {
|
||||
context->decoder = avcodec_find_decoder(context->av_codec_id);
|
||||
|
||||
if (!context->decoder && context->av_codec_id == AV_CODEC_ID_H263P) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot find AV_CODEC_ID_H263P decoder, trying AV_CODEC_ID_H263 instead\n");
|
||||
context->decoder = avcodec_find_decoder(AV_CODEC_ID_H263);
|
||||
}
|
||||
|
||||
if (!context->decoder) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find codec id %d\n", context->av_codec_id);
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "codec: id=%d %s\n", context->decoder->id, context->decoder->long_name);
|
||||
|
||||
context->decoder_ctx = avcodec_alloc_context3(context->decoder);
|
||||
if (avcodec_open2(context->decoder_ctx, context->decoder, NULL) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error openning codec\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (encoding) {
|
||||
// never mind
|
||||
}
|
||||
|
||||
switch_buffer_create_dynamic(&(context->nalu_buffer), H264_NALU_BUFFER_SIZE, H264_NALU_BUFFER_SIZE * 8, 0);
|
||||
codec->private_info = context;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (codec->fmtp_in) {
|
||||
codec->fmtp_out = switch_core_strdup(codec->memory_pool, codec->fmtp_in);
|
||||
}
|
||||
|
||||
context = switch_core_alloc(codec->memory_pool, sizeof(h264_codec_context_t));
|
||||
switch_assert(context);
|
||||
memset(context, 0, sizeof(*context));
|
||||
|
||||
if (codec_settings) {
|
||||
context->codec_settings = *codec_settings;
|
||||
}
|
||||
|
||||
if (!strcmp(codec->implementation->iananame, "H263")) {
|
||||
context->av_codec_id = AV_CODEC_ID_H263;
|
||||
} else if (!strcmp(codec->implementation->iananame, "H263-1998")) {
|
||||
context->av_codec_id = AV_CODEC_ID_H263P;
|
||||
} else {
|
||||
context->av_codec_id = AV_CODEC_ID_H264;
|
||||
}
|
||||
|
||||
if (decoding) {
|
||||
context->decoder = avcodec_find_decoder(context->av_codec_id);
|
||||
|
||||
if (!context->decoder && context->av_codec_id == AV_CODEC_ID_H263P) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cannot find AV_CODEC_ID_H263P decoder, trying AV_CODEC_ID_H263 instead\n");
|
||||
context->decoder = avcodec_find_decoder(AV_CODEC_ID_H263);
|
||||
}
|
||||
|
||||
if (!context->decoder) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find codec id %d\n", context->av_codec_id);
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "codec: id=%d %s\n", context->decoder->id, context->decoder->long_name);
|
||||
|
||||
context->decoder_ctx = avcodec_alloc_context3(context->decoder);
|
||||
if (avcodec_open2(context->decoder_ctx, context->decoder, NULL) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error openning codec\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
switch_buffer_create_dynamic(&(context->nalu_buffer), H264_NALU_BUFFER_SIZE, H264_NALU_BUFFER_SIZE * 8, 0);
|
||||
codec->private_info = context;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
error:
|
||||
// todo, do some clean up
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@ -990,22 +1026,9 @@ error:
|
||||
|
||||
static void __attribute__((unused)) fill_avframe(AVFrame *pict, switch_image_t *img)
|
||||
{
|
||||
int i;
|
||||
uint8_t *y = img->planes[0];
|
||||
uint8_t *u = img->planes[1];
|
||||
uint8_t *v = img->planes[2];
|
||||
|
||||
/* Y */
|
||||
for (i = 0; i < pict->height; i++) {
|
||||
memcpy(&pict->data[0][i * pict->linesize[0]], y + i * img->stride[0], pict->width);
|
||||
}
|
||||
|
||||
/* U/V */
|
||||
for(i = 0; i < pict->height / 2; i++) {
|
||||
memcpy(&pict->data[1][i * pict->linesize[1]], u + i * img->stride[1], pict->width / 2);
|
||||
memcpy(&pict->data[2][i * pict->linesize[2]], v + i * img->stride[2], pict->width / 2);
|
||||
}
|
||||
|
||||
switch_I420_copy2(img->planes, img->stride,
|
||||
pict->data, pict->linesize,
|
||||
img->d_w, img->d_h);
|
||||
}
|
||||
|
||||
static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t *frame)
|
||||
@ -1029,7 +1052,8 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
|
||||
height = img->d_h;
|
||||
|
||||
if (context->av_codec_id == AV_CODEC_ID_H263 && (!is_valid_h263_dimension(width, height))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "You want %dx%d, but valid H263 sizes are 128x96, 176x144, 352x288, 704x576, and 1408x1152. Try H.263+\n", width, height);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"You want %dx%d, but valid H263 sizes are 128x96, 176x144, 352x288, 704x576, and 1408x1152. Try H.263+\n", width, height);
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -1149,7 +1173,10 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
|
||||
*got_output = 0;
|
||||
|
||||
if (context->av_codec_id == AV_CODEC_ID_H263) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG5, "Encoded frame %" SWITCH_INT64_T_FMT " (size=%5d) [0x%02x 0x%02x 0x%02x 0x%02x] got_output: %d slices: %d\n", context->pts, pkt->size, *((uint8_t *)pkt->data), *((uint8_t *)(pkt->data + 1)), *((uint8_t *)(pkt->data + 2)), *((uint8_t *)(pkt->data + 3)), *got_output, avctx->slices);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG5,
|
||||
"Encoded frame %" SWITCH_INT64_T_FMT " (size=%5d) [0x%02x 0x%02x 0x%02x 0x%02x] got_output: %d slices: %d\n",
|
||||
context->pts, pkt->size, *((uint8_t *)pkt->data), *((uint8_t *)(pkt->data + 1)), *((uint8_t *)(pkt->data + 2)),
|
||||
*((uint8_t *)(pkt->data + 3)), *got_output, avctx->slices);
|
||||
|
||||
#ifdef H263_MODE_B
|
||||
fs_rtp_parse_h263_rfc2190(context, pkt);
|
||||
@ -1158,12 +1185,17 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
|
||||
context->nalu_current_index = 0;
|
||||
return consume_nalu(context, frame);
|
||||
} else if (context->av_codec_id == AV_CODEC_ID_H263P){
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG5, "Encoded frame %" SWITCH_INT64_T_FMT " (size=%5d) [0x%02x 0x%02x 0x%02x 0x%02x] got_output: %d slices: %d\n", context->pts, pkt->size, *((uint8_t *)pkt->data), *((uint8_t *)(pkt->data + 1)), *((uint8_t *)(pkt->data + 2)), *((uint8_t *)(pkt->data + 3)), *got_output, avctx->slices);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG5,
|
||||
"Encoded frame %" SWITCH_INT64_T_FMT " (size=%5d) [0x%02x 0x%02x 0x%02x 0x%02x] got_output: %d slices: %d\n",
|
||||
context->pts, pkt->size, *((uint8_t *)pkt->data), *((uint8_t *)(pkt->data + 1)), *((uint8_t *)(pkt->data + 2)),
|
||||
*((uint8_t *)(pkt->data + 3)), *got_output, avctx->slices);
|
||||
fs_rtp_parse_h263_rfc4629(context, pkt);
|
||||
context->nalu_current_index = 0;
|
||||
return consume_nalu(context, frame);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG5, "Encoded frame %" SWITCH_INT64_T_FMT " (size=%5d) nalu_type=0x%x %d\n", context->pts, pkt->size, *((uint8_t *)pkt->data +4), *got_output);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG5,
|
||||
"Encoded frame %" SWITCH_INT64_T_FMT " (size=%5d) nalu_type=0x%x %d\n",
|
||||
context->pts, pkt->size, *((uint8_t *)pkt->data +4), *got_output);
|
||||
}
|
||||
/* split into nalus */
|
||||
memset(context->nalus, 0, sizeof(context->nalus));
|
||||
@ -1237,57 +1269,40 @@ static switch_status_t switch_h264_decode(switch_codec_t *codec, switch_frame_t
|
||||
|
||||
if (size > 0) {
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = NULL;
|
||||
pkt.size = 0;
|
||||
switch_buffer_write(context->nalu_buffer, ff_input_buffer_padding, sizeof(ff_input_buffer_padding));
|
||||
switch_buffer_peek_zerocopy(context->nalu_buffer, (const void **)&pkt.data);
|
||||
pkt.size = size;
|
||||
picture = av_frame_alloc();
|
||||
assert(picture);
|
||||
|
||||
if (!context->decoder_avframe) context->decoder_avframe = av_frame_alloc();
|
||||
picture = context->decoder_avframe;
|
||||
switch_assert(picture);
|
||||
decoded_len = avcodec_decode_video2(avctx, picture, &got_picture, &pkt);
|
||||
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buffer: %d got pic: %d len: %d [%dx%d]\n", size, got_picture, decoded_len, avctx->width, avctx->height);
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buffer: %d got pic: %d len: %d [%dx%d]\n", size, got_picture, decoded_len, picture->width, picture->height);
|
||||
|
||||
if (got_picture && decoded_len > 0) {
|
||||
int width = avctx->width;
|
||||
int height = avctx->height;
|
||||
int i;
|
||||
int width = picture->width;
|
||||
int height = picture->height;
|
||||
|
||||
if (!context->img || (context->img->d_w != width || context->img->d_h != height)) {
|
||||
//context->img = switch_img_wrap(NULL, SWITCH_IMG_FMT_I420, width, height, 0, picture->data[0]);
|
||||
switch_img_free(&context->img);
|
||||
context->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, width, height, 1);
|
||||
assert(context->img);
|
||||
switch_assert(context->img);
|
||||
}
|
||||
|
||||
#if 0
|
||||
context->img->w = picture->linesize[0];
|
||||
context->img->h = picture->linesize[1];
|
||||
context->img->d_w = width;
|
||||
context->img->d_h = height;
|
||||
|
||||
//context->img->planes[0] = picture->data[0];
|
||||
//context->img->planes[1] = picture->data[1];
|
||||
//context->img->planes[2] = picture->data[2];
|
||||
//context->img->stride[0] = picture->linesize[0];
|
||||
//context->img->stride[1] = picture->linesize[1];
|
||||
//context->img->stride[2] = picture->linesize[2];
|
||||
|
||||
for (i = 0; i < height; i++) {
|
||||
memcpy(context->img->planes[SWITCH_PLANE_Y] + context->img->stride[SWITCH_PLANE_Y] * i,
|
||||
picture->data[SWITCH_PLANE_Y] + picture->linesize[SWITCH_PLANE_Y] * i, width);
|
||||
}
|
||||
|
||||
for (i = 0; i < height / 2; i++) {
|
||||
memcpy(context->img->planes[SWITCH_PLANE_U] + context->img->stride[SWITCH_PLANE_U] * i,
|
||||
picture->data[SWITCH_PLANE_U] + picture->linesize[SWITCH_PLANE_U] * i, width / 2);
|
||||
memcpy(context->img->planes[SWITCH_PLANE_V] + context->img->stride[SWITCH_PLANE_V] * i,
|
||||
picture->data[SWITCH_PLANE_V] + picture->linesize[SWITCH_PLANE_V] * i, width / 2);
|
||||
}
|
||||
#endif
|
||||
switch_I420_copy2(picture->data, picture->linesize,
|
||||
context->img->planes, context->img->stride,
|
||||
width, height);
|
||||
|
||||
frame->img = context->img;
|
||||
}
|
||||
|
||||
av_frame_free(&picture);
|
||||
av_free_packet(&pkt);
|
||||
av_frame_unref(picture);
|
||||
}
|
||||
|
||||
switch_buffer_zero(context->nalu_buffer);
|
||||
@ -1366,6 +1381,10 @@ static switch_status_t switch_h264_destroy(switch_codec_t *codec)
|
||||
av_frame_free(&context->encoder_avframe);
|
||||
}
|
||||
|
||||
if (context->decoder_avframe) {
|
||||
av_frame_free(&context->decoder_avframe);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1416,8 +1435,9 @@ static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs)
|
||||
return 0;
|
||||
}
|
||||
desc = NULL;
|
||||
while ((desc = avcodec_descriptor_next(desc)))
|
||||
while ((desc = avcodec_descriptor_next(desc))) {
|
||||
codecs[i++] = desc;
|
||||
}
|
||||
switch_assert(i == nb_codecs);
|
||||
qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc);
|
||||
*rcodecs = codecs;
|
||||
@ -1430,8 +1450,9 @@ static void print_codecs_for_id(switch_stream_handle_t *stream, enum AVCodecID i
|
||||
|
||||
stream->write_function(stream, " (%s: ", encoder ? "encoders" : "decoders");
|
||||
|
||||
while ((codec = next_codec_for_id(id, codec, encoder)))
|
||||
while ((codec = next_codec_for_id(id, codec, encoder))) {
|
||||
stream->write_function(stream, "%s ", codec->name);
|
||||
}
|
||||
|
||||
stream->write_function(stream, ")");
|
||||
}
|
||||
|
@ -282,8 +282,15 @@ static switch_status_t add_stream(MediaStream *mst, AVFormatContext *fc, AVCodec
|
||||
int buffer_bytes = 2097152; /* 2 mb */
|
||||
int fps = 15;
|
||||
|
||||
/* find the encoder */
|
||||
*codec = avcodec_find_encoder(codec_id);
|
||||
if (mm->try_hardware_encoder && codec_id == AV_CODEC_ID_H264) {
|
||||
*codec = avcodec_find_encoder_by_name("nvenc_h264");
|
||||
}
|
||||
|
||||
if (!*codec) {
|
||||
/* find the encoder */
|
||||
*codec = avcodec_find_encoder(codec_id);
|
||||
}
|
||||
|
||||
if (!(*codec)) {
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find encoder for '%s'\n", avcodec_get_name(codec_id));
|
||||
return status;
|
||||
@ -360,13 +367,15 @@ static switch_status_t add_stream(MediaStream *mst, AVFormatContext *fc, AVCodec
|
||||
c->ticks_per_frame = 2;
|
||||
|
||||
|
||||
c->coder_type = 1; // coder = 1
|
||||
c->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop
|
||||
c->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1
|
||||
c->me_method=ME_HEX; // me_method=hex
|
||||
c->me_range = 16; // me_range=16
|
||||
c->max_b_frames = 3; // bf=3
|
||||
|
||||
|
||||
av_opt_set_int(c->priv_data, "b_strategy", 1, 0);
|
||||
av_opt_set_int(c->priv_data, "motion_est", ME_HEX, 0);
|
||||
av_opt_set_int(c->priv_data, "coder", 1, 0);
|
||||
|
||||
switch (mm->vprofile) {
|
||||
case SWITCH_VIDEO_PROFILE_BASELINE:
|
||||
av_opt_set(c->priv_data, "profile", "baseline", 0);
|
||||
@ -402,14 +411,12 @@ static switch_status_t add_stream(MediaStream *mst, AVFormatContext *fc, AVCodec
|
||||
|
||||
c->gop_size = 250; // g=250
|
||||
c->keyint_min = 25; // keyint_min=25
|
||||
c->scenechange_threshold = 40; // sc_threshold=40
|
||||
c->i_quant_factor = 0.71; // i_qfactor=0.71
|
||||
c->b_frame_strategy = 1; // b_strategy=1
|
||||
c->qcompress = 0.6; // qcomp=0.6
|
||||
c->qmin = 10; // qmin=10
|
||||
c->qmax = 31; // qmax=31
|
||||
c->max_qdiff = 4; // qdiff=4
|
||||
av_opt_set(c->priv_data, "crf", "18", 0);
|
||||
av_opt_set_int(c->priv_data, "crf", 18, 0);
|
||||
|
||||
|
||||
if (codec_id == AV_CODEC_ID_VP8) {
|
||||
@ -493,8 +500,18 @@ static switch_status_t open_audio(AVFormatContext *fc, AVCodec *codec, MediaStre
|
||||
c = mst->st->codec;
|
||||
|
||||
ret = avcodec_open2(c, codec, NULL);
|
||||
|
||||
if (ret == AVERROR_EXPERIMENTAL) {
|
||||
const AVCodecDescriptor *desc = avcodec_descriptor_get(c->codec_id);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Codec [%s] is experimental feature in libavcodec, never mind\n", desc->name);
|
||||
c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
|
||||
ret = avcodec_open2(c, codec, NULL);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open audio codec: %s\n", get_error_text(ret));
|
||||
const AVCodecDescriptor *desc = avcodec_descriptor_get(c->codec_id);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open audio codec [%s], error: %s\n", desc->name, get_error_text(ret));
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -677,21 +694,21 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
|
||||
eh->video_st->frame->pts += delta;
|
||||
} else {
|
||||
switch_core_timer_sync(eh->timer);
|
||||
|
||||
|
||||
if (eh->video_st->frame->pts == eh->timer->samplecount) {
|
||||
// never use the same pts, or the encoder coughs
|
||||
eh->video_st->frame->pts++;
|
||||
} else {
|
||||
uint64_t delta_tmp = eh->timer->samplecount - last_ts;
|
||||
|
||||
|
||||
if (delta_tmp > 10) {
|
||||
delta = delta_tmp;
|
||||
}
|
||||
|
||||
|
||||
eh->video_st->frame->pts = eh->timer->samplecount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
last_ts = eh->video_st->frame->pts;
|
||||
|
||||
//eh->video_st->frame->pts = switch_time_now() / 1000 - eh->video_st->next_pts;
|
||||
@ -709,7 +726,7 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
|
||||
switch_mutex_lock(eh->mutex);
|
||||
ret = write_frame(eh->fc, &eh->video_st->st->codec->time_base, eh->video_st->st, &pkt);
|
||||
switch_mutex_unlock(eh->mutex);
|
||||
av_free_packet(&pkt);
|
||||
av_packet_unref(&pkt);
|
||||
}
|
||||
|
||||
eh->in_callback = 0;
|
||||
@ -725,7 +742,7 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
|
||||
|
||||
av_init_packet(&pkt);
|
||||
|
||||
ret = avcodec_encode_video2(eh->video_st->st->codec, &pkt, eh->video_st->frame, &got_packet);
|
||||
ret = avcodec_encode_video2(eh->video_st->st->codec, &pkt, NULL, &got_packet);
|
||||
|
||||
if (ret < 0) {
|
||||
break;
|
||||
@ -733,8 +750,10 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
|
||||
switch_mutex_lock(eh->mutex);
|
||||
ret = write_frame(eh->fc, &eh->video_st->st->codec->time_base, eh->video_st->st, &pkt);
|
||||
switch_mutex_unlock(eh->mutex);
|
||||
av_free_packet(&pkt);
|
||||
av_packet_unref(&pkt);
|
||||
if (ret < 0) break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1075,7 +1094,7 @@ SWITCH_STANDARD_APP(record_av_function)
|
||||
|
||||
if (got_packet) {
|
||||
ret = write_frame(fc, &video_st.st->codec->time_base, video_st.st, &pkt);
|
||||
av_free_packet(&pkt);
|
||||
av_packet_unref(&pkt);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
@ -1245,6 +1264,8 @@ struct av_file_context {
|
||||
switch_image_t *last_img;
|
||||
int read_fps;
|
||||
switch_time_t last_vid_push;
|
||||
int64_t seek_ts;
|
||||
switch_bool_t read_paused;
|
||||
};
|
||||
|
||||
typedef struct av_file_context av_file_context_t;
|
||||
@ -1277,6 +1298,9 @@ static switch_status_t open_input_file(av_file_context_t *context, switch_file_h
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, err);
|
||||
}
|
||||
|
||||
handle->seekable = context->fc->iformat->read_seek2 ? 1 : (context->fc->iformat->read_seek ? 1 : 0);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "file %s is %sseekable\n", filename, handle->seekable ? "" : "not ");
|
||||
|
||||
/** Get information on the input file (number of streams etc.). */
|
||||
if ((error = avformat_find_stream_info(context->fc, NULL)) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open find stream info (error '%s')\n", get_error_text(error));
|
||||
@ -1293,6 +1317,7 @@ static switch_status_t open_input_file(av_file_context_t *context, switch_file_h
|
||||
context->video_st.st = context->fc->streams[i];
|
||||
if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
|
||||
context->has_video = 1;
|
||||
handle->duration = av_rescale_q(context->video_st.st->duration, context->video_st.st->time_base, AV_TIME_BASE_Q);
|
||||
}
|
||||
handle->mm.source_fps = ceil(av_q2d(context->video_st.st->avg_frame_rate));
|
||||
context->read_fps = (int)handle->mm.source_fps;
|
||||
@ -1346,14 +1371,18 @@ static switch_status_t open_input_file(av_file_context_t *context, switch_file_h
|
||||
av_opt_set_int(resample_ctx, "in_channel_count", c->channels, 0);
|
||||
av_opt_set_int(resample_ctx, "in_sample_rate", c->sample_rate, 0);
|
||||
av_opt_set_int(resample_ctx, "in_sample_fmt", c->sample_fmt, 0);
|
||||
av_opt_set_int(resample_ctx, "in_channel_layout", c->channel_layout, 0);
|
||||
av_opt_set_int(resample_ctx, "in_channel_layout",
|
||||
(c->channel_layout == 0 && c->channels == 2) ? AV_CH_LAYOUT_STEREO : c->channel_layout, 0);
|
||||
av_opt_set_int(resample_ctx, "out_channel_count", handle->channels, 0);
|
||||
av_opt_set_int(resample_ctx, "out_sample_rate", handle->samplerate,0);
|
||||
av_opt_set_int(resample_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
|
||||
av_opt_set_int(resample_ctx, "out_channel_layout", handle->channels == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO, 0);
|
||||
|
||||
if ((ret = avresample_open(resample_ctx)) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the resampling context\n");
|
||||
char errbuf[1024];
|
||||
av_strerror(ret, errbuf, 1024);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the resampling context, ret=%d: %s\n", ret, errbuf);
|
||||
av_free(resample_ctx);
|
||||
switch_goto_status(SWITCH_STATUS_FALSE, err);
|
||||
}
|
||||
@ -1392,11 +1421,32 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
|
||||
while (context->file_read_thread_running && !context->closed) {
|
||||
int vid_frames = 0;
|
||||
|
||||
if (context->seek_ts >= 0) {
|
||||
int stream_id = -1;
|
||||
|
||||
switch_mutex_lock(context->mutex);
|
||||
switch_buffer_zero(context->audio_buffer);
|
||||
switch_mutex_unlock(context->mutex);
|
||||
|
||||
if (context->eh.video_queue) {
|
||||
flush_video_queue(context->eh.video_queue, 0);
|
||||
}
|
||||
|
||||
// if (context->has_audio) stream_id = context->audio_st.st->index;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "seeking to %" SWITCH_INT64_T_FMT "\n", context->seek_ts);
|
||||
avformat_seek_file(context->fc, stream_id, 0, context->seek_ts, INT64_MAX, 0);
|
||||
context->seek_ts = -2;
|
||||
context->video_st.next_pts = 0;
|
||||
context->video_start_time = 0;
|
||||
|
||||
avcodec_flush_buffers(context->video_st.st->codec);
|
||||
}
|
||||
|
||||
if (context->has_video) {
|
||||
vid_frames = switch_queue_size(context->eh.video_queue);
|
||||
}
|
||||
|
||||
if (switch_buffer_inuse(context->audio_buffer) > AUDIO_BUF_SEC * context->audio_st.sample_rate * context->audio_st.channels * 2 &&
|
||||
if (switch_buffer_inuse(context->audio_buffer) > AUDIO_BUF_SEC * context->audio_st.sample_rate * context->audio_st.channels * 2 &&
|
||||
(!context->has_video || vid_frames > 5)) {
|
||||
switch_yield(context->has_video ? 1000 : 10000);
|
||||
continue;
|
||||
@ -1434,13 +1484,13 @@ again:
|
||||
|
||||
if ((error = avcodec_decode_video2(context->video_st.st->codec, vframe, &got_data, &pkt)) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not decode frame (error '%s')\n", get_error_text(error));
|
||||
av_free_packet(&pkt);
|
||||
av_packet_unref(&pkt);
|
||||
av_frame_free(&vframe);
|
||||
break;
|
||||
}
|
||||
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "pkt: %d, pts: %lld dts: %lld\n", pkt.size, pkt.pts, pkt.dts);
|
||||
av_free_packet(&pkt);
|
||||
av_packet_unref(&pkt);
|
||||
|
||||
//if (switch_queue_size(context->eh.video_queue) > 300) {
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Dropping frames\n");
|
||||
@ -1495,7 +1545,7 @@ again:
|
||||
|
||||
img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, vframe->width, vframe->height, 1);
|
||||
if (img) {
|
||||
uint64_t *pts = malloc(sizeof(uint64_t));
|
||||
int64_t *pts = malloc(sizeof(int64_t));
|
||||
|
||||
if (pts) {
|
||||
#ifdef ALT_WAY
|
||||
@ -1537,12 +1587,12 @@ again:
|
||||
|
||||
if ((error = avcodec_decode_audio4(context->audio_st.st->codec, &in_frame, &got_data, &pkt)) < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not decode frame (error '%s')\n", get_error_text(error));
|
||||
av_free_packet(&pkt);
|
||||
av_packet_unref(&pkt);
|
||||
break;
|
||||
}
|
||||
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "pkt: %d, decodedddd: %d pts: %lld dts: %lld\n", pkt.size, error, pkt.pts, pkt.dts);
|
||||
av_free_packet(&pkt);
|
||||
av_packet_unref(&pkt);
|
||||
|
||||
if (got_data) {
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got data frm->format: %d samples: %d\n", in_frame.format, in_frame.nb_samples);
|
||||
@ -1624,7 +1674,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
|
||||
memset(context, 0, sizeof(av_file_context_t));
|
||||
handle->private_info = context;
|
||||
context->pool = handle->memory_pool;
|
||||
|
||||
context->seek_ts = -1;
|
||||
context->offset = DFT_RECORD_OFFSET;
|
||||
if (handle->params && (tmp = switch_event_get_header(handle->params, "av_video_offset"))) {
|
||||
context->offset = atoi(tmp);
|
||||
@ -1699,7 +1749,7 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
|
||||
const AVCodecDescriptor *desc;
|
||||
|
||||
if ((handle->stream_name && (!strcasecmp(handle->stream_name, "rtmp") || !strcasecmp(handle->stream_name, "youtube")))) {
|
||||
|
||||
|
||||
if (fmt->video_codec != AV_CODEC_ID_H264 ) {
|
||||
fmt->video_codec = AV_CODEC_ID_H264; // force H264
|
||||
}
|
||||
@ -1915,6 +1965,15 @@ static switch_status_t av_file_command(switch_file_handle_t *handle, switch_file
|
||||
switch_buffer_zero(context->audio_buffer);
|
||||
switch_mutex_unlock(context->mutex);
|
||||
break;
|
||||
case SCFC_PAUSE_READ:
|
||||
if (context->read_paused) {
|
||||
context->read_paused = SWITCH_FALSE;
|
||||
context->video_st.next_pts = 0;
|
||||
context->video_start_time = 0;
|
||||
} else {
|
||||
context->read_paused = SWITCH_TRUE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1970,7 +2029,15 @@ static switch_status_t av_file_close(switch_file_handle_t *handle)
|
||||
|
||||
static switch_status_t av_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence)
|
||||
{
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "seek not implemented\n");
|
||||
av_file_context_t *context = (av_file_context_t *)handle->private_info;
|
||||
|
||||
if (whence == SEEK_SET) {
|
||||
handle->pos = handle->offset_pos = samples;
|
||||
}
|
||||
|
||||
context->seek_ts = samples / handle->native_rate * AV_TIME_BASE;
|
||||
*cur_sample = context->seek_ts;
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
@ -2067,6 +2134,7 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
double fl_to = 0.02;
|
||||
int do_fl = 0;
|
||||
int smaller_ts = context->read_fps;
|
||||
|
||||
if (!context->has_video) return SWITCH_STATUS_FALSE;
|
||||
|
||||
@ -2074,13 +2142,74 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
fl_to = (1000 / context->read_fps) * 1000;
|
||||
if (handle->mm.fps > 0 && handle->mm.fps < smaller_ts) {
|
||||
smaller_ts = handle->mm.fps;
|
||||
}
|
||||
|
||||
fl_to = (1000 / smaller_ts) * 1000;
|
||||
//printf("WTF %d (%f)\n",switch_queue_size(context->eh.video_queue), fl_to);
|
||||
if (flags & SVR_FLUSH) {
|
||||
max_delta = fl_to;
|
||||
do_fl = 1;
|
||||
}
|
||||
|
||||
if (!context->file_read_thread_running && switch_queue_size(context->eh.video_queue) == 0) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (context->read_paused) {
|
||||
int sanity = 10;
|
||||
|
||||
if (context->seek_ts == -2) { // just seeked, try read a new img
|
||||
again1:
|
||||
status = switch_queue_trypop(context->eh.video_queue, &pop);
|
||||
if (pop && status == SWITCH_STATUS_SUCCESS) {
|
||||
context->seek_ts = -1;
|
||||
switch_img_free(&context->last_img);
|
||||
context->last_img = (switch_image_t *)pop;
|
||||
switch_img_copy(context->last_img, &frame->img);
|
||||
context->vid_ready = 1;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (context->last_img) { // repeat the last img
|
||||
switch_img_copy(context->last_img, &frame->img);
|
||||
context->vid_ready = 1;
|
||||
context->seek_ts = -1;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if ((flags & SVR_BLOCK) && sanity-- > 0) {
|
||||
switch_yield(10000);
|
||||
goto again1;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
if (context->last_img) { // repeat the last img
|
||||
if ((flags & SVR_BLOCK)) switch_yield(100000);
|
||||
switch_img_copy(context->last_img, &frame->img);
|
||||
context->vid_ready = 1;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if ((flags & SVR_BLOCK)) {
|
||||
status = switch_queue_pop(context->eh.video_queue, &pop);
|
||||
} else {
|
||||
status = switch_queue_trypop(context->eh.video_queue, &pop);
|
||||
}
|
||||
|
||||
if (pop && status == SWITCH_STATUS_SUCCESS) {
|
||||
context->last_img = (switch_image_t *)pop;
|
||||
switch_img_copy(context->last_img, &frame->img);
|
||||
context->vid_ready = 1;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
|
||||
if (context->last_img) {
|
||||
if (mst->next_pts && (switch_time_now() - mst->next_pts > max_delta)) {
|
||||
switch_img_free(&context->last_img); // too late
|
||||
@ -2102,10 +2231,6 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
|
||||
}
|
||||
}
|
||||
|
||||
if (!context->file_read_thread_running && switch_queue_size(context->eh.video_queue) == 0) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (st->codec->time_base.num) {
|
||||
ticks = st->parser ? st->parser->repeat_pict + 1 : st->codec->ticks_per_frame;
|
||||
// mst->next_pts += ((int64_t)AV_TIME_BASE * st->codec->time_base.num * ticks) / st->codec->time_base.den;
|
||||
@ -2132,6 +2257,7 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
|
||||
|
||||
pts = av_rescale_q(*((uint64_t *)img->user_priv), st->time_base, AV_TIME_BASE_Q);
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "pkt_pts: %lld pts: %lld queue size: %u\n", *((uint64_t *)img->user_priv), pts, switch_queue_size(context->eh.video_queue));
|
||||
handle->vpos = pts;
|
||||
|
||||
if (!context->video_start_time) {
|
||||
context->video_start_time = now - pts;
|
||||
@ -2150,10 +2276,10 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
|
||||
if (pts == 0 || context->video_start_time == 0) mst->next_pts = 0;
|
||||
|
||||
if ((mst->next_pts && (now - mst->next_pts) > max_delta)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "picture is too late, off: %" SWITCH_INT64_T_FMT " max delta: %" SWITCH_INT64_T_FMT " queue size:%u\n", (int64_t)(now - mst->next_pts), max_delta, switch_queue_size(context->eh.video_queue));
|
||||
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "picture is too late, off: %" SWITCH_INT64_T_FMT " max delta: %" SWITCH_INT64_T_FMT " queue size:%u fps:%u/%0.2f\n", (int64_t)(now - mst->next_pts), max_delta, switch_queue_size(context->eh.video_queue), context->read_fps, handle->mm.fps);
|
||||
switch_img_free(&img);
|
||||
max_delta = AV_TIME_BASE;
|
||||
|
||||
//max_delta = AV_TIME_BASE;
|
||||
|
||||
if (switch_queue_size(context->eh.video_queue) > 0) {
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "WTF again\n");
|
||||
goto again;
|
||||
@ -2161,7 +2287,7 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
|
||||
mst->next_pts = 0;
|
||||
context->video_start_time = 0;
|
||||
return SWITCH_STATUS_BREAK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & SVR_BLOCK) || do_fl) {
|
||||
|
@ -2,7 +2,7 @@ include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_avmd
|
||||
|
||||
mod_LTLIBRARIES = mod_avmd.la
|
||||
mod_avmd_la_SOURCES = mod_avmd.c amplitude.c buffer.c desa2.c goertzel.c fast_acosf.c
|
||||
mod_avmd_la_SOURCES = mod_avmd.c avmd_buffer.c avmd_desa2_tweaked.c avmd_fast_acosf.c
|
||||
mod_avmd_la_CFLAGS = $(AM_CFLAGS) $(AM_MOD_AVMD_CXXFLAGS)
|
||||
mod_avmd_la_LIBADD = $(switch_builddir)/libfreeswitch.la
|
||||
mod_avmd_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
||||
|
@ -1,10 +0,0 @@
|
||||
#ifndef __AMPLITUDE_H__
|
||||
#define __AMPLITUDE_H__
|
||||
#include "buffer.h"
|
||||
|
||||
extern double amplitude(circ_buffer_t *, size_t i, double f);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
#ifndef __AMPLITUDE_H__
|
||||
#ifndef __AVMD_AMPLITUDE_H__
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include "amplitude.h"
|
||||
#include "psi.h"
|
||||
#include "avmd_amplitude.h"
|
||||
#include "avmd_psi.h"
|
||||
|
||||
/*! \brief
|
||||
* @author Eric des Courtis
|
||||
@ -10,14 +12,13 @@
|
||||
* @param f Frequency estimate
|
||||
* @return The amplitude at position i
|
||||
*/
|
||||
extern double amplitude(circ_buffer_t *b, size_t i, double f)
|
||||
extern double avmd_amplitude(circ_buffer_t *b, size_t i, double f)
|
||||
{
|
||||
double result;
|
||||
|
||||
result = sqrt(PSI(b, i) / sin(f * f));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __AVMD_AMPLITUDE_H__ */
|
||||
|
18
src/mod/applications/mod_avmd/avmd_amplitude.h
Normal file
18
src/mod/applications/mod_avmd/avmd_amplitude.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* @brief Estimation of amplitude using DESA-2 algorithm.
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_AMPLITUDE_H__
|
||||
#define __AVMD_AMPLITUDE_H__
|
||||
|
||||
|
||||
#include "avmd_buffer.h"
|
||||
|
||||
|
||||
extern double avmd_amplitude(circ_buffer_t *, size_t i, double f);
|
||||
|
||||
|
||||
#endif /* __AVMD_AMPLITUDE_H__ */
|
@ -1,5 +1,5 @@
|
||||
#ifndef __BUFFER_H__
|
||||
#include "buffer.h"
|
||||
#include "avmd_buffer.h"
|
||||
#endif
|
||||
|
||||
extern size_t next_power_of_2(size_t v)
|
@ -1,5 +1,15 @@
|
||||
#ifndef __BUFFER_H__
|
||||
#define __BUFFER_H__
|
||||
/*
|
||||
* @brief Circular buffer.
|
||||
*
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_BUFFER_H__
|
||||
#define __AVMD_BUFFER_H__
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
@ -55,6 +65,10 @@ extern size_t next_power_of_2(size_t v);
|
||||
if ((b)->backlog > (b)->buf_len) (b)->backlog = (b)->buf_len; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* ((f)[(b)->i] >= 0) ? \
|
||||
((BUFF_TYPE)(f)[(b)->i] / (BUFF_TYPE)INT16_MAX): \
|
||||
(0.0 - ((BUFF_TYPE)(f)[(b)->i] / (BUFF_TYPE)INT16_MIN)) \ */
|
||||
#define INSERT_INT16_FRAME(b, f, l) \
|
||||
{ \
|
||||
for ((b)->i = 0; (b)->i < (l); (b)->i++) { \
|
||||
@ -62,9 +76,7 @@ extern size_t next_power_of_2(size_t v);
|
||||
(b), \
|
||||
((b)->i + (b)->pos), \
|
||||
( \
|
||||
((f)[(b)->i] >= 0) ? \
|
||||
((BUFF_TYPE)(f)[(b)->i] / (BUFF_TYPE)INT16_MAX): \
|
||||
(0.0 - ((BUFF_TYPE)(f)[(b)->i] / (BUFF_TYPE)INT16_MIN)) \
|
||||
(BUFF_TYPE)(f)[(b)->i] \
|
||||
) \
|
||||
); \
|
||||
} \
|
||||
@ -92,14 +104,14 @@ extern size_t next_power_of_2(size_t v);
|
||||
|
||||
//#define DESTROY_CIRC_BUFFER(b) free((b)->buf)
|
||||
#define GET_BACKLOG_POS(b) ((b)->lpos - (b)->backlog)
|
||||
#define GET_CURRENT_POS(b) ((b)->lpos)
|
||||
#define GET_CURRENT_SAMPLE(b) GET_SAMPLE((b), GET_CURRENT_POS((b)))
|
||||
#define GET_CURRENT_POS(b) ((b)->pos)
|
||||
#define GET_CURRENT_LPOS(b) ((b)->lpos)
|
||||
#define GET_CURRENT_SAMPLE(b) GET_SAMPLE((b), GET_CURRENT_LPOS((b)))
|
||||
|
||||
#define ADD_SAMPLE(b, s) \
|
||||
do { \
|
||||
INC_POS((b)); \
|
||||
SET_SAMPLE((b), GET_CURRENT_POS((b)), (s)); \
|
||||
SET_SAMPLE((b), GET_CURRENT_LPOS((b)), (s)); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __AVMD_BUFFER_H__ */
|
@ -1,4 +1,6 @@
|
||||
#ifndef __DESA2_H__
|
||||
#ifndef __AVMD_DESA2_H__
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <float.h>
|
||||
@ -6,15 +8,15 @@
|
||||
#else
|
||||
#define ISNAN(x) (isnan(x))
|
||||
#endif
|
||||
#include "buffer.h"
|
||||
#include "desa2.h"
|
||||
#include "options.h"
|
||||
#include "avmd_buffer.h"
|
||||
#include "avmd_desa2.h"
|
||||
#include "avmd_options.h"
|
||||
|
||||
#ifdef FASTMATH
|
||||
#include "fast_acosf.h"
|
||||
#ifdef AVMD_FAST_MATH
|
||||
#include "avmd_fast_acosf.h"
|
||||
#endif
|
||||
|
||||
extern double desa2(circ_buffer_t *b, size_t i)
|
||||
extern double avmd_desa2(circ_buffer_t *b, size_t i)
|
||||
{
|
||||
double d;
|
||||
double n;
|
||||
@ -33,14 +35,11 @@ extern double desa2(circ_buffer_t *b, size_t i)
|
||||
x4 = GET_SAMPLE((b), ((i) + 4));
|
||||
|
||||
x2sq = x2 * x2;
|
||||
|
||||
d = 2.0 * ((x2sq) - (x1 * x3));
|
||||
if (d == 0.0) return 0.0;
|
||||
|
||||
n = ((x2sq) - (x0 * x4)) - ((x1 * x1) - (x0 * x2)) - ((x3 * x3) - (x2 * x4));
|
||||
|
||||
|
||||
#ifdef FASTMATH
|
||||
#ifdef AVMD_FAST_MATH
|
||||
result = 0.5 * (double)fast_acosf((float)n/d);
|
||||
#else
|
||||
result = 0.5 * acos(n/d);
|
||||
@ -52,4 +51,4 @@ extern double desa2(circ_buffer_t *b, size_t i)
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* __AVMD_DESA2_H__ */
|
19
src/mod/applications/mod_avmd/avmd_desa2.h
Normal file
19
src/mod/applications/mod_avmd/avmd_desa2.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* @brief DESA-2 algorithm implementation.
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_DESA2_H__
|
||||
#define __AVMD_DESA2_H__
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include "avmd_buffer.h"
|
||||
|
||||
/* Returns digital frequency estimation. */
|
||||
extern double avmd_desa2(circ_buffer_t *b, size_t i);
|
||||
|
||||
|
||||
#endif /* __AVMD_DESA2_H__ */
|
64
src/mod/applications/mod_avmd/avmd_desa2_tweaked.c
Normal file
64
src/mod/applications/mod_avmd/avmd_desa2_tweaked.c
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef __AVMD_DESA2_TWEAKED_H__
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <float.h>
|
||||
#define ISNAN(x) (!!(_isnan(x)))
|
||||
#else
|
||||
#define ISNAN(x) (isnan(x))
|
||||
#endif
|
||||
#include "avmd_buffer.h"
|
||||
#include "avmd_desa2_tweaked.h"
|
||||
#include "avmd_options.h"
|
||||
|
||||
#ifdef AVMD_FAST_MATH
|
||||
#include "avmd_fast_acosf.h"
|
||||
#endif
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
|
||||
double
|
||||
avmd_desa2_tweaked(circ_buffer_t *b, size_t i,
|
||||
switch_core_session_t *session)
|
||||
{
|
||||
double d;
|
||||
double n;
|
||||
double x0;
|
||||
double x1;
|
||||
double x2;
|
||||
double x3;
|
||||
double x4;
|
||||
double x2sq;
|
||||
double result;
|
||||
|
||||
x0 = GET_SAMPLE((b), (i));
|
||||
x1 = GET_SAMPLE((b), ((i) + 1));
|
||||
x2 = GET_SAMPLE((b), ((i) + 2));
|
||||
x3 = GET_SAMPLE((b), ((i) + 3));
|
||||
x4 = GET_SAMPLE((b), ((i) + 4));
|
||||
x2sq = x2 * x2;
|
||||
d = 2.0 * ((x2sq) - (x1 * x3));
|
||||
n = ((x2sq) - (x0 * x4)) - ((x1 * x1)
|
||||
- (x0 * x2)) - ((x3 * x3) - (x2 * x4));
|
||||
|
||||
/* instead of
|
||||
#ifdef FASTMATH
|
||||
result = 0.5 * (double)fast_acosf((float)n/d);
|
||||
#else
|
||||
result = 0.5 * acos(n/d);
|
||||
#endif
|
||||
we do simplified, modified for speed version : */
|
||||
|
||||
result = n/d;
|
||||
if (isinf(result)) {
|
||||
if (n < 0.0)
|
||||
return -10.0;
|
||||
else
|
||||
return 10.0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* __AVMD_DESA2_TWEAKED_H__ */
|
42
src/mod/applications/mod_avmd/avmd_desa2_tweaked.h
Normal file
42
src/mod/applications/mod_avmd/avmd_desa2_tweaked.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* @brief Estimator of cosine of digital frequency.
|
||||
* @details It is tweaked DESA implementation which
|
||||
* returns partial product of DESA-2 estimation
|
||||
* so that arc cosine transform can be ommited
|
||||
* on all computations, but these values can
|
||||
* be checked for convergence in the same time.
|
||||
* If the partial results converge then frequency
|
||||
* converges too.
|
||||
* @author Piotr Gregor < piotrek.gregor gmail.com >
|
||||
* @date 20 Mar 2016
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_DESA2_TWEAKED_H__
|
||||
#define __AVMD_DESA2_TWEAKED_H__
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include "avmd_buffer.h"
|
||||
#include <switch.h>
|
||||
|
||||
|
||||
/* Instead of returning digital frequency estimation using
|
||||
* result = 0.5 * acos(n/d),
|
||||
* which involves expensive computation of arc cosine on
|
||||
* each new sample, this function returns only (n/d) factor.
|
||||
* The series of these partial DESA-2 results can be still
|
||||
* checked for convergence, though measures and thresholds
|
||||
* used to assess this will differ from those used for
|
||||
* assessment of convergence of instantaneous frequency
|
||||
* estimates since transformation of tweaked results
|
||||
* to corresponding frequencies is nonlinear.
|
||||
* The actual frequency estimation can be retrieved later
|
||||
* from this partial result using
|
||||
* 0.5 * acos(n/d)
|
||||
*/
|
||||
double avmd_desa2_tweaked(circ_buffer_t *b, size_t i,
|
||||
switch_core_session_t *session);
|
||||
|
||||
|
||||
#endif /* __AVMD_DESA2_TWEAKED_H__ */
|
320
src/mod/applications/mod_avmd/avmd_fast_acosf.c
Normal file
320
src/mod/applications/mod_avmd/avmd_fast_acosf.c
Normal file
@ -0,0 +1,320 @@
|
||||
#include <switch.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "avmd_fast_acosf.h"
|
||||
#include "avmd_options.h"
|
||||
|
||||
#ifdef AVMD_FAST_MATH
|
||||
|
||||
|
||||
typedef union {
|
||||
uint32_t i;
|
||||
float f;
|
||||
} float_conv_t;
|
||||
|
||||
/*
|
||||
* Manipulate these parameters to change
|
||||
* mapping's resolution. The sine tone
|
||||
* of 1600Hz is detected even with 20
|
||||
* bits discarded in float integer representation
|
||||
* with only slightly increased amount of false
|
||||
* positives (keeping variance threshold on 0.0001).
|
||||
* 12 bits seem to be good choice when there is
|
||||
* a need to compute faster and/or decrease mapped file
|
||||
* size on disk while keeping false positives low.
|
||||
*/
|
||||
#define ACOS_TABLE_CONST_EXPONENT (0x70)
|
||||
#define ACOS_TABLE_CONST_EXPONENT_BITS (3)
|
||||
#define ACOS_TABLE_DISCARDED_BITS (3)
|
||||
/* rosolution:
|
||||
3: 15 728 640 indices spreading range [0.0, 1.0], table size on disk 134 217 728 bytes (default)
|
||||
4: 7 364 320 indices spreading range [0.0, 1.0], table size on disk 67 108 864 bytes
|
||||
5: 3 932 160 indices spreading range [0.0, 1.0], table size on disk 33 554 432 bytes
|
||||
12: 30 720 indices spreading range [0.0, 1.0], table size on disk 262 144 bytes
|
||||
16: 1 920 indices spreading range [0.0, 1.0], table size on disk 16 384 bytes
|
||||
20: 120 indices spreading range [0.0, 1.0], table size on disk 1 024 bytes
|
||||
24: 7 indices spreading range [0.0, 1.0], table size on disk 64 bytes
|
||||
26: 1 indices spreading range [0.0, 1.0], table size on disk 16 bytes
|
||||
*/
|
||||
#define ACOS_TABLE_FREE_EXPONENT_BITS (7 - ACOS_TABLE_CONST_EXPONENT_BITS)
|
||||
#define ACOS_TABLE_DATA_BITS (31 - ACOS_TABLE_CONST_EXPONENT_BITS - ACOS_TABLE_DISCARDED_BITS)
|
||||
#define ACOS_TABLE_LENGTH (1 << (31 - ACOS_TABLE_CONST_EXPONENT_BITS - ACOS_TABLE_DISCARDED_BITS))
|
||||
|
||||
#define VARIA_DATA_MASK (0x87FFFFFF & ~((1 << ACOS_TABLE_DISCARDED_BITS) - 1))
|
||||
#define CONST_DATA_MASK (((1 << ACOS_TABLE_CONST_EXPONENT_BITS) - 1) \
|
||||
<< (ACOS_TABLE_DATA_BITS - 1 + ACOS_TABLE_DISCARDED_BITS))
|
||||
|
||||
#define SIGN_UNPACK_MASK (1 << (ACOS_TABLE_DATA_BITS - 1))
|
||||
#define DATA_UNPACK_MASK ((1 << (ACOS_TABLE_DATA_BITS - 1)) - 1)
|
||||
|
||||
#define SIGN_MASK (0x80000000)
|
||||
#define DATA_MASK (DATA_UNPACK_MASK << ACOS_TABLE_DISCARDED_BITS)
|
||||
|
||||
#define ACOS_TABLE_FILENAME "/tmp/acos_table.dat"
|
||||
|
||||
static uint32_t index_from_float(float f);
|
||||
static float float_from_index(uint32_t d);
|
||||
static float *acos_table = NULL;
|
||||
static int acos_fd = -1;
|
||||
|
||||
|
||||
#ifdef FAST_ACOSF_TESTING
|
||||
|
||||
#define INF(x) printf("[%s] [%u]\n", #x, x)
|
||||
#define INFX(x) printf("[%s] [%08x]\n", #x, x)
|
||||
|
||||
static void
|
||||
debug_print(void);
|
||||
|
||||
static void
|
||||
dump_table_summary(void);
|
||||
|
||||
#endif /* FAST_ACOSF_TESTING */
|
||||
|
||||
|
||||
extern int compute_table(void)
|
||||
{
|
||||
uint32_t i;
|
||||
float f;
|
||||
FILE *acos_table_file;
|
||||
size_t res;
|
||||
|
||||
acos_table_file = fopen(ACOS_TABLE_FILENAME, "w");
|
||||
|
||||
for (i = 0; i < ACOS_TABLE_LENGTH; i++) {
|
||||
f = acosf(float_from_index(i));
|
||||
res = fwrite(&f, sizeof(f), 1, acos_table_file);
|
||||
if (res != 1) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
res = fclose(acos_table_file);
|
||||
if (res != 0) {
|
||||
return -2;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fclose(acos_table_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern int init_fast_acosf(void)
|
||||
{
|
||||
int ret, errsv;
|
||||
FILE *acos_fp;
|
||||
char err[150];
|
||||
|
||||
if (acos_table == NULL) {
|
||||
ret = access(ACOS_TABLE_FILENAME, F_OK);
|
||||
if (ret == -1) {
|
||||
/* file doesn't exist, bad permissions,
|
||||
* or some other error occured */
|
||||
errsv = errno;
|
||||
strerror_r(errsv, err, 150);
|
||||
if (errsv != ENOENT) return -1;
|
||||
else {
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_NOTICE,
|
||||
"File [%s] doesn't exist. Creating file...\n", ACOS_TABLE_FILENAME
|
||||
);
|
||||
ret = compute_table();
|
||||
if (ret != 0) return -2;
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_INFO,
|
||||
"Using previously created file [%s]\n", ACOS_TABLE_FILENAME
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
acos_fp = fopen(ACOS_TABLE_FILENAME, "r");
|
||||
if (acos_fp == NULL) return -3;
|
||||
/* can't fail */
|
||||
acos_fd = fileno(acos_fp);
|
||||
acos_table = (float *) mmap(
|
||||
NULL, /* kernel chooses the address at which to create the mapping */
|
||||
ACOS_TABLE_LENGTH * sizeof(float),
|
||||
PROT_READ,
|
||||
MAP_SHARED | MAP_POPULATE, /* read-ahead on the file. Later accesses to the mapping
|
||||
* will not be blocked by page faults */
|
||||
acos_fd,
|
||||
0
|
||||
);
|
||||
if (acos_table == MAP_FAILED) return -4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern int destroy_fast_acosf(void)
|
||||
{
|
||||
if (munmap(acos_table, ACOS_TABLE_LENGTH) == -1) return -1;
|
||||
if (acos_fd != -1) {
|
||||
if (close(acos_fd) == -1) return -2;
|
||||
}
|
||||
/* disable use of fast arc cosine file */
|
||||
acos_table = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern float fast_acosf(float x)
|
||||
{
|
||||
return acos_table[index_from_float(x)];
|
||||
}
|
||||
|
||||
static uint32_t index_from_float(float f)
|
||||
{
|
||||
float_conv_t d;
|
||||
d.f = f;
|
||||
return ((d.i & SIGN_MASK) >> (32 - ACOS_TABLE_DATA_BITS)) |
|
||||
((d.i & DATA_MASK) >> ACOS_TABLE_DISCARDED_BITS);
|
||||
}
|
||||
|
||||
static float float_from_index(uint32_t d)
|
||||
{
|
||||
float_conv_t f;
|
||||
f.i = ((d & SIGN_UNPACK_MASK) << (32 - ACOS_TABLE_DATA_BITS)) |
|
||||
((d & DATA_UNPACK_MASK) << ACOS_TABLE_DISCARDED_BITS) | CONST_DATA_MASK;
|
||||
return f.f;
|
||||
}
|
||||
|
||||
#ifdef FAST_ACOSF_TESTING
|
||||
|
||||
#define INF(x) printf("[%s] [%u]\n", #x, x)
|
||||
#define INFX(x) printf("[%s] [%08x]\n", #x, x)
|
||||
|
||||
static void
|
||||
debug_print(void)
|
||||
{
|
||||
INF(ACOS_TABLE_CONST_EXPONENT);
|
||||
INF(ACOS_TABLE_CONST_EXPONENT_BITS);
|
||||
INF(ACOS_TABLE_FREE_EXPONENT_BITS);
|
||||
INF(ACOS_TABLE_DISCARDED_BITS);
|
||||
INF(ACOS_TABLE_DATA_BITS);
|
||||
INF(ACOS_TABLE_LENGTH);
|
||||
INFX(VARIA_DATA_MASK);
|
||||
INFX(CONST_DATA_MASK);
|
||||
INFX(SIGN_UNPACK_MASK);
|
||||
INFX(DATA_UNPACK_MASK);
|
||||
INFX(SIGN_MASK);
|
||||
INFX(DATA_MASK);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_table_summary(void)
|
||||
{
|
||||
uint32_t i, i_0, i_1, di;
|
||||
float f;
|
||||
|
||||
i = 1;
|
||||
i_0 = index_from_float(0.0);
|
||||
i_1 = index_from_float(1.0);
|
||||
di = (i_1 - i_0)/100;
|
||||
if (di == 0) di = 1;
|
||||
|
||||
for (; i < ACOS_TABLE_LENGTH; i += di )
|
||||
{
|
||||
f = float_from_index(i);
|
||||
printf("-01i[%.10u] : ffi[%f] fa[%f] acos[%f]\n",
|
||||
i, f, fast_acosf(f), acos(f));
|
||||
}
|
||||
|
||||
i = 1;
|
||||
for (; i < ACOS_TABLE_LENGTH; i = (i << 1))
|
||||
{
|
||||
f = fast_acosf(float_from_index(i));
|
||||
printf("--i[%.10u] : fa[%f] ffi[%f]\n",
|
||||
i, f, float_from_index(i));
|
||||
}
|
||||
|
||||
f = 0.0;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.1;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.2;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.3;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.4;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.5;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.6;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.7;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 7.5;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.8;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.9;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.95;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.99;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 1.0;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 1.1;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 1.2;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = 0.0;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.1;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.2;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.3;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.4;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.5;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.6;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.7;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -7.5;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.8;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.9;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.95;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -0.99;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -1.0;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -1.1;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
f = -1.2;
|
||||
printf("i [%d] from float [%f]\n", index_from_float(f), f);
|
||||
}
|
||||
|
||||
#endif /* FAST_ACOSF_TESTING */
|
||||
|
||||
|
||||
#endif
|
53
src/mod/applications/mod_avmd/avmd_fast_acosf.h
Normal file
53
src/mod/applications/mod_avmd/avmd_fast_acosf.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* @brief Fast arithmetic using precomputed arc cosine table.
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_FAST_ACOSF_H__
|
||||
#define __AVMD_FAST_ACOSF_H__
|
||||
|
||||
|
||||
#define ACOS_TABLE_FILENAME "/tmp/acos_table.dat"
|
||||
|
||||
|
||||
/*! \brief Arc cosine table initialization.
|
||||
*
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
* @return 0 on success, negative value otherwise:
|
||||
* -1 can't access arc cos table with error != NOENT,
|
||||
* -2 table creation failed (compute_table)
|
||||
* -3 can access table but fopen failed
|
||||
* -4 mmap failed
|
||||
*/
|
||||
extern int init_fast_acosf(void);
|
||||
|
||||
/*! \brief Arc cosine table deinitialization.
|
||||
*
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
* @return 0 on success, negative value otherwise:
|
||||
* -1 munmap failed,
|
||||
* -2 close failed
|
||||
*/
|
||||
extern int destroy_fast_acosf(void);
|
||||
|
||||
/*! \brief Return arc cos for this argument.
|
||||
* @details Uses previously created and mmapped file.
|
||||
* @author Eric des Courtis
|
||||
*/
|
||||
extern float fast_acosf(float x);
|
||||
|
||||
/*! \brief Arc cosine table creation.
|
||||
*
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
* @return 0 on success, negative value otherwise:
|
||||
* -1 fwrite failed,
|
||||
* -2 fclose failed
|
||||
*/
|
||||
extern int compute_table(void);
|
||||
|
||||
#endif /* __AVMD_FAST_ACOSF_H__ */
|
17
src/mod/applications/mod_avmd/avmd_fir.h
Normal file
17
src/mod/applications/mod_avmd/avmd_fir.h
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* @brief Filters.
|
||||
* @author Piotr Gregor < piotrek.gregor gmail.com >
|
||||
* @date 23 Mar 2016
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_FIR_H__
|
||||
#define __AVMD_FIR_H__
|
||||
|
||||
|
||||
#define DESA_MAX(a, b) (a) > (b) ? (a) : (b)
|
||||
#define MEDIAN_FILTER(a, b, c) (a) > (b) ? ((a) > (c) ? \
|
||||
DESA_MAX((b), (c)) : a) : ((b) > (c) ? DESA_MAX((a), (c)) : (b))
|
||||
|
||||
|
||||
#endif
|
30
src/mod/applications/mod_avmd/avmd_goertzel.c
Normal file
30
src/mod/applications/mod_avmd/avmd_goertzel.c
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __AVMD_GOERTZEL_H__
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include "avmd_goertzel.h"
|
||||
#include "avmd_buffer.h"
|
||||
|
||||
|
||||
extern double avmd_goertzel(circ_buffer_t *b, size_t pos, double f, size_t num)
|
||||
{
|
||||
double s = 0.0;
|
||||
double p = 0.0;
|
||||
double p2 = 0.0;
|
||||
double coeff;
|
||||
size_t i;
|
||||
|
||||
coeff = 2.0 * cos(2.0 * M_PI * f);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* TODO: optimize to avoid GET_SAMPLE when possible */
|
||||
s = GET_SAMPLE(b, i + pos) + (coeff * p) - p2;
|
||||
p2 = p;
|
||||
p = s;
|
||||
}
|
||||
|
||||
return (p2 * p2) + (p * p) - (coeff * p2 * p);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __AVMD_GOERTZEL_H__ */
|
33
src/mod/applications/mod_avmd/avmd_goertzel.h
Normal file
33
src/mod/applications/mod_avmd/avmd_goertzel.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* @brief Goertzel algorithm.
|
||||
* @author Eric des Courtis
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_GOERTZEL_H__
|
||||
#define __AVMD_GOERTZEL_H__
|
||||
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include "avmd_buffer.h"
|
||||
|
||||
#if !defined(M_PI)
|
||||
/* C99 systems may not define M_PI */
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
|
||||
|
||||
/*! \brief Identify frequency components of a signal
|
||||
* @author Eric des Courtis
|
||||
* @param b A circular buffer
|
||||
* @param pos Position in the buffer
|
||||
* @param f Frequency to look at
|
||||
* @param num Number of samples to look at
|
||||
* @return A power estimate for frequency f at position pos in the stream
|
||||
*/
|
||||
extern double avmd_goertzel(circ_buffer_t *b, size_t pos, double f, size_t num);
|
||||
|
||||
|
||||
#endif /* __AVMD_GOERTZEL_H__ */
|
49
src/mod/applications/mod_avmd/avmd_options.h
Normal file
49
src/mod/applications/mod_avmd/avmd_options.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* @brief Options controlling avmd module.
|
||||
*
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_OPTIONS_H__
|
||||
#define __AVMD_OPTIONS_H__
|
||||
|
||||
|
||||
/* define/undefine this to enable/disable printing of avmd
|
||||
* intermediate computations to log */
|
||||
/*#define AVMD_DEBUG */
|
||||
|
||||
/* define/undef this to enable/disable reporting of beep
|
||||
* detection status after session ended */
|
||||
#define AVMD_REPORT_STATUS
|
||||
|
||||
/* define/undefine this to enable/disable faster computation
|
||||
* of arcus cosine - table will be created mapping floats
|
||||
* to integers and returning arc cos values given these integer
|
||||
* indices into table */
|
||||
/* #define AVMD_FAST_MATH */
|
||||
|
||||
/* define/undefine this to classify avmd beep detection as valid
|
||||
* only when there is required number of consecutive elements
|
||||
* in the SMA buffer without reset */
|
||||
#define AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||
|
||||
/* define number of samples to skip starting from the beginning
|
||||
* of frame and after reset */
|
||||
#define AVMD_SAMLPE_TO_SKIP_N 6
|
||||
|
||||
/* define/undefine this to enable/disable simplified estimation
|
||||
* of frequency based on approximation of sin(x) with (x)
|
||||
* in the range x=[0,PI/2] */
|
||||
#define AVMD_SIMPLIFIED_ESTIMATION
|
||||
|
||||
/* define/undefine to enable/disable avmd on incoming audio */
|
||||
#define AVMD_INBOUND_CHANNEL
|
||||
|
||||
/* define/undefine to enable/disable avmd on outgoing audio */
|
||||
/*#define AVMD_OUTBOUND_CHANNEL*/
|
||||
|
||||
|
||||
#endif /* __AVMD_OPTIONS_H__ */
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef __PSI_H__
|
||||
#define __PSI_H__
|
||||
#include "buffer.h"
|
||||
#ifndef __AVMD_PSI_H__
|
||||
#define __AVMD_PSI_H__
|
||||
|
||||
|
||||
#include "avmd_buffer.h"
|
||||
|
||||
#define PSI(b, i) (GET_SAMPLE((b), ((i) + 1))*GET_SAMPLE((b), ((i) + 1))-GET_SAMPLE((b), ((i) + 2))*GET_SAMPLE((b), ((i) + 0)))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __AVMD_PSI_H__ */
|
@ -1,5 +1,15 @@
|
||||
#ifndef __SMA_BUFFER_H__
|
||||
#define __SMA_BUFFER_H__
|
||||
/*
|
||||
* @brief SMA buffer.
|
||||
*
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor < piotrek.gregor gmail.com >
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __AVMD_SMA_BUFFER_H__
|
||||
#define __AVMD_SMA_BUFFER_H__
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef _MSC_VER
|
||||
@ -7,7 +17,7 @@
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "buffer.h"
|
||||
#include "avmd_buffer.h"
|
||||
|
||||
typedef struct {
|
||||
size_t len;
|
||||
@ -31,7 +41,8 @@ typedef struct {
|
||||
|
||||
#define GET_SMA_SAMPLE(b, p) ((b)->data[(p) % (b)->len])
|
||||
#define SET_SMA_SAMPLE(b, p, v) ((b)->data[(p) % (b)->len] = (v))
|
||||
#define GET_CURRENT_SMA_POS(b) ((b)->lpos)
|
||||
#define GET_CURRENT_SMA_POS(b) ((b)->pos)
|
||||
#define GET_CURRENT_SMA_LPOS(b) ((b)->lpos)
|
||||
|
||||
#define INC_SMA_POS(b) \
|
||||
{ \
|
||||
@ -41,16 +52,19 @@ typedef struct {
|
||||
|
||||
#define APPEND_SMA_VAL(b, v) \
|
||||
{ \
|
||||
INC_SMA_POS(b); \
|
||||
(b)->sma -= ((b)->data[(b)->pos] / (BUFF_TYPE)(b)->len); \
|
||||
(b)->data[(b)->pos] = (v); \
|
||||
(b)->sma += ((b)->data[(b)->pos] / (BUFF_TYPE)(b)->len); \
|
||||
(((b)->lpos) >= ((b)->len)) ? ((b)->sma += ((b)->data[(b)->pos] / (BUFF_TYPE)(b)->len)) : \
|
||||
((b)->sma = ((((b)->sma)*((b)->pos)) + ((b)->data[(b)->pos])) / ((BUFF_TYPE)(((b)->pos) + 1))) ; \
|
||||
INC_SMA_POS(b); \
|
||||
}
|
||||
|
||||
#define RESET_SMA_BUFFER(b) \
|
||||
{ \
|
||||
(b)->sma = 0.0; \
|
||||
(void)memset((b)->data, 0, sizeof(BUFF_TYPE) * (b)->len); \
|
||||
(b)->pos = 0; \
|
||||
(b)->lpos = 0; \
|
||||
}
|
||||
|
||||
/*
|
||||
@ -60,7 +74,11 @@ typedef struct {
|
||||
}while(0);
|
||||
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __AVMD_SMA_BUFFER_H__ */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
int main(void)
|
@ -1,8 +0,0 @@
|
||||
#ifndef __DESA2_H__
|
||||
#define __DESA2_H__
|
||||
#include <math.h>
|
||||
#include "buffer.h"
|
||||
|
||||
extern double desa2(circ_buffer_t *b, size_t i);
|
||||
#endif
|
||||
|
@ -1,136 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "fast_acosf.h"
|
||||
#include "options.h"
|
||||
|
||||
#ifdef FASTMATH
|
||||
|
||||
#define SIGN_MASK (0x80000000)
|
||||
#define DATA_MASK (0x07FFFFF8)
|
||||
|
||||
#define SIGN_UNPACK_MASK (0x01000000)
|
||||
#define DATA_UNPACK_MASK (0x00FFFFFF)
|
||||
|
||||
#define VARIA_DATA_MASK (0x87FFFFF8)
|
||||
#define CONST_DATA_MASK (0x38000000)
|
||||
|
||||
#define ACOS_TABLE_LENGTH (1 << 25)
|
||||
#define ACOS_TABLE_FILENAME "/tmp/acos_table.dat"
|
||||
|
||||
typedef union {
|
||||
uint32_t i;
|
||||
float f;
|
||||
} float_conv_t;
|
||||
|
||||
#ifdef FAST_ACOSF_TESTING
|
||||
static float strip_float(float f);
|
||||
#endif
|
||||
static uint32_t index_from_float(float f);
|
||||
static float float_from_index(uint32_t d);
|
||||
static float *acos_table = NULL;
|
||||
static int acos_fd = -1;
|
||||
|
||||
#ifdef FAST_ACOSF_TESTING
|
||||
static float strip_float(float f)
|
||||
{
|
||||
float_conv_t d;
|
||||
|
||||
d.i = d.i & (VARIA_DATA_MASK | CONST_DATA_MASK);
|
||||
|
||||
return d.i;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void compute_table(void)
|
||||
{
|
||||
uint32_t i;
|
||||
float f;
|
||||
FILE *acos_table_file;
|
||||
size_t ret;
|
||||
|
||||
acos_table_file = fopen(ACOS_TABLE_FILENAME, "w");
|
||||
|
||||
for (i = 0; i < ACOS_TABLE_LENGTH; i++) {
|
||||
f = acosf(float_from_index(i));
|
||||
ret = fwrite(&f, sizeof(f), 1, acos_table_file);
|
||||
assert(ret != 0);
|
||||
}
|
||||
|
||||
ret = fclose(acos_table_file);
|
||||
assert(ret != EOF);
|
||||
}
|
||||
|
||||
|
||||
extern void init_fast_acosf(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (acos_table == NULL) {
|
||||
ret = access(ACOS_TABLE_FILENAME, F_OK);
|
||||
if (ret == 0) compute_table();
|
||||
|
||||
acos_fd = open(ACOS_TABLE_FILENAME, O_RDONLY);
|
||||
if (acos_fd == -1) perror("Could not open file " ACOS_TABLE_FILENAME);
|
||||
assert(acos_fd != -1);
|
||||
acos_table = (float *)mmap(
|
||||
NULL,
|
||||
ACOS_TABLE_LENGTH * sizeof(float),
|
||||
PROT_READ,
|
||||
MAP_SHARED | MAP_POPULATE,
|
||||
acos_fd,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extern void destroy_fast_acosf(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = munmap(acos_table, ACOS_TABLE_LENGTH);
|
||||
assert(ret != -1);
|
||||
ret = close(acos_fd);
|
||||
assert(ret != -1);
|
||||
acos_table = NULL;
|
||||
}
|
||||
|
||||
extern float fast_acosf(float x)
|
||||
{
|
||||
return acos_table[index_from_float(x)];
|
||||
}
|
||||
|
||||
|
||||
static uint32_t index_from_float(float f)
|
||||
{
|
||||
float_conv_t d;
|
||||
|
||||
d.f = f;
|
||||
return ((d.i & SIGN_MASK) >> 7) | ((d.i & DATA_MASK) >> 3);
|
||||
}
|
||||
|
||||
|
||||
static float float_from_index(uint32_t d)
|
||||
{
|
||||
float_conv_t f;
|
||||
|
||||
f.i = ((d & SIGN_UNPACK_MASK) << 7) | ((d & DATA_UNPACK_MASK) << 3) | CONST_DATA_MASK;
|
||||
return f.f;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@ -1,10 +0,0 @@
|
||||
#ifndef __FAST_ACOSF_H__
|
||||
#define __FAST_ACOSF_H__
|
||||
|
||||
extern void init_fast_acosf(void);
|
||||
extern float fast_acosf(float x);
|
||||
extern void destroy_fast_acosf(void);
|
||||
extern void compute_table(void);
|
||||
|
||||
#endif
|
||||
|
@ -1,36 +0,0 @@
|
||||
#ifndef __GOERTZEL_H__
|
||||
#include <math.h>
|
||||
#include "goertzel.h"
|
||||
#include "buffer.h"
|
||||
|
||||
/*! \brief Identify frequency components of a signal
|
||||
* @author Eric des Courtis
|
||||
* @param b A circular buffer
|
||||
* @param pos Position in the buffer
|
||||
* @param f Frequency to look at
|
||||
* @param num Number of samples to look at
|
||||
* @return A power estimate for frequency f at position pos in the stream
|
||||
*/
|
||||
extern double goertzel(circ_buffer_t *b, size_t pos, double f, size_t num)
|
||||
{
|
||||
double s = 0.0;
|
||||
double p = 0.0;
|
||||
double p2 = 0.0;
|
||||
double coeff;
|
||||
size_t i;
|
||||
|
||||
coeff = 2.0 * cos(2.0 * M_PI * f);
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* TODO: optimize to avoid GET_SAMPLE when possible */
|
||||
s = GET_SAMPLE(b, i + pos) + (coeff * p) - p2;
|
||||
p2 = p;
|
||||
p = s;
|
||||
}
|
||||
|
||||
return (p2 * p2) + (p * p) - (coeff * p2 * p);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -1,18 +0,0 @@
|
||||
#ifndef __GOERTZEL_H__
|
||||
#define __GOERTZEL_H__
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include "buffer.h"
|
||||
|
||||
#if !defined(M_PI)
|
||||
/* C99 systems may not define M_PI */
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
|
||||
extern double goertzel(circ_buffer_t *b, size_t pos, double f, size_t num);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -6,37 +6,37 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="amplitude.h">
|
||||
<ClInclude Include="avmd_amplitude.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="buffer.h">
|
||||
<ClInclude Include="avmd_buffer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="desa2.h">
|
||||
<ClInclude Include="avmd_desa2.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fast_acosf.h">
|
||||
<ClInclude Include="avmd_fast_acosf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="goertzel.h">
|
||||
<ClInclude Include="avmd_goertzel.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="options.h">
|
||||
<ClInclude Include="avmd_options.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="psi.h">
|
||||
<ClInclude Include="avmd_psi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="sma_buf.h">
|
||||
<ClInclude Include="avmd_sma_buf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="amplitude.c" />
|
||||
<ClCompile Include="buffer.c" />
|
||||
<ClCompile Include="desa2.c" />
|
||||
<ClCompile Include="fast_acosf.c" />
|
||||
<ClCompile Include="goertzel.c" />
|
||||
<ClCompile Include="avmd_amplitude.c" />
|
||||
<ClCompile Include="avmd_buffer.c" />
|
||||
<ClCompile Include="avmd_desa2.c" />
|
||||
<ClCompile Include="avmd_fast_acosf.c" />
|
||||
<ClCompile Include="avmd_goertzel.c" />
|
||||
<ClCompile Include="mod_avmd.c" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -124,21 +124,21 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="amplitude.h" />
|
||||
<ClInclude Include="buffer.h" />
|
||||
<ClInclude Include="desa2.h" />
|
||||
<ClInclude Include="fast_acosf.h" />
|
||||
<ClInclude Include="goertzel.h" />
|
||||
<ClInclude Include="options.h" />
|
||||
<ClInclude Include="psi.h" />
|
||||
<ClInclude Include="sma_buf.h" />
|
||||
<ClInclude Include="avmd_amplitude.h" />
|
||||
<ClInclude Include="avmd_buffer.h" />
|
||||
<ClInclude Include="avmd_desa2.h" />
|
||||
<ClInclude Include="avmd_fast_acosf.h" />
|
||||
<ClInclude Include="avmd_goertzel.h" />
|
||||
<ClInclude Include="avmd_options.h" />
|
||||
<ClInclude Include="avmd_psi.h" />
|
||||
<ClInclude Include="avmd_sma_buf.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="amplitude.c" />
|
||||
<ClCompile Include="buffer.c" />
|
||||
<ClCompile Include="desa2.c" />
|
||||
<ClCompile Include="fast_acosf.c" />
|
||||
<ClCompile Include="goertzel.c" />
|
||||
<ClCompile Include="avmd_amplitude.c" />
|
||||
<ClCompile Include="avmd_buffer.c" />
|
||||
<ClCompile Include="avmd_desa2.c" />
|
||||
<ClCompile Include="avmd_fast_acosf.c" />
|
||||
<ClCompile Include="avmd_goertzel.c" />
|
||||
<ClCompile Include="mod_avmd.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -154,4 +154,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -25,9 +25,14 @@
|
||||
*
|
||||
* This module detects voicemail beeps using a generalized approach.
|
||||
*
|
||||
* Modifications:
|
||||
* Piotr Gregor <piotrek.gregor gmail.com>:
|
||||
* FS-8808, FS-8809, FS-8810, FS-8852, FS-8853, FS-8854, FS-8855,
|
||||
* FS-8860, FS-8861, FS-8875
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <g711.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -39,12 +44,23 @@
|
||||
#define ISNAN(x) (isnan(x))
|
||||
#endif
|
||||
|
||||
|
||||
#include "avmd_buffer.h"
|
||||
#include "avmd_desa2_tweaked.h"
|
||||
#include "avmd_sma_buf.h"
|
||||
#include "avmd_options.h"
|
||||
|
||||
#ifdef AVMD_FAST_MATH
|
||||
#include "avmd_fast_acosf.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*! Calculate how many audio samples per ms based on the rate */
|
||||
#define SAMPLES_PER_MS(r, m) ((r) / (1000/(m)))
|
||||
/*! Minimum beep length */
|
||||
#define BEEP_TIME (100)
|
||||
#define BEEP_TIME (2)
|
||||
/*! How often to evaluate the output of desa2 in ms */
|
||||
#define SINE_TIME (10)
|
||||
#define SINE_TIME (2*0.125)
|
||||
/*! How long in samples does desa2 results get evaluated */
|
||||
#define SINE_LEN(r) SAMPLES_PER_MS((r), SINE_TIME)
|
||||
/*! How long in samples is the minimum beep length */
|
||||
@ -59,23 +75,27 @@
|
||||
#define TO_HZ(r, f) (((r) * (f)) / (2.0 * M_PI))
|
||||
/*! Minimum beep frequency in Hertz */
|
||||
#define MIN_FREQUENCY (300.0)
|
||||
/*! Minimum frequency as digital normalized frequency */
|
||||
#define MIN_FREQUENCY_R(r) ((2.0 * M_PI * MIN_FREQUENCY) / (r))
|
||||
/*! Maximum beep frequency in Hertz */
|
||||
/*!
|
||||
* Maximum beep frequency in Hertz
|
||||
* Note: The maximum frequency the DESA-2 algorithm can uniquely
|
||||
* identify is 0.25 of the sampling rate. All the frequencies
|
||||
* below that level are detected unambiguously. This means 2kHz
|
||||
* for 8kHz audio. All the frequencies above 0.25 sampling rate
|
||||
* will be aliased to some frequency below that threshold.
|
||||
* This is not a problem here as we are interested in detection
|
||||
* of any sine wave instead of detection of particular frequency.
|
||||
*/
|
||||
#define MAX_FREQUENCY (2500.0)
|
||||
/*! Maximum frequency as digital normalized frequency */
|
||||
#define MAX_FREQUENCY_R(r) ((2.0 * M_PI * MAX_FREQUENCY) / (r))
|
||||
/* decrease this value to eliminate false positives */
|
||||
#define VARIANCE_THRESHOLD (0.001)
|
||||
#define VARIANCE_THRESHOLD (0.00025)
|
||||
|
||||
#include "amplitude.h"
|
||||
#include "buffer.h"
|
||||
#include "desa2.h"
|
||||
//#include "goertzel.h"
|
||||
#include "psi.h"
|
||||
#include "sma_buf.h"
|
||||
#include "options.h"
|
||||
|
||||
#ifdef FASTMATH
|
||||
#include "fast_acosf.h"
|
||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||
/* increase this value to eliminate false positives */
|
||||
#define SAMPLES_CONSECUTIVE_STREAK 15
|
||||
#endif
|
||||
|
||||
/*! Syntax of the API call. */
|
||||
@ -87,13 +107,16 @@
|
||||
/*! FreeSWITCH CUSTOM event type. */
|
||||
#define AVMD_EVENT_BEEP "avmd::beep"
|
||||
|
||||
#define AVMD_CHAR_BUF_LEN 10
|
||||
#define AVMD_BUF_LINEAR_LEN 160
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown);
|
||||
SWITCH_STANDARD_API(avmd_api_main);
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_avmd, mod_avmd_load, NULL, NULL);
|
||||
SWITCH_MODULE_DEFINITION(mod_avmd, mod_avmd_load, mod_avmd_shutdown, NULL);
|
||||
SWITCH_STANDARD_APP(avmd_start_function);
|
||||
|
||||
/*! Status of the beep detection */
|
||||
@ -121,11 +144,18 @@ typedef struct {
|
||||
/* freq_table_t ft; */
|
||||
avmd_state_t state;
|
||||
switch_time_t start_time;
|
||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||
size_t samples_streak; /* number of DESA samples in single streak without reset
|
||||
needed to validate SMA estimator */
|
||||
#endif
|
||||
size_t sample_count;
|
||||
} avmd_session_t;
|
||||
|
||||
static void avmd_process(avmd_session_t *session, switch_frame_t *frame);
|
||||
static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, switch_abc_type_t type);
|
||||
static void init_avmd_session_data(avmd_session_t *avmd_session, switch_core_session_t *fs_session);
|
||||
static switch_bool_t avmd_callback(switch_media_bug_t * bug,
|
||||
void *user_data, switch_abc_type_t type);
|
||||
static void init_avmd_session_data(avmd_session_t *avmd_session,
|
||||
switch_core_session_t *fs_session);
|
||||
|
||||
|
||||
/*! \brief The avmd session data initialization function.
|
||||
@ -133,17 +163,25 @@ static void init_avmd_session_data(avmd_session_t *avmd_session, switch_core_se
|
||||
* @param avmd_session A reference to a avmd session.
|
||||
* @param fs_session A reference to a FreeSWITCH session.
|
||||
*/
|
||||
static void init_avmd_session_data(avmd_session_t *avmd_session, switch_core_session_t *fs_session)
|
||||
static void init_avmd_session_data(avmd_session_t *avmd_session,
|
||||
switch_core_session_t *fs_session)
|
||||
{
|
||||
/*! This is a worst case sample rate estimate */
|
||||
avmd_session->rate = 48000;
|
||||
INIT_CIRC_BUFFER(&avmd_session->b, (size_t)BEEP_LEN(avmd_session->rate), (size_t)FRAME_LEN(avmd_session->rate), fs_session);
|
||||
INIT_CIRC_BUFFER(&avmd_session->b,
|
||||
(size_t)BEEP_LEN(avmd_session->rate),
|
||||
(size_t)FRAME_LEN(avmd_session->rate),
|
||||
fs_session);
|
||||
|
||||
avmd_session->session = fs_session;
|
||||
avmd_session->pos = 0;
|
||||
avmd_session->f = 0.0;
|
||||
avmd_session->state.last_beep = 0;
|
||||
avmd_session->state.beep_state = BEEP_NOTDETECTED;
|
||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||
avmd_session->samples_streak = SAMPLES_CONSECUTIVE_STREAK;
|
||||
#endif
|
||||
avmd_session->sample_count = 0;
|
||||
|
||||
INIT_SMA_BUFFER(
|
||||
&avmd_session->sma_b,
|
||||
@ -167,7 +205,8 @@ static void init_avmd_session_data(avmd_session_t *avmd_session, switch_core_se
|
||||
* @param type The switch callback type.
|
||||
* @return The success or failure of the function.
|
||||
*/
|
||||
static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, switch_abc_type_t type)
|
||||
static switch_bool_t avmd_callback(switch_media_bug_t * bug,
|
||||
void *user_data, switch_abc_type_t type)
|
||||
{
|
||||
avmd_session_t *avmd_session;
|
||||
switch_codec_t *read_codec;
|
||||
@ -185,7 +224,8 @@ static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, sw
|
||||
read_codec = switch_core_session_get_read_codec(avmd_session->session);
|
||||
avmd_session->rate = read_codec->implementation->samples_per_second;
|
||||
avmd_session->start_time = switch_micro_time_now();
|
||||
/* avmd_session->vmd_codec.channels = read_codec->implementation->number_of_channels; */
|
||||
/* avmd_session->vmd_codec.channels =
|
||||
* read_codec->implementation->number_of_channels; */
|
||||
break;
|
||||
|
||||
case SWITCH_ABC_TYPE_READ_REPLACE:
|
||||
@ -194,7 +234,9 @@ static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, sw
|
||||
return SWITCH_TRUE;
|
||||
|
||||
case SWITCH_ABC_TYPE_WRITE_REPLACE:
|
||||
break;
|
||||
frame = switch_core_media_bug_get_write_replace_frame(bug);
|
||||
avmd_process(avmd_session, frame);
|
||||
return SWITCH_TRUE;
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -206,35 +248,92 @@ static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, sw
|
||||
/*! \brief FreeSWITCH module loading function.
|
||||
*
|
||||
* @author Eric des Courtis
|
||||
* @return Load success or failure.
|
||||
* @par Modifications: Piotr Gregor
|
||||
* @return On success SWITCH_STATUS_SUCCES,
|
||||
* on failure SWITCH_STATUS_TERM.
|
||||
*/
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
|
||||
{
|
||||
#ifdef AVMD_FAST_MATH
|
||||
char err[150];
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
switch_application_interface_t *app_interface;
|
||||
switch_api_interface_t *api_interface;
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
|
||||
if (switch_event_reserve_subclass(AVMD_EVENT_BEEP) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", AVMD_EVENT_BEEP);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Couldn't register subclass [%s]!\n", AVMD_EVENT_BEEP);
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
|
||||
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_NOTICE,
|
||||
"Advanced Voicemail detection enabled\n"
|
||||
);
|
||||
);
|
||||
|
||||
#ifdef FASTMATH
|
||||
init_fast_acosf();
|
||||
#ifdef AVMD_FAST_MATH
|
||||
ret = init_fast_acosf();
|
||||
if (ret != 0) {
|
||||
strerror_r(errno, err, 150);
|
||||
switch (ret) {
|
||||
|
||||
case -1:
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_ERROR,
|
||||
"Can't access file [%s], error [%s]\n",
|
||||
ACOS_TABLE_FILENAME, err
|
||||
);
|
||||
break;
|
||||
|
||||
case -2:
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_ERROR,
|
||||
"Error creating file [%s], error [%s]\n",
|
||||
ACOS_TABLE_FILENAME, err
|
||||
);
|
||||
break;
|
||||
|
||||
case -3:
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_ERROR,
|
||||
"Access rights are OK but can't open file [%s], error [%s]\n",
|
||||
ACOS_TABLE_FILENAME, err
|
||||
);
|
||||
break;
|
||||
|
||||
case -4:
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_ERROR,
|
||||
"Access rights are OK but can't mmap file [%s], error [%s]\n",
|
||||
ACOS_TABLE_FILENAME, err
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_ERROR,
|
||||
"Unknown error [%d] while initializing fast cos table [%s], "
|
||||
"errno [%s]\n", ret, ACOS_TABLE_FILENAME, err
|
||||
);
|
||||
return SWITCH_STATUS_TERM;
|
||||
}
|
||||
return SWITCH_STATUS_TERM;
|
||||
} else
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_NOTICE,
|
||||
"Advanced Voicemail detection: fast math enabled\n"
|
||||
"Advanced Voicemail detection: fast math enabled, arc cosine table "
|
||||
"is [%s]\n", ACOS_TABLE_FILENAME
|
||||
);
|
||||
#endif
|
||||
|
||||
@ -246,9 +345,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
|
||||
avmd_start_function,
|
||||
"[start] [stop]",
|
||||
SAF_NONE
|
||||
);
|
||||
);
|
||||
|
||||
SWITCH_ADD_API(api_interface, "avmd", "Voicemail beep detection", avmd_api_main, AVMD_SYNTAX);
|
||||
SWITCH_ADD_API(api_interface, "avmd", "Voicemail beep detection",
|
||||
avmd_api_main, AVMD_SYNTAX);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@ -266,6 +366,7 @@ SWITCH_STANDARD_APP(avmd_start_function)
|
||||
switch_status_t status;
|
||||
switch_channel_t *channel;
|
||||
avmd_session_t *avmd_session;
|
||||
switch_media_bug_flag_t flags = 0;
|
||||
|
||||
if (session == NULL)
|
||||
return;
|
||||
@ -293,10 +394,19 @@ SWITCH_STANDARD_APP(avmd_start_function)
|
||||
return;
|
||||
}
|
||||
|
||||
avmd_session = (avmd_session_t *)switch_core_session_alloc(session, sizeof(avmd_session_t));
|
||||
avmd_session = (avmd_session_t *)switch_core_session_alloc(
|
||||
session, sizeof(avmd_session_t));
|
||||
|
||||
init_avmd_session_data(avmd_session, session);
|
||||
|
||||
#ifdef AVMD_INBOUND_CHANNEL
|
||||
flags |= SMBF_READ_REPLACE;
|
||||
#endif
|
||||
#ifdef AVMD_OUTBOUND_CHANNEL
|
||||
flags |= SMBF_WRITE_REPLACE;
|
||||
#endif
|
||||
switch_assert(flags != 0);
|
||||
|
||||
status = switch_core_media_bug_add(
|
||||
session,
|
||||
"avmd",
|
||||
@ -304,7 +414,7 @@ SWITCH_STANDARD_APP(avmd_start_function)
|
||||
avmd_callback,
|
||||
avmd_session,
|
||||
0,
|
||||
SMBF_READ_REPLACE,
|
||||
flags,
|
||||
&bug
|
||||
);
|
||||
|
||||
@ -328,11 +438,34 @@ SWITCH_STANDARD_APP(avmd_start_function)
|
||||
*/
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
|
||||
{
|
||||
#ifdef AVMD_FAST_MATH
|
||||
int res;
|
||||
#endif
|
||||
|
||||
switch_event_free_subclass(AVMD_EVENT_BEEP);
|
||||
|
||||
#ifdef FASTMATH
|
||||
destroy_fast_acosf();
|
||||
#ifdef AVMD_FAST_MATH
|
||||
res = destroy_fast_acosf();
|
||||
if (res != 0) {
|
||||
switch (res) {
|
||||
case -1:
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_ERROR,
|
||||
"Failed unmap arc cosine table\n"
|
||||
);
|
||||
break;
|
||||
case -2:
|
||||
switch_log_printf(
|
||||
SWITCH_CHANNEL_LOG,
|
||||
SWITCH_LOG_ERROR,
|
||||
"Failed closing arc cosine table\n"
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
switch_log_printf(
|
||||
@ -363,6 +496,7 @@ SWITCH_STANDARD_API(avmd_api_main)
|
||||
char *ccmd = NULL;
|
||||
char *uuid;
|
||||
char *command;
|
||||
switch_core_media_flag_t flags = 0;
|
||||
|
||||
/* No command? Display usage */
|
||||
if (zstr(cmd)) {
|
||||
@ -429,10 +563,19 @@ SWITCH_STANDARD_API(avmd_api_main)
|
||||
|
||||
/* Allocate memory attached to this FreeSWITCH session for
|
||||
* use in the callback routine and to store state information */
|
||||
avmd_session = (avmd_session_t *) switch_core_session_alloc(fs_session, sizeof(avmd_session_t));
|
||||
avmd_session = (avmd_session_t *) switch_core_session_alloc(
|
||||
fs_session, sizeof(avmd_session_t));
|
||||
|
||||
init_avmd_session_data(avmd_session, fs_session);
|
||||
|
||||
#ifdef AVMD_INBOUND_CHANNEL
|
||||
flags |= SMBF_READ_REPLACE;
|
||||
#endif
|
||||
#ifdef AVMD_OUTBOUND_CHANNEL
|
||||
flags |= SMBF_WRITE_REPLACE;
|
||||
#endif
|
||||
switch_assert(flags != 0);
|
||||
|
||||
/* Add a media bug that allows me to intercept the
|
||||
* reading leg of the audio stream */
|
||||
status = switch_core_media_bug_add(
|
||||
@ -442,7 +585,7 @@ SWITCH_STANDARD_API(avmd_api_main)
|
||||
avmd_callback,
|
||||
avmd_session,
|
||||
0,
|
||||
SMBF_READ_REPLACE,
|
||||
flags,
|
||||
&bug
|
||||
);
|
||||
|
||||
@ -478,6 +621,7 @@ end:
|
||||
|
||||
/*! \brief Process one frame of data with avmd algorithm.
|
||||
* @author Eric des Courtis
|
||||
* @par Modifications: Piotr Gregor
|
||||
* @param session An avmd session.
|
||||
* @param frame An audio frame.
|
||||
*/
|
||||
@ -490,90 +634,177 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame)
|
||||
|
||||
circ_buffer_t *b;
|
||||
size_t pos;
|
||||
double f;
|
||||
double omega;
|
||||
#ifdef AVMD_DEBUG
|
||||
double f;
|
||||
#endif
|
||||
double v;
|
||||
// double error = 0.0;
|
||||
// double success = 0.0;
|
||||
// double amp = 0.0;
|
||||
// double s_rate;
|
||||
// double e_rate;
|
||||
// double avg_a;
|
||||
//double sine_len;
|
||||
double sma_digital_freq;
|
||||
uint32_t sine_len_i;
|
||||
//uint32_t beep_len_i;
|
||||
// int valid;
|
||||
char buf[AVMD_CHAR_BUF_LEN];
|
||||
int sample_to_skip_n = AVMD_SAMLPE_TO_SKIP_N;
|
||||
size_t sample_n = 0;
|
||||
|
||||
b = &session->b;
|
||||
|
||||
/*! If beep has already been detected skip the CPU heavy stuff */
|
||||
/* If beep has already been detected skip the CPU heavy stuff */
|
||||
if (session->state.beep_state == BEEP_DETECTED) return;
|
||||
|
||||
/*! Precompute values used heavily in the inner loop */
|
||||
/* Precompute values used heavily in the inner loop */
|
||||
sine_len_i = SINE_LEN(session->rate);
|
||||
//sine_len = (double)sine_len_i;
|
||||
//beep_len_i = BEEP_LEN(session->rate);
|
||||
|
||||
channel = switch_core_session_get_channel(session->session);
|
||||
|
||||
/*! Insert frame of 16 bit samples into buffer */
|
||||
/* Insert frame of 16 bit samples into buffer */
|
||||
INSERT_INT16_FRAME(b, (int16_t *)(frame->data), frame->samples);
|
||||
session->sample_count += frame->samples;
|
||||
|
||||
//switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_INFO, "<<< AVMD sine_len_i=%d >>>\n", sine_len_i);
|
||||
/* INNER LOOP -- OPTIMIZATION TARGET */
|
||||
pos = session->pos;
|
||||
while (sample_n < (frame->samples - P)) {
|
||||
/*for (pos = session->pos; pos < (GET_CURRENT_POS(b) - P); pos++) { */
|
||||
if ((sample_n % sine_len_i) == 0) {
|
||||
/* Get a desa2 frequency estimate every sine len */
|
||||
omega = avmd_desa2_tweaked(b, pos + sample_n, session->session);
|
||||
|
||||
/*! INNER LOOP -- OPTIMIZATION TARGET */
|
||||
for (pos = session->pos; pos < (GET_CURRENT_POS(b) - P); pos++) {
|
||||
if ((pos % sine_len_i) == 0) {
|
||||
/*! Get a desa2 frequency estimate every sine len */
|
||||
f = desa2(b, pos);
|
||||
|
||||
if (f < MIN_FREQUENCY_R(session->rate) || f > MAX_FREQUENCY_R(session->rate)) {
|
||||
if (omega < -0.999999 || omega > 0.999999) {
|
||||
#ifdef AVMD_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session),
|
||||
SWITCH_LOG_DEBUG, "<<< AVMD RESET >>>\n");
|
||||
#endif
|
||||
v = 99999.0;
|
||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||
RESET_SMA_BUFFER(&session->sma_b);
|
||||
RESET_SMA_BUFFER(&session->sqa_b);
|
||||
session->samples_streak = SAMPLES_CONSECUTIVE_STREAK;
|
||||
sample_to_skip_n = AVMD_SAMLPE_TO_SKIP_N;
|
||||
#endif
|
||||
} else {
|
||||
APPEND_SMA_VAL(&session->sma_b, f);
|
||||
APPEND_SMA_VAL(&session->sqa_b, f * f);
|
||||
if (isnan(omega)) {
|
||||
#ifdef AVMD_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session),
|
||||
SWITCH_LOG_DEBUG, "<<< AVMD, SKIP NaN >>>\n");
|
||||
#endif
|
||||
sample_to_skip_n = AVMD_SAMLPE_TO_SKIP_N;
|
||||
goto loop_continue;
|
||||
}
|
||||
if (session->sma_b.pos > 0 &&
|
||||
(fabs(omega - session->sma_b.data[session->sma_b.pos - 1]) < 0.00000001)) {
|
||||
#ifdef AVMD_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG,
|
||||
"<<< AVMD, SKIP >>>\n");
|
||||
#endif
|
||||
goto loop_continue;
|
||||
}
|
||||
#ifdef AVMD_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session),
|
||||
SWITCH_LOG_DEBUG, "<<< AVMD omega [%f] >>>\n", omega);
|
||||
#endif
|
||||
if (sample_to_skip_n > 0) {
|
||||
sample_to_skip_n--;
|
||||
goto loop_continue;
|
||||
}
|
||||
|
||||
/* calculate variance */
|
||||
/* saturate */
|
||||
if (omega < -0.9999)
|
||||
omega = -0.9999;
|
||||
if (omega > 0.9999)
|
||||
omega = 0.9999;
|
||||
|
||||
/* append */
|
||||
APPEND_SMA_VAL(&session->sma_b, omega);
|
||||
APPEND_SMA_VAL(&session->sqa_b, omega * omega);
|
||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||
if (session->samples_streak > 0)
|
||||
--session->samples_streak;
|
||||
#endif
|
||||
/* calculate variance (biased estimator) */
|
||||
v = session->sqa_b.sma - (session->sma_b.sma * session->sma_b.sma);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, "<<< AVMD v=%f f=%f %fHz sma=%f sqa=%f >>>\n", v, f, TO_HZ(session->rate, f), session->sma_b.sma, session->sqa_b.sma);
|
||||
#ifdef AVMD_DEBUG
|
||||
#ifdef AVMD_FAST_MATH
|
||||
f = 0.5 * (double) fast_acosf((float)omega);
|
||||
sma_digital_freq = 0.5 * (double) fast_acosf((float)session->sma_b.sma);
|
||||
#else
|
||||
f = 0.5 * acos(omega);
|
||||
sma_digital_freq = 0.5 * acos(session->sma_b.sma);
|
||||
#endif /* AVMD_FAST_MATH */
|
||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG,
|
||||
"<<< AVMD v[%.10f]\tomega[%f]\tf[%f] [%f]Hz\t\tsma[%f][%f]Hz\t\tsqa[%f]\t"
|
||||
"streak[%zu] pos[%zu] sample_n[%zu] lpos[%zu] s[%zu]>>>\n",
|
||||
v, omega, f, TO_HZ(session->rate, f), session->sma_b.sma,
|
||||
TO_HZ(session->rate, sma_digital_freq), session->sqa_b.sma, session->samples_streak,
|
||||
session->sma_b.pos, sample_n, session->sma_b.lpos, pos);
|
||||
#else
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG,
|
||||
"<<< AVMD v[%.10f]\tomega[%f]\tf[%f] [%f]Hz\t\tsma[%f][%f]Hz\t\tsqa[%f]\tpos[%zu]"
|
||||
" sample_n[%zu] lpos[%zu] s[%zu]>>>\n", v, omega, f,
|
||||
TO_HZ(session->rate, f), session->sma_b.sma, TO_HZ(session->rate, sma_digital_freq),
|
||||
session->sqa_b.sma, session->sma_b.pos, sample_n, session->sma_b.lpos, pos);
|
||||
#endif /* AVMD_REQUIRE_CONTINUOUS_STREAK */
|
||||
#endif /* AVMD_DEBUG */
|
||||
}
|
||||
|
||||
/*! If variance is less than threshold then we have detection */
|
||||
if (v < VARIANCE_THRESHOLD) {
|
||||
|
||||
switch_channel_set_variable_printf(channel, "avmd_total_time", "%d", (int)(switch_micro_time_now() - session->start_time) / 1000);
|
||||
/* DECISION */
|
||||
/* If variance is less than threshold
|
||||
* and we have at least two estimates
|
||||
* then we have detection */
|
||||
#ifdef AVMD_REQUIRE_CONTINUOUS_STREAK
|
||||
if (v < VARIANCE_THRESHOLD && (session->sma_b.lpos > 1) && (session->samples_streak == 0)) {
|
||||
#else
|
||||
if (v < VARIANCE_THRESHOLD && (session->sma_b.lpos > 1)) {
|
||||
#endif
|
||||
#ifdef AVMD_FAST_MATH
|
||||
sma_digital_freq = 0.5 * (double) fast_acosf((float)session->sma_b.sma);
|
||||
#else
|
||||
sma_digital_freq = 0.5 * acos(session->sma_b.sma);
|
||||
#endif /* AVMD_FAST_MATH */
|
||||
snprintf(buf, AVMD_CHAR_BUF_LEN, "%f", TO_HZ(session->rate, sma_digital_freq));
|
||||
switch_channel_set_variable_printf(channel, "avmd_total_time",
|
||||
"[%d]", (int)(switch_micro_time_now() - session->start_time) / 1000);
|
||||
switch_channel_execute_on(channel, "execute_on_avmd_beep");
|
||||
|
||||
/*! Throw an event to FreeSWITCH */
|
||||
/* Throw an event to FreeSWITCH */
|
||||
status = switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, AVMD_EVENT_BEEP);
|
||||
if (status != SWITCH_STATUS_SUCCESS) return;
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Beep-Status", "stop");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session->session));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID",
|
||||
switch_core_session_get_uuid(session->session));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "avmd");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "frequency", buf);
|
||||
snprintf(buf, AVMD_CHAR_BUF_LEN, "%f", v);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "variance", buf);
|
||||
|
||||
if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS) return;
|
||||
|
||||
switch_core_session_queue_event(session->session, &event);
|
||||
switch_event_fire(&event_copy);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, "<<< AVMD - Beep Detected >>>\n");
|
||||
#ifdef AVMD_REPORT_STATUS
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_NOTICE,
|
||||
"<<< AVMD - Beep Detected: f = [%f], variance = [%f] >>>\n",
|
||||
TO_HZ(session->rate, sma_digital_freq), v);
|
||||
#endif
|
||||
switch_channel_set_variable(channel, "avmd_detect", "TRUE");
|
||||
RESET_SMA_BUFFER(&session->sma_b);
|
||||
RESET_SMA_BUFFER(&session->sqa_b);
|
||||
session->state.beep_state = BEEP_DETECTED;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//amp = 0.0;
|
||||
//success = 0.0;
|
||||
//error = 0.0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
loop_continue:
|
||||
++sample_n;
|
||||
}
|
||||
session->pos = pos;
|
||||
|
||||
done:
|
||||
session->pos += sample_n;
|
||||
session->pos &= b->mask;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
|
@ -1,7 +0,0 @@
|
||||
#ifndef __OPTIONS_H__
|
||||
#define __OPTIONS_H__
|
||||
|
||||
/* #define FASTMATH */
|
||||
|
||||
#endif
|
||||
|
@ -55,12 +55,14 @@ api_command_t conference_api_sub_commands[] = {
|
||||
{"auto-3d-position", (void_fn_t) & conference_api_sub_auto_position, CONF_API_SUB_ARGS_SPLIT, "auto-3d-position", "[on|off]"},
|
||||
{"play", (void_fn_t) & conference_api_sub_play, CONF_API_SUB_ARGS_SPLIT, "play", "<file_path> [async|<member_id> [nomux]]"},
|
||||
{"pause_play", (void_fn_t) & conference_api_sub_pause_play, CONF_API_SUB_ARGS_SPLIT, "pause", "[<member_id>]"},
|
||||
{"play_status", (void_fn_t) & conference_api_sub_play_status, CONF_API_SUB_ARGS_SPLIT, "play_status", "[<member_id>]"},
|
||||
{"file_seek", (void_fn_t) & conference_api_sub_file_seek, CONF_API_SUB_ARGS_SPLIT, "file_seek", "[+-]<val> [<member_id>]"},
|
||||
{"say", (void_fn_t) & conference_api_sub_say, CONF_API_SUB_ARGS_AS_ONE, "say", "<text>"},
|
||||
{"saymember", (void_fn_t) & conference_api_sub_saymember, CONF_API_SUB_ARGS_AS_ONE, "saymember", "<member_id> <text>"},
|
||||
{"stop", (void_fn_t) & conference_api_sub_stop, CONF_API_SUB_ARGS_SPLIT, "stop", "<[current|all|async|last]> [<member_id>]"},
|
||||
{"dtmf", (void_fn_t) & conference_api_sub_dtmf, CONF_API_SUB_MEMBER_TARGET, "dtmf", "<[member_id|all|last|non_moderator]> <digits>"},
|
||||
{"kick", (void_fn_t) & conference_api_sub_kick, CONF_API_SUB_MEMBER_TARGET, "kick", "<[member_id|all|last|non_moderator]> [<optional sound file>]"},
|
||||
{"vid-flip", (void_fn_t) & conference_api_sub_vid_flip, CONF_API_SUB_MEMBER_TARGET, "vid-flip", "<[member_id|all|last|non_moderator]>"},
|
||||
{"hup", (void_fn_t) & conference_api_sub_hup, CONF_API_SUB_MEMBER_TARGET, "hup", "<[member_id|all|last|non_moderator]>"},
|
||||
{"mute", (void_fn_t) & conference_api_sub_mute, CONF_API_SUB_MEMBER_TARGET, "mute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
||||
{"tmute", (void_fn_t) & conference_api_sub_tmute, CONF_API_SUB_MEMBER_TARGET, "tmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
|
||||
@ -135,6 +137,34 @@ switch_status_t conference_api_sub_pause_play(conference_obj_t *conference, swit
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
switch_status_t conference_api_sub_play_status(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
|
||||
{
|
||||
if (argc == 2) {
|
||||
switch_mutex_lock(conference->mutex);
|
||||
conference_fnode_check_status(conference->fnode, stream);
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (argc == 3) {
|
||||
uint32_t id = atoi(argv[2]);
|
||||
conference_member_t *member;
|
||||
|
||||
if ((member = conference_member_get(conference, id))) {
|
||||
switch_mutex_lock(member->fnode_mutex);
|
||||
conference_fnode_check_status(member->fnode, stream);
|
||||
switch_mutex_unlock(member->fnode_mutex);
|
||||
switch_thread_rwlock_unlock(member->rwlock);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
stream->write_function(stream, "Member: %u not found.\n", id);
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
/* _In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream */
|
||||
switch_status_t conference_api_main_real(const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream)
|
||||
{
|
||||
@ -490,11 +520,9 @@ switch_status_t conference_api_sub_unvmute(conference_member_t *member, switch_s
|
||||
if (switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
layer = conference_video_get_layer_locked(member);
|
||||
|
||||
if (layer) {
|
||||
conference_video_clear_layer(layer);
|
||||
|
||||
if ((layer = conference_video_get_layer_locked(member))) {
|
||||
layer->clear = 1;
|
||||
conference_video_release_layer(&layer);
|
||||
}
|
||||
|
||||
@ -628,6 +656,36 @@ switch_status_t conference_api_sub_kick(conference_member_t *member, switch_stre
|
||||
}
|
||||
|
||||
|
||||
switch_status_t conference_api_sub_vid_flip(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||
{
|
||||
switch_event_t *event;
|
||||
|
||||
if (member == NULL) {
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_FLIP_VIDEO)) {
|
||||
conference_utils_member_clear_flag_locked(member, MFLAG_FLIP_VIDEO);
|
||||
} else {
|
||||
conference_utils_member_set_flag_locked(member, MFLAG_FLIP_VIDEO);
|
||||
}
|
||||
|
||||
if (stream != NULL) {
|
||||
stream->write_function(stream, "OK flipped %u\n", member->id);
|
||||
}
|
||||
|
||||
if (member->conference && test_eflag(member->conference, EFLAG_KICK_MEMBER)) {
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "vid-flip-member");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
switch_status_t conference_api_sub_dtmf(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||
{
|
||||
switch_event_t *event;
|
||||
@ -1163,6 +1221,8 @@ switch_status_t conference_api_sub_write_png(conference_obj_t *conference, switc
|
||||
switch_status_t conference_api_sub_vid_layout(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
|
||||
{
|
||||
video_layout_t *vlayout = NULL;
|
||||
char *group_name = NULL;
|
||||
|
||||
int idx = 0;
|
||||
|
||||
if (!argv[2]) {
|
||||
@ -1188,7 +1248,6 @@ switch_status_t conference_api_sub_vid_layout(conference_obj_t *conference, swit
|
||||
|
||||
if (!strncasecmp(argv[2], "group", 5)) {
|
||||
layout_group_t *lg = NULL;
|
||||
char *group_name = NULL;
|
||||
int xx = 4;
|
||||
|
||||
if ((group_name = strchr(argv[2], ':'))) {
|
||||
@ -1197,7 +1256,7 @@ switch_status_t conference_api_sub_vid_layout(conference_obj_t *conference, swit
|
||||
} else {
|
||||
group_name = argv[3];
|
||||
}
|
||||
|
||||
|
||||
if (!group_name) {
|
||||
stream->write_function(stream, "Group name not specified.\n");
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@ -1208,33 +1267,30 @@ switch_status_t conference_api_sub_vid_layout(conference_obj_t *conference, swit
|
||||
conference->video_layout_group = switch_core_strdup(conference->pool, group_name);
|
||||
conference_utils_set_flag(conference, CFLAG_REFRESH_LAYOUT);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
vlayout = conference_video_find_best_layout(conference, lg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!vlayout) {
|
||||
stream->write_function(stream, "Invalid group layout [%s]\n", group_name);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
group_name = NULL;
|
||||
}
|
||||
|
||||
stream->write_function(stream, "Change to layout group [%s]\n", group_name);
|
||||
conference->video_layout_group = switch_core_strdup(conference->pool, group_name);
|
||||
|
||||
if (argv[xx]) {
|
||||
idx = atoi(argv[xx]);
|
||||
if ((idx = atoi(argv[xx])) > 0) {
|
||||
idx--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!vlayout && (vlayout = switch_core_hash_find(conference->layout_hash, argv[2]))) {
|
||||
conference->video_layout_group = NULL;
|
||||
if (argv[3]) {
|
||||
idx = atoi(argv[3]);
|
||||
if ((idx = atoi(argv[3]))) {
|
||||
idx--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!vlayout) {
|
||||
if (!vlayout && !group_name) {
|
||||
stream->write_function(stream, "Invalid layout [%s]\n", argv[2]);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1248,9 +1304,15 @@ switch_status_t conference_api_sub_vid_layout(conference_obj_t *conference, swit
|
||||
conference->new_personal_vlayout = vlayout;
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
} else {
|
||||
stream->write_function(stream, "Change canvas %d to layout [%s]\n", idx + 1, vlayout->name);
|
||||
|
||||
switch_mutex_lock(conference->canvases[idx]->mutex);
|
||||
conference->canvases[idx]->new_vlayout = vlayout;
|
||||
if (vlayout) {
|
||||
stream->write_function(stream, "Change canvas %d to layout [%s]\n", idx + 1, vlayout->name);
|
||||
conference->canvases[idx]->new_vlayout = vlayout;
|
||||
} else if (group_name) {
|
||||
conference->canvases[idx]->video_layout_group = switch_core_strdup(conference->pool, group_name);
|
||||
conference_utils_set_flag(conference, CFLAG_REFRESH_LAYOUT);
|
||||
}
|
||||
switch_mutex_unlock(conference->canvases[idx]->mutex);
|
||||
}
|
||||
|
||||
@ -1589,6 +1651,24 @@ switch_status_t conference_api_sub_get_uuid(conference_member_t *member, switch_
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void clear_res_id(conference_obj_t *conference, conference_member_t *member, const char *id)
|
||||
{
|
||||
conference_member_t *imember;
|
||||
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
if (imember == member) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (imember->video_reservation_id && !strcasecmp(imember->video_reservation_id, id)) {
|
||||
imember->video_reservation_id = NULL;
|
||||
conference_video_detach_video_layer(imember);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
}
|
||||
|
||||
switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||
{
|
||||
char *text = (char *) data;
|
||||
@ -1608,12 +1688,18 @@ switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switc
|
||||
if (zstr(text) || !strcasecmp(text, "clear") || (member->video_reservation_id && !strcasecmp(text, member->video_reservation_id))) {
|
||||
member->video_reservation_id = NULL;
|
||||
stream->write_function(stream, "+OK reservation_id cleared\n");
|
||||
conference_video_detach_video_layer(member);
|
||||
} else {
|
||||
member->video_reservation_id = switch_core_strdup(member->pool, text);
|
||||
clear_res_id(member->conference, member, text);
|
||||
if (!member->video_reservation_id || strcmp(member->video_reservation_id, text)) {
|
||||
member->video_reservation_id = switch_core_strdup(member->pool, text);
|
||||
}
|
||||
stream->write_function(stream, "+OK reservation_id %s\n", text);
|
||||
conference_video_detach_video_layer(member);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
@ -736,6 +736,10 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
||||
|
||||
channel = switch_core_session_get_channel(member->session);
|
||||
|
||||
if (switch_true(switch_channel_get_variable_dup(member->channel, "video_second_screen", SWITCH_FALSE, -1))) {
|
||||
conference_utils_member_set_flag(member, MFLAG_SECOND_SCREEN);
|
||||
}
|
||||
|
||||
conference_video_check_avatar(member, SWITCH_FALSE);
|
||||
|
||||
if ((var = switch_channel_get_variable_dup(member->channel, "video_initial_canvas", SWITCH_FALSE, -1))) {
|
||||
@ -748,16 +752,16 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
||||
|
||||
if ((var = switch_channel_get_variable_dup(member->channel, "video_initial_watching_canvas", SWITCH_FALSE, -1))) {
|
||||
uint32_t id = atoi(var) - 1;
|
||||
|
||||
|
||||
if (id == 0) {
|
||||
id = conference->canvas_count;
|
||||
}
|
||||
|
||||
|
||||
if (id <= conference->canvas_count && conference->canvases[id]) {
|
||||
member->watching_canvas_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
conference_video_reset_member_codec_index(member);
|
||||
|
||||
if (has_video) {
|
||||
|
@ -74,6 +74,13 @@ const char *conference_utils_combine_flag_var(switch_core_session_t *session, co
|
||||
ret = switch_core_session_sprintf(session, "%s|%s", ret, val);
|
||||
}
|
||||
}
|
||||
} else if (!strncasecmp(var, var_name, strlen(var_name)) && switch_true(val)) {
|
||||
char *p = var + strlen(var_name);
|
||||
|
||||
if (*p == '_' && *(p+1)) {
|
||||
p++;
|
||||
ret = switch_core_session_sprintf(session, "%s|%s", ret, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,6 +136,8 @@ void conference_utils_set_mflags(const char *flags, member_flag_t *f)
|
||||
f[MFLAG_GHOST] = 1;
|
||||
} else if (!strcasecmp(argv[i], "join-only")) {
|
||||
f[MFLAG_JOIN_ONLY] = 1;
|
||||
} else if (!strcasecmp(argv[i], "flip-video")) {
|
||||
f[MFLAG_FLIP_VIDEO] = 1;
|
||||
} else if (!strcasecmp(argv[i], "positional")) {
|
||||
f[MFLAG_POSITIONAL] = 1;
|
||||
} else if (!strcasecmp(argv[i], "no-positional")) {
|
||||
@ -338,12 +347,18 @@ switch_bool_t conference_utils_test_mflag(conference_obj_t *conference, member_f
|
||||
void conference_utils_member_set_flag(conference_member_t *member, member_flag_t flag)
|
||||
{
|
||||
member->flags[flag] = 1;
|
||||
|
||||
if (flag == MFLAG_SECOND_SCREEN) {
|
||||
member->flags[MFLAG_CAN_SPEAK] = 0;
|
||||
member->flags[MFLAG_CAN_HEAR] = 0;
|
||||
member->flags[MFLAG_CAN_BE_SEEN] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void conference_utils_member_set_flag_locked(conference_member_t *member, member_flag_t flag)
|
||||
{
|
||||
switch_mutex_lock(member->flag_mutex);
|
||||
member->flags[flag] = 1;
|
||||
conference_utils_member_set_flag(member, flag);
|
||||
switch_mutex_unlock(member->flag_mutex);
|
||||
}
|
||||
|
||||
|
@ -375,6 +375,11 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
|
||||
return;
|
||||
}
|
||||
|
||||
if (layer->clear) {
|
||||
conference_video_clear_layer(layer);
|
||||
layer->clear = 0;
|
||||
}
|
||||
|
||||
if (layer->refresh) {
|
||||
switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &layer->canvas->letterbox_bgcolor);
|
||||
layer->refresh = 0;
|
||||
@ -551,14 +556,16 @@ mcu_layer_t *conference_video_get_layer_locked(conference_member_t *member)
|
||||
mcu_layer_t *layer = NULL;
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
if (!member || member->canvas_id < 0 || member->video_layer_id < 0) return NULL;
|
||||
|
||||
if ((canvas = conference_video_get_canvas_locked(member))) {
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
|
||||
if (member->video_layer_id > -1) {
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
}
|
||||
|
||||
if (!layer) {
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
conference_video_release_canvas(&canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@ -585,10 +592,11 @@ mcu_canvas_t *conference_video_get_canvas_locked(conference_member_t *member)
|
||||
{
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
if (!member || member->canvas_id < 0 || member->video_layer_id < 0) return NULL;
|
||||
|
||||
switch_mutex_lock(member->conference->canvas_mutex);
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
|
||||
if (member->canvas_id > -1 && member->video_layer_id > -1) {
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
}
|
||||
|
||||
if (!canvas) {
|
||||
switch_mutex_unlock(member->conference->canvas_mutex);
|
||||
@ -1225,6 +1233,7 @@ void conference_video_write_canvas_image_to_codec_group(conference_obj_t *confer
|
||||
conference_member_t *imember;
|
||||
switch_frame_t write_frame = { 0 }, *frame = NULL;
|
||||
switch_status_t encode_status = SWITCH_STATUS_FALSE;
|
||||
switch_image_t *scaled_img = codec_set->scaled_img;
|
||||
|
||||
write_frame = codec_set->frame;
|
||||
frame = &write_frame;
|
||||
@ -1246,6 +1255,16 @@ void conference_video_write_canvas_image_to_codec_group(conference_obj_t *confer
|
||||
switch_core_codec_control(&codec_set->codec, SCC_VIDEO_GEN_KEYFRAME, SCCT_NONE, NULL, SCCT_NONE, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (scaled_img) {
|
||||
if (!send_keyframe && codec_set->fps_divisor > 1 && (codec_set->frame_count++) % codec_set->fps_divisor) {
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Skip one frame, total: %d\n", codec_set->frame_count);
|
||||
return;
|
||||
}
|
||||
|
||||
switch_img_scale(frame->img, &scaled_img, scaled_img->d_w, scaled_img->d_h);
|
||||
frame->img = scaled_img;
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
frame->data = ((unsigned char *)frame->packet) + 12;
|
||||
@ -1321,7 +1340,13 @@ video_layout_t *conference_video_find_best_layout(conference_obj_t *conference,
|
||||
{
|
||||
video_layout_node_t *vlnode = NULL, *last = NULL;
|
||||
|
||||
if (!count) count = conference->members_with_video + conference->members_with_avatar;
|
||||
if (!count) {
|
||||
count = conference->members_with_video;
|
||||
|
||||
if (!conference_utils_test_flag(conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS)) {
|
||||
count += conference->members_with_avatar;
|
||||
}
|
||||
}
|
||||
|
||||
for (vlnode = lg->layouts; vlnode; vlnode = vlnode->next) {
|
||||
if (vlnode->vlayout->layers >= (int)count) {
|
||||
@ -1356,21 +1381,22 @@ void conference_video_vmute_snap(conference_member_t *member, switch_bool_t clea
|
||||
if (member->canvas_id > -1 && member->video_layer_id > -1) {
|
||||
mcu_layer_t *layer = NULL;
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
canvas = conference_video_get_canvas_locked(member);
|
||||
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
switch_img_free(&layer->mute_img);
|
||||
switch_img_free(&member->video_mute_img);
|
||||
if ((canvas = conference_video_get_canvas_locked(member))) {
|
||||
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
switch_img_free(&layer->mute_img);
|
||||
switch_img_free(&member->video_mute_img);
|
||||
|
||||
if (!clear && layer->cur_img) {
|
||||
switch_img_copy(layer->cur_img, &member->video_mute_img);
|
||||
switch_img_copy(layer->cur_img, &layer->mute_img);
|
||||
if (!clear && layer->cur_img) {
|
||||
switch_img_copy(layer->cur_img, &member->video_mute_img);
|
||||
switch_img_copy(layer->cur_img, &layer->mute_img);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
conference_video_release_canvas(&canvas);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
conference_video_release_canvas(&canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1539,18 +1565,17 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_write_thread_run(switch_thread_
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
|
||||
if (!layer->need_patch || switch_thread_rwlock_tryrdlock(canvas->video_rwlock) != SWITCH_STATUS_SUCCESS) {
|
||||
canvas = NULL;
|
||||
layer = NULL;
|
||||
if (layer->need_patch && switch_thread_rwlock_tryrdlock(canvas->video_rwlock) == SWITCH_STATUS_SUCCESS) {
|
||||
if (layer->need_patch) {
|
||||
conference_video_scale_and_patch(layer, NULL, SWITCH_FALSE);
|
||||
layer->need_patch = 0;
|
||||
}
|
||||
switch_thread_rwlock_unlock(canvas->video_rwlock);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(member->conference->canvas_mutex);
|
||||
|
||||
if (canvas && layer && layer->need_patch) {
|
||||
conference_video_scale_and_patch(layer, NULL, SWITCH_FALSE);
|
||||
layer->need_patch = 0;
|
||||
switch_thread_rwlock_unlock(canvas->video_rwlock);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1605,6 +1630,10 @@ void conference_video_check_avatar(conference_member_t *member, switch_bool_t fo
|
||||
return;
|
||||
}
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_SECOND_SCREEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas = conference_video_get_canvas_locked(member);
|
||||
|
||||
if (conference_utils_test_flag(member->conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS) &&
|
||||
@ -2130,6 +2159,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
int last_personal = conference_utils_test_flag(conference, CFLAG_PERSONAL_CANVAS) ? 1 : 0;
|
||||
|
||||
canvas->video_timer_reset = 1;
|
||||
canvas->video_layout_group = conference->video_layout_group;
|
||||
|
||||
packet = switch_core_alloc(conference->pool, SWITCH_RTP_MAX_BUF_LEN);
|
||||
|
||||
@ -2142,13 +2172,13 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
switch_image_t *async_file_img = NULL, *normal_file_img = NULL, *file_imgs[2] = { 0 };
|
||||
switch_frame_t file_frame = { 0 };
|
||||
int j = 0, personal = conference_utils_test_flag(conference, CFLAG_PERSONAL_CANVAS) ? 1 : 0;
|
||||
|
||||
int video_count = 0;
|
||||
|
||||
if (!personal) {
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
if (canvas->new_vlayout) {
|
||||
if (canvas->new_vlayout && switch_mutex_trylock(conference->canvas_mutex) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_video_init_canvas_layers(conference, canvas, NULL);
|
||||
switch_mutex_unlock(conference->canvas_mutex);
|
||||
}
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
}
|
||||
|
||||
if (canvas->video_timer_reset) {
|
||||
@ -2162,7 +2192,24 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
canvas->send_keyframe = 1;
|
||||
}
|
||||
|
||||
|
||||
video_count = 0;
|
||||
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
int no_muted = conference_utils_test_flag(imember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS);
|
||||
int no_av = conference_utils_test_flag(imember->conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS);
|
||||
int seen = conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN);
|
||||
|
||||
if (imember->channel && switch_channel_ready(imember->channel) && switch_channel_test_flag(imember->channel, CF_VIDEO_READY) &&
|
||||
!conference_utils_member_test_flag(imember, MFLAG_SECOND_SCREEN) &&
|
||||
conference_utils_member_test_flag(imember, MFLAG_RUNNING) && (!no_muted || seen) && (!no_av || imember->avatar_png_img)
|
||||
&& imember->canvas_id == canvas->canvas_id && imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
video_count++;
|
||||
}
|
||||
}
|
||||
canvas->video_count = video_count;
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
|
||||
switch_core_timer_next(&canvas->timer);
|
||||
|
||||
now = switch_micro_time_now();
|
||||
@ -2186,28 +2233,18 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
if (members_with_avatar != conference->members_with_avatar) {
|
||||
count_changed = 1;
|
||||
}
|
||||
|
||||
if (conference_utils_test_flag(conference, CFLAG_REFRESH_LAYOUT)) {
|
||||
count_changed = 1;
|
||||
conference_utils_clear_flag(conference, CFLAG_REFRESH_LAYOUT);
|
||||
}
|
||||
|
||||
if (count_changed && !personal) {
|
||||
layout_group_t *lg = NULL;
|
||||
video_layout_t *vlayout = NULL;
|
||||
int canvas_count = 0;
|
||||
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
int no_muted = conference_utils_test_flag(imember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS);
|
||||
int no_av = conference_utils_test_flag(imember->conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS);
|
||||
int seen = conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN);
|
||||
|
||||
if (imember->channel && switch_channel_ready(imember->channel) && switch_channel_test_flag(imember->channel, CF_VIDEO_READY) &&
|
||||
conference_utils_member_test_flag(imember, MFLAG_RUNNING) && (!no_muted || seen) && (!no_av || imember->avatar_png_img)
|
||||
&& imember->canvas_id == canvas->canvas_id && imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
canvas_count++;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
|
||||
if (conference->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group))) {
|
||||
if ((vlayout = conference_video_find_best_layout(conference, lg, canvas_count))) {
|
||||
if (canvas->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, canvas->video_layout_group))) {
|
||||
if ((vlayout = conference_video_find_best_layout(conference, lg, canvas->video_count))) {
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
canvas->new_vlayout = vlayout;
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
@ -2313,6 +2350,28 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
write_codecs[i]->frame.data = ((uint8_t *)write_codecs[i]->frame.packet) + 12;
|
||||
write_codecs[i]->frame.packetlen = buflen;
|
||||
write_codecs[i]->frame.buflen = buflen - 12;
|
||||
if (conference->scale_h264_canvas_width > 0 && conference->scale_h264_canvas_height > 0 && !strcmp(check_codec->implementation->iananame, "H264")) {
|
||||
int32_t bw = -1;
|
||||
|
||||
write_codecs[i]->fps_divisor = conference->scale_h264_canvas_fps_divisor;
|
||||
write_codecs[i]->scaled_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->scale_h264_canvas_width, conference->scale_h264_canvas_height, 16);
|
||||
|
||||
if (conference->scale_h264_canvas_bandwidth) {
|
||||
if (strcasecmp(conference->scale_h264_canvas_bandwidth, "auto")) {
|
||||
bw = switch_parse_bandwidth_string(conference->scale_h264_canvas_bandwidth);
|
||||
}
|
||||
}
|
||||
|
||||
if (bw == -1) {
|
||||
float fps = conference->video_fps.fps;
|
||||
|
||||
if (write_codecs[i]->fps_divisor) fps /= write_codecs[i]->fps_divisor;
|
||||
|
||||
bw = switch_calc_bitrate(conference->scale_h264_canvas_width, conference->scale_h264_canvas_height, conference->video_quality, fps);
|
||||
}
|
||||
|
||||
switch_core_codec_control(&write_codecs[i]->codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, &bw, SCCT_NONE, NULL, NULL, NULL);
|
||||
}
|
||||
switch_set_flag((&write_codecs[i]->frame), SFF_RAW_RTP);
|
||||
|
||||
}
|
||||
@ -2348,7 +2407,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
}
|
||||
|
||||
//VIDFLOOR
|
||||
if (canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder &&
|
||||
if (conference->canvas_count == 1 && canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder &&
|
||||
imember->video_layer_id != canvas->layout_floor_id) {
|
||||
conference_video_attach_video_layer(imember, canvas, canvas->layout_floor_id);
|
||||
}
|
||||
@ -2494,11 +2553,6 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
|
||||
if (conference_utils_test_flag(conference, CFLAG_REFRESH_LAYOUT)) {
|
||||
count_changed = 1;
|
||||
conference_utils_clear_flag(conference, CFLAG_REFRESH_LAYOUT);
|
||||
}
|
||||
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
|
||||
if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO_READY) ||
|
||||
@ -2506,17 +2560,19 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!imember->canvas) {
|
||||
if ((vlayout = conference_video_get_layout(conference, conference->video_layout_name, canvas->video_layout_group))) {
|
||||
conference_video_init_canvas(conference, vlayout, &imember->canvas);
|
||||
conference_video_init_canvas_layers(conference, imember->canvas, vlayout);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (conference->new_personal_vlayout) {
|
||||
conference_video_init_canvas_layers(conference, imember->canvas, conference->new_personal_vlayout);
|
||||
layout_applied++;
|
||||
}
|
||||
|
||||
if (!imember->canvas) {
|
||||
if ((vlayout = conference_video_get_layout(conference, conference->video_layout_name, conference->video_layout_group))) {
|
||||
conference_video_init_canvas(conference, vlayout, &imember->canvas);
|
||||
conference_video_init_canvas_layers(conference, imember->canvas, vlayout);
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(imember->channel, CF_VIDEO_REFRESH_REQ)) {
|
||||
switch_channel_clear_flag(imember->channel, CF_VIDEO_REFRESH_REQ);
|
||||
@ -2542,7 +2598,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
total = 0;
|
||||
}
|
||||
|
||||
if (conference->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group))) {
|
||||
if (canvas->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, canvas->video_layout_group))) {
|
||||
if ((vlayout = conference_video_find_best_layout(conference, lg, total + file_count))) {
|
||||
conference_video_init_canvas_layers(conference, imember->canvas, vlayout);
|
||||
}
|
||||
@ -2598,7 +2654,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
int i = 0;
|
||||
mcu_layer_t *floor_layer = NULL;
|
||||
|
||||
if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) ||
|
||||
if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) || !imember->canvas ||
|
||||
(switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY) ||
|
||||
(switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS)) {
|
||||
continue;
|
||||
@ -2669,6 +2725,10 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
|
||||
use_img = omember->pcanvas_img;
|
||||
|
||||
if (files_playing && layer && layer == &imember->canvas->layers[imember->canvas->layout_floor_id]) {
|
||||
use_img = NULL;
|
||||
}
|
||||
|
||||
if (layer) {
|
||||
|
||||
if (use_img && !omember->avatar_png_img) {
|
||||
@ -2977,6 +3037,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
for (i = 0; i < MAX_MUX_CODECS; i++) {
|
||||
if (write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec)) {
|
||||
switch_core_codec_destroy(&write_codecs[i]->codec);
|
||||
switch_img_free(&(write_codecs[i]->scaled_img));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3403,6 +3464,10 @@ void conference_video_set_floor_holder(conference_obj_t *conference, conference_
|
||||
conference_utils_clear_flag(conference, CFLAG_VID_FLOOR_LOCK);
|
||||
}
|
||||
|
||||
if (conference->canvas_count > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (member && member->video_reservation_id) {
|
||||
/* no video floor when a reservation id is set */
|
||||
return;
|
||||
@ -3664,6 +3729,11 @@ switch_status_t conference_video_thread_callback(switch_core_session_t *session,
|
||||
switch_queue_size(member->video_queue) < member->conference->video_fps.fps * 2 &&
|
||||
!member->conference->playing_video_file) {
|
||||
switch_img_copy(frame->img, &img_copy);
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_FLIP_VIDEO)) {
|
||||
switch_img_flip(img_copy);
|
||||
}
|
||||
|
||||
if (switch_queue_trypush(member->video_queue, img_copy) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_img_free(&img_copy);
|
||||
}
|
||||
|
@ -279,7 +279,12 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_channel_ready(channel) && switch_channel_test_flag(channel, CF_VIDEO_READY) && imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY && (!conference_utils_test_flag(conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS) || conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN))) {
|
||||
if (switch_channel_ready(channel) &&
|
||||
switch_channel_test_flag(channel, CF_VIDEO_READY) &&
|
||||
imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY &&
|
||||
!conference_utils_member_test_flag(imember, MFLAG_SECOND_SCREEN) &&
|
||||
(!conference_utils_test_flag(conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS) ||
|
||||
conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN))) {
|
||||
members_with_video++;
|
||||
}
|
||||
|
||||
@ -1249,6 +1254,7 @@ void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, i
|
||||
void conference_fnode_toggle_pause(conference_file_node_t *fnode, switch_stream_handle_t *stream)
|
||||
{
|
||||
if (fnode) {
|
||||
switch_core_file_command(&fnode->fh, SCFC_PAUSE_READ);
|
||||
if (switch_test_flag(fnode, NFLAG_PAUSE)) {
|
||||
stream->write_function(stream, "+OK Resume\n");
|
||||
switch_clear_flag(fnode, NFLAG_PAUSE);
|
||||
@ -1259,6 +1265,15 @@ void conference_fnode_toggle_pause(conference_file_node_t *fnode, switch_stream_
|
||||
}
|
||||
}
|
||||
|
||||
void conference_fnode_check_status(conference_file_node_t *fnode, switch_stream_handle_t *stream)
|
||||
{
|
||||
if (fnode) {
|
||||
stream->write_function(stream, "+OK %"SWITCH_INT64_T_FMT "/%" SWITCH_INT64_T_FMT " %s\n",
|
||||
fnode->fh.vpos, fnode->fh.duration, fnode->fh.file_path);
|
||||
} else {
|
||||
stream->write_function(stream, "-ERR Nothing is playing\n");
|
||||
}
|
||||
}
|
||||
|
||||
void conference_fnode_seek(conference_file_node_t *fnode, switch_stream_handle_t *stream, char *arg)
|
||||
{
|
||||
@ -2411,7 +2426,12 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
||||
const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = NULL;
|
||||
uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = 0, video_auto_floor_msec = 0;
|
||||
switch_event_t *event;
|
||||
|
||||
|
||||
int scale_h264_canvas_width = 0;
|
||||
int scale_h264_canvas_height = 0;
|
||||
int scale_h264_canvas_fps_divisor = 0;
|
||||
char *scale_h264_canvas_bandwidth = NULL;
|
||||
|
||||
/* Validate the conference name */
|
||||
if (zstr(name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Record! no name.\n");
|
||||
@ -2720,6 +2740,28 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "video-mode invalid, valid settings are 'passthrough', 'transcode' and 'mux'\n");
|
||||
}
|
||||
} else if (!strcasecmp(var, "scale-h264-canvas-size") && !zstr(val)) {
|
||||
char *p;
|
||||
|
||||
if ((scale_h264_canvas_width = atoi(val))) {
|
||||
if ((p = strchr(val, 'x'))) {
|
||||
p++;
|
||||
if (*p) {
|
||||
scale_h264_canvas_height = atoi(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scale_h264_canvas_width < 320 || scale_h264_canvas_width < 180) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid scale-h264-canvas-size, falling back to 320x180\n");
|
||||
scale_h264_canvas_width = 320;
|
||||
scale_h264_canvas_width = 180;
|
||||
}
|
||||
} else if (!strcasecmp(var, "scale-h264-canvas-fps-divisor") && !zstr(val)) {
|
||||
scale_h264_canvas_fps_divisor = atoi(val);
|
||||
if (scale_h264_canvas_fps_divisor < 0) scale_h264_canvas_fps_divisor = 0;
|
||||
} else if (!strcasecmp(var, "scale-h264-canvas-bandwidth") && !zstr(val)) {
|
||||
scale_h264_canvas_bandwidth = val;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2783,6 +2825,11 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
||||
|
||||
conference->conference_video_mode = conference_video_mode;
|
||||
|
||||
conference->scale_h264_canvas_width = scale_h264_canvas_width;
|
||||
conference->scale_h264_canvas_height = scale_h264_canvas_height;
|
||||
conference->scale_h264_canvas_fps_divisor = scale_h264_canvas_fps_divisor;
|
||||
conference->scale_h264_canvas_bandwidth = switch_core_strdup(conference->pool, scale_h264_canvas_bandwidth);
|
||||
|
||||
if (!switch_core_has_video() && (conference->conference_video_mode == CONF_VIDEO_MODE_MUX || conference->conference_video_mode == CONF_VIDEO_MODE_TRANSCODE)) {
|
||||
conference->conference_video_mode = CONF_VIDEO_MODE_PASSTHROUGH;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "video-mode invalid, only valid setting is 'passthrough' due to no video capabilities\n");
|
||||
@ -2860,6 +2907,8 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
||||
}
|
||||
}
|
||||
|
||||
conference->video_codec_settings.video.try_hardware_encoder = 1;
|
||||
|
||||
if (zstr(video_layout_name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No video-layout-name specified, using " CONFERENCE_MUX_DEFAULT_LAYOUT "\n");
|
||||
video_layout_name = CONFERENCE_MUX_DEFAULT_LAYOUT;
|
||||
|
@ -208,6 +208,7 @@ typedef enum {
|
||||
MFLAG_CAN_BE_SEEN,
|
||||
MFLAG_SECOND_SCREEN,
|
||||
MFLAG_SILENT,
|
||||
MFLAG_FLIP_VIDEO,
|
||||
///////////////////////////
|
||||
MFLAG_MAX
|
||||
} member_flag_t;
|
||||
@ -439,6 +440,7 @@ typedef struct mcu_layer_s {
|
||||
int mute_patched;
|
||||
int avatar_patched;
|
||||
int refresh;
|
||||
int clear;
|
||||
int is_avatar;
|
||||
switch_size_t last_img_addr;
|
||||
switch_img_position_t logo_pos;
|
||||
@ -484,6 +486,8 @@ typedef struct mcu_canvas_s {
|
||||
int refresh;
|
||||
int send_keyframe;
|
||||
int play_file;
|
||||
int video_count;
|
||||
char *video_layout_group;
|
||||
switch_rgb_color_t bgcolor;
|
||||
switch_rgb_color_t border_color;
|
||||
switch_rgb_color_t letterbox_bgcolor;
|
||||
@ -662,6 +666,12 @@ typedef struct conference_obj {
|
||||
video_layout_t *new_personal_vlayout;
|
||||
int max_bw_in;
|
||||
int force_bw_in;
|
||||
|
||||
/* special use case, scalling shared h264 canvas*/
|
||||
int scale_h264_canvas_width;
|
||||
int scale_h264_canvas_height;
|
||||
int scale_h264_canvas_fps_divisor;
|
||||
char *scale_h264_canvas_bandwidth;
|
||||
} conference_obj_t;
|
||||
|
||||
/* Relationship with another member */
|
||||
@ -793,6 +803,9 @@ typedef struct codec_set_s {
|
||||
switch_codec_t codec;
|
||||
switch_frame_t frame;
|
||||
uint8_t *packet;
|
||||
switch_image_t *scaled_img;
|
||||
uint8_t fps_divisor;
|
||||
uint32_t frame_count;
|
||||
} codec_set_t;
|
||||
|
||||
typedef void (*conference_key_callback_t) (conference_member_t *, struct caller_control_actions *);
|
||||
@ -955,6 +968,7 @@ int conference_member_noise_gate_check(conference_member_t *member);
|
||||
void conference_member_check_channels(switch_frame_t *frame, conference_member_t *member, switch_bool_t in);
|
||||
|
||||
void conference_fnode_toggle_pause(conference_file_node_t *fnode, switch_stream_handle_t *stream);
|
||||
void conference_fnode_check_status(conference_file_node_t *fnode, switch_stream_handle_t *stream);
|
||||
|
||||
// static conference_relationship_t *conference_member_get_relationship(conference_member_t *member, conference_member_t *other_member);
|
||||
// static void conference_list(conference_obj_t *conference, switch_stream_handle_t *stream, char *delim);
|
||||
@ -1050,6 +1064,7 @@ switch_status_t conference_api_sub_position(conference_member_t *member, switch_
|
||||
switch_status_t conference_api_sub_conference_video_vmute_snap(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_dtmf(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_pause_play(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_play_status(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_play(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_say(conference_obj_t *conference, switch_stream_handle_t *stream, const char *text);
|
||||
switch_status_t conference_api_sub_dial(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
@ -1091,6 +1106,7 @@ switch_status_t conference_api_sub_watching_canvas(conference_member_t *member,
|
||||
switch_status_t conference_api_sub_canvas(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_layer(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_kick(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_vid_flip(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_transfer(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_record(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_norecord(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
|
@ -82,14 +82,16 @@ SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_custom_query, globals.custom_query)
|
||||
static int route_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
route_callback_t *cbt = (route_callback_t *) pArg;
|
||||
|
||||
switch_copy_string(cbt->gateway, argv[0], 128);
|
||||
switch_copy_string(cbt->group, argv[1], 128);
|
||||
switch_copy_string(cbt->limit, argv[2], 128);
|
||||
switch_copy_string(cbt->techprofile, argv[3], 128);
|
||||
switch_copy_string(cbt->acctcode, argv[4], 128);
|
||||
switch_copy_string(cbt->translated, argv[5], 60);
|
||||
|
||||
if (argc >= 6) {
|
||||
switch_copy_string(cbt->gateway, argv[0], 128);
|
||||
switch_copy_string(cbt->group, argv[1], 128);
|
||||
switch_copy_string(cbt->limit, argv[2], 128);
|
||||
switch_copy_string(cbt->techprofile, argv[3], 128);
|
||||
switch_copy_string(cbt->acctcode, argv[4], 128);
|
||||
switch_copy_string(cbt->translated, argv[5], 60);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql for route_callback only returning %d fields\n", argc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -367,7 +367,8 @@ SWITCH_STANDARD_APP(play_fsv_function)
|
||||
goto end;
|
||||
}
|
||||
switch_core_session_set_read_codec(session, &codec);
|
||||
|
||||
switch_channel_set_flag(channel, CF_VIDEO_WRITING);
|
||||
|
||||
while (switch_channel_ready(channel)) {
|
||||
|
||||
if (read(fd, &bytes, sizeof(bytes)) != sizeof(bytes)) {
|
||||
@ -464,9 +465,8 @@ SWITCH_STANDARD_APP(play_fsv_function)
|
||||
switch_core_timer_destroy(&timer);
|
||||
}
|
||||
|
||||
|
||||
switch_core_session_set_read_codec(session, NULL);
|
||||
|
||||
switch_channel_clear_flag(channel, CF_VIDEO_WRITING);
|
||||
|
||||
if (switch_core_codec_ready(&codec)) {
|
||||
switch_core_codec_destroy(&codec);
|
||||
@ -510,6 +510,8 @@ SWITCH_STANDARD_APP(play_yuv_function)
|
||||
|
||||
switch_channel_answer(channel);
|
||||
|
||||
switch_core_session_request_video_refresh(session);
|
||||
|
||||
switch_channel_audio_sync(channel);
|
||||
switch_core_session_raw_read(session);
|
||||
|
||||
@ -529,7 +531,7 @@ SWITCH_STANDARD_APP(play_yuv_function)
|
||||
done = switch_micro_time_now() + (to * 1000);
|
||||
}
|
||||
|
||||
switch_channel_set_flag(channel, CF_VIDEO_DECODED_READ);
|
||||
// switch_channel_set_flag(channel, CF_VIDEO_DECODED_READ);
|
||||
|
||||
while (switch_channel_ready(channel) && !switch_channel_test_flag(channel, CF_VIDEO)) {
|
||||
if ((++loops % 100) == 0) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Waiting for video......\n");
|
||||
@ -555,7 +557,7 @@ SWITCH_STANDARD_APP(play_yuv_function)
|
||||
|
||||
yuv = img->planes[SWITCH_PLANE_PACKED];
|
||||
|
||||
// switch_channel_set_flag(channel, CF_VIDEO_PASSIVE);
|
||||
switch_channel_set_flag(channel, CF_VIDEO_WRITING);
|
||||
//SWITCH_RTP_MAX_BUF_LEN
|
||||
vid_buffer = switch_core_session_alloc(session, SWITCH_RTP_MAX_BUF_LEN);
|
||||
|
||||
@ -653,7 +655,7 @@ SWITCH_STANDARD_APP(play_yuv_function)
|
||||
|
||||
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
|
||||
switch_core_session_video_reset(session);
|
||||
// switch_channel_clear_flag(channel, CF_VIDEO_PASSIVE);
|
||||
switch_channel_clear_flag(channel, CF_VIDEO_WRITING);
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,6 +51,18 @@ static struct {
|
||||
char *memcached_str;
|
||||
} globals;
|
||||
|
||||
#define BYTES_PER_SAMPLE 2
|
||||
|
||||
struct memcache_context {
|
||||
memcached_st *memcached;
|
||||
char *path;
|
||||
int ok;
|
||||
size_t offset;
|
||||
size_t remaining;
|
||||
void *data;
|
||||
};
|
||||
typedef struct memcache_context memcache_context_t;
|
||||
|
||||
static switch_event_node_t *NODE = NULL;
|
||||
|
||||
static switch_status_t config_callback_memcached(switch_xml_config_item_t *data, const char *newvalue, switch_config_callback_type_t callback_type,
|
||||
@ -431,10 +443,149 @@ SWITCH_STANDARD_API(memcache_function)
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t memcache_file_open(switch_file_handle_t *handle, const char *path)
|
||||
{
|
||||
memcache_context_t *context;
|
||||
size_t string_length = 0;
|
||||
uint32_t flags = 0;
|
||||
memcached_return rc;
|
||||
|
||||
if (handle->offset_pos) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Offset unsupported.\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
context = switch_core_alloc(handle->memory_pool, sizeof(*context));
|
||||
|
||||
/* Clone memcached struct so we're thread safe */
|
||||
context->memcached = memcached_clone(NULL, globals.memcached);
|
||||
if (!context->memcached) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error cloning memcached object\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* All of the actual data is read into the buffer here, the memcache_file_read
|
||||
* function just iterates over the buffer
|
||||
*/
|
||||
if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) {
|
||||
handle->private_info = context;
|
||||
|
||||
context->data = memcached_get(context->memcached, path, strlen(path), &string_length, &flags, &rc);
|
||||
|
||||
if (context->data && rc == MEMCACHED_SUCCESS) {
|
||||
context->ok = 1;
|
||||
context->offset = 0;
|
||||
context->remaining = string_length / BYTES_PER_SAMPLE;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
memcached_free(context->memcached);
|
||||
context->memcached = NULL;
|
||||
switch_safe_free(context->data);
|
||||
context->data = NULL;
|
||||
context->ok = 0;
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
} else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
|
||||
if (switch_test_flag(handle, SWITCH_FILE_WRITE_OVER)) {
|
||||
memcached_free(context->memcached);
|
||||
context->memcached = NULL;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unsupported file mode.\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
context->path = switch_core_strdup(handle->memory_pool, path);
|
||||
|
||||
if (! switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) {
|
||||
/* If not appending, we need to write an empty string to the key so that
|
||||
* memcache_file_write appends do the right thing
|
||||
*/
|
||||
rc = memcached_set(context->memcached, context->path, strlen(context->path), "", 0, 0, 0);
|
||||
if (rc != MEMCACHED_SUCCESS) {
|
||||
memcached_free(context->memcached);
|
||||
context->memcached = NULL;
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
}
|
||||
|
||||
context->ok = 1;
|
||||
handle->private_info = context;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File opened with unknown flags!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
static switch_status_t memcache_file_close(switch_file_handle_t *handle)
|
||||
{
|
||||
memcache_context_t *memcache_context = handle->private_info;
|
||||
|
||||
if (memcache_context->data) {
|
||||
switch_safe_free(memcache_context->data);
|
||||
memcache_context->data = NULL;
|
||||
}
|
||||
if (memcache_context->memcached) {
|
||||
memcached_free(memcache_context->memcached);
|
||||
memcache_context->memcached = NULL;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t memcache_file_read(switch_file_handle_t *handle, void *data, size_t *len)
|
||||
{
|
||||
memcache_context_t *context= handle->private_info;
|
||||
|
||||
if (context->ok) {
|
||||
if (context->remaining <= 0) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (*len > (size_t) context->remaining) {
|
||||
*len = context->remaining;
|
||||
}
|
||||
|
||||
memcpy(data, (uint8_t *)context->data + (context->offset * BYTES_PER_SAMPLE), *len * BYTES_PER_SAMPLE);
|
||||
|
||||
context->offset += (int32_t)*len;
|
||||
context->remaining -= (int32_t)*len;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
static switch_status_t memcache_file_write(switch_file_handle_t *handle, void *data, size_t *len)
|
||||
{
|
||||
memcache_context_t *context = handle->private_info;
|
||||
memcached_return rc;
|
||||
|
||||
/* Append this chunk */
|
||||
if (context->ok) {
|
||||
rc = memcached_append(context->memcached, context->path, strlen(context->path), data, *len, 0, 0);
|
||||
|
||||
if (rc != MEMCACHED_SUCCESS) {
|
||||
context->ok = 0;
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
|
||||
|
||||
/* Macro expands to: switch_status_t mod_memcache_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_memcache_load)
|
||||
{
|
||||
switch_api_interface_t *api_interface;
|
||||
switch_file_interface_t *file_interface;
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
@ -449,6 +600,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_memcache_load)
|
||||
|
||||
SWITCH_ADD_API(api_interface, "memcache", "Memcache API", memcache_function, "syntax");
|
||||
|
||||
/* file interface */
|
||||
supported_formats[0] = "memcache";
|
||||
file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
|
||||
file_interface->interface_name = modname;
|
||||
file_interface->extens = supported_formats;
|
||||
file_interface->file_open = memcache_file_open;
|
||||
file_interface->file_close = memcache_file_close;
|
||||
file_interface->file_read = memcache_file_read;
|
||||
file_interface->file_write = memcache_file_write;
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_NOUNLOAD;
|
||||
}
|
||||
|
@ -333,18 +333,16 @@ static switch_status_t switch_sangoma_init(switch_codec_t *codec, switch_codec_f
|
||||
if (!(sess = switch_core_alloc(codec->memory_pool, sizeof(*sess)))) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
memset(sess, 0, sizeof(*sess));
|
||||
|
||||
sess->encoder.lastrxseqno = -1;
|
||||
sess->decoder.lastrxseqno = -1;
|
||||
|
||||
sess->pool = codec->memory_pool;
|
||||
sess->impl = codec->implementation;
|
||||
switch_assert(sess->pool);
|
||||
switch_assert(sess->impl);
|
||||
|
||||
vcodec = get_codec_from_iana(codec->implementation->ianacode, codec->implementation->bits_per_second);
|
||||
|
||||
switch_mutex_lock(g_sessions_lock);
|
||||
|
||||
if (encoding) {
|
||||
sess->encoder.request.usr_priv = sess;
|
||||
sess->encoder.request.a.host_ip = g_rtpip;
|
||||
@ -370,13 +368,15 @@ static switch_status_t switch_sangoma_init(switch_codec_t *codec, switch_codec_f
|
||||
|
||||
}
|
||||
|
||||
switch_mutex_lock(g_sessions_lock);
|
||||
|
||||
sess->sessid = g_next_session_id++;
|
||||
switch_snprintf(sess->hashkey, sizeof(sess->hashkey), SANGOMA_SESS_HASH_KEY_FORMAT, sess->sessid);
|
||||
switch_core_hash_insert(g_sessions_hash, sess->hashkey, sess);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sangoma init done for codec %s/%s, iana = %d\n", codec->implementation->iananame, vcodec->fs_name, codec->implementation->ianacode);
|
||||
switch_mutex_unlock(g_sessions_lock);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sangoma init done for codec %s/%s, iana = %d\n", codec->implementation->iananame, vcodec->fs_name, codec->implementation->ianacode);
|
||||
codec->private_info = sess;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@ -864,14 +864,13 @@ static switch_status_t switch_sangoma_destroy(switch_codec_t *codec)
|
||||
|
||||
if (sess->encoder.txrtp) {
|
||||
sngtc_free_transcoding_session(&sess->encoder.reply);
|
||||
memset(&sess->encoder, 0, sizeof(sess->encoder));
|
||||
}
|
||||
if (sess->decoder.txrtp) {
|
||||
sngtc_free_transcoding_session(&sess->decoder.reply);
|
||||
memset(&sess->decoder, 0, sizeof(sess->decoder));
|
||||
}
|
||||
|
||||
switch_core_hash_delete(g_sessions_hash, sess->hashkey);
|
||||
memset(sess, 0, sizeof(*sess));
|
||||
|
||||
switch_mutex_unlock(g_sessions_lock);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
@ -911,7 +911,6 @@ switch_status_t rtmp_session_request(rtmp_profile_t *profile, rtmp_session_t **n
|
||||
{
|
||||
char buf[1024];
|
||||
#ifndef _WIN32
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), "/tmp/rtmp-%s-in.txt", (*newsession)->uuid);
|
||||
(*newsession)->io_debug_in = fopen(buf, "w");
|
||||
snprintf(buf, sizeof(buf), "/tmp/rtmp-%s-out.txt", (*newsession)->uuid);
|
||||
|
@ -515,6 +515,7 @@ struct rtmp_session {
|
||||
uint32_t media_streamid; /* < The stream id that was used for the last "play" command,
|
||||
where we should send media */
|
||||
switch_size_t dropped_video_frame;
|
||||
switch_queue_t *video_send_queue;
|
||||
|
||||
uint8_t media_debug;
|
||||
};
|
||||
|
@ -41,6 +41,17 @@ typedef struct {
|
||||
size_t len;
|
||||
} buffer_helper_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t amfnumber;
|
||||
uint32_t timestamp;
|
||||
uint8_t type;
|
||||
uint32_t stream_id;
|
||||
switch_size_t len;
|
||||
uint32_t flags;
|
||||
unsigned char *message;
|
||||
} video_send_buffer_t;
|
||||
|
||||
|
||||
size_t my_buffer_read(void * out_buffer, size_t size, void * user_data)
|
||||
{
|
||||
buffer_helper_t *helper = (buffer_helper_t*)user_data;
|
||||
@ -561,8 +572,62 @@ switch_status_t rtmp_send_invoke_v(rtmp_session_t *rsession, uint8_t amfnumber,
|
||||
return rtmp_send_message(rsession, amfnumber, timestamp, type, stream_id, buf, helper.pos, 0);
|
||||
}
|
||||
|
||||
static int flush_video_send_queue(rtmp_session_t *rsession, switch_bool_t lock)
|
||||
{
|
||||
video_send_buffer_t *b;
|
||||
void *pop;
|
||||
switch_queue_t *q = rsession->video_send_queue;
|
||||
int x = 0;
|
||||
|
||||
if (!q) return 0;
|
||||
|
||||
if (lock) switch_mutex_lock(rsession->socket_mutex);
|
||||
while (switch_queue_size(q) > 0 && switch_queue_trypop(q, &pop) == SWITCH_STATUS_SUCCESS && pop) {
|
||||
b = (video_send_buffer_t *)pop;
|
||||
free(b->message);
|
||||
free(b);
|
||||
x++;
|
||||
}
|
||||
if (lock) switch_mutex_unlock(rsession->socket_mutex);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Dropped %d Video Frames\n", x);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
static void buffer_video_send(rtmp_session_t *rsession, uint8_t amfnumber, uint32_t timestamp, uint8_t type, uint32_t stream_id, const unsigned char *message, switch_size_t len, uint32_t flags)
|
||||
{
|
||||
video_send_buffer_t *vbuf;
|
||||
|
||||
switch_mutex_lock(rsession->socket_mutex);
|
||||
|
||||
if (!rsession->video_send_queue) {
|
||||
switch_queue_create(&rsession->video_send_queue, 1000, rsession->pool);
|
||||
}
|
||||
|
||||
if (*message == 0x17) {
|
||||
flush_video_send_queue(rsession, SWITCH_FALSE);
|
||||
}
|
||||
|
||||
vbuf = malloc(sizeof(video_send_buffer_t));
|
||||
switch_assert(vbuf);
|
||||
|
||||
vbuf->amfnumber = amfnumber;
|
||||
vbuf->timestamp = timestamp;
|
||||
vbuf->type = type;
|
||||
vbuf->stream_id = stream_id;
|
||||
vbuf->len = len;
|
||||
vbuf->flags = flags;
|
||||
vbuf->message = malloc(len);
|
||||
switch_assert(vbuf->message);
|
||||
|
||||
memcpy(vbuf->message, message, len);
|
||||
|
||||
switch_queue_push(rsession->video_send_queue, (void *)vbuf);
|
||||
switch_mutex_unlock(rsession->socket_mutex);
|
||||
}
|
||||
|
||||
/* Break message down into 128 bytes chunks, add the appropriate headers and send it out */
|
||||
switch_status_t rtmp_send_message(rtmp_session_t *rsession, uint8_t amfnumber, uint32_t timestamp, uint8_t type, uint32_t stream_id, const unsigned char *message, switch_size_t len, uint32_t flags)
|
||||
switch_status_t _rtmp_send_message(rtmp_session_t *rsession, uint8_t amfnumber, uint32_t timestamp, uint8_t type, uint32_t stream_id, const unsigned char *message, switch_size_t len, uint32_t flags)
|
||||
{
|
||||
switch_size_t pos = 0;
|
||||
uint8_t header[12] = { amfnumber & 0x3F, INT24(0), INT24(len), type, INT32_LE(stream_id) };
|
||||
@ -575,52 +640,6 @@ switch_status_t rtmp_send_message(rtmp_session_t *rsession, uint8_t amfnumber, u
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%d send_ack=%d send=%d window=%d wait_ack=%d\n",
|
||||
// type, rsession->send_ack, rsession->send, rsession->send_ack_window, rsession->send + 3073 - rsession->send_ack);
|
||||
|
||||
if (type == RTMP_TYPE_VIDEO) {
|
||||
uint32_t window = rsession->send_ack_window;
|
||||
|
||||
if (rsession->media_debug & RTMP_MD_VIDEO_WRITE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "W V ts:%u data:0x%02x len:%" SWITCH_SIZE_T_FMT "\n", timestamp, *message, len);
|
||||
}
|
||||
|
||||
/* start to drop video frame on window/2 if the frame is a non-IDR video frame
|
||||
start to drop video frame on window * 3/4 if the frame is a IDR frame
|
||||
start to drop audio frame on widnow full
|
||||
*/
|
||||
|
||||
if (*message == 0x17) {
|
||||
window = window / 4 * 3;
|
||||
} else {
|
||||
window /= 2;
|
||||
}
|
||||
|
||||
if ((rsession->send_ack + window) < (rsession->send + 3073)) {
|
||||
/* We're sending too fast, drop the frame */
|
||||
rsession->dropped_video_frame++;
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_DEBUG,
|
||||
"DROP VIDEO FRAME [amfnumber=%d type=0x%x stream_id=0x%x ftype=0x%x] len=%"SWITCH_SIZE_T_FMT
|
||||
" dropped=%"SWITCH_SIZE_T_FMT"\n",
|
||||
amfnumber, type, stream_id, *message, len, rsession->dropped_video_frame);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (rsession->dropped_video_frame) {
|
||||
if (*message != 0x17) {
|
||||
rsession->dropped_video_frame++;
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_DEBUG,
|
||||
"DROP VIDEO FRAME [amfnumber=%d type=0x%x stream_id=0x%x ftype=0x%x] len=%"SWITCH_SIZE_T_FMT
|
||||
" dropped=%"SWITCH_SIZE_T_FMT" waiting for the next IDR\n",
|
||||
amfnumber, type, stream_id, *message, len, rsession->dropped_video_frame);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO,
|
||||
"Got IDR frame after %"SWITCH_SIZE_T_FMT" frame(s) dropped\n",
|
||||
rsession->dropped_video_frame);
|
||||
rsession->dropped_video_frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == RTMP_TYPE_AUDIO && (rsession->media_debug & RTMP_MD_AUDIO_WRITE)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "W A ts:%u data:0x%02x len:%" SWITCH_SIZE_T_FMT "\n", timestamp, *message, len);
|
||||
}
|
||||
@ -696,6 +715,8 @@ switch_status_t rtmp_send_message(rtmp_session_t *rsession, uint8_t amfnumber, u
|
||||
header[3] = timestamp & 0xFF;
|
||||
}
|
||||
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "=== send type: %d ts: %d bytes: %zu\n", type, timestamp, len);
|
||||
|
||||
state->ts = timestamp;
|
||||
state->type = type;
|
||||
state->origlen = len;
|
||||
@ -740,6 +761,79 @@ end:
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_status_t rtmp_send_message(rtmp_session_t *rsession, uint8_t amfnumber, uint32_t timestamp, uint8_t type, uint32_t stream_id, const unsigned char *message, switch_size_t len, uint32_t flags)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
int window = rsession->send_ack_window;
|
||||
|
||||
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%d send_ack=%d send=%d window=%d wait_ack=%d\n",
|
||||
// type, rsession->send_ack, rsession->send, rsession->send_ack_window, rsession->send + 3073 - rsession->send_ack);
|
||||
|
||||
if (type != RTMP_TYPE_VIDEO) {
|
||||
return _rtmp_send_message(rsession, amfnumber, timestamp, type, stream_id, message, len, flags);
|
||||
}
|
||||
|
||||
if (rsession->media_debug & RTMP_MD_VIDEO_WRITE) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "W V ts:%u data:0x%02x len:%" SWITCH_SIZE_T_FMT "\n", timestamp, *message, len);
|
||||
}
|
||||
|
||||
window = window / 4 * 3;
|
||||
// window = 65000;
|
||||
|
||||
if ((rsession->send_ack + window) < (rsession->send + 3073)) {
|
||||
buffer_video_send(rsession, amfnumber, timestamp, type, stream_id, message, len, flags);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "queued %zu bytes, ts: %d, queue size:%d\n", len, timestamp, switch_queue_size(rsession->video_send_queue));
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (rsession->video_send_queue && switch_queue_size(rsession->video_send_queue)) {
|
||||
if (*message == 0x17) { // key frame
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Got a key frame, flush video queue %d\n", switch_queue_size(rsession->video_send_queue));
|
||||
flush_video_send_queue(rsession, SWITCH_TRUE);
|
||||
return _rtmp_send_message(rsession, amfnumber, timestamp, type, stream_id, message, len, flags);
|
||||
} else {
|
||||
int x = 0;
|
||||
void *pop = NULL;
|
||||
|
||||
buffer_video_send(rsession, amfnumber, timestamp, type, stream_id, message, len, flags);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "queued %zu bytes, ts: %d, queue size:%d\n", len, timestamp, switch_queue_size(rsession->video_send_queue));
|
||||
|
||||
again:
|
||||
switch_mutex_lock(rsession->socket_mutex);
|
||||
switch_queue_trypop(rsession->video_send_queue, &pop);
|
||||
switch_mutex_unlock(rsession->socket_mutex);
|
||||
|
||||
if (pop) {
|
||||
video_send_buffer_t *vbuf = (video_send_buffer_t *)pop;
|
||||
|
||||
amfnumber = vbuf->amfnumber;
|
||||
// timestamp = vbuf->timestamp;
|
||||
type = vbuf->type;
|
||||
stream_id = vbuf->stream_id;
|
||||
len = vbuf->len;
|
||||
flags = vbuf->flags;
|
||||
message = vbuf->message;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "pop len: %zu, ts: %d, queue size: %d\n", len, timestamp, switch_queue_size(rsession->video_send_queue));
|
||||
|
||||
status = _rtmp_send_message(rsession, amfnumber, timestamp, type, stream_id, message, len, flags);
|
||||
|
||||
free(vbuf->message);
|
||||
free(vbuf);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS && ((rsession->send_ack + window) >= (rsession->send + 3073) && (++x < 3))) {
|
||||
pop = NULL;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return _rtmp_send_message(rsession, amfnumber, timestamp, type, stream_id, message, len, flags);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Returns SWITCH_STATUS_SUCCESS of the connection is still active or SWITCH_STATUS_FALSE to tear it down */
|
||||
switch_status_t rtmp_handle_data(rtmp_session_t *rsession)
|
||||
{
|
||||
|
@ -301,6 +301,10 @@ switch_status_t rtmp_tcp_init(rtmp_profile_t *profile, const char *bindaddr, rtm
|
||||
if (switch_socket_opt_set(io_tcp->listen_socket, SWITCH_SO_TCP_NODELAY, 1)) {
|
||||
goto fail;
|
||||
}
|
||||
if (1) {
|
||||
switch_socket_opt_set(io_tcp->listen_socket, SWITCH_SO_RCVBUF, 1572864);
|
||||
switch_socket_opt_set(io_tcp->listen_socket, SWITCH_SO_SNDBUF, 1572864);
|
||||
}
|
||||
if (switch_socket_bind(io_tcp->listen_socket, sa)) {
|
||||
goto fail;
|
||||
}
|
||||
|
@ -583,7 +583,7 @@ switch_status_t rtmp_write_video_frame(switch_core_session_t *session, switch_fr
|
||||
rtmp_rtp2rtmpH264(helper, frame);
|
||||
|
||||
if (helper->send) {
|
||||
uint16_t used = switch_buffer_inuse(helper->rtmp_buf);
|
||||
uint32_t used = switch_buffer_inuse(helper->rtmp_buf);
|
||||
const void *rtmp_data = NULL;
|
||||
|
||||
switch_buffer_peek_zerocopy(helper->rtmp_buf, &rtmp_data);
|
||||
@ -633,6 +633,11 @@ switch_status_t rtmp_write_video_frame(switch_core_session_t *session, switch_fr
|
||||
switch_core_session_rwunlock(other_session);
|
||||
}
|
||||
}
|
||||
|
||||
if (rsession->video_send_queue && switch_queue_size(rsession->video_send_queue) > 30) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Need a key frame\n");
|
||||
switch_channel_set_flag(channel, CF_VIDEO_REFRESH_REQ);
|
||||
}
|
||||
skip:
|
||||
switch_buffer_zero(helper->rtmp_buf);
|
||||
switch_buffer_zero(helper->fua_buf);
|
||||
|
@ -320,7 +320,7 @@ void skinny_line_get(listener_t *listener, uint32_t instance, struct line_stat_r
|
||||
switch_assert(listener->profile);
|
||||
switch_assert(listener->device_name);
|
||||
|
||||
helper.button = switch_core_alloc(listener->pool, sizeof(struct line_stat_res_message));
|
||||
helper.button = calloc(sizeof(struct line_stat_res_message),1);
|
||||
|
||||
if ((sql = switch_mprintf(
|
||||
"SELECT '%d' AS wanted_position, position, label, value, caller_name "
|
||||
@ -363,7 +363,7 @@ void skinny_speed_dial_get(listener_t *listener, uint32_t instance, struct speed
|
||||
switch_assert(listener->profile);
|
||||
switch_assert(listener->device_name);
|
||||
|
||||
helper.button = switch_core_alloc(listener->pool, sizeof(struct speed_dial_stat_res_message));
|
||||
helper.button = calloc(sizeof(struct speed_dial_stat_res_message),1);
|
||||
|
||||
if ((sql = switch_mprintf(
|
||||
"SELECT '%d' AS wanted_position, position, label, value, settings "
|
||||
@ -407,7 +407,7 @@ void skinny_service_url_get(listener_t *listener, uint32_t instance, struct serv
|
||||
switch_assert(listener->profile);
|
||||
switch_assert(listener->device_name);
|
||||
|
||||
helper.button = switch_core_alloc(listener->pool, sizeof(struct service_url_stat_res_message));
|
||||
helper.button = calloc(sizeof(struct service_url_stat_res_message), 1);
|
||||
|
||||
if ((sql = switch_mprintf(
|
||||
"SELECT '%d' AS wanted_position, position, label, value, settings "
|
||||
@ -453,7 +453,7 @@ void skinny_feature_get(listener_t *listener, uint32_t instance, struct feature_
|
||||
switch_assert(listener->profile);
|
||||
switch_assert(listener->device_name);
|
||||
|
||||
helper.button = switch_core_alloc(listener->pool, sizeof(struct feature_stat_res_message));
|
||||
helper.button = calloc(sizeof(struct feature_stat_res_message), 1);
|
||||
|
||||
if ((sql = switch_mprintf(
|
||||
"SELECT '%d' AS wanted_position, position, label, value, settings "
|
||||
|
@ -116,6 +116,9 @@ switch_status_t skinny_create_incoming_session(listener_t *listener, uint32_t *l
|
||||
|
||||
if (!button || !button->shortname[0]) {
|
||||
skinny_log_l(listener, SWITCH_LOG_CRIT, "Line %d not found on device\n", *line_instance_p);
|
||||
if ( button ) {
|
||||
switch_safe_free(button);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -199,11 +202,17 @@ error:
|
||||
}
|
||||
|
||||
listener->profile->ib_failed_calls++;
|
||||
if ( button ) {
|
||||
switch_safe_free(button);
|
||||
}
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
||||
done:
|
||||
*session = nsession;
|
||||
listener->profile->ib_calls++;
|
||||
if ( button ) {
|
||||
switch_safe_free(button);
|
||||
}
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1524,6 +1533,7 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
skinny_session_process_dest(session, listener, line_instance, button_speed_dial->line, '\0', 0);
|
||||
switch_safe_free(button_speed_dial);
|
||||
}
|
||||
break;
|
||||
case SKINNY_BUTTON_HOLD:
|
||||
@ -1582,10 +1592,12 @@ switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_mess
|
||||
skinny_create_incoming_session(listener, &line_instance, &session);
|
||||
if ( ! session ) {
|
||||
skinny_log_l_msg(listener, SWITCH_LOG_CRIT, "Unable to handle stimulus message, couldn't create incoming session.\n");
|
||||
switch_safe_free(button_line);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0);
|
||||
}
|
||||
switch_safe_free(button_line);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1709,6 +1721,8 @@ switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skin
|
||||
|
||||
send_speed_dial_stat_res(listener, request->data.speed_dial_req.number, button->line, button->label);
|
||||
|
||||
switch_safe_free(button);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1725,6 +1739,8 @@ switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_mes
|
||||
|
||||
memcpy(&message->data.line_res, button, sizeof(struct line_stat_res_message));
|
||||
|
||||
switch_safe_free(button);
|
||||
|
||||
skinny_send_reply(listener, message, SWITCH_TRUE);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@ -2407,6 +2423,8 @@ switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, ski
|
||||
|
||||
skinny_send_reply(listener, message, SWITCH_TRUE);
|
||||
|
||||
switch_safe_free(button);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -2425,6 +2443,8 @@ switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_
|
||||
|
||||
skinny_send_reply(listener, message, SWITCH_TRUE);
|
||||
|
||||
switch_safe_free(button);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -2568,7 +2588,7 @@ switch_status_t skinny_handle_updatecapabilities(listener_t *listener, skinny_me
|
||||
}
|
||||
i = 0;
|
||||
pos = 0;
|
||||
codec_string = switch_core_alloc(listener->pool, string_len+1);
|
||||
codec_string = calloc(string_len+1, 1);
|
||||
for (string_pos = 0; string_pos < string_len; string_pos++) {
|
||||
char *codec = codec_order[i];
|
||||
switch_assert(i < n);
|
||||
@ -2591,6 +2611,7 @@ switch_status_t skinny_handle_updatecapabilities(listener_t *listener, skinny_me
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"Codecs %s supported.\n", codec_string);
|
||||
switch_safe_free(codec_string);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -343,6 +343,11 @@ switch_status_t sofia_on_destroy(switch_core_session_t *session)
|
||||
|
||||
if (tech_pvt) {
|
||||
|
||||
if (tech_pvt->proxy_refer_msg) {
|
||||
msg_ref_destroy(tech_pvt->proxy_refer_msg);
|
||||
tech_pvt->proxy_refer_msg = NULL;
|
||||
}
|
||||
|
||||
if (tech_pvt->respond_phrase) {
|
||||
switch_yield(100000);
|
||||
}
|
||||
@ -598,6 +603,15 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session)
|
||||
switch_safe_free(bye_headers);
|
||||
}
|
||||
|
||||
if (cause == SWITCH_CAUSE_WRONG_CALL_STATE) {
|
||||
switch_event_t *s_event;
|
||||
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_WRONG_CALL_STATE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "network_ip", tech_pvt->mparams.remote_ip);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "network_port", "%d", tech_pvt->mparams.remote_port);
|
||||
switch_event_fire(&s_event);
|
||||
}
|
||||
}
|
||||
|
||||
sofia_clear_flag(tech_pvt, TFLAG_IO);
|
||||
|
||||
if (tech_pvt->sofia_private) {
|
||||
@ -1318,9 +1332,46 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
|
||||
switch (msg->message_id) {
|
||||
|
||||
#if 1
|
||||
case SWITCH_MESSAGE_INDICATE_DEFLECT: {
|
||||
|
||||
char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
|
||||
char ref_to[1024] = "";
|
||||
const char *var;
|
||||
|
||||
if (!strcasecmp(msg->string_arg, "sip:")) {
|
||||
const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s";
|
||||
|
||||
switch_snprintf(ref_to, sizeof(ref_to), format, msg->string_arg, tech_pvt->profile->sipip);
|
||||
} else {
|
||||
switch_set_string(ref_to, msg->string_arg);
|
||||
}
|
||||
|
||||
nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(tech_pvt->contact_url),
|
||||
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
|
||||
TAG_END());
|
||||
|
||||
if (msg->string_array_arg[0]) {
|
||||
tech_pvt->proxy_refer_uuid = (char *)msg->string_array_arg[0];
|
||||
} else {
|
||||
switch_mutex_unlock(tech_pvt->sofia_mutex);
|
||||
sofia_wait_for_reply(tech_pvt, 9999, 10);
|
||||
switch_mutex_lock(tech_pvt->sofia_mutex);
|
||||
|
||||
if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_refer_reply"))) {
|
||||
msg->string_reply = switch_core_session_strdup(session, var);
|
||||
} else {
|
||||
msg->string_reply = "no reply";
|
||||
}
|
||||
|
||||
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BLIND_TRANSFER);
|
||||
}
|
||||
|
||||
switch_safe_free(extra_headers);
|
||||
}
|
||||
break;
|
||||
|
||||
case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
|
||||
{
|
||||
if (!switch_channel_test_flag(channel, CF_AVPF)) {
|
||||
//const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent");
|
||||
//if (ua && switch_stristr("polycom", ua)) {
|
||||
|
||||
@ -1341,7 +1392,6 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
//}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SWITCH_MESSAGE_INDICATE_BROADCAST:
|
||||
{
|
||||
const char *ip = NULL, *port = NULL;
|
||||
@ -1945,34 +1995,6 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SWITCH_MESSAGE_INDICATE_DEFLECT:
|
||||
{
|
||||
char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
|
||||
char ref_to[1024] = "";
|
||||
const char *var;
|
||||
|
||||
if (!strcasecmp(msg->string_arg, "sip:")) {
|
||||
const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s";
|
||||
switch_snprintf(ref_to, sizeof(ref_to), format, msg->string_arg, tech_pvt->profile->sipip);
|
||||
} else {
|
||||
switch_set_string(ref_to, msg->string_arg);
|
||||
}
|
||||
nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(tech_pvt->contact_url),
|
||||
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
|
||||
TAG_END());
|
||||
switch_mutex_unlock(tech_pvt->sofia_mutex);
|
||||
sofia_wait_for_reply(tech_pvt, 9999, 10);
|
||||
switch_mutex_lock(tech_pvt->sofia_mutex);
|
||||
if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_refer_reply"))) {
|
||||
msg->string_reply = switch_core_session_strdup(session, var);
|
||||
} else {
|
||||
msg->string_reply = "no reply";
|
||||
}
|
||||
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BLIND_TRANSFER);
|
||||
switch_safe_free(extra_headers);
|
||||
}
|
||||
break;
|
||||
|
||||
case SWITCH_MESSAGE_INDICATE_RESPOND:
|
||||
{
|
||||
|
||||
@ -2009,6 +2031,16 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
}
|
||||
}
|
||||
|
||||
if (tech_pvt->proxy_refer_uuid) {
|
||||
if (tech_pvt->proxy_refer_msg) {
|
||||
nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
|
||||
SIPTAG_EXPIRES_STR("60"), NUTAG_WITH_THIS_MSG(tech_pvt->proxy_refer_msg), TAG_END());
|
||||
msg_ref_destroy(tech_pvt->proxy_refer_msg);
|
||||
tech_pvt->proxy_refer_msg = NULL;
|
||||
}
|
||||
goto end_lock;
|
||||
}
|
||||
|
||||
if (code == 302 && !zstr(msg->string_arg)) {
|
||||
char *p;
|
||||
|
||||
@ -5008,7 +5040,7 @@ static int notify_callback(void *pArg, int argc, char **argv, char **columnNames
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void general_event_handler(switch_event_t *event)
|
||||
void general_event_handler(switch_event_t *event)
|
||||
{
|
||||
switch (event->event_id) {
|
||||
case SWITCH_EVENT_NOTIFY:
|
||||
@ -5546,6 +5578,14 @@ static void general_event_handler(switch_event_t *event)
|
||||
}
|
||||
}
|
||||
|
||||
static void general_queue_event_handler(switch_event_t *event)
|
||||
{
|
||||
switch_event_t *dup;
|
||||
switch_event_dup(&dup, event);
|
||||
switch_queue_push(mod_sofia_globals.general_event_queue, dup);
|
||||
}
|
||||
|
||||
|
||||
void write_csta_xml_chunk(switch_event_t *event, switch_stream_handle_t stream, const char *csta_event, char *fwdtype)
|
||||
{
|
||||
const char *device = switch_event_get_header(event, "device");
|
||||
@ -5882,6 +5922,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
|
||||
mod_sofia_globals.auto_nat = (switch_nat_get_type() ? 1 : 0);
|
||||
|
||||
switch_queue_create(&mod_sofia_globals.presence_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
|
||||
switch_queue_create(&mod_sofia_globals.general_event_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
|
||||
|
||||
mod_sofia_globals.cpu_count = switch_core_cpu_count();
|
||||
mod_sofia_globals.max_msg_queues = (mod_sofia_globals.cpu_count / 2) + 1;
|
||||
@ -5952,27 +5993,27 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_NOTIFY, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_NOTIFY, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_PHONE_FEATURE, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_PHONE_FEATURE, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_SEND_MESSAGE, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_SEND_MESSAGE, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_SEND_INFO, SWITCH_EVENT_SUBCLASS_ANY, general_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_SEND_INFO, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
@ -6075,7 +6116,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown)
|
||||
|
||||
switch_event_unbind_callback(sofia_presence_event_handler);
|
||||
|
||||
switch_event_unbind_callback(general_event_handler);
|
||||
switch_event_unbind_callback(general_queue_event_handler);
|
||||
switch_event_unbind_callback(event_handler);
|
||||
|
||||
switch_queue_push(mod_sofia_globals.presence_queue, NULL);
|
||||
|
@ -97,6 +97,7 @@ typedef struct private_object private_object_t;
|
||||
#define MY_EVENT_ERROR "sofia::error"
|
||||
#define MY_EVENT_PROFILE_START "sofia::profile_start"
|
||||
#define MY_EVENT_NOTIFY_WATCHED_HEADER "sofia::notify_watched_header"
|
||||
#define MY_EVENT_WRONG_CALL_STATE "sofia::wrong_call_state"
|
||||
|
||||
#define MY_EVENT_TRANSFEROR "sofia::transferor"
|
||||
#define MY_EVENT_TRANSFEREE "sofia::transferee"
|
||||
@ -365,6 +366,7 @@ struct mod_sofia_globals {
|
||||
char hostname[512];
|
||||
switch_queue_t *presence_queue;
|
||||
switch_queue_t *msg_queue;
|
||||
switch_queue_t *general_event_queue;
|
||||
switch_thread_t *msg_queue_thread[SOFIA_MAX_MSG_QUEUE];
|
||||
int msg_queue_len;
|
||||
struct sofia_private destroy_private;
|
||||
@ -800,6 +802,8 @@ struct private_object {
|
||||
char *x_freeswitch_support_local;
|
||||
char *last_sent_callee_id_name;
|
||||
char *last_sent_callee_id_number;
|
||||
char *proxy_refer_uuid;
|
||||
msg_t *proxy_refer_msg;
|
||||
switch_mutex_t *flag_mutex;
|
||||
switch_mutex_t *sofia_mutex;
|
||||
switch_payload_t te;
|
||||
@ -1193,6 +1197,7 @@ void sofia_glue_fire_events(sofia_profile_t *profile);
|
||||
void sofia_event_fire(sofia_profile_t *profile, switch_event_t **event);
|
||||
void sofia_queue_message(sofia_dispatch_event_t *de);
|
||||
int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip);
|
||||
void general_event_handler(switch_event_t *event);
|
||||
|
||||
switch_status_t sofia_glue_ext_address_lookup(sofia_profile_t *profile, char **ip, switch_port_t *port,
|
||||
const char *sourceip, switch_memory_pool_t *pool);
|
||||
|
@ -84,12 +84,30 @@ static void sofia_handle_sip_r_options(switch_core_session_t *session, int statu
|
||||
nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
|
||||
sofia_dispatch_event_t *de, tagi_t tags[]);
|
||||
|
||||
|
||||
void sofia_handle_sip_r_notify(switch_core_session_t *session, int status,
|
||||
char const *phrase,
|
||||
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
|
||||
sofia_dispatch_event_t *de, tagi_t tags[])
|
||||
{
|
||||
private_object_t *tech_pvt = switch_core_session_get_private(session);
|
||||
switch_core_session_t *other_session;
|
||||
|
||||
if (tech_pvt->proxy_refer_uuid && (other_session = switch_core_session_locate(tech_pvt->proxy_refer_uuid))) {
|
||||
switch_core_session_message_t *msg;
|
||||
|
||||
msg = switch_core_session_alloc(other_session, sizeof(*msg));
|
||||
msg->message_id = SWITCH_MESSAGE_INDICATE_RESPOND;
|
||||
msg->from = __FILE__;
|
||||
msg->numeric_arg = status;
|
||||
msg->string_arg = switch_core_session_strdup(other_session, phrase);
|
||||
switch_core_session_queue_message(other_session, msg);
|
||||
switch_core_session_rwunlock(other_session);
|
||||
} else {
|
||||
tech_pvt->proxy_refer_uuid = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (status == 481 && sip && !sip->sip_retry_after && sip->sip_call_id && (!sofia_private || !sofia_private->is_call)) {
|
||||
char *sql;
|
||||
|
||||
@ -517,6 +535,27 @@ static void sofia_parse_all_invite_headers(sip_t const *sip, switch_core_session
|
||||
}
|
||||
}
|
||||
|
||||
static switch_status_t sofia_pass_notify(switch_core_session_t *session, const char *uuid, const char *payload)
|
||||
{
|
||||
switch_core_session_t *other_session;
|
||||
|
||||
if ((other_session = switch_core_session_locate(uuid))) {
|
||||
switch_core_session_message_t *msg;
|
||||
|
||||
msg = switch_core_session_alloc(other_session, sizeof(*msg));
|
||||
MESSAGE_STAMP_FFL(msg);
|
||||
msg->message_id = SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE;
|
||||
msg->string_arg = switch_core_session_strdup(other_session, payload);
|
||||
msg->from = __FILE__;
|
||||
switch_core_session_queue_message(other_session, msg);
|
||||
switch_core_session_rwunlock(other_session);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
|
||||
char const *phrase,
|
||||
nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
|
||||
@ -551,24 +590,21 @@ void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
|
||||
}
|
||||
|
||||
|
||||
if (sofia_test_pflag(profile, PFLAG_PROXY_REFER) && sip->sip_payload && sip->sip_payload->pl_data &&
|
||||
sip->sip_content_type && sip->sip_content_type->c_type &&
|
||||
switch_stristr("sipfrag", sip->sip_content_type->c_type)) {
|
||||
switch_core_session_t *other_session;
|
||||
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_core_session_message_t *msg;
|
||||
|
||||
msg = switch_core_session_alloc(other_session, sizeof(*msg));
|
||||
MESSAGE_STAMP_FFL(msg);
|
||||
msg->message_id = SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE;
|
||||
msg->string_arg = switch_core_session_strdup(other_session, sip->sip_payload->pl_data);
|
||||
msg->from = __FILE__;
|
||||
switch_core_session_queue_message(other_session, msg);
|
||||
switch_core_session_rwunlock(other_session);
|
||||
|
||||
nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
|
||||
goto end;
|
||||
if (tech_pvt && tech_pvt->proxy_refer_uuid && sofia_test_pflag(profile, PFLAG_PROXY_REFER) && sip->sip_payload && sip->sip_payload->pl_data &&
|
||||
sip->sip_content_type && sip->sip_content_type->c_type && switch_stristr("sipfrag", sip->sip_content_type->c_type)) {
|
||||
|
||||
if (sofia_pass_notify(session, tech_pvt->proxy_refer_uuid, sip->sip_payload->pl_data) == SWITCH_STATUS_SUCCESS) {
|
||||
if (tech_pvt->proxy_refer_msg) {
|
||||
msg_ref_destroy(tech_pvt->proxy_refer_msg);
|
||||
tech_pvt->proxy_refer_msg = NULL;
|
||||
}
|
||||
tech_pvt->proxy_refer_msg = msg_ref_create(de->data->e_msg);
|
||||
//nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), TAG_END());
|
||||
} else {
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
}
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* For additional NOTIFY event packages see http://www.iana.org/assignments/sip-events. */
|
||||
@ -1288,6 +1324,34 @@ static void notify_watched_header(switch_core_session_t *session, const char *ms
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sofia_handle_sip_r_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, int status, const char *phrase, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[])
|
||||
{
|
||||
private_object_t *tech_pvt = switch_core_session_get_private(session);
|
||||
switch_core_session_t *other_session;
|
||||
|
||||
if (status < 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tech_pvt->proxy_refer_uuid && (other_session = switch_core_session_locate(tech_pvt->proxy_refer_uuid))) {
|
||||
switch_core_session_message_t *msg;
|
||||
|
||||
msg = switch_core_session_alloc(other_session, sizeof(*msg));
|
||||
msg->message_id = SWITCH_MESSAGE_INDICATE_RESPOND;
|
||||
msg->from = __FILE__;
|
||||
msg->numeric_arg = status;
|
||||
msg->string_arg = switch_core_session_strdup(other_session, phrase);
|
||||
switch_core_session_queue_message(other_session, msg);
|
||||
switch_core_session_rwunlock(other_session);
|
||||
} else {
|
||||
tech_pvt->proxy_refer_uuid = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//sofia_dispatch_event_t *de
|
||||
static void our_sofia_event_callback(nua_event_t event,
|
||||
int status,
|
||||
@ -1552,7 +1616,9 @@ static void our_sofia_event_callback(nua_event_t event,
|
||||
sofia_handle_sip_i_bye(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
|
||||
break;
|
||||
case nua_r_notify:
|
||||
sofia_handle_sip_r_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
|
||||
if (session) {
|
||||
sofia_handle_sip_r_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
|
||||
}
|
||||
break;
|
||||
case nua_i_notify:
|
||||
sofia_handle_sip_i_notify(session, status, phrase, nua, profile, nh, sofia_private, sip, de, tags);
|
||||
@ -1601,6 +1667,9 @@ static void our_sofia_event_callback(nua_event_t event,
|
||||
}
|
||||
break;
|
||||
case nua_r_refer:
|
||||
if (session) {
|
||||
sofia_handle_sip_r_refer(nua, profile, nh, session, status, phrase, sip, de, tags);
|
||||
}
|
||||
break;
|
||||
case nua_i_refer:
|
||||
if (session) {
|
||||
@ -1958,18 +2027,14 @@ void sofia_process_dispatch_event_in_thread(sofia_dispatch_event_t **dep)
|
||||
sofia_dispatch_event_t *de = *dep;
|
||||
switch_memory_pool_t *pool;
|
||||
//sofia_profile_t *profile = (*dep)->profile;
|
||||
switch_thread_data_t *td;
|
||||
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
|
||||
*dep = NULL;
|
||||
de->pool = pool;
|
||||
|
||||
td = switch_core_alloc(pool, sizeof(*td));
|
||||
td->func = sofia_msg_thread_run_once;
|
||||
td->obj = de;
|
||||
|
||||
switch_thread_pool_launch_thread(&td);
|
||||
|
||||
}
|
||||
|
||||
@ -2659,64 +2724,88 @@ void *SWITCH_THREAD_FUNC sofia_profile_worker_thread_run(switch_thread_t *thread
|
||||
uint32_t ireg_loops = profile->ireg_seconds; /* Number of loop iterations done when we haven't checked for registrations */
|
||||
uint32_t iping_loops = profile->iping_freq; /* Number of loop iterations done when we haven't checked for ping expires */
|
||||
uint32_t gateway_loops = GATEWAY_SECONDS; /* Number of loop iterations done when we haven't checked for gateways */
|
||||
void *pop;
|
||||
int tick = 0, x = 0;
|
||||
|
||||
sofia_set_pflag_locked(profile, PFLAG_WORKER_RUNNING);
|
||||
|
||||
while ((mod_sofia_globals.running == 1 && sofia_test_pflag(profile, PFLAG_RUNNING))) {
|
||||
|
||||
if (profile->watchdog_enabled) {
|
||||
uint32_t event_diff = 0, step_diff = 0, event_fail = 0, step_fail = 0;
|
||||
if (tick) {
|
||||
if (profile->watchdog_enabled) {
|
||||
uint32_t event_diff = 0, step_diff = 0, event_fail = 0, step_fail = 0;
|
||||
|
||||
if (profile->step_timeout) {
|
||||
step_diff = (uint32_t) ((switch_time_now() - profile->last_root_step) / 1000);
|
||||
if (profile->step_timeout) {
|
||||
step_diff = (uint32_t) ((switch_time_now() - profile->last_root_step) / 1000);
|
||||
|
||||
if (step_diff > profile->step_timeout) {
|
||||
step_fail = 1;
|
||||
if (step_diff > profile->step_timeout) {
|
||||
step_fail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (profile->event_timeout) {
|
||||
event_diff = (uint32_t) ((switch_time_now() - profile->last_sip_event) / 1000);
|
||||
|
||||
if (event_diff > profile->event_timeout) {
|
||||
event_fail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (step_fail && profile->event_timeout && !event_fail) {
|
||||
step_fail = 0;
|
||||
}
|
||||
|
||||
if (event_fail || step_fail) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile %s: SIP STACK FAILURE DETECTED BY WATCHDOG!\n"
|
||||
"GOODBYE CRUEL WORLD, I'M LEAVING YOU TODAY....GOODBYE, GOODBYE, GOOD BYE\n", profile->name);
|
||||
switch_yield(2000000);
|
||||
watchdog_triggered_abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (profile->event_timeout) {
|
||||
event_diff = (uint32_t) ((switch_time_now() - profile->last_sip_event) / 1000);
|
||||
|
||||
if (event_diff > profile->event_timeout) {
|
||||
event_fail = 1;
|
||||
if (!sofia_test_pflag(profile, PFLAG_STANDBY)) {
|
||||
if (++ireg_loops >= (uint32_t)profile->ireg_seconds) {
|
||||
time_t now = switch_epoch_time_now(NULL);
|
||||
sofia_reg_check_expire(profile, now, 0);
|
||||
ireg_loops = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (step_fail && profile->event_timeout && !event_fail) {
|
||||
step_fail = 0;
|
||||
}
|
||||
|
||||
if (event_fail || step_fail) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile %s: SIP STACK FAILURE DETECTED BY WATCHDOG!\n"
|
||||
"GOODBYE CRUEL WORLD, I'M LEAVING YOU TODAY....GOODBYE, GOODBYE, GOOD BYE\n", profile->name);
|
||||
switch_yield(2000000);
|
||||
watchdog_triggered_abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!sofia_test_pflag(profile, PFLAG_STANDBY)) {
|
||||
if (++ireg_loops >= (uint32_t)profile->ireg_seconds) {
|
||||
time_t now = switch_epoch_time_now(NULL);
|
||||
sofia_reg_check_expire(profile, now, 0);
|
||||
ireg_loops = 0;
|
||||
}
|
||||
|
||||
if(++iping_loops >= (uint32_t)profile->iping_freq) {
|
||||
time_t now = switch_epoch_time_now(NULL);
|
||||
sofia_reg_check_ping_expire(profile, now, profile->iping_seconds);
|
||||
iping_loops = 0;
|
||||
if(++iping_loops >= (uint32_t)profile->iping_freq) {
|
||||
time_t now = switch_epoch_time_now(NULL);
|
||||
sofia_reg_check_ping_expire(profile, now, profile->iping_seconds);
|
||||
iping_loops = 0;
|
||||
}
|
||||
|
||||
if (++gateway_loops >= GATEWAY_SECONDS) {
|
||||
sofia_reg_check_gateway(profile, switch_epoch_time_now(NULL));
|
||||
sofia_sub_check_gateway(profile, switch_epoch_time_now(NULL));
|
||||
gateway_loops = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (++gateway_loops >= GATEWAY_SECONDS) {
|
||||
sofia_reg_check_gateway(profile, switch_epoch_time_now(NULL));
|
||||
sofia_sub_check_gateway(profile, switch_epoch_time_now(NULL));
|
||||
gateway_loops = 0;
|
||||
}
|
||||
tick = 0;
|
||||
}
|
||||
|
||||
switch_yield(1000000);
|
||||
if (switch_queue_pop_timeout(mod_sofia_globals.general_event_queue, &pop, 100000) == SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
do {
|
||||
switch_event_t *event = (switch_event_t *) pop;
|
||||
general_event_handler(event);
|
||||
switch_event_destroy(&event);
|
||||
|
||||
pop = NULL;
|
||||
switch_queue_trypop(mod_sofia_globals.general_event_queue, &pop);
|
||||
} while (pop);
|
||||
|
||||
}
|
||||
|
||||
sofia_glue_fire_events(profile);
|
||||
|
||||
if (++x == 10) {
|
||||
tick = 1;
|
||||
x = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6537,9 +6626,9 @@ void *SWITCH_THREAD_FUNC media_on_hold_thread_run(switch_thread_t *thread, void
|
||||
switch_channel_wait_for_flag(other_channel, CF_MEDIA_ACK, SWITCH_TRUE, 10000, NULL);
|
||||
|
||||
if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
switch_ivr_media(switch_core_session_get_uuid(other_session), SMF_REBRIDGE|SMF_REPLYONLY_B);
|
||||
switch_ivr_3p_media(switch_core_session_get_uuid(other_session), SMF_REBRIDGE|SMF_REPLYONLY_B);
|
||||
} else {
|
||||
switch_ivr_media(switch_core_session_get_uuid(other_session), SMF_REBRIDGE);
|
||||
switch_ivr_3p_media(switch_core_session_get_uuid(other_session), SMF_REBRIDGE);
|
||||
}
|
||||
|
||||
|
||||
@ -7094,6 +7183,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
case nua_callstate_received:
|
||||
tech_pvt->recv_invites++;
|
||||
tech_pvt->sent_last_invite = 0;
|
||||
|
||||
if (!sofia_test_flag(tech_pvt, TFLAG_SDP)) {
|
||||
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||
private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
|
||||
@ -7113,6 +7203,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (r_sdp && !sofia_test_flag(tech_pvt, TFLAG_SDP)) {
|
||||
if (switch_channel_test_flag(channel, CF_PROXY_MODE)) {
|
||||
@ -7342,6 +7433,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
is_t38 = 1;
|
||||
}
|
||||
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
|
||||
if ((sofia_test_media_flag(profile, SCMF_DISABLE_HOLD)
|
||||
|| ((var = switch_channel_get_variable(channel, "rtp_disable_hold")) && switch_true(var)))
|
||||
@ -7363,6 +7455,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
int media_on_hold = switch_true(switch_channel_get_variable_dup(channel, "bypass_media_resume_on_hold", SWITCH_FALSE, -1));
|
||||
|
||||
switch_core_media_clear_rtp_flag(other_session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_RTP_FLAG_AUTOADJ);
|
||||
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_PROXY_MODE) && !is_t38 &&
|
||||
((profile->media_options & MEDIA_OPT_MEDIA_ON_HOLD) || media_on_hold)) {
|
||||
@ -7374,7 +7467,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
switch_core_media_clear_rtp_flag(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_RTP_FLAG_AUTOADJ);
|
||||
|
||||
if (!switch_channel_media_ready(channel)) {
|
||||
if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
//if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
|
||||
//const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
|
||||
|
||||
|
||||
@ -7383,9 +7476,10 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
switch_core_session_rwunlock(other_session);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
@ -7397,6 +7491,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 1);
|
||||
|
||||
if (sofia_use_soa(tech_pvt)) {
|
||||
@ -7431,8 +7526,9 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
}
|
||||
}
|
||||
|
||||
other_tech_pvt = switch_core_session_get_private(other_session);
|
||||
if(sofia_test_flag(other_tech_pvt, TFLAG_REINVITED)) {
|
||||
other_tech_pvt = switch_core_session_get_private(other_session);
|
||||
|
||||
if (sofia_test_flag(other_tech_pvt, TFLAG_REINVITED)) {
|
||||
/* The other leg won the reinvite race */
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Other leg already handling reinvite, so responding with 491\n");
|
||||
nua_respond(tech_pvt->nh, SIP_491_REQUEST_PENDING, TAG_END());
|
||||
@ -7528,25 +7624,18 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (is_ok) {
|
||||
|
||||
if (switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
|
||||
switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
|
||||
}
|
||||
if (sofia_use_soa(tech_pvt)) {
|
||||
nua_respond(tech_pvt->nh, SIP_200_OK,
|
||||
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
|
||||
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
|
||||
SOATAG_REUSE_REJECTED(1),
|
||||
SOATAG_AUDIO_AUX("cn telephone-event"),
|
||||
TAG_IF(sofia_test_pflag(profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)), TAG_END());
|
||||
} else {
|
||||
nua_respond(tech_pvt->nh, SIP_200_OK,
|
||||
NUTAG_MEDIA_ENABLE(0),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
|
||||
SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END());
|
||||
}
|
||||
|
||||
nua_respond(tech_pvt->nh, SIP_200_OK,
|
||||
NUTAG_MEDIA_ENABLE(0),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
|
||||
SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str), TAG_END());
|
||||
|
||||
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REINVITE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session));
|
||||
switch_event_fire(&s_event);
|
||||
@ -7962,6 +8051,29 @@ nua_handle_t *sofia_global_nua_handle_by_replaces(sip_replaces_t *replaces)
|
||||
|
||||
}
|
||||
|
||||
static switch_status_t sofia_process_proxy_refer(switch_core_session_t *session, const char *refer_to)
|
||||
{
|
||||
switch_core_session_t *other_session;
|
||||
private_object_t *tech_pvt = switch_core_session_get_private(session);
|
||||
|
||||
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_core_session_message_t *msg;
|
||||
|
||||
tech_pvt->proxy_refer_uuid = switch_core_session_strdup(session, switch_core_session_get_uuid(other_session));
|
||||
msg = switch_core_session_alloc(other_session, sizeof(*msg));
|
||||
MESSAGE_STAMP_FFL(msg);
|
||||
msg->message_id = SWITCH_MESSAGE_INDICATE_DEFLECT;
|
||||
msg->string_arg = switch_core_session_strdup(other_session, refer_to);
|
||||
msg->string_array_arg[0] = switch_core_session_strdup(other_session, switch_core_session_get_uuid(session));
|
||||
msg->from = __FILE__;
|
||||
switch_core_session_queue_message(other_session, msg);
|
||||
switch_core_session_rwunlock(other_session);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, sip_t const *sip,
|
||||
sofia_dispatch_event_t *de, tagi_t tags[])
|
||||
{
|
||||
@ -7994,27 +8106,18 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
|
||||
full_ref_to = sip_header_as_string(home, (void *) sip->sip_refer_to);
|
||||
}
|
||||
|
||||
|
||||
if (sofia_test_pflag(profile, PFLAG_PROXY_REFER)) {
|
||||
switch_core_session_t *other_session;
|
||||
|
||||
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_core_session_message_t *msg;
|
||||
|
||||
msg = switch_core_session_alloc(other_session, sizeof(*msg));
|
||||
MESSAGE_STAMP_FFL(msg);
|
||||
msg->message_id = SWITCH_MESSAGE_INDICATE_DEFLECT;
|
||||
msg->string_arg = switch_core_session_strdup(other_session, full_ref_to);
|
||||
msg->from = __FILE__;
|
||||
switch_core_session_queue_message(other_session, msg);
|
||||
switch_core_session_rwunlock(other_session);
|
||||
|
||||
nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), TAG_END());
|
||||
if (full_ref_to && sofia_test_pflag(profile, PFLAG_PROXY_REFER)) {
|
||||
if (sofia_process_proxy_refer(session, full_ref_to) == SWITCH_STATUS_SUCCESS) {
|
||||
if (tech_pvt->proxy_refer_msg) {
|
||||
msg_ref_destroy(tech_pvt->proxy_refer_msg);
|
||||
tech_pvt->proxy_refer_msg = NULL;
|
||||
}
|
||||
tech_pvt->proxy_refer_msg = msg_ref_create(de->data->e_msg);
|
||||
//nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), TAG_END());
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
from = sip->sip_from;
|
||||
//to = sip->sip_to;
|
||||
|
||||
@ -9104,6 +9207,11 @@ void sofia_handle_sip_i_reinvite(switch_core_session_t *session,
|
||||
if (session) {
|
||||
channel = switch_core_session_get_channel(session);
|
||||
tech_pvt = switch_core_session_get_private(session);
|
||||
|
||||
|
||||
if (sip->sip_payload && sip->sip_payload->pl_data) {
|
||||
tech_pvt->mparams.last_sdp_str = switch_core_session_strdup(session, sip->sip_payload->pl_data);
|
||||
}
|
||||
}
|
||||
|
||||
if (session && profile && sip && sofia_test_pflag(profile, PFLAG_TRACK_CALLS)) {
|
||||
@ -9467,6 +9575,10 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tech_pvt->mparams.remote_ip = switch_core_session_strdup(session, network_ip);
|
||||
tech_pvt->mparams.remote_port = network_port;
|
||||
|
||||
if (!is_auth &&
|
||||
(sofia_test_pflag(profile, PFLAG_AUTH_CALLS)
|
||||
|| (!sofia_test_pflag(profile, PFLAG_BLIND_AUTH) && (sip->sip_proxy_authorization || sip->sip_authorization)))) {
|
||||
@ -9493,11 +9605,6 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia
|
||||
is_auth++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
tech_pvt->mparams.remote_ip = switch_core_session_strdup(session, network_ip);
|
||||
tech_pvt->mparams.remote_port = network_port;
|
||||
|
||||
channel = tech_pvt->channel = switch_core_session_get_channel(session);
|
||||
|
||||
switch_channel_set_variable_printf(channel, "sip_local_network_addr", "%s", profile->extsipip ? profile->extsipip : profile->sipip);
|
||||
|
@ -2476,9 +2476,6 @@ switch_bool_t sofia_glue_execute_sql_callback(sofia_profile_t *profile,
|
||||
|
||||
switch_cache_db_release_db_handle(&dbh);
|
||||
|
||||
|
||||
sofia_glue_fire_events(profile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2515,9 +2512,6 @@ char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex
|
||||
|
||||
switch_cache_db_release_db_handle(&dbh);
|
||||
|
||||
|
||||
sofia_glue_fire_events(profile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1447,14 +1447,29 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
|
||||
|
||||
|
||||
if (sip->sip_path) {
|
||||
if ((path_val = sip_header_as_string(nua_handle_home(nh), (void *) sip->sip_path))) {
|
||||
char *path_stripped = sofia_glue_get_url_from_contact(path_val, SWITCH_TRUE);
|
||||
su_free(nua_handle_home(nh), path_val);
|
||||
path_val = path_stripped;
|
||||
path_encoded_len = (int)(strlen(path_val) * 3) + 1;
|
||||
char *path_stripped = NULL;
|
||||
char *path_val_to_encode = NULL;
|
||||
su_strlst_t *path_list = su_strlst_create(nua_handle_home(nh));
|
||||
sip_path_t *next_path = sip->sip_path;
|
||||
for (; next_path; next_path = next_path->r_next) {
|
||||
path_val = sip_header_as_string(nua_handle_home(nh), (void *) next_path);
|
||||
if (path_val) {
|
||||
path_stripped = sofia_glue_get_url_from_contact(path_val, SWITCH_TRUE);
|
||||
su_free(nua_handle_home(nh), path_val);
|
||||
su_strlst_dup_append(path_list, path_stripped);
|
||||
switch_safe_free(path_stripped);
|
||||
}
|
||||
}
|
||||
|
||||
path_val = su_strlst_join(path_list, nua_handle_home(nh), ",");
|
||||
path_val_to_encode = su_strlst_join(path_list, nua_handle_home(nh), "%2C");
|
||||
su_strlst_destroy(path_list);
|
||||
if (path_val_to_encode) {
|
||||
path_encoded_len = (int)(strlen(path_val_to_encode) * 3) + 1;
|
||||
switch_zmalloc(path_encoded, path_encoded_len);
|
||||
switch_copy_string(path_encoded, ";fs_path=", 10);
|
||||
switch_url_encode(path_val, path_encoded + 9, path_encoded_len - 9);
|
||||
switch_url_encode(path_val_to_encode, path_encoded + 9, path_encoded_len - 9);
|
||||
su_free(nua_handle_home(nh), path_val_to_encode);
|
||||
}
|
||||
} else if (is_nat) {
|
||||
char my_contact_str[1024];
|
||||
@ -2195,7 +2210,7 @@ uint8_t sofia_reg_handle_register_token(nua_t *nua, sofia_profile_t *profile, nu
|
||||
switch_safe_free(display_m);
|
||||
switch_safe_free(dup_mwi_account);
|
||||
switch_safe_free(utmp);
|
||||
switch_safe_free(path_val);
|
||||
su_free(nua_handle_home(nh), path_val);
|
||||
switch_safe_free(token_val);
|
||||
|
||||
if (auth_params) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user