"
]
diff --git a/html5/verto/verto_communicator/src/css/verto.css b/html5/verto/verto_communicator/src/css/verto.css
index df7efea2f7..9bc3a8b70c 100644
--- a/html5/verto/verto_communicator/src/css/verto.css
+++ b/html5/verto/verto_communicator/src/css/verto.css
@@ -8,6 +8,18 @@ body {
padding-top: 60px;
}
+.ellipsis {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ width: 160px;
+ display: inline-block;
+}
+
+.clickable {
+ cursor: pointer;
+}
+
.inline-block {
display: inline-block;
}
@@ -110,6 +122,10 @@ button.btn i {
color: #F45A5A;
}
+.mdi-navigation-more-vert.dark {
+ color: #333;
+}
+
.incall-number {
font-weight: bold;
padding-top: 22px;
@@ -223,6 +239,29 @@ button.btn i {
}
}
+/* --- Splash Screen --- */
+.splash-errors {
+ background: rgba(249, 21, 21, 0.55);
+ color: white;
+ padding: 8px;
+ margin-top: 11px;
+}
+
+.splash-errors ul {
+ padding-start: 0em;
+ -moz-padding-start: 0em;
+ -webkit-padding-start: 0em;
+ padding-start: 0em;
+}
+
+.splash-errors li {
+ background-color: rgba(154, 36, 36, 0.28);
+ padding: 8px;
+ font-weight: bold;
+ list-style: none;
+}
+/* --- End of Splash Screen --- */
+
/* --- Modal settings page --- */
@@ -231,6 +270,10 @@ body .modal-body .btn-group .btn.active {
color: #EEE;
}
+.dedicated_encoder {
+ color: #0B3A84;
+}
+
/* --- End of Modal settings page --- */
@@ -410,7 +453,7 @@ body .modal-body .btn-group .btn.active {
}
#dialpad .date {
- margin-top: 15px;
+ margin-top: 15px;
display: block;
font-size: 11px;
color: #CCC;
@@ -529,7 +572,7 @@ body .modal-body .btn-group .btn.active {
}
#incall .phone li button .big-icon {
- font-size: 36px;
+ font-size: 36px;
}
#incall .video-wrapper {
@@ -857,10 +900,31 @@ body .modal-body .btn-group .btn.active {
width: 160px;
overflow: hidden;
text-overflow: ellipsis;
- margin-top: 5px;
white-space: nowrap;
}
+.members-number {
+ font-size: 10px;
+}
+
+.members-badges {
+ font-size: 10px;
+ text-transform: uppercase;
+ margin-top: -2px;
+}
+
+.badge-floor span {
+ display: inline-block;
+}
+
+.lock-floor {
+ position: relative;
+ top: -3px;
+ display: inline-block;
+ font-size: 10px;
+ color: #FFF;
+}
+
.chat-members .chat-member-item {
padding: 8px 16px;
height: 56px;
@@ -892,7 +956,8 @@ body .modal-body .btn-group .btn.active {
margin: 0;
font-size: 16px;
display: inline-block;
- line-height: 18px;
+ line-height: 16px;
+ margin-top: -3px;
}
.chat-members .chat-members-status i {
@@ -1206,11 +1271,11 @@ body:-webkit-full-screen #incall .video-footer {
body {
overflow-x: hidden;
}
-
+
#dialpad .call-history li {
overflow-x: hidden;
}
-
+
#sidebar-wrapper {
margin-right: -750px;
}
@@ -1260,7 +1325,7 @@ body:-webkit-full-screen #incall .video-footer {
margin: 0 auto;
float: none;
}
-
+
#incall .phone li button {
padding: 10px;
}
@@ -1285,8 +1350,8 @@ body:-webkit-full-screen #incall .video-footer {
}
}
-@media screen
- and (min-device-width: 320px)
+@media screen
+ and (min-device-width: 320px)
and (max-device-width: 780px) {
body {
@@ -1354,7 +1419,7 @@ body:-webkit-full-screen #incall .video-footer {
margin: 0 auto;
float: none;
}
-
+
#incall.centered-block-frame {
display: block;
justify-content: none;
@@ -1375,7 +1440,7 @@ body:-webkit-full-screen #incall .video-footer {
padding-top: calc(50% - 25%);
padding-bottom: calc(50% - 25%);
}
-
+
.contributors {
-webkit-padding-start: 0px;
text-align: center;
diff --git a/html5/verto/verto_communicator/src/img/fs_logo_small.png b/html5/verto/verto_communicator/src/img/fs_logo_small.png
new file mode 100644
index 0000000000..a875564480
Binary files /dev/null and b/html5/verto/verto_communicator/src/img/fs_logo_small.png differ
diff --git a/html5/verto/verto_communicator/src/img/logo.png b/html5/verto/verto_communicator/src/img/logo.png
deleted file mode 100644
index 04bce2b5b2..0000000000
Binary files a/html5/verto/verto_communicator/src/img/logo.png and /dev/null differ
diff --git a/html5/verto/verto_communicator/src/img/logo_big.png b/html5/verto/verto_communicator/src/img/logo_big.png
deleted file mode 100644
index 99184e9565..0000000000
Binary files a/html5/verto/verto_communicator/src/img/logo_big.png and /dev/null differ
diff --git a/html5/verto/verto_communicator/src/img/logo_med.png b/html5/verto/verto_communicator/src/img/logo_med.png
deleted file mode 100644
index 1b47ebfacc..0000000000
Binary files a/html5/verto/verto_communicator/src/img/logo_med.png and /dev/null differ
diff --git a/html5/verto/verto_communicator/src/img/vc_logo.png b/html5/verto/verto_communicator/src/img/vc_logo.png
new file mode 100644
index 0000000000..27972c5a9b
Binary files /dev/null and b/html5/verto/verto_communicator/src/img/vc_logo.png differ
diff --git a/html5/verto/verto_communicator/src/index.html b/html5/verto/verto_communicator/src/index.html
index 5945f72fe5..a1594f8a7f 100644
--- a/html5/verto/verto_communicator/src/index.html
+++ b/html5/verto/verto_communicator/src/index.html
@@ -98,15 +98,18 @@
+
+
+
@@ -118,10 +121,13 @@
+
+
+
diff --git a/html5/verto/verto_communicator/src/partials/about.html b/html5/verto/verto_communicator/src/partials/about.html
new file mode 100644
index 0000000000..97ff126660
--- /dev/null
+++ b/html5/verto/verto_communicator/src/partials/about.html
@@ -0,0 +1,22 @@
+
+
+
+ -
+
+
+ -
+
Version: 0.1.0
+
+ -
+
Git Rev: {{ githash }}
+
+ -
+
Powered By:

+
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/src/partials/chat.html b/html5/verto/verto_communicator/src/partials/chat.html
index 06eee1da7d..6fb10a878f 100644
--- a/html5/verto/verto_communicator/src/partials/chat.html
+++ b/html5/verto/verto_communicator/src/partials/chat.html
@@ -19,13 +19,23 @@
-
+
-
{{ member.name }}
({{ member.number }})
+
+
+
{{ member.name }}
+ ({{ member.number }})
+
+
+
+
diff --git a/html5/verto/verto_communicator/src/partials/login.html b/html5/verto/verto_communicator/src/partials/login.html
index 5a0c03c7dd..1d20188885 100644
--- a/html5/verto/verto_communicator/src/partials/login.html
+++ b/html5/verto/verto_communicator/src/partials/login.html
@@ -28,6 +28,11 @@
+
+
+
+
+
@@ -58,9 +58,15 @@
-
+
+
+
diff --git a/html5/verto/verto_communicator/src/partials/modal_logininfo.html b/html5/verto/verto_communicator/src/partials/modal_logininfo.html
index e41eef4de1..efb964f447 100644
--- a/html5/verto/verto_communicator/src/partials/modal_logininfo.html
+++ b/html5/verto/verto_communicator/src/partials/modal_logininfo.html
@@ -23,6 +23,10 @@
+
+
+
+
-
-
-
+
+
+ Dedicated Remote Encoder
+ Select a non default bandwidth to use a dedicated remote encoder.
+
+
+
Dedicated Remote Encoder enabled.
+
+
@@ -107,6 +111,7 @@
diff --git a/html5/verto/verto_communicator/src/partials/splash_screen.html b/html5/verto/verto_communicator/src/partials/splash_screen.html
new file mode 100644
index 0000000000..993999ec3a
--- /dev/null
+++ b/html5/verto/verto_communicator/src/partials/splash_screen.html
@@ -0,0 +1,21 @@
+
+
diff --git a/html5/verto/verto_communicator/src/partials/ws_reconnect.html b/html5/verto/verto_communicator/src/partials/ws_reconnect.html
new file mode 100644
index 0000000000..7879b587f7
--- /dev/null
+++ b/html5/verto/verto_communicator/src/partials/ws_reconnect.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/html5/verto/verto_communicator/src/storageService/services/splash_screen.js b/html5/verto/verto_communicator/src/storageService/services/splash_screen.js
new file mode 100644
index 0000000000..da7a156f63
--- /dev/null
+++ b/html5/verto/verto_communicator/src/storageService/services/splash_screen.js
@@ -0,0 +1,235 @@
+'use strict';
+
+ angular
+ .module('storageService')
+ .service('splashscreen', ['$rootScope', '$q', 'storage', 'config', 'verto',
+ function($rootScope, $q, storage, config, verto) {
+
+ var checkBrowser = function() {
+ return $q(function(resolve, reject) {
+ var activity = 'browser-upgrade';
+ var result = {
+ 'activity': activity,
+ 'soft': false,
+ 'status': 'success',
+ 'message': 'Checking browser compability.'
+ };
+
+ navigator.getUserMedia = navigator.getUserMedia ||
+ navigator.webkitGetUserMedia ||
+ navigator.mozGetUserMedia;
+
+ if (!navigator.getUserMedia) {
+ result['status'] = 'error';
+ result['message'] = 'Error: browser doesn\'t support WebRTC.';
+ reject(result);
+ }
+
+ resolve(result);
+
+ });
+ };
+
+ var checkMediaPerm = function() {
+ return $q(function(resolve, reject) {
+ var activity = 'media-perm';
+ var result = {
+ 'activity': activity,
+ 'soft': false,
+ 'status': 'success',
+ 'message': 'Checking media permissions'
+ };
+
+ verto.mediaPerm(function(status) {
+ if(!status) {
+ result['status'] = 'error';
+ result['message'] = 'Error: Media Permission Denied';
+ verto.data.mediaPerm = false;
+ reject(result);
+ }
+ verto.data.mediaPerm = true;
+ resolve(result);
+ });
+ });
+ };
+
+ var refreshMediaDevices = function() {
+ return $q(function(resolve, reject) {
+ var activity = 'refresh-devices';
+ var result = {
+ 'status': 'success',
+ 'soft': true,
+ 'activity': activity,
+ 'message': 'Refresh Media Devices.'
+ };
+
+ verto.refreshDevices(function(status) {
+ verto.refreshDevicesCallback(function() {
+ resolve(result);
+ });
+ });
+
+ });
+ };
+
+ var provisionConfig = function() {
+ return $q(function(resolve, reject) {
+ var activity = 'provision-config';
+ var result = {
+ 'status': 'promise',
+ 'soft': true,
+ 'activity': activity,
+ 'message': 'Provisioning configuration.'
+ };
+
+ var configResponse = config.configure();
+
+ var configPromise = configResponse.then(
+ function(response) {
+ /**
+ * from angular docs:
+ * A response status code between 200 and 299 is considered a success status and will result in the success callback being called
+ */
+ if(response.status >= 200 && response.status <= 299) {
+ return result;
+ } else {
+ result['status'] = 'error';
+ result['message'] = 'Error: Provision failed.';
+ return result;
+ }
+ });
+
+ result['promise'] = configPromise;
+
+ resolve(result);
+ });
+ };
+
+ var checkLogin = function() {
+ return $q(function(resolve, reject) {
+ var activity = 'check-login';
+ var result = {
+ 'status': 'success',
+ 'soft': true,
+ 'activity': activity,
+ 'message': 'Checking login.'
+ };
+
+ if(verto.data.connecting || verto.data.connected) {
+ resolve(result);
+ return;
+ };
+
+ var checkUserStored = function() {
+ /**
+ * if user data saved, use stored data for logon and not connecting
+ * not connecting prevent two connects
+ */
+ if (storage.data.ui_connected && storage.data.ws_connected && !verto.data.connecting) {
+ verto.data.name = storage.data.name;
+ verto.data.email = storage.data.email;
+ verto.data.login = storage.data.login;
+ verto.data.password = storage.data.password;
+
+ verto.data.connecting = true;
+ verto.connect(function(v, connected) {
+ verto.data.connecting = false;
+ resolve(result);
+ });
+ };
+ };
+
+ if(storage.data.ui_connected && storage.data.ws_connected) {
+ checkUserStored();
+ } else {
+ resolve(result);
+ };
+ });
+ };
+
+ var progress = [
+ checkBrowser,
+ checkMediaPerm,
+ refreshMediaDevices,
+ provisionConfig,
+ checkLogin
+ ];
+
+ var progress_message = [
+ 'Checking browser compability.',
+ 'Checking media permissions',
+ 'Refresh Media Devices.',
+ 'Provisioning configuration.',
+ 'Checking login.'
+ ];
+
+ var getProgressMessage = function(current_progress) {
+ if(progress_message[current_progress] != undefined) {
+ return progress_message[current_progress];
+ } else {
+ return 'Please wait...';
+ }
+ };
+
+ var current_progress = -1;
+ var progress_percentage = 0;
+
+ var calculateProgress = function(index) {
+ var _progress;
+
+ _progress = index + 1;
+ progress_percentage = (_progress / progress.length) * 100;
+ return progress_percentage;
+ };
+
+ var nextProgress = function() {
+ var fn, fn_return, status, interrupt, activity, soft, message, promise;
+ interrupt = false;
+ current_progress++;
+
+ if(current_progress >= progress.length) {
+ $rootScope.$emit('progress.complete', current_progress);
+ return;
+ }
+
+ fn = progress[current_progress];
+ fn_return = fn();
+
+ var emitNextProgress = function(fn_return) {
+ if(fn_return['promise'] != undefined) {
+ promise = fn_return['promise'];
+ }
+
+ status = fn_return['status'];
+ soft = fn_return['soft'];
+ activity = fn_return['activity'];
+ message = fn_return['message'];
+
+ if(status != 'success') {
+ interrupt = true;
+ }
+
+ $rootScope.$emit('progress.next', current_progress, status, promise, activity, soft, interrupt, message);
+
+ };
+
+ fn_return.then(
+ function(fn_return) {
+ emitNextProgress(fn_return);
+ },
+ function(fn_return) {
+ emitNextProgress(fn_return);
+ }
+ );
+
+ };
+
+ return {
+ 'next': nextProgress,
+ 'getProgressMessage': getProgressMessage,
+ 'progress_percentage': progress_percentage,
+ 'calculate': calculateProgress
+ };
+
+ }]);
+
diff --git a/html5/verto/verto_communicator/src/storageService/services/storage.js b/html5/verto/verto_communicator/src/storageService/services/storage.js
index 7120db18de..f0b8bb1b80 100644
--- a/html5/verto/verto_communicator/src/storageService/services/storage.js
+++ b/html5/verto/verto_communicator/src/storageService/services/storage.js
@@ -53,6 +53,8 @@
data.userStatus = 'disconnected';
},
factoryReset: function() {
+ localStorage.clear();
+ // set defaultSettings again
data.$reset(defaultSettings);
},
};
diff --git a/html5/verto/verto_communicator/src/vertoApp/vertoApp.module.js b/html5/verto/verto_communicator/src/vertoApp/vertoApp.module.js
index 2c7cffc381..0952ed1dce 100644
--- a/html5/verto/verto_communicator/src/vertoApp/vertoApp.module.js
+++ b/html5/verto/verto_communicator/src/vertoApp/vertoApp.module.js
@@ -19,6 +19,11 @@
vertoApp.config(['$routeProvider', 'gravatarServiceProvider',
function($routeProvider, gravatarServiceProvider) {
$routeProvider.
+ when('/', {
+ title: 'Loading',
+ templateUrl: 'partials/splash_screen.html',
+ controller: 'SplashScreenController'
+ }).
when('/login', {
title: 'Login',
templateUrl: 'partials/login.html',
@@ -40,7 +45,7 @@
controller: 'BrowserUpgradeController'
}).
otherwise({
- redirectTo: '/login'
+ redirectTo: '/'
});
gravatarServiceProvider.defaults = {
@@ -49,8 +54,19 @@
}
]);
- vertoApp.run(['$rootScope', '$location', 'toastr', 'prompt',
- function($rootScope, $location, toastr, prompt) {
+ vertoApp.run(['$rootScope', '$location', 'toastr', 'prompt', 'verto',
+ function($rootScope, $location, toastr, prompt, verto) {
+
+ $rootScope.$on( "$routeChangeStart", function(event, next, current) {
+ if (!verto.data.connected) {
+ if ( next.templateUrl === "partials/login.html") {
+ // pass
+ } else {
+ $location.path("/");
+ }
+ }
+ });
+
$rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
$rootScope.title = current.$$route.title;
});
@@ -61,17 +77,7 @@
$rootScope.safeProtocol = true;
}
- $rootScope.checkBrowser = function() {
- navigator.getUserMedia = navigator.getUserMedia ||
- navigator.webkitGetUserMedia ||
- navigator.mozGetUserMedia;
-
- if (!navigator.getUserMedia) {
- $location.path('/browser-upgrade');
- }
-
- };
-
+
$rootScope.promptInput = function(title, message, label, callback) {
var ret = prompt({
title: title,
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/AboutController.source.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/AboutController.source.js
new file mode 100644
index 0000000000..83b8a489cb
--- /dev/null
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/AboutController.source.js
@@ -0,0 +1,23 @@
+(function() {
+ 'use strict';
+
+ angular
+ .module('vertoControllers')
+ .controller('AboutController', ['$scope', '$http',
+ 'toastr',
+ function($scope, $http, toastr) {
+ var githash = '/* @echo revision */' || 'something is not right';
+ $scope.githash = githash;
+
+ /* leave this here for later, but its not needed right now
+ $http.get(window.location.pathname + '/contributors.txt')
+ .success(function(data) {
+
+ })
+ .error(function() {
+ toastr.error('contributors not found.');
+ });
+ */
+ }
+ ]);
+})();
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/ChatController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/ChatController.js
index 0bb3f6f6a0..cd8fff2021 100644
--- a/html5/verto/verto_communicator/src/vertoControllers/controllers/ChatController.js
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/ChatController.js
@@ -122,7 +122,7 @@
});
$rootScope.$on('members.clear', function(event) {
- $scope.$apply(function() {
+ $scope.$applyAsync(function() {
clearConferenceChat();
$scope.closeChat();
});
@@ -146,13 +146,17 @@
};
$scope.confMuteMic = function(memberID) {
- console.log('$scope.confMuteMic');
- verto.data.conf.muteMic(memberID);
+ if(verto.data.confRole == 'moderator') {
+ console.log('$scope.confMuteMic');
+ verto.data.conf.muteMic(memberID);
+ }
};
$scope.confMuteVideo = function(memberID) {
- console.log('$scope.confMuteVideo');
- verto.data.conf.muteVideo(memberID);
+ if(verto.data.confRole == 'moderator') {
+ console.log('$scope.confMuteVideo');
+ verto.data.conf.muteVideo(memberID);
+ }
};
$scope.confPresenter = function(memberID) {
@@ -167,7 +171,22 @@
$scope.confBanner = function(memberID) {
console.log('$scope.confBanner');
- var text = 'New Banner';
+
+ prompt({
+ title: 'Please insert the banner text',
+ input: true,
+ label: '',
+ value: '',
+ }).then(function(text) {
+ if (text) {
+ verto.data.conf.banner(memberID, text);
+ }
+ });
+ };
+
+ $scope.confResetBanner = function(memberID) {
+ console.log('$scope.confResetBanner');
+ var text = 'reset';
verto.data.conf.banner(memberID, text);
};
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/ContributorsController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/ContributorsController.js
index c66f421346..aa00f64e04 100644
--- a/html5/verto/verto_communicator/src/vertoControllers/controllers/ContributorsController.js
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/ContributorsController.js
@@ -6,7 +6,8 @@
.controller('ContributorsController', ['$scope', '$http',
'toastr',
function($scope, $http, toastr) {
- $http.get(window.location.pathname + '/contributors.txt')
+ var url = window.location.origin + window.location.pathname;
+ $http.get(url + 'contributors.txt')
.success(function(data) {
var contributors = [];
@@ -29,4 +30,4 @@
});
}
]);
-})();
\ No newline at end of file
+})();
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/DialPadController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/DialPadController.js
index 8c7589c93d..2944cae46d 100644
--- a/html5/verto/verto_communicator/src/vertoControllers/controllers/DialPadController.js
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/DialPadController.js
@@ -4,10 +4,12 @@
angular
.module('vertoControllers')
.controller('DialPadController', ['$rootScope', '$scope',
- '$http', '$location', 'toastr', 'verto', 'storage', 'CallHistory',
- function($rootScope, $scope, $http, $location, toastr, verto, storage, CallHistory) {
+ '$http', '$location', 'toastr', 'verto', 'storage', 'CallHistory', 'eventQueue',
+ function($rootScope, $scope, $http, $location, toastr, verto, storage, CallHistory, eventQueue) {
console.debug('Executing DialPadController.');
- $scope.checkBrowser();
+
+ eventQueue.process();
+
$scope.call_history = CallHistory.all();
$scope.history_control = CallHistory.all_control();
$scope.has_history = Object.keys($scope.call_history).length;
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/InCallController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/InCallController.js
index 47eb987a28..84d8894b28 100644
--- a/html5/verto/verto_communicator/src/vertoControllers/controllers/InCallController.js
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/InCallController.js
@@ -10,7 +10,6 @@
console.debug('Executing InCallController.');
$scope.layout = null;
- $scope.checkBrowser();
$rootScope.dialpadNumber = '';
$scope.callTemplate = 'partials/phone_call.html';
$scope.dialpadTemplate = '';
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/LoginController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/LoginController.js
index bae60ac31e..d6f1d0366f 100644
--- a/html5/verto/verto_communicator/src/vertoControllers/controllers/LoginController.js
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/LoginController.js
@@ -1,60 +1,23 @@
(function() {
- 'use strict';
+ 'use strict';
- angular
- .module('vertoControllers')
- .controller('LoginController', ['$scope', '$http', '$location', 'verto',
- function($scope, $http, $location, verto) {
- $scope.checkBrowser();
+ angular
+ .module('vertoControllers')
+ .controller('LoginController', ['$scope', '$http', '$location', 'verto',
+ function($scope, $http, $location, verto) {
+ var preRoute = function() {
+ if(verto.data.connected) {
+ $location.path('/dialpad');
+ }
+ }
+ preRoute();
+
+ verto.data.name = $scope.storage.data.name;
+ verto.data.email = $scope.storage.data.email;
- /*
- * Load the Configs before logging in
- * with cache buster
- */
-
- $http.get(window.location.pathname + '/config.json?cachebuster=' + Math.floor((Math.random()*1000000)+1))
- .success(function(data) {
-
- /* save these for later as we're about to possibly over write them */
- var name = verto.data.name;
- var email = verto.data.email;
-
- console.debug("googlelogin: " + data.googlelogin);
- if (data.googlelogin){
- $scope.googlelogin = data.googlelogin;
- $scope.googleclientid = data.googleclientid;
- }
-
- angular.extend(verto.data, data);
-
- /**
- * use stored data (localStorage) for login, allow config.json to take precedence
- */
-
- if (name != '' && data.name == '') {
- verto.data.name = name;
- }
- if (email != '' && data.email == '') {
- verto.data.email = email;
- }
- if (verto.data.login == '' && verto.data.password == '' && $scope.storage.data.login != '' && $scope.storage.data.password != '') {
- verto.data.login = $scope.storage.data.login;
- verto.data.password = $scope.storage.data.password;
- }
-
- if (verto.data.autologin == "true" && !verto.data.autologin_done) {
- console.debug("auto login per config.json");
- verto.data.autologin_done = true;
- $scope.login();
- }
- });
-
- verto.data.name = $scope.storage.data.name;
- verto.data.email = $scope.storage.data.email;
-
- console.debug('Executing LoginController.');
- }
- ]);
+ console.debug('Executing LoginController.');
+ }
+ ]);
})();
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js
index 0363d91f27..daa9b95b69 100644
--- a/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js
@@ -4,7 +4,7 @@
angular
.module('vertoControllers')
.controller('MainController',
- function($scope, $rootScope, $location, $modal, $timeout, verto, storage, CallHistory, toastr, Fullscreen, prompt) {
+ function($scope, $rootScope, $location, $modal, $timeout, $q, verto, storage, CallHistory, toastr, Fullscreen, prompt, eventQueue) {
console.debug('Executing MainController.');
@@ -24,58 +24,42 @@
* @type {string}
*/
$rootScope.dialpadNumber = '';
-
-
- /**
- * if user data saved, use stored data for logon
- */
- if (storage.data.ui_connected && storage.data.ws_connected) {
- $scope.verto.data.name = storage.data.name;
- $scope.verto.data.email = storage.data.email;
- $scope.verto.data.login = storage.data.login;
- $scope.verto.data.password = storage.data.password;
-
- verto.connect(function(v, connected) {
- $scope.$apply(function() {
- if (connected) {
- toastr.success('Nice to see you again.', 'Welcome back');
- $location.path('/dialpad');
- }
- });
- });
-
- }
-
+
// If verto is not connected, redirects to login page.
if (!verto.data.connected) {
console.debug('MainController: WebSocket not connected. Redirecting to login.');
- $location.path('/login');
+ $location.path('/');
}
-
+
+ $rootScope.$on('config.http.success', function(ev) {
+ $scope.login(false);
+ });
/**
* Login the user to verto server and
* redirects him to dialpad page.
*/
- $scope.login = function() {
+ $scope.login = function(redirect) {
+ if(redirect == undefined) {
+ redirect = true;
+ }
var connectCallback = function(v, connected) {
$scope.$apply(function() {
- if (connected) {
- storage.data.ui_connected = verto.data.connected;
- storage.data.ws_connected = verto.data.connected;
- storage.data.name = verto.data.name;
- storage.data.email = verto.data.email;
- storage.data.login = verto.data.login;
- storage.data.password = verto.data.password;
-
- console.debug('Redirecting to dialpad page.');
- toastr.success('Login successful.', 'Welcome');
+ verto.data.connecting = false;
+ if (connected) {
+ storage.data.ui_connected = verto.data.connected;
+ storage.data.ws_connected = verto.data.connected;
+ storage.data.name = verto.data.name;
+ storage.data.email = verto.data.email;
+ storage.data.login = verto.data.login;
+ storage.data.password = verto.data.password;
+ if (redirect) {
$location.path('/dialpad');
- } else {
- toastr.error('There was an error while trying to login. Please try again.', 'Error');
}
+ }
});
};
-
+
+ verto.data.connecting = true;
verto.connect(connectCallback);
};
@@ -144,12 +128,16 @@
);
};
- $rootScope.openModal = function(templateUrl, controller) {
- var modalInstance = $modal.open({
+ $rootScope.openModal = function(templateUrl, controller, _options) {
+ var options = {
animation: $scope.animationsEnabled,
templateUrl: templateUrl,
controller: controller,
- });
+ };
+
+ angular.extend(options, _options);
+
+ var modalInstance = $modal.open(options);
modalInstance.result.then(
function(result) {
@@ -165,7 +153,37 @@
jQuery.material.init();
}
);
+
+ return modalInstance;
+ };
+ $rootScope.$on('ws.close', onWSClose);
+ $rootScope.$on('ws.login', onWSLogin);
+
+ var ws_modalInstance;
+
+ function onWSClose(ev, data) {
+ if(ws_modalInstance) {
+ return;
+ };
+ var options = {
+ backdrop: 'static',
+ keyboard: false
+ };
+ ws_modalInstance = $scope.openModal('partials/ws_reconnect.html', 'ModalWsReconnectController', options);
+ };
+
+ function onWSLogin(ev, data) {
+ if(!ws_modalInstance) {
+ return;
+ };
+
+ ws_modalInstance.close();
+ ws_modalInstance = null;
+ };
+
+ $scope.showAbout = function() {
+ $scope.openModal('partials/about.html', 'AboutController');
};
$scope.showContributors = function() {
@@ -261,22 +279,27 @@
});
$rootScope.$on('page.incall', function(event, data) {
- 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?'
- }).then(function() {
- console.log('redirect to incall page');
- $location.path('/incall');
- }, function() {
- storage.data.userStatus = 'connecting';
- verto.hangup();
+ var page_incall = function() {
+ 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?'
+ }).then(function() {
+ console.log('redirect to incall page');
+ $location.path('/incall');
+ }, function() {
+ storage.data.userStatus = 'connecting';
+ verto.hangup();
+ });
+ } else {
+ console.log('redirect to incall page');
+ $location.path('/incall');
+ }
+ resolve();
});
- } else {
- console.log('redirect to incall page');
- $location.path('/incall');
- }
-
+ };
+ eventQueue.events.push(page_incall);
});
$scope.$on('event:google-plus-signin-success', function (event,authResult) {
@@ -313,7 +336,7 @@
console.log('Google+ Login Failure');
});
- $rootScope.callActive = function(data) {
+ $rootScope.callActive = function(data, params) {
verto.data.mutedMic = storage.data.mutedMic;
verto.data.mutedVideo = storage.data.mutedVideo;
@@ -331,10 +354,16 @@
storage.data.calling = false;
storage.data.cur_call = 1;
+
+ $location.path('/incall');
+
+ if(params.useVideo) {
+ $rootScope.$emit('call.video', 'video');
+ }
};
- $rootScope.$on('call.active', function(event, data) {
- $rootScope.callActive(data);
+ $rootScope.$on('call.active', function(event, data, params) {
+ $rootScope.callActive(data, params);
});
$rootScope.$on('call.calling', function(event, data) {
@@ -360,11 +389,11 @@
$scope.answerCall();
storage.data.called_number = data;
- CallHistory.add(number, 'inbound', true);
+ CallHistory.add(data, 'inbound', true);
$location.path('/incall');
}, function() {
$scope.declineCall();
- CallHistory.add(number, 'inbound', false);
+ CallHistory.add(data, 'inbound', false);
});
});
@@ -380,6 +409,7 @@
if (!verto.data.call) {
toastr.warning('There is no call to hangup.');
$location.path('/dialpad');
+ return;
}
//var hangupCallback = function(v, hangup) {
@@ -394,7 +424,10 @@
if (verto.data.shareCall) {
verto.screenshareHangup();
}
+
verto.hangup();
+
+ $location.path('/dialpad');
};
$scope.answerCall = function() {
@@ -403,6 +436,7 @@
verto.data.call.answer({
useStereo: storage.data.useStereo,
useCamera: storage.data.selectedVideo,
+ useVideo: storage.data.useVideo,
useMic: storage.data.useMic,
callee_id_name: verto.data.name,
callee_id_number: verto.data.login
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/ModalSettingsController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/ModalSettingsController.js
index b144d3026e..2b70948bbe 100644
--- a/html5/verto/verto_communicator/src/vertoControllers/controllers/ModalSettingsController.js
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/ModalSettingsController.js
@@ -34,6 +34,14 @@
window.location.reload();
};
};
+
+ $scope.checkUseDedRemoteEncoder = function(option) {
+ if ($scope.mydata.incomingBandwidth != 'default' || $scope.mydata.outgoingBandwidth != 'default') {
+ $scope.mydata.useDedenc = true;
+ } else {
+ $scope.mydata.useDedenc = false;
+ }
+ };
}
]);
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/ModalWsReconnectController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/ModalWsReconnectController.js
new file mode 100644
index 0000000000..374ad18c8d
--- /dev/null
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/ModalWsReconnectController.js
@@ -0,0 +1,15 @@
+(function() {
+ 'use strict';
+
+ angular
+ .module('vertoControllers')
+ .controller('ModalWsReconnectController', ModalWsReconnectController);
+
+ ModalWsReconnectController.$inject = ['$scope', 'storage', 'verto'];
+
+ function ModalWsReconnectController($scope, storage, verto) {
+ console.debug('Executing ModalWsReconnectController');
+ };
+
+
+})();
diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/SplashScreenController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/SplashScreenController.js
new file mode 100644
index 0000000000..fdc96efd59
--- /dev/null
+++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/SplashScreenController.js
@@ -0,0 +1,88 @@
+(function() {
+ 'use strict';
+
+ angular
+ .module('vertoControllers')
+ .controller('SplashScreenController', ['$scope', '$rootScope', '$location', '$timeout', 'splashscreen', 'prompt', 'verto',
+ function($scope, $rootScope, $location, $timeout, splashscreen, prompt, verto) {
+ console.debug('Executing SplashScreenController.');
+
+ $scope.progress_percentage = splashscreen.progress_percentage;
+ $scope.message = '';
+ $scope.interrupt_next = false;
+ $scope.errors = [];
+
+ var redirectTo = function(link, activity) {
+ if(activity) {
+ if(activity == 'browser-upgrade') {
+ link = activity;
+ }
+ }
+
+ $location.path(link);
+ }
+
+ var checkProgressState = function(current_progress, status, promise, activity, soft, interrupt, message) {
+ $scope.progress_percentage = splashscreen.calculate(current_progress);
+ $scope.message = message;
+
+ if(interrupt && status == 'error') {
+ $scope.errors.push(message);
+ if(!soft) {
+ redirectTo('', activity);
+ return;
+ } else {
+ message = message + '. Continue?';
+ };
+
+ if(!confirm(message)) {
+ $scope.interrupt_next = true;
+ };
+ };
+
+ if($scope.interrupt_next) {
+ return;
+ };
+
+ $scope.message = splashscreen.getProgressMessage(current_progress+1);
+
+ return true;
+ };
+
+ $rootScope.$on('progress.next', function(ev, current_progress, status, promise, activity, soft, interrupt, message) {
+ $timeout(function() {
+ if(promise) {
+ promise.then(function(response) {
+ message = response['message'];
+ status = response['status'];
+ if(checkProgressState(current_progress, status, promise, activity, soft, interrupt, message)) {
+ splashscreen.next();
+ };
+ });
+
+ return;
+ }
+
+ if(!checkProgressState(current_progress, status, promise, activity, soft, interrupt, message)) {
+ return;
+ }
+
+ splashscreen.next();
+ }, 400);
+ });
+
+ $rootScope.$on('progress.complete', function(ev, current_progress) {
+ $scope.message = 'Complete';
+ if(verto.data.connected) {
+ redirectTo('/dialpad');
+ } else {
+ redirectTo('/login');
+ $location.path('/login');
+ }
+ });
+
+ splashscreen.next();
+
+ }]);
+
+})();
diff --git a/html5/verto/verto_communicator/src/vertoControllers/vertoControllers.module.js b/html5/verto/verto_communicator/src/vertoControllers/vertoControllers.module.js
index f27923b322..a20bb2cfee 100644
--- a/html5/verto/verto_communicator/src/vertoControllers/vertoControllers.module.js
+++ b/html5/verto/verto_communicator/src/vertoControllers/vertoControllers.module.js
@@ -2,10 +2,10 @@
'use strict';
var vertoControllers = angular.module('vertoControllers', [
- 'ui.bootstrap',
+ 'ui.bootstrap',
'vertoService',
'storageService',
'ui.gravatar'
]);
-})();
\ No newline at end of file
+})();
diff --git a/html5/verto/verto_communicator/src/vertoDirectives/directives/videoTag.js b/html5/verto/verto_communicator/src/vertoDirectives/directives/videoTag.js
index 2e85168569..38b50552f7 100644
--- a/html5/verto/verto_communicator/src/vertoDirectives/directives/videoTag.js
+++ b/html5/verto/verto_communicator/src/vertoDirectives/directives/videoTag.js
@@ -18,7 +18,7 @@
console.log('Moving the video to element.');
jQuery('video').removeClass('hide').appendTo(element);
jQuery('video').css('display', 'block');
- scope.callActive();
+ scope.callActive("", {useVideo: true});
element.on('$destroy', function() {
// Move the video back to the body.
diff --git a/html5/verto/verto_communicator/src/vertoService/services/configService.js b/html5/verto/verto_communicator/src/vertoService/services/configService.js
new file mode 100644
index 0000000000..105a20b324
--- /dev/null
+++ b/html5/verto/verto_communicator/src/vertoService/services/configService.js
@@ -0,0 +1,82 @@
+'use strict';
+
+var vertoService = angular.module('vertoService');
+
+vertoService.service('config', ['$rootScope', '$http', '$location', 'storage', 'verto',
+ function($rootScope, $http, $location, storage, verto) {
+ var configure = function() {
+ /**
+ * Load stored user info into verto service
+ */
+ if(storage.data.name) {
+ verto.data.name = storage.data.name;
+ }
+ if(storage.data.email) {
+ verto.data.email = storage.data.email;
+ }
+ if(storage.data.login) {
+ verto.data.login = storage.data.login;
+ }
+ if(storage.data.password) {
+ verto.data.password = storage.data.password;
+ }
+
+ /*
+ * Load the Configs before logging in
+ * with cache buster
+ */
+ var url = window.location.origin + window.location.pathname;
+ var httpRequest = $http.get(url + 'config.json?cachebuster=' + Math.floor((Math.random()*1000000)+1));
+
+ var httpReturn = httpRequest.then(function(response) {
+ var data = response.data;
+
+ /* save these for later as we're about to possibly over write them */
+ var name = verto.data.name;
+ var email = verto.data.email;
+
+ console.debug("googlelogin: " + data.googlelogin);
+ if (data.googlelogin){
+ verto.data.googlelogin = data.googlelogin;
+ verto.data.googleclientid = data.googleclientid;
+ }
+
+ angular.extend(verto.data, data);
+
+ /**
+ * use stored data (localStorage) for login, allow config.json to take precedence
+ */
+
+ if (name != '' && data.name == '') {
+ verto.data.name = name;
+ }
+ if (email != '' && data.email == '') {
+ verto.data.email = email;
+ }
+ if (verto.data.login == '' && verto.data.password == '' && storage.data.login != '' && storage.data.password != '') {
+ verto.data.login = storage.data.login;
+ verto.data.password = storage.data.password;
+ }
+
+ if (verto.data.autologin == "true" && !verto.data.autologin_done) {
+ console.debug("auto login per config.json");
+ verto.data.autologin_done = true;
+ }
+
+ if(verto.data.autologin && storage.data.name.length && storage.data.email.length && storage.data.login.length && storage.data.password.length) {
+ $rootScope.$emit('config.http.success', data);
+ };
+ return response;
+ }, function(response) {
+ $rootScope.$emit('config.http.error', response);
+ return response;
+ });
+
+ return httpReturn;
+ };
+
+ return {
+ 'configure': configure
+ };
+ }]);
+
diff --git a/html5/verto/verto_communicator/src/vertoService/services/eventQueueService.js b/html5/verto/verto_communicator/src/vertoService/services/eventQueueService.js
new file mode 100644
index 0000000000..71c48bcefa
--- /dev/null
+++ b/html5/verto/verto_communicator/src/vertoService/services/eventQueueService.js
@@ -0,0 +1,50 @@
+'use strict';
+
+ angular
+ .module('vertoService')
+ .service('eventQueue', ['$rootScope', '$q', 'storage', 'verto',
+ function($rootScope, $q, storage, verto) {
+
+ var events = [];
+
+ var next = function() {
+ var fn, fn_return;
+
+ fn = events.shift();
+
+ if (fn == undefined) {
+ $rootScope.$emit('eventqueue.complete');
+ return;
+ }
+ fn_return = fn();
+
+ var emitNextProgress = function() {
+ $rootScope.$emit('eventqueue.next');
+ };
+
+ fn_return.then(
+ function() {
+ emitNextProgress();
+ },
+ function() {
+ emitNextProgress();
+ }
+ );
+ };
+
+ var process = function() {
+ $rootScope.$on('eventqueue.next', function (ev){
+ next();
+ });
+
+ next();
+ };
+
+ return {
+ 'next': next,
+ 'process': process,
+ 'events': events
+ };
+
+ }]);
+
diff --git a/html5/verto/verto_communicator/src/vertoService/services/vertoService.js b/html5/verto/verto_communicator/src/vertoService/services/vertoService.js
index 940ae1059d..652d5aa0da 100644
--- a/html5/verto/verto_communicator/src/vertoService/services/vertoService.js
+++ b/html5/verto/verto_communicator/src/vertoService/services/vertoService.js
@@ -1,8 +1,8 @@
'use strict';
/* Controllers */
-
-var videoQuality = [{
+var videoQuality = [];
+var videoQualitySource = [{
id: 'qvga',
label: 'QVGA 320x240',
width: 320,
@@ -143,8 +143,8 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
$rootScope.$emit('page.incall', 'call');
}
- function callActive(last_state) {
- $rootScope.$emit('call.active', last_state);
+ function callActive(last_state, params) {
+ $rootScope.$emit('call.active', last_state, params);
}
function calling() {
@@ -158,28 +158,28 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
function updateResolutions(supportedResolutions) {
console.debug('Attempting to sync supported and available resolutions');
- var removed = 0;
+ //var removed = 0;
- angular.forEach(videoQuality, function(resolution, id) {
- var supported = false;
+ console.debug("VQ length: " + videoQualitySource.length);
+ console.debug(supportedResolutions);
+
+ angular.forEach(videoQualitySource, function(resolution, id) {
angular.forEach(supportedResolutions, function(res) {
var width = res[0];
var height = res[1];
if(resolution.width == width && resolution.height == height) {
- supported = true;
+ videoQuality.push(resolution);
}
});
-
- if(!supported) {
- delete videoQuality[id];
- ++removed;
- }
});
- videoQuality.length = videoQuality.length - removed;
+ // videoQuality.length = videoQuality.length - removed;
+ console.debug("VQ length 2: " + videoQuality.length);
data.videoQuality = videoQuality;
+ console.debug(videoQuality);
data.vidQual = (videoQuality.length > 0) ? videoQuality[videoQuality.length - 1].id : null;
+ console.debug(data.vidQual);
return videoQuality;
};
@@ -198,7 +198,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
videoResolution: videoResolution,
bandwidth: bandwidth,
- refreshDevicesCallback : function refreshDevicesCallback() {
+ refreshDevicesCallback : function refreshDevicesCallback(callback) {
data.videoDevices = [{
id: 'none',
label: 'No Camera'
@@ -278,11 +278,19 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
} else {
data.canVideo = true;
}
+
+ if(angular.isFunction(callback)) {
+ callback();
+ }
},
refreshDevices: function(callback) {
console.debug('Attempting to refresh the devices.');
- jQuery.verto.refreshDevices(this.refreshDevicesCallback);
+ if(callback) {
+ jQuery.verto.refreshDevices(callback);
+ } else {
+ jQuery.verto.refreshDevices(this.refreshDevicesCallback);
+ }
},
/**
@@ -364,8 +372,11 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
}
});
- console.log('>>> conf.listVideoLayouts();');
- conf.listVideoLayouts();
+ if (data.confRole == "moderator") {
+ console.log('>>> conf.listVideoLayouts();');
+ conf.listVideoLayouts();
+ }
+
data.conf = conf;
data.liveArray = new $.verto.liveArray(
@@ -425,15 +436,20 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
console.log('Has data.liveArray.');
$rootScope.$emit('members.clear');
data.liveArray = null;
-
} else {
console.log('Doesn\'t found data.liveArray.');
}
+
+ if (data.conf) {
+ data.conf.destroy();
+ data.conf = null;
+ }
}
var callbacks = {
onWSLogin: function(v, success) {
data.connected = success;
+ $rootScope.$emit('ws.login', success);
console.debug('Connected to verto server:', success);
if (angular.isFunction(callback)) {
@@ -450,6 +466,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
switch (params.pvtData.action) {
case "conference-liveArray-join":
console.log("conference-liveArray-join");
+ stopConference();
startConference(v, dialog, params.pvtData);
break;
case "conference-liveArray-part":
@@ -472,6 +489,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
});
break;
default:
+ console.warn('Got a not implemented message:', msg, dialog, params);
break;
}
},
@@ -479,9 +497,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
onDialogState: function(d) {
if (!data.call) {
data.call = d;
- if (d.state.name !== 'ringing') {
- inCall();
- }
+
}
console.debug('onDialogState:', d);
@@ -501,7 +517,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
case "active":
console.debug('Talking to:', d.cidString());
data.callState = 'active';
- callActive(d.lastState.name);
+ callActive(d.lastState.name, d.params);
break;
case "hangup":
console.debug('Call ended with cause: ' + d.cause);
@@ -512,21 +528,22 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
if (d.params.screenShare) {
cleanShareCall(that);
} else {
- if (data.liveArray) {
- data.liveArray.destroy();
+ stopConference();
+ if (!that.reloaded) {
+ cleanCall();
}
-
- if (data.conf) {
- data.conf.destroy();
- }
- cleanCall();
}
break;
+ default:
+ console.warn('Got a not implemented state:', d);
+ break;
}
},
onWSClose: function(v, success) {
console.debug('onWSClose:', success);
+
+ $rootScope.$emit('ws.close', success);
},
onEvent: function(v, e) {
@@ -538,10 +555,11 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
function ourBootstrap() {
// Checking if we have a failed connection attempt before
// connecting again.
- that.refreshDevicesCallback();
if (data.instance && !data.instance.rpcClient.socketReady()) {
clearTimeout(data.instance.rpcClient.to);
data.instance.logout();
+ data.instance.login();
+ return;
};
data.instance = new jQuery.verto({
login: data.login + '@' + data.hostname,
@@ -551,22 +569,36 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
ringFile: "sounds/bell_ring2.wav",
// TODO: Add options for this.
audioParams: {
- googEchoCancellation: storage.data.googEchoCancellation || false,
- googNoiseSuppression: storage.data.googNoiseSuppression || false,
- googHighpassFilter: storage.data.googHighpassFilter || false
+ googEchoCancellation: storage.data.googEchoCancellation || true,
+ googNoiseSuppression: storage.data.googNoiseSuppression || true,
+ googHighpassFilter: storage.data.googHighpassFilter || true
},
iceServers: storage.data.useSTUN
}, callbacks);
- data.instance.deviceParams({
- useCamera: storage.data.selectedVideo,
- useMic: storage.data.selectedAudio,
- onResCheck: that.refreshVideoResolution
+ // We need to know when user reloaded page and not react to
+ // verto events in order to not stop the reload and redirect user back
+ // to the dialpad.
+ that.reloaded = false;
+ jQuery.verto.unloadJobs.push(function() {
+ that.reloaded = true;
});
-
+ data.instance.deviceParams({
+ useCamera: storage.data.selectedVideo,
+ useMic: storage.data.selectedAudio,
+ onResCheck: that.refreshVideoResolution
+ });
}
- $.verto.init({}, ourBootstrap);
+ if (data.mediaPerm) {
+ ourBootstrap();
+ } else {
+ $.FSRTC.checkPerms(ourBootstrap, true, true);
+ }
+ },
+
+ mediaPerm: function(callback) {
+ $.FSRTC.checkPerms(callback, true, true);
},
/**
@@ -616,7 +648,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
var call = data.instance.newCall({
destination_number: destination,
caller_id_name: data.name,
- caller_id_number: data.login,
+ caller_id_number: data.callerid ? data.callerid : data.email,
outgoingBandwidth: storage.data.outgoingBandwidth,
incomingBandwidth: storage.data.incomingBandwidth,
useVideo: storage.data.useVideo,
diff --git a/html5/verto/video_demo/js/verto-min.js b/html5/verto/video_demo/js/verto-min.js
index 622cfa10a4..da28e4dd7f 100644
--- a/html5/verto/video_demo/js/verto-min.js
+++ b/html5/verto/video_demo/js/verto-min.js
@@ -30,9 +30,10 @@ self.options.useAudio.play();self.remoteStream=stream;}
function onOfferSDP(self,sdp){self.mediaData.SDP=self.stereoHack(sdp.sdp);console.log("Offer SDP");doCallback(self,"onOfferSDP");}
$.FSRTC.prototype.answer=function(sdp,onSuccess,onError){this.peer.addAnswerSDP({type:"answer",sdp:sdp},onSuccess,onError);};$.FSRTC.prototype.stopPeer=function(){if(self.peer){console.log("stopping peer");self.peer.stop();}}
$.FSRTC.prototype.stop=function(){var self=this;if(self.options.useVideo){self.options.useVideo.style.display='none';if(moz){self.options.useVideo['mozSrcObject']=null;}else{self.options.useVideo['src']='';}}
-if(self.localStream){self.localStream.stop();self.localStream=null;}
+if(self.localStream){if(typeof self.localStream.stop=='function'){self.localStream.stop();}else{if(self.localStream.active){var tracks=self.localStream.getTracks();console.error(tracks);tracks.forEach(function(track,index){console.log(track);track.stop();})}}
+self.localStream=null;}
if(self.options.localVideo){self.options.localVideo.style.display='none';if(moz){self.options.localVideo['mozSrcObject']=null;}else{self.options.localVideo['src']='';}}
-if(self.options.localVideoStream){self.options.localVideoStream.stop();}
+if(self.options.localVideoStream){if(typeof self.options.localVideoStream.stop=='function'){self.options.localVideoStream.stop();}else{if(self.localVideoStream.active){var tracks=self.localVideoStream.getTracks();console.error(tracks);tracks.forEach(function(track,index){console.log(track);track.stop();})}}}
if(self.peer){console.log("stopping peer");self.peer.stop();}};$.FSRTC.prototype.getMute=function(){var self=this;return self.enabled;}
$.FSRTC.prototype.setMute=function(what){var self=this;var audioTracks=self.localStream.getAudioTracks();for(var i=0,len=audioTracks.length;iremaining_samples != INT_MAX)
{
@@ -151,7 +151,7 @@ SPAN_DECLARE(int) silence_gen_free(silence_gen_state_t *s)
/* The following dummy routines, to absorb data, don't really have a proper home,
so they have been put here. */
-SPAN_DECLARE_NONSTD(int) span_dummy_rx(void *user_data, const int16_t amp[], int len)
+SPAN_DECLARE(int) span_dummy_rx(void *user_data, const int16_t amp[], int len)
{
return 0;
}
@@ -163,7 +163,7 @@ SPAN_DECLARE(int) span_dummy_mod(void *user_data, int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) span_dummy_rx_fillin(void *user_data, int len)
+SPAN_DECLARE(int) span_dummy_rx_fillin(void *user_data, int len)
{
return 0;
}
diff --git a/libs/spandsp/src/spandsp/async.h b/libs/spandsp/src/spandsp/async.h
index eabb41d3f1..290b3acc1d 100644
--- a/libs/spandsp/src/spandsp/async.h
+++ b/libs/spandsp/src/spandsp/async.h
@@ -156,7 +156,7 @@ SPAN_DECLARE(const char *) signal_status_to_str(int status);
- SIG_STATUS_TRAINING_SUCCEEDED
- SIG_STATUS_TRAINING_FAILED
- SIG_STATUS_END_OF_DATA */
-SPAN_DECLARE_NONSTD(void) async_rx_put_bit(void *user_data, int bit);
+SPAN_DECLARE(void) async_rx_put_bit(void *user_data, int bit);
/*! Initialise an asynchronous data receiver context.
\brief Initialise an asynchronous data receiver context.
@@ -190,7 +190,7 @@ SPAN_DECLARE(void) async_tx_presend_bits(async_tx_state_t *s, int bits);
\brief Get the next bit of a transmitted serial bit stream.
\param user_data An opaque point which must point to a transmitter context.
\return the next bit, or PUTBIT_END_OF_DATA to indicate the data stream has ended. */
-SPAN_DECLARE_NONSTD(int) async_tx_get_bit(void *user_data);
+SPAN_DECLARE(int) async_tx_get_bit(void *user_data);
/*! Initialise an asynchronous data transmit context.
\brief Initialise an asynchronous data transmit context.
diff --git a/libs/spandsp/src/spandsp/fax.h b/libs/spandsp/src/spandsp/fax.h
index 499b2b3b25..de6d52da0e 100644
--- a/libs/spandsp/src/spandsp/fax.h
+++ b/libs/spandsp/src/spandsp/fax.h
@@ -50,7 +50,7 @@ extern "C"
\return The number of samples unprocessed. This should only be non-zero if
the software has reached the end of the FAX call.
*/
-SPAN_DECLARE_NONSTD(int) fax_rx(fax_state_t *s, int16_t *amp, int len);
+SPAN_DECLARE(int) fax_rx(fax_state_t *s, int16_t *amp, int len);
/*! Apply fake T.30 receive processing when a block of audio samples is missing (e.g due
to packet loss).
@@ -60,7 +60,7 @@ SPAN_DECLARE_NONSTD(int) fax_rx(fax_state_t *s, int16_t *amp, int len);
\return The number of samples unprocessed. This should only be non-zero if
the software has reached the end of the FAX call.
*/
-SPAN_DECLARE_NONSTD(int) fax_rx_fillin(fax_state_t *s, int len);
+SPAN_DECLARE(int) fax_rx_fillin(fax_state_t *s, int len);
/*! Apply T.30 transmit processing to generate a block of audio samples.
\brief Apply T.30 transmit processing to generate a block of audio samples.
@@ -70,7 +70,7 @@ SPAN_DECLARE_NONSTD(int) fax_rx_fillin(fax_state_t *s, int len);
\return The number of samples actually generated. This will be zero when
there is nothing to send.
*/
-SPAN_DECLARE_NONSTD(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len);
+SPAN_DECLARE(int) fax_tx(fax_state_t *s, int16_t *amp, int max_len);
/*! Select whether silent audio will be sent when FAX transmit is idle.
\brief Select whether silent audio will be sent when FAX transmit is idle.
diff --git a/libs/spandsp/src/spandsp/fax_modems.h b/libs/spandsp/src/spandsp/fax_modems.h
index a076c0332f..15cc802474 100644
--- a/libs/spandsp/src/spandsp/fax_modems.h
+++ b/libs/spandsp/src/spandsp/fax_modems.h
@@ -64,7 +64,7 @@ extern "C"
#endif
/* TEMPORARY FUDGE */
-SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok);
+SPAN_DECLARE(void) fax_modems_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok);
/*! Convert a FAX modem type to a short text description.
\brief Convert a FAX modem type to a short text description.
@@ -73,14 +73,14 @@ SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_accept(void *user_data, const uint8_t
SPAN_DECLARE(const char *) fax_modem_to_str(int modem);
/* N.B. the following are currently a work in progress */
-SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len);
-SPAN_DECLARE_NONSTD(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len);
+SPAN_DECLARE(int) fax_modems_v17_v21_rx(void *user_data, const int16_t amp[], int len);
+SPAN_DECLARE(int) fax_modems_v27ter_v21_rx(void *user_data, const int16_t amp[], int len);
+SPAN_DECLARE(int) fax_modems_v29_v21_rx(void *user_data, const int16_t amp[], int len);
+SPAN_DECLARE(int) fax_modems_v17_v21_rx_fillin(void *user_data, int len);
+SPAN_DECLARE(int) fax_modems_v27ter_v21_rx_fillin(void *user_data, int len);
+SPAN_DECLARE(int) fax_modems_v29_v21_rx_fillin(void *user_data, int len);
-SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_t *msg, int len);
+SPAN_DECLARE(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_t *msg, int len);
SPAN_DECLARE(void) fax_modems_hdlc_tx_flags(fax_modems_state_t *s, int flags);
diff --git a/libs/spandsp/src/spandsp/fsk.h b/libs/spandsp/src/spandsp/fsk.h
index b65cd7842f..c016eca8a5 100644
--- a/libs/spandsp/src/spandsp/fsk.h
+++ b/libs/spandsp/src/spandsp/fsk.h
@@ -187,7 +187,7 @@ SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_stat
\param len The number of samples to be generated.
\return The number of samples actually generated.
*/
-SPAN_DECLARE_NONSTD(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len);
/*! Get the current received signal power.
\param s The modem context.
@@ -228,7 +228,7 @@ SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s);
\param len The number of samples in the buffer.
\return The number of samples unprocessed.
*/
-SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len);
+SPAN_DECLARE(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len);
/*! Fake processing of a missing block of received FSK modem audio samples
(e.g due to packet loss).
@@ -237,7 +237,7 @@ SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len);
\param len The number of samples to fake.
\return The number of samples unprocessed.
*/
-SPAN_DECLARE_NONSTD(int) fsk_rx_fillin(fsk_rx_state_t *s, int len);
+SPAN_DECLARE(int) fsk_rx_fillin(fsk_rx_state_t *s, int len);
SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, void *user_data);
diff --git a/libs/spandsp/src/spandsp/hdlc.h b/libs/spandsp/src/spandsp/hdlc.h
index a9369475c1..1349a57a04 100644
--- a/libs/spandsp/src/spandsp/hdlc.h
+++ b/libs/spandsp/src/spandsp/hdlc.h
@@ -160,20 +160,20 @@ SPAN_DECLARE(int) hdlc_rx_get_stats(hdlc_rx_state_t *s,
\param s A pointer to an HDLC receiver context.
\param new_bit The bit.
*/
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit);
+SPAN_DECLARE(void) hdlc_rx_put_bit(hdlc_rx_state_t *s, int new_bit);
/*! \brief Put a byte of data to an HDLC receiver.
\param s A pointer to an HDLC receiver context.
\param new_byte The byte of data.
*/
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte);
+SPAN_DECLARE(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte);
/*! \brief Put a series of bytes of data to an HDLC receiver.
\param s A pointer to an HDLC receiver context.
\param buf The buffer of data.
\param len The length of the data in the buffer.
*/
-SPAN_DECLARE_NONSTD(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len);
+SPAN_DECLARE(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len);
/*! Initialise an HDLC transmitter context.
\brief Initialise an HDLC transmitter context.
@@ -250,13 +250,13 @@ SPAN_DECLARE(int) hdlc_tx_abort(hdlc_tx_state_t *s);
\param s A pointer to an HDLC transmitter context.
\return The next bit for transmission.
*/
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get_bit(hdlc_tx_state_t *s);
+SPAN_DECLARE(int) hdlc_tx_get_bit(hdlc_tx_state_t *s);
/*! \brief Get the next byte for transmission.
\param s A pointer to an HDLC transmitter context.
\return The next byte for transmission.
*/
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s);
+SPAN_DECLARE(int) hdlc_tx_get_byte(hdlc_tx_state_t *s);
/*! \brief Get the next sequence of bytes for transmission.
\param s A pointer to an HDLC transmitter context.
@@ -264,7 +264,7 @@ SPAN_DECLARE_NONSTD(int) hdlc_tx_get_byte(hdlc_tx_state_t *s);
\param max_len The number of bytes to get.
\return The number of bytes actually got.
*/
-SPAN_DECLARE_NONSTD(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len);
+SPAN_DECLARE(int) hdlc_tx_get(hdlc_tx_state_t *s, uint8_t buf[], size_t max_len);
#if defined(__cplusplus)
}
diff --git a/libs/spandsp/src/spandsp/modem_connect_tones.h b/libs/spandsp/src/spandsp/modem_connect_tones.h
index 713f813bbb..bbfc6f3b97 100644
--- a/libs/spandsp/src/spandsp/modem_connect_tones.h
+++ b/libs/spandsp/src/spandsp/modem_connect_tones.h
@@ -127,9 +127,9 @@ SPAN_DECLARE(int) modem_connect_tones_tx_free(modem_connect_tones_tx_state_t *s)
\param len The number of samples to generate.
\return The number of samples generated.
*/
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s,
- int16_t amp[],
- int len);
+SPAN_DECLARE(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s,
+ int16_t amp[],
+ int len);
/*! \brief Process a block of samples through an instance of the modem connect
tones detector.
@@ -138,9 +138,9 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *
\param len The number of samples in the array.
\return The number of unprocessed samples.
*/
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s,
- const int16_t amp[],
- int len);
+SPAN_DECLARE(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s,
+ const int16_t amp[],
+ int len);
/*! Fake processing of a missing block of received modem connect tone samples
(e.g due to packet loss).
@@ -149,7 +149,7 @@ SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *
\param len The number of samples to fake.
\return The number of samples unprocessed.
*/
-SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_state_t *s, int len);
+SPAN_DECLARE(int) modem_connect_tones_rx_fillin(modem_connect_tones_rx_state_t *s, int len);
/*! \brief Test if a modem_connect tone has been detected.
\param s The context.
diff --git a/libs/spandsp/src/spandsp/silence_gen.h b/libs/spandsp/src/spandsp/silence_gen.h
index df90ec0e9e..94357b7247 100644
--- a/libs/spandsp/src/spandsp/silence_gen.h
+++ b/libs/spandsp/src/spandsp/silence_gen.h
@@ -41,7 +41,7 @@ extern "C"
\return The number of samples actually generated. This will be zero when
there is nothing to send.
*/
-SPAN_DECLARE_NONSTD(int) silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len);
+SPAN_DECLARE(int) silence_gen(silence_gen_state_t *s, int16_t *amp, int max_len);
/*! Set a silence generator context to output continuous silence.
\brief Set a silence generator context to output continuous silence.
@@ -110,7 +110,7 @@ SPAN_DECLARE(int) silence_gen_free(silence_gen_state_t *s);
\param len The length of the signal buffer
\return 0.
*/
-SPAN_DECLARE_NONSTD(int) span_dummy_rx(void *user_data, const int16_t amp[], int len);
+SPAN_DECLARE(int) span_dummy_rx(void *user_data, const int16_t amp[], int len);
/*! A dummy routine to use as a signal modifier callback, when we aren't
really trying to process the signal. It just returns without affecting
@@ -131,7 +131,7 @@ SPAN_DECLARE(int) span_dummy_mod(void *user_data, int16_t amp[], int len);
\param len The length of the signal buffer
\return 0.
*/
-SPAN_DECLARE_NONSTD(int) span_dummy_rx_fillin(void *user_data, int len);
+SPAN_DECLARE(int) span_dummy_rx_fillin(void *user_data, int len);
#if defined(__cplusplus)
}
diff --git a/libs/spandsp/src/spandsp/stdbool.h b/libs/spandsp/src/spandsp/stdbool.h
index ce1dc387b5..faceaac3f9 100644
--- a/libs/spandsp/src/spandsp/stdbool.h
+++ b/libs/spandsp/src/spandsp/stdbool.h
@@ -32,14 +32,16 @@
#if !defined(_STDBOOL_H)
#define _STDBOOL_H
+
#ifdef _MSC_VER
#pragma warning (disable: 4005)
#endif
+
#if !defined(__cplusplus)
#define _Bool int
-#define false 0
#define bool int
+#define false 0
#define true (!false)
#else
diff --git a/libs/spandsp/src/spandsp/t30.h b/libs/spandsp/src/spandsp/t30.h
index b3c0b6ad36..00749004f2 100644
--- a/libs/spandsp/src/spandsp/t30.h
+++ b/libs/spandsp/src/spandsp/t30.h
@@ -576,7 +576,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status);
\brief Get a bit of received non-ECM image data.
\param user_data An opaque pointer, which must point to the T.30 context.
\return The next bit to transmit. */
-SPAN_DECLARE_NONSTD(int) t30_non_ecm_get_bit(void *user_data);
+SPAN_DECLARE(int) t30_non_ecm_get_bit(void *user_data);
/*! Get a chunk of received non-ECM image data.
\brief Get a bit of received non-ECM image data.
@@ -590,7 +590,7 @@ SPAN_DECLARE(int) t30_non_ecm_get(void *user_data, uint8_t buf[], int max_len);
\brief Process a bit of received non-ECM image data
\param user_data An opaque pointer, which must point to the T.30 context.
\param bit The received bit. */
-SPAN_DECLARE_NONSTD(void) t30_non_ecm_put_bit(void *user_data, int bit);
+SPAN_DECLARE(void) t30_non_ecm_put_bit(void *user_data, int bit);
/*! Process a chunk of received non-ECM image data.
\brief Process a chunk of received non-ECM image data
@@ -605,7 +605,7 @@ SPAN_DECLARE(void) t30_non_ecm_put(void *user_data, const uint8_t buf[], int len
\param msg The HDLC message.
\param len The length of the message, in octets.
\param ok True if the frame was received without error. */
-SPAN_DECLARE_NONSTD(void) t30_hdlc_accept(void *user_data, const uint8_t msg[], int len, int ok);
+SPAN_DECLARE(void) t30_hdlc_accept(void *user_data, const uint8_t msg[], int len, int ok);
/*! Report the passage of time to the T.30 engine.
\brief Report the passage of time to the T.30 engine.
diff --git a/libs/spandsp/src/spandsp/t31.h b/libs/spandsp/src/spandsp/t31.h
index b61a4142f9..45237c4e7c 100644
--- a/libs/spandsp/src/spandsp/t31.h
+++ b/libs/spandsp/src/spandsp/t31.h
@@ -65,7 +65,7 @@ SPAN_DECLARE(int) t31_at_rx(t31_state_t *s, const char *t, int len);
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) t31_rx(t31_state_t *s, int16_t amp[], int len);
/*! Fake processing of a missing block of received T.31 modem audio samples
(e.g due to packet loss).
@@ -73,7 +73,7 @@ SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len);
\param s The T.31 modem context.
\param len The number of samples to fake.
\return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len);
+SPAN_DECLARE(int) t31_rx_fillin(t31_state_t *s, int len);
/*! Generate a block of T.31 modem audio samples.
\brief Generate a block of T.31 modem audio samples.
@@ -82,7 +82,7 @@ SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len);
\param max_len The number of samples to be generated.
\return The number of samples actually generated.
*/
-SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len);
+SPAN_DECLARE(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len);
SPAN_DECLARE(int) t31_t38_send_timeout(t31_state_t *s, int samples);
diff --git a/libs/spandsp/src/spandsp/t38_core.h b/libs/spandsp/src/spandsp/t38_core.h
index 86e45089ac..3d3d83da51 100644
--- a/libs/spandsp/src/spandsp/t38_core.h
+++ b/libs/spandsp/src/spandsp/t38_core.h
@@ -288,7 +288,7 @@ SPAN_DECLARE(int) t38_core_send_data_multi_field(t38_core_state_t *s, int data_t
\param len The length of the packet contents.
\param seq_no The packet sequence number.
\return 0 for OK, else -1. */
-SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no);
+SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no);
/*! \brief Process a received T.38 IFP packet from a reliable stream (e.g. TCP).
\param s The T.38 context.
@@ -296,7 +296,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8
\param len The length of the packet contents.
\param seq_no The packet sequence number, used for logging purposes.
\return The length of the packet processed, or -1 if there is an error in the packet, or too few bytes of data to complete it. */
-SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no);
+SPAN_DECLARE(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no);
/*! Set the method to be used for data rate management, as per the T.38 spec.
\param s The T.38 context.
diff --git a/libs/spandsp/src/spandsp/t38_gateway.h b/libs/spandsp/src/spandsp/t38_gateway.h
index 8d7f2e0500..c6f4a876f3 100644
--- a/libs/spandsp/src/spandsp/t38_gateway.h
+++ b/libs/spandsp/src/spandsp/t38_gateway.h
@@ -102,7 +102,7 @@ SPAN_DECLARE(int) t38_gateway_free(t38_gateway_state_t *s);
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len);
/*! Apply fake processing when a block of audio samples is missing (e.g due
to packet loss).
@@ -112,7 +112,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i
\return The number of samples unprocessed. This should only be non-zero if
the software has reached the end of the FAX call.
*/
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len);
+SPAN_DECLARE(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len);
/*! Generate a block of FAX audio samples.
\brief Generate a block of FAX audio samples.
@@ -121,7 +121,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len);
\param max_len The number of samples to be generated.
\return The number of samples actually generated.
*/
-SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len);
+SPAN_DECLARE(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len);
/*! Control whether error correcting mode (ECM) is allowed.
\brief Control whether error correcting mode (ECM) is allowed.
diff --git a/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h b/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h
index 3ca28c3d12..a841177d60 100644
--- a/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h
+++ b/libs/spandsp/src/spandsp/t38_non_ecm_buffer.h
@@ -124,7 +124,7 @@ SPAN_DECLARE(void) t38_non_ecm_buffer_report_output_status(t38_non_ecm_buffer_st
/*! \brief Get the next bit of data from a T.38 rate adapting non-ECM buffer context.
\param user_data The buffer context, cast to a void pointer.
\return The next bit, or one of the values indicating a change of modem status. */
-SPAN_DECLARE_NONSTD(int) t38_non_ecm_buffer_get_bit(void *user_data);
+SPAN_DECLARE(int) t38_non_ecm_buffer_get_bit(void *user_data);
#if defined(__cplusplus)
}
diff --git a/libs/spandsp/src/spandsp/telephony.h b/libs/spandsp/src/spandsp/telephony.h
index 58a8e29c6a..0d0f306fe1 100644
--- a/libs/spandsp/src/spandsp/telephony.h
+++ b/libs/spandsp/src/spandsp/telephony.h
@@ -28,21 +28,17 @@
#if defined(_M_IX86) || defined(_M_X64)
#if defined(LIBSPANDSP_EXPORTS)
-#define SPAN_DECLARE(type) __declspec(dllexport) type __stdcall
-#define SPAN_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl
+#define SPAN_DECLARE(type) __declspec(dllexport) type
#define SPAN_DECLARE_DATA __declspec(dllexport)
#else
-#define SPAN_DECLARE(type) __declspec(dllimport) type __stdcall
-#define SPAN_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl
+#define SPAN_DECLARE(type) __declspec(dllimport) type
#define SPAN_DECLARE_DATA __declspec(dllimport)
#endif
#elif defined(SPANDSP_USE_EXPORT_CAPABILITY) && (defined(__GNUC__) || defined(__SUNCC__))
#define SPAN_DECLARE(type) __attribute__((visibility("default"))) type
-#define SPAN_DECLARE_NONSTD(type) __attribute__((visibility("default"))) type
#define SPAN_DECLARE_DATA __attribute__((visibility("default")))
#else
#define SPAN_DECLARE(type) /**/ type
-#define SPAN_DECLARE_NONSTD(type) /**/ type
#define SPAN_DECLARE_DATA /**/
#endif
diff --git a/libs/spandsp/src/spandsp/tone_generate.h b/libs/spandsp/src/spandsp/tone_generate.h
index 7fe140c216..a3d1b5a893 100644
--- a/libs/spandsp/src/spandsp/tone_generate.h
+++ b/libs/spandsp/src/spandsp/tone_generate.h
@@ -88,7 +88,7 @@ SPAN_DECLARE(tone_gen_descriptor_t *) tone_gen_descriptor_init(tone_gen_descript
SPAN_DECLARE(void) tone_gen_descriptor_free(tone_gen_descriptor_t *s);
-SPAN_DECLARE_NONSTD(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples);
+SPAN_DECLARE(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples);
SPAN_DECLARE(tone_gen_state_t *) tone_gen_init(tone_gen_state_t *s, tone_gen_descriptor_t *t);
diff --git a/libs/spandsp/src/spandsp/v17rx.h b/libs/spandsp/src/spandsp/v17rx.h
index 8aebe85263..8f6c34993d 100644
--- a/libs/spandsp/src/spandsp/v17rx.h
+++ b/libs/spandsp/src/spandsp/v17rx.h
@@ -284,7 +284,7 @@ SPAN_DECLARE(void) v17_rx_set_modem_status_handler(v17_rx_state_t *s, modem_stat
\param len The number of samples in the buffer.
\return The number of samples unprocessed.
*/
-SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len);
/*! Fake processing of a missing block of received V.17 modem audio samples.
(e.g due to packet loss).
@@ -293,7 +293,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
\param len The number of samples to fake.
\return The number of samples unprocessed.
*/
-SPAN_DECLARE_NONSTD(int) v17_rx_fillin(v17_rx_state_t *s, int len);
+SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len);
/*! Get a snapshot of the current equalizer coefficients.
\brief Get a snapshot of the current equalizer coefficients.
diff --git a/libs/spandsp/src/spandsp/v17tx.h b/libs/spandsp/src/spandsp/v17tx.h
index 02fb7309ad..79d65629fc 100644
--- a/libs/spandsp/src/spandsp/v17tx.h
+++ b/libs/spandsp/src/spandsp/v17tx.h
@@ -155,7 +155,7 @@ SPAN_DECLARE(void) v17_tx_set_modem_status_handler(v17_tx_state_t *s, modem_stat
\param len The number of samples to be generated.
\return The number of samples actually generated.
*/
-SPAN_DECLARE_NONSTD(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len);
#if defined(__cplusplus)
}
diff --git a/libs/spandsp/src/spandsp/v18.h b/libs/spandsp/src/spandsp/v18.h
index 04c0db7c15..50aa5ab260 100644
--- a/libs/spandsp/src/spandsp/v18.h
+++ b/libs/spandsp/src/spandsp/v18.h
@@ -143,7 +143,7 @@ SPAN_DECLARE(int) v18_free(v18_state_t *s);
\param max_len The number of samples to be generated.
\return The number of samples actually generated.
*/
-SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t amp[], int max_len);
+SPAN_DECLARE(int) v18_tx(v18_state_t *s, int16_t amp[], int max_len);
/*! Process a block of received V.18 audio samples.
\brief Process a block of received V.18 audio samples.
@@ -152,7 +152,7 @@ SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t amp[], int max_len);
\param len The number of samples in the buffer.
\return The number of unprocessed samples.
*/
-SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v18_rx(v18_state_t *s, const int16_t amp[], int len);
/*! Fake processing of a missing block of received V.18 audio samples.
(e.g due to packet loss).
@@ -161,7 +161,7 @@ SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len);
\param len The number of samples to fake.
\return The number of unprocessed samples.
*/
-SPAN_DECLARE_NONSTD(int) v18_rx_fillin(v18_state_t *s, int len);
+SPAN_DECLARE(int) v18_rx_fillin(v18_state_t *s, int len);
/*! \brief Put a string to a V.18 context's input buffer.
\param s The V.18 context.
diff --git a/libs/spandsp/src/spandsp/v22bis.h b/libs/spandsp/src/spandsp/v22bis.h
index 50b2fb4467..fd93373cec 100644
--- a/libs/spandsp/src/spandsp/v22bis.h
+++ b/libs/spandsp/src/spandsp/v22bis.h
@@ -78,7 +78,7 @@ extern "C"
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len);
/*! Fake processing of a missing block of received V.22bis modem audio samples.
(e.g due to packet loss).
@@ -86,7 +86,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
\param s The modem context.
\param len The number of samples to fake.
\return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) v22bis_rx_fillin(v22bis_state_t *s, int len);
+SPAN_DECLARE(int) v22bis_rx_fillin(v22bis_state_t *s, int len);
/*! Get a snapshot of the current equalizer coefficients.
\brief Get a snapshot of the current equalizer coefficients.
@@ -130,7 +130,7 @@ SPAN_DECLARE(void) v22bis_rx_set_qam_report_handler(v22bis_state_t *s, qam_repor
\param amp The audio sample buffer.
\param len The number of samples to be generated.
\return The number of samples actually generated. */
-SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len);
/*! Adjust a V.22bis modem transmit context's power output.
\brief Adjust a V.22bis modem transmit context's output power.
diff --git a/libs/spandsp/src/spandsp/v27ter_rx.h b/libs/spandsp/src/spandsp/v27ter_rx.h
index 80fdb3655f..cf8eaa99f7 100644
--- a/libs/spandsp/src/spandsp/v27ter_rx.h
+++ b/libs/spandsp/src/spandsp/v27ter_rx.h
@@ -117,7 +117,7 @@ SPAN_DECLARE(void) v27ter_rx_set_modem_status_handler(v27ter_rx_state_t *s, mode
\param len The number of samples in the buffer.
\return The number of samples unprocessed.
*/
-SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len);
/*! Fake processing of a missing block of received V.27ter modem audio samples.
(e.g due to packet loss).
@@ -126,7 +126,7 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
\param len The number of samples to fake.
\return The number of samples unprocessed.
*/
-SPAN_DECLARE_NONSTD(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len);
+SPAN_DECLARE(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len);
/*! Get a snapshot of the current equalizer coefficients.
\brief Get a snapshot of the current equalizer coefficients.
diff --git a/libs/spandsp/src/spandsp/v27ter_tx.h b/libs/spandsp/src/spandsp/v27ter_tx.h
index fba064fea0..96a0df5f54 100644
--- a/libs/spandsp/src/spandsp/v27ter_tx.h
+++ b/libs/spandsp/src/spandsp/v27ter_tx.h
@@ -136,7 +136,7 @@ SPAN_DECLARE(void) v27ter_tx_set_modem_status_handler(v27ter_tx_state_t *s, mode
\param len The number of samples to be generated.
\return The number of samples actually generated.
*/
-SPAN_DECLARE_NONSTD(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len);
#if defined(__cplusplus)
}
diff --git a/libs/spandsp/src/spandsp/v29rx.h b/libs/spandsp/src/spandsp/v29rx.h
index 378d4fe955..9ef548e4c7 100644
--- a/libs/spandsp/src/spandsp/v29rx.h
+++ b/libs/spandsp/src/spandsp/v29rx.h
@@ -196,7 +196,7 @@ SPAN_DECLARE(void) v29_rx_set_modem_status_handler(v29_rx_state_t *s, modem_stat
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
\return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len);
+SPAN_DECLARE(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len);
/*! Fake processing of a missing block of received V.29 modem audio samples.
(e.g due to packet loss).
@@ -204,7 +204,7 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
\param s The modem context.
\param len The number of samples to fake.
\return The number of samples unprocessed. */
-SPAN_DECLARE_NONSTD(int) v29_rx_fillin(v29_rx_state_t *s, int len);
+SPAN_DECLARE(int) v29_rx_fillin(v29_rx_state_t *s, int len);
/*! Get a snapshot of the current equalizer coefficients.
\brief Get a snapshot of the current equalizer coefficients.
diff --git a/libs/spandsp/src/spandsp/v29tx.h b/libs/spandsp/src/spandsp/v29tx.h
index 18bcf66b6a..6bdb5de9e7 100644
--- a/libs/spandsp/src/spandsp/v29tx.h
+++ b/libs/spandsp/src/spandsp/v29tx.h
@@ -167,7 +167,7 @@ SPAN_DECLARE(void) v29_tx_set_modem_status_handler(v29_tx_state_t *s, modem_stat
\param len The number of samples to be generated.
\return The number of samples actually generated.
*/
-SPAN_DECLARE_NONSTD(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len);
+SPAN_DECLARE(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len);
#if defined(__cplusplus)
}
diff --git a/libs/spandsp/src/spandsp/v42.h b/libs/spandsp/src/spandsp/v42.h
index 8002d43eed..fa1d7c1b5f 100644
--- a/libs/spandsp/src/spandsp/v42.h
+++ b/libs/spandsp/src/spandsp/v42.h
@@ -45,7 +45,7 @@ extern "C"
SPAN_DECLARE(const char *) lapm_status_to_str(int status);
-SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok);
+SPAN_DECLARE(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok);
SPAN_DECLARE(void) v42_start(v42_state_t *s);
diff --git a/libs/spandsp/src/spandsp/v8.h b/libs/spandsp/src/spandsp/v8.h
index 9ded271aec..ab3d1466c5 100644
--- a/libs/spandsp/src/spandsp/v8.h
+++ b/libs/spandsp/src/spandsp/v8.h
@@ -173,7 +173,7 @@ SPAN_DECLARE(logging_state_t *) v8_get_logging_state(v8_state_t *s);
\param max_len The number of samples to be generated.
\return The number of samples actually generated.
*/
-SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len);
+SPAN_DECLARE(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len);
/*! Process a block of received V.8 audio samples.
\brief Process a block of received V.8 audio samples.
@@ -181,7 +181,7 @@ SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len);
\param amp The audio sample buffer.
\param len The number of samples in the buffer.
*/
-SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len);
+SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len);
/*! Log the list of supported modulations.
\brief Log the list of supported modulations.
diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c
index 3a31893e30..f13d4eb879 100644
--- a/libs/spandsp/src/t30.c
+++ b/libs/spandsp/src/t30.c
@@ -6401,7 +6401,7 @@ static void t30_non_ecm_rx_status(void *user_data, int status)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(void) t30_non_ecm_put_bit(void *user_data, int bit)
+SPAN_DECLARE(void) t30_non_ecm_put_bit(void *user_data, int bit)
{
t30_state_t *s;
int res;
@@ -6499,7 +6499,7 @@ SPAN_DECLARE(void) t30_non_ecm_put(void *user_data, const uint8_t buf[], int len
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t30_non_ecm_get_bit(void *user_data)
+SPAN_DECLARE(int) t30_non_ecm_get_bit(void *user_data)
{
int bit;
t30_state_t *s;
@@ -6705,7 +6705,7 @@ static void t30_hdlc_rx_status(void *user_data, int status)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(void) t30_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
+SPAN_DECLARE(void) t30_hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
{
t30_state_t *s;
diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c
index e63eb229e8..91e1e8063c 100644
--- a/libs/spandsp/src/t31.c
+++ b/libs/spandsp/src/t31.c
@@ -2772,7 +2772,7 @@ static int initial_timed_rx(void *user_data, const int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) t31_rx(t31_state_t *s, int16_t amp[], int len)
{
int i;
int32_t power;
@@ -2822,7 +2822,7 @@ SPAN_DECLARE_NONSTD(int) t31_rx(t31_state_t *s, int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len)
+SPAN_DECLARE(int) t31_rx_fillin(t31_state_t *s, int len)
{
/* To mitigate the effect of lost packets on a packet network we should
try to sustain the status quo. If there is no receive modem running, keep
@@ -2848,7 +2848,7 @@ SPAN_DECLARE_NONSTD(int) t31_rx_fillin(t31_state_t *s, int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len)
+SPAN_DECLARE(int) t31_tx(t31_state_t *s, int16_t amp[], int max_len)
{
int len;
diff --git a/libs/spandsp/src/t38_core.c b/libs/spandsp/src/t38_core.c
index de13af3e11..347549549f 100644
--- a/libs/spandsp/src/t38_core.c
+++ b/libs/spandsp/src/t38_core.c
@@ -347,7 +347,7 @@ static __inline__ int classify_seq_no_offset(int expected, int actual)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no)
+SPAN_DECLARE(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t log_seq_no)
{
int i;
int t30_indicator;
@@ -668,7 +668,7 @@ SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_stream(t38_core_state_t *s, const uint8
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no)
+SPAN_DECLARE(int) t38_core_rx_ifp_packet(t38_core_state_t *s, const uint8_t *buf, int len, uint16_t seq_no)
{
int log_seq_no;
int ptr;
diff --git a/libs/spandsp/src/t38_gateway.c b/libs/spandsp/src/t38_gateway.c
index 4467a615ad..53c877e591 100644
--- a/libs/spandsp/src/t38_gateway.c
+++ b/libs/spandsp/src/t38_gateway.c
@@ -2134,7 +2134,7 @@ static void update_rx_timing(t38_gateway_state_t *s, int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len)
{
int i;
@@ -2153,7 +2153,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len)
+SPAN_DECLARE(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len)
{
/* To mitigate the effect of lost packets on a packet network we should
try to sustain the status quo. If there is no receive modem running, keep
@@ -2181,7 +2181,7 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len)
+SPAN_DECLARE(int) t38_gateway_tx(t38_gateway_state_t *s, int16_t amp[], int max_len)
{
int len;
#if defined(LOG_FAX_AUDIO)
diff --git a/libs/spandsp/src/t38_non_ecm_buffer.c b/libs/spandsp/src/t38_non_ecm_buffer.c
index b5b2c8244b..99fa456a96 100644
--- a/libs/spandsp/src/t38_non_ecm_buffer.c
+++ b/libs/spandsp/src/t38_non_ecm_buffer.c
@@ -85,7 +85,7 @@ static void restart_buffer(t38_non_ecm_buffer_state_t *s)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) t38_non_ecm_buffer_get_bit(void *user_data)
+SPAN_DECLARE(int) t38_non_ecm_buffer_get_bit(void *user_data)
{
t38_non_ecm_buffer_state_t *s;
int bit;
diff --git a/libs/spandsp/src/tone_generate.c b/libs/spandsp/src/tone_generate.c
index be3f6854a4..c01c970674 100644
--- a/libs/spandsp/src/tone_generate.c
+++ b/libs/spandsp/src/tone_generate.c
@@ -119,7 +119,7 @@ SPAN_DECLARE(void) tone_gen_descriptor_free(tone_gen_descriptor_t *s)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples)
+SPAN_DECLARE(int) tone_gen(tone_gen_state_t *s, int16_t amp[], int max_samples)
{
int samples;
int limit;
diff --git a/libs/spandsp/src/v17rx.c b/libs/spandsp/src/v17rx.c
index aea4e5913d..cda544990e 100644
--- a/libs/spandsp/src/v17rx.c
+++ b/libs/spandsp/src/v17rx.c
@@ -1229,7 +1229,7 @@ static __inline__ int signal_detect(v17_rx_state_t *s, int16_t amp)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
{
int i;
int step;
@@ -1341,7 +1341,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v17_rx_fillin(v17_rx_state_t *s, int len)
+SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len)
{
int i;
diff --git a/libs/spandsp/src/v17tx.c b/libs/spandsp/src/v17tx.c
index 4d3d8f9990..a57bc9f705 100644
--- a/libs/spandsp/src/v17tx.c
+++ b/libs/spandsp/src/v17tx.c
@@ -296,7 +296,7 @@ static __inline__ complexf_t getbaud(v17_tx_state_t *s)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) v17_tx(v17_tx_state_t *s, int16_t amp[], int len)
{
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t v;
diff --git a/libs/spandsp/src/v18.c b/libs/spandsp/src/v18.c
index 3b72b296e1..0f34415720 100644
--- a/libs/spandsp/src/v18.c
+++ b/libs/spandsp/src/v18.c
@@ -978,7 +978,7 @@ static void v18_textphone_put_async_byte(void *user_data, int byte)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len)
+SPAN_DECLARE(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len)
{
int len;
int lenx;
@@ -1006,7 +1006,7 @@ SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v18_rx(v18_state_t *s, const int16_t amp[], int len)
{
if (s->rx_suppression > 0)
{
@@ -1037,7 +1037,7 @@ SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v18_rx_fillin(v18_state_t *s, int len)
+SPAN_DECLARE(int) v18_rx_fillin(v18_state_t *s, int len)
{
if (s->rx_suppression > 0)
{
diff --git a/libs/spandsp/src/v22bis_rx.c b/libs/spandsp/src/v22bis_rx.c
index af922882a6..cfb4e1378a 100644
--- a/libs/spandsp/src/v22bis_rx.c
+++ b/libs/spandsp/src/v22bis_rx.c
@@ -776,7 +776,7 @@ static __inline__ void process_half_baud(v22bis_state_t *s, const complexf_t *sa
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
{
int i;
int step;
@@ -919,7 +919,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v22bis_rx_fillin(v22bis_state_t *s, int len)
+SPAN_DECLARE(int) v22bis_rx_fillin(v22bis_state_t *s, int len)
{
int i;
diff --git a/libs/spandsp/src/v22bis_tx.c b/libs/spandsp/src/v22bis_tx.c
index 430ebc5d84..41afff55c7 100644
--- a/libs/spandsp/src/v22bis_tx.c
+++ b/libs/spandsp/src/v22bis_tx.c
@@ -469,7 +469,7 @@ static complexf_t getbaud(v22bis_state_t *s)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
{
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t v;
diff --git a/libs/spandsp/src/v27ter_rx.c b/libs/spandsp/src/v27ter_rx.c
index 93d3b4680d..9383d46af0 100644
--- a/libs/spandsp/src/v27ter_rx.c
+++ b/libs/spandsp/src/v27ter_rx.c
@@ -828,7 +828,7 @@ static __inline__ int signal_detect(v27ter_rx_state_t *s, int16_t amp)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
{
int i;
int step;
@@ -978,7 +978,7 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len)
+SPAN_DECLARE(int) v27ter_rx_fillin(v27ter_rx_state_t *s, int len)
{
int i;
diff --git a/libs/spandsp/src/v27ter_tx.c b/libs/spandsp/src/v27ter_tx.c
index f6b69917bb..e0f2aaf1af 100644
--- a/libs/spandsp/src/v27ter_tx.c
+++ b/libs/spandsp/src/v27ter_tx.c
@@ -241,7 +241,7 @@ static complexf_t getbaud(v27ter_tx_state_t *s)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) v27ter_tx(v27ter_tx_state_t *s, int16_t amp[], int len)
{
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t v;
diff --git a/libs/spandsp/src/v29rx.c b/libs/spandsp/src/v29rx.c
index da1ef0c909..4bed319246 100644
--- a/libs/spandsp/src/v29rx.c
+++ b/libs/spandsp/src/v29rx.c
@@ -910,7 +910,7 @@ static __inline__ int signal_detect(v29_rx_state_t *s, int16_t amp)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
+SPAN_DECLARE(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
{
int i;
int step;
@@ -1026,7 +1026,7 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v29_rx_fillin(v29_rx_state_t *s, int len)
+SPAN_DECLARE(int) v29_rx_fillin(v29_rx_state_t *s, int len)
{
int i;
diff --git a/libs/spandsp/src/v29tx.c b/libs/spandsp/src/v29tx.c
index c36027701d..bef54364e8 100644
--- a/libs/spandsp/src/v29tx.c
+++ b/libs/spandsp/src/v29tx.c
@@ -212,7 +212,7 @@ static __inline__ complexf_t getbaud(v29_tx_state_t *s)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len)
+SPAN_DECLARE(int) v29_tx(v29_tx_state_t *s, int16_t amp[], int len)
{
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t v;
diff --git a/libs/spandsp/src/v42.c b/libs/spandsp/src/v42.c
index 44e6bd01d9..4dac118f65 100644
--- a/libs/spandsp/src/v42.c
+++ b/libs/spandsp/src/v42.c
@@ -1065,7 +1065,7 @@ static void lapm_hdlc_underflow(void *user_data)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok)
+SPAN_DECLARE(void) lapm_receive(void *user_data, const uint8_t *frame, int len, int ok)
{
lapm_state_t *s;
v42_state_t *ss;
diff --git a/libs/spandsp/src/v8.c b/libs/spandsp/src/v8.c
index 40cc6feac1..4c5dd43244 100644
--- a/libs/spandsp/src/v8.c
+++ b/libs/spandsp/src/v8.c
@@ -734,7 +734,7 @@ static void send_cm_jm(v8_state_t *s)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
+SPAN_DECLARE(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len)
{
int len;
@@ -852,7 +852,7 @@ static void handle_modem_connect_tone(v8_state_t *s, int tone)
}
/*- End of function --------------------------------------------------------*/
-SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
+SPAN_DECLARE(int) v8_rx(v8_state_t *s, const int16_t *amp, int len)
{
int residual_samples;
int tone;
diff --git a/libs/spandsp/tests/Makefile.am b/libs/spandsp/tests/Makefile.am
index 47ee06aec3..55d84e4d99 100644
--- a/libs/spandsp/tests/Makefile.am
+++ b/libs/spandsp/tests/Makefile.am
@@ -225,7 +225,7 @@ echo_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspand
fax_decode_SOURCES = fax_decode.c
fax_decode_LDADD = $(LIBDIR) -lspandsp
-fax_tests_SOURCES = fax_tests.c fax_utils.c media_monitor.cpp
+fax_tests_SOURCES = fax_tests.c fax_utils.c media_monitor.cpp fax_tester.c
fax_tests_LDADD = -L$(top_builddir)/spandsp-sim -lspandsp-sim $(LIBDIR) -lspandsp
fsk_tests_SOURCES = fsk_tests.c
diff --git a/libs/spandsp/tests/fax_tester.c b/libs/spandsp/tests/fax_tester.c
index fb5dcc1ac1..8885957972 100644
--- a/libs/spandsp/tests/fax_tester.c
+++ b/libs/spandsp/tests/fax_tester.c
@@ -85,7 +85,7 @@ struct xml_node_parms_s
xmlChar *compression;
};
-static struct
+struct
{
const char *tag;
int code;
@@ -162,16 +162,278 @@ static void timer_update(faxtester_state_t *s, int len)
if (s->timer > s->timeout)
{
s->timeout = 0x7FFFFFFFFFFFFFFFLL;
- if (s->front_end_step_timeout_handler)
- s->front_end_step_timeout_handler(s, s->front_end_step_timeout_user_data);
+ span_log(&s->logging, SPAN_LOG_FLOW, "FAX tester step timed out\n");
+ printf("Test failed\n");
+ exit(2);
}
}
/*- End of function --------------------------------------------------------*/
static void front_end_step_complete(faxtester_state_t *s)
{
- if (s->front_end_step_complete_handler)
- s->front_end_step_complete_handler(s, s->front_end_step_complete_user_data);
+ while (faxtester_next_step(s) == 0)
+ ;
+ /*endwhile*/
+}
+/*- End of function --------------------------------------------------------*/
+
+static int faxtester_phase_b_handler(void *user_data, int result)
+{
+ int ch;
+ int status;
+ faxtester_state_t *s;
+ const char *u;
+
+ s = (faxtester_state_t *) user_data;
+ ch = s->far_tag;
+ status = T30_ERR_OK;
+ if ((u = t30_get_rx_ident(s->far_t30)))
+ {
+ printf("%c: Phase B: remote ident '%s'\n", ch, u);
+ if (s->expected_rx_info.ident[0] && strcmp(s->expected_rx_info.ident, u))
+ {
+ printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, s->expected_rx_info.ident);
+ status = T30_ERR_IDENT_UNACCEPTABLE;
+ }
+ }
+ else
+ {
+ if (s->expected_rx_info.ident[0])
+ {
+ printf("%c: Phase B: remote ident missing!\n", ch);
+ status = T30_ERR_IDENT_UNACCEPTABLE;
+ }
+ }
+ if ((u = t30_get_rx_sub_address(s->far_t30)))
+ {
+ printf("%c: Phase B: remote sub-address '%s'\n", ch, u);
+ if (s->expected_rx_info.sub_address[0] && strcmp(s->expected_rx_info.sub_address, u))
+ {
+ printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, s->expected_rx_info.sub_address);
+ status = T30_ERR_SUB_UNACCEPTABLE;
+ }
+ }
+ else
+ {
+ if (s->expected_rx_info.sub_address[0])
+ {
+ printf("%c: Phase B: remote sub-address missing!\n", ch);
+ status = T30_ERR_SUB_UNACCEPTABLE;
+ }
+ }
+ if ((u = t30_get_rx_polled_sub_address(s->far_t30)))
+ {
+ printf("%c: Phase B: remote polled sub-address '%s'\n", ch, u);
+ if (s->expected_rx_info.polled_sub_address[0] && strcmp(s->expected_rx_info.polled_sub_address, u))
+ {
+ printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, s->expected_rx_info.polled_sub_address);
+ status = T30_ERR_PSA_UNACCEPTABLE;
+ }
+ }
+ else
+ {
+ if (s->expected_rx_info.polled_sub_address[0])
+ {
+ printf("%c: Phase B: remote polled sub-address missing!\n", ch);
+ status = T30_ERR_PSA_UNACCEPTABLE;
+ }
+ }
+ if ((u = t30_get_rx_selective_polling_address(s->far_t30)))
+ {
+ printf("%c: Phase B: remote selective polling address '%s'\n", ch, u);
+ if (s->expected_rx_info.selective_polling_address[0] && strcmp(s->expected_rx_info.selective_polling_address, u))
+ {
+ printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, s->expected_rx_info.selective_polling_address);
+ status = T30_ERR_SEP_UNACCEPTABLE;
+ }
+ }
+ else
+ {
+ if (s->expected_rx_info.selective_polling_address[0])
+ {
+ printf("%c: Phase B: remote selective polling address missing!\n", ch);
+ status = T30_ERR_SEP_UNACCEPTABLE;
+ }
+ }
+ if ((u = t30_get_rx_sender_ident(s->far_t30)))
+ {
+ printf("%c: Phase B: remote sender ident '%s'\n", ch, u);
+ if (s->expected_rx_info.sender_ident[0] && strcmp(s->expected_rx_info.sender_ident, u))
+ {
+ printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, s->expected_rx_info.sender_ident);
+ status = T30_ERR_SID_UNACCEPTABLE;
+ }
+ }
+ else
+ {
+ if (s->expected_rx_info.sender_ident[0])
+ {
+ printf("%c: Phase B: remote sender ident missing!\n", ch);
+ status = T30_ERR_SID_UNACCEPTABLE;
+ }
+ }
+ if ((u = t30_get_rx_password(s->far_t30)))
+ {
+ printf("%c: Phase B: remote password '%s'\n", ch, u);
+ if (s->expected_rx_info.password[0] && strcmp(s->expected_rx_info.password, u))
+ {
+ printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, s->expected_rx_info.password);
+ status = T30_ERR_PWD_UNACCEPTABLE;
+ }
+ }
+ else
+ {
+ if (s->expected_rx_info.password[0])
+ {
+ printf("%c: Phase B: remote password missing!\n", ch);
+ status = T30_ERR_PWD_UNACCEPTABLE;
+ }
+ }
+ printf("%c: Phase B handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result));
+ return status;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int faxtester_phase_d_handler(void *user_data, int result)
+{
+ int i;
+ int ch;
+ faxtester_state_t *s;
+ char tag[20];
+
+ s = (faxtester_state_t *) user_data;
+ ch = s->far_tag;
+ i = 0;
+ snprintf(tag, sizeof(tag), "%c: Phase D", ch);
+ printf("%c: Phase D handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result));
+ fax_log_page_transfer_statistics(s->far_t30, tag);
+ fax_log_tx_parameters(s->far_t30, tag);
+ fax_log_rx_parameters(s->far_t30, tag);
+
+ if (s->use_receiver_not_ready)
+ t30_set_receiver_not_ready(s->far_t30, 3);
+
+ if (s->test_local_interrupt)
+ {
+ if (i == 0)
+ {
+ printf("%c: Initiating interrupt request\n", ch);
+ t30_local_interrupt_request(s->far_t30, true);
+ }
+ else
+ {
+ switch (result)
+ {
+ case T30_PIP:
+ case T30_PRI_MPS:
+ case T30_PRI_EOM:
+ case T30_PRI_EOP:
+ printf("%c: Accepting interrupt request\n", ch);
+ t30_local_interrupt_request(s->far_t30, true);
+ break;
+ case T30_PIN:
+ break;
+ }
+ }
+ }
+ return T30_ERR_OK;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void faxtester_phase_e_handler(void *user_data, int result)
+{
+ int ch;
+ faxtester_state_t *s;
+ char tag[20];
+
+ s = (faxtester_state_t *) user_data;
+ ch = s->far_tag;
+ snprintf(tag, sizeof(tag), "%c: Phase E", ch);
+ printf("%c: Phase E handler on channel %c - (%d) %s\n", ch, ch, result, t30_completion_code_to_str(result));
+ fax_log_final_transfer_statistics(s->far_t30, tag);
+ fax_log_tx_parameters(s->far_t30, tag);
+ fax_log_rx_parameters(s->far_t30, tag);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void t30_real_time_frame_handler(void *user_data,
+ bool incoming,
+ const uint8_t *msg,
+ int len)
+{
+ if (msg == NULL)
+ {
+ }
+ else
+ {
+ fprintf(stderr,
+ "T.30: Real time frame handler - %s, %s, length = %d\n",
+ (incoming) ? "line->T.30" : "T.30->line",
+ t30_frametype(msg[2]),
+ len);
+ }
+}
+/*- End of function --------------------------------------------------------*/
+
+static int faxtester_document_handler(void *user_data, int event)
+{
+ int ch;
+ faxtester_state_t *s;
+ t30_state_t *t;
+
+ s = (faxtester_state_t *) user_data;
+ ch = s->far_tag;
+ t = s->far_t30;
+ fprintf(stderr, "%c: Document handler on channel %c - event %d\n", ch, ch, event);
+ if (s->next_tx_file[0])
+ {
+ t30_set_tx_file(t, s->next_tx_file, -1, -1);
+ s->next_tx_file[0] = '\0';
+ return true;
+ }
+ return false;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void faxtester_real_time_frame_handler(faxtester_state_t *s,
+ int direction,
+ const uint8_t *msg,
+ int len)
+{
+ if (msg == NULL)
+ {
+ while (faxtester_next_step(s) == 0)
+ ;
+ /*endwhile*/
+ }
+ else
+ {
+ fprintf(stderr,
+ "TST: Real time frame handler - %s, %s, length = %d\n",
+ (direction) ? "line->tester" : "tester->line",
+ t30_frametype(msg[2]),
+ len);
+ if (direction && msg[1] == s->awaited[1])
+ {
+ if ((s->awaited_len >= 0 && len != abs(s->awaited_len))
+ ||
+ (s->awaited_len < 0 && len < abs(s->awaited_len))
+ ||
+ memcmp(msg, s->awaited, abs(s->awaited_len)) != 0)
+ {
+ span_log_buf(&s->logging, SPAN_LOG_FLOW, "Expected", s->awaited, abs(s->awaited_len));
+ span_log_buf(&s->logging, SPAN_LOG_FLOW, "Received", msg, len);
+ printf("Test failed\n");
+ exit(2);
+ }
+ }
+ if (msg[1] == s->awaited[1])
+ {
+ while (faxtester_next_step(s) == 0)
+ ;
+ /*endwhile*/
+ }
+ }
}
/*- End of function --------------------------------------------------------*/
@@ -295,29 +557,17 @@ static int non_ecm_get_bit(void *user_data)
}
/*- End of function --------------------------------------------------------*/
-void faxtester_set_non_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len)
+static void faxtester_set_ecm_image_buffer(faxtester_state_t *s, int block, int frame_size, int crc_hit)
{
- s->image_ptr = 0;
- s->image_bit_ptr = 8;
- s->image_len = len;
- s->image_buffer = buf;
-}
-/*- End of function --------------------------------------------------------*/
-
-void faxtester_set_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len, int block, int frame_size, int crc_hit)
-{
- int start;
-
- start = 256*frame_size*block;
- if (len > start + 256*frame_size)
- len = start + 256*frame_size;
+ s->image_ptr = 256*frame_size*block;
+ if (s->image_len > s->image_ptr + 256*frame_size)
+ s->image_len = s->image_ptr + 256*frame_size;
s->ecm_frame_size = frame_size;
- s->image_ptr = start;
s->image_bit_ptr = 8;
- s->image_len = len;
- s->image_buffer = buf;
s->corrupt_crc = crc_hit;
+ s->image_buffer = s->image;
+
/* Send the first frame */
hdlc_underflow_handler(s);
}
@@ -343,10 +593,7 @@ static void non_ecm_rx_status(void *user_data, int status)
break;
case SIG_STATUS_CARRIER_DOWN:
if (s->modems.rx_trained)
- {
- if (s->real_time_frame_handler)
- s->real_time_frame_handler(s, s->real_time_frame_user_data, true, NULL, 0);
- }
+ faxtester_real_time_frame_handler(s, true, NULL, 0);
s->modems.rx_signal_present = false;
s->modems.rx_trained = false;
break;
@@ -400,8 +647,7 @@ static void hdlc_accept(void *user_data, const uint8_t *msg, int len, int ok)
return;
}
s = (faxtester_state_t *) user_data;
- if (s->real_time_frame_handler)
- s->real_time_frame_handler(s, s->real_time_frame_user_data, true, msg, len);
+ faxtester_real_time_frame_handler(s, true, msg, len);
}
/*- End of function --------------------------------------------------------*/
@@ -546,7 +792,7 @@ void faxtester_set_tx_type(void *user_data, int type, int bit_rate, int short_tr
break;
case T30_MODEM_CED:
case T30_MODEM_CNG:
- tone = (type == T30_MODEM_CED) ? MODEM_CONNECT_TONES_FAX_CED : MODEM_CONNECT_TONES_FAX_CNG;
+ tone = (type == T30_MODEM_CED) ? FAX_MODEM_CED_TONE_TX : FAX_MODEM_CNG_TONE_TX;
fax_modems_start_slow_modem(t, tone);
s->transmit = true;
break;
@@ -613,34 +859,996 @@ void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep)
}
/*- End of function --------------------------------------------------------*/
-void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t handler, void *user_data)
+static void corrupt_image(faxtester_state_t *s, const char *bad_rows)
{
- s->real_time_frame_handler = handler;
- s->real_time_frame_user_data = user_data;
+ int i;
+ int j;
+ int k;
+ uint32_t bits;
+ uint32_t bitsx;
+ int list[1000];
+ int x;
+ int row;
+ const char *t;
+
+ /* Form the list of rows to be hit */
+ x = 0;
+ t = bad_rows;
+ while (*t)
+ {
+ while (isspace((int) *t))
+ t++;
+ if (sscanf(t, "%d", &list[x]) < 1)
+ break;
+ x++;
+ while (isdigit((int) *t))
+ t++;
+ if (*t == ',')
+ t++;
+ }
+
+ /* Go through the image, and corrupt the first bit of every listed row */
+ bits = 0x7FF;
+ bitsx = 0x7FF;
+ row = 0;
+ for (i = 0; i < s->image_len; i++)
+ {
+ bits ^= (s->image[i] << 11);
+ bitsx ^= (s->image[i] << 11);
+ for (j = 0; j < 8; j++)
+ {
+ if ((bits & 0xFFF) == 0x800)
+ {
+ /* We are at an EOL. Is this row in the list of rows to be corrupted? */
+ row++;
+ for (k = 0; k < x; k++)
+ {
+ if (list[k] == row)
+ {
+ /* Corrupt this row. TSB85 says to hit the first bit after the EOL */
+ bitsx ^= 0x1000;
+ }
+ }
+ }
+ bits >>= 1;
+ bitsx >>= 1;
+ }
+ s->image[i] = (bitsx >> 3) & 0xFF;
+ }
+ span_log(&s->logging, SPAN_LOG_FLOW, "%d rows found. %d corrupted\n", row, x);
}
/*- End of function --------------------------------------------------------*/
-void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data)
+static int string_to_msg(uint8_t msg[], uint8_t mask[], const char buf[])
{
- s->front_end_step_complete_handler = handler;
- s->front_end_step_complete_user_data = user_data;
+ int i;
+ int x;
+ const char *t;
+
+ msg[0] = 0;
+ mask[0] = 0xFF;
+ i = 0;
+ t = (char *) buf;
+ while (*t)
+ {
+ /* Skip white space */
+ while (isspace((int) *t))
+ t++;
+ /* If we find ... we allow arbitrary additional info beyond this point in the message */
+ if (t[0] == '.' && t[1] == '.' && t[2] == '.')
+ {
+ return -i;
+ }
+ else if (isxdigit((int) *t))
+ {
+ for ( ; isxdigit((int) *t); t++)
+ {
+ x = *t;
+ if (x >= 'a')
+ x -= 0x20;
+ if (x >= 'A')
+ x -= ('A' - 10);
+ else
+ x -= '0';
+ msg[i] = (msg[i] << 4) | x;
+ }
+ mask[i] = 0xFF;
+ if (*t == '/')
+ {
+ /* There is a mask following the byte */
+ mask[i] = 0;
+ for (t++; isxdigit((int) *t); t++)
+ {
+ x = *t;
+ if (x >= 'a')
+ x -= 0x20;
+ if (x >= 'A')
+ x -= ('A' - 10);
+ else
+ x -= '0';
+ mask[i] = (mask[i] << 4) | x;
+ }
+ }
+ if (*t && !isspace((int) *t))
+ {
+ /* Bad string */
+ return 0;
+ }
+ i++;
+ }
+ }
+ return i;
}
/*- End of function --------------------------------------------------------*/
-void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data)
+void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t handler, void *user_data)
{
- s->front_end_step_timeout_handler = handler;
- s->front_end_step_timeout_user_data = user_data;
+ s->flush_handler = handler;
+ s->flush_user_data = user_data;
}
/*- End of function --------------------------------------------------------*/
-faxtester_state_t *faxtester_init(faxtester_state_t *s, int calling_party)
+static void fax_prepare(faxtester_state_t *s)
+{
+ if (s->far_fax)
+ {
+ fax_set_transmit_on_idle(s->far_fax, true);
+ fax_set_tep_mode(s->far_fax, true);
+ }
+#if 0
+ t30_set_tx_ident(s->far_t30, "1234567890");
+ t30_set_tx_sub_address(s->far_t30, "Sub-address");
+ t30_set_tx_sender_ident(s->far_t30, "Sender ID");
+ t30_set_tx_password(s->far_t30, "Password");
+ t30_set_tx_polled_sub_address(s->far_t30, "Polled sub-address");
+ t30_set_tx_selective_polling_address(s->far_t30, "Sel polling address");
+#endif
+ t30_set_tx_nsf(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSF\x00", 16);
+ //t30_set_tx_nss(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSS\x00", 16);
+ t30_set_tx_nsc(s->far_t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSC\x00", 16);
+ t30_set_ecm_capability(s->far_t30, true);
+ t30_set_supported_t30_features(s->far_t30,
+ T30_SUPPORT_IDENTIFICATION
+ | T30_SUPPORT_SELECTIVE_POLLING
+ | T30_SUPPORT_SUB_ADDRESSING);
+ t30_set_supported_image_sizes(s->far_t30,
+ T4_SUPPORT_WIDTH_215MM
+ | T4_SUPPORT_WIDTH_255MM
+ | T4_SUPPORT_WIDTH_303MM
+ | T4_SUPPORT_LENGTH_US_LETTER
+ | T4_SUPPORT_LENGTH_US_LEGAL
+ | T4_SUPPORT_LENGTH_UNLIMITED);
+ t30_set_supported_bilevel_resolutions(s->far_t30,
+ T4_RESOLUTION_R8_STANDARD
+ | T4_RESOLUTION_R8_FINE
+ | T4_RESOLUTION_R8_SUPERFINE
+ | T4_RESOLUTION_R16_SUPERFINE
+ | T4_RESOLUTION_100_100
+ | T4_RESOLUTION_200_100
+ | T4_RESOLUTION_200_200
+ | T4_RESOLUTION_200_400
+ | T4_RESOLUTION_300_300
+ | T4_RESOLUTION_300_600
+ | T4_RESOLUTION_400_400
+ | T4_RESOLUTION_400_800
+ | T4_RESOLUTION_600_600
+ | T4_RESOLUTION_600_1200
+ | T4_RESOLUTION_1200_1200);
+ t30_set_supported_colour_resolutions(s->far_t30, 0);
+ t30_set_supported_modems(s->far_t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
+ t30_set_supported_compressions(s->far_t30, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6);
+ t30_set_phase_b_handler(s->far_t30, faxtester_phase_b_handler, (void *) s);
+ t30_set_phase_d_handler(s->far_t30, faxtester_phase_d_handler, (void *) s);
+ t30_set_phase_e_handler(s->far_t30, faxtester_phase_e_handler, (void *) s);
+ t30_set_real_time_frame_handler(s->far_t30, t30_real_time_frame_handler, (void *) s);
+ t30_set_document_handler(s->far_t30, faxtester_document_handler, (void *) s);
+}
+/*- End of function --------------------------------------------------------*/
+
+static void get_node_parms(struct xml_node_parms_s *parms, xmlNodePtr node)
+{
+ parms->dir = xmlGetProp(node, (const xmlChar *) "dir");
+ parms->type = xmlGetProp(node, (const xmlChar *) "type");
+ parms->modem = xmlGetProp(node, (const xmlChar *) "modem");
+ parms->value = xmlGetProp(node, (const xmlChar *) "value");
+ parms->tag = xmlGetProp(node, (const xmlChar *) "tag");
+ parms->bad_rows = xmlGetProp(node, (const xmlChar *) "bad_rows");
+ parms->crc_error = xmlGetProp(node, (const xmlChar *) "crc_error");
+ parms->pattern = xmlGetProp(node, (const xmlChar *) "pattern");
+ parms->timein = xmlGetProp(node, (const xmlChar *) "timein");
+ parms->timeout = xmlGetProp(node, (const xmlChar *) "timeout");
+ parms->min_bits = xmlGetProp(node, (const xmlChar *) "min_bits");
+ parms->frame_size = xmlGetProp(node, (const xmlChar *) "frame_size");
+ parms->block = xmlGetProp(node, (const xmlChar *) "block");
+ parms->compression = xmlGetProp(node, (const xmlChar *) "compression");
+}
+/*- End of function --------------------------------------------------------*/
+
+static void free_node_parms(struct xml_node_parms_s *parms)
+{
+ if (parms->dir)
+ xmlFree(parms->dir);
+ if (parms->type)
+ xmlFree(parms->type);
+ if (parms->modem)
+ xmlFree(parms->modem);
+ if (parms->value)
+ xmlFree(parms->value);
+ if (parms->tag)
+ xmlFree(parms->tag);
+ if (parms->bad_rows)
+ xmlFree(parms->bad_rows);
+ if (parms->crc_error)
+ xmlFree(parms->crc_error);
+ if (parms->pattern)
+ xmlFree(parms->pattern);
+ if (parms->timein)
+ xmlFree(parms->timein);
+ if (parms->timeout)
+ xmlFree(parms->timeout);
+ if (parms->min_bits)
+ xmlFree(parms->min_bits);
+ if (parms->frame_size)
+ xmlFree(parms->frame_size);
+ if (parms->block)
+ xmlFree(parms->block);
+ if (parms->compression)
+ xmlFree(parms->compression);
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(int) faxtester_next_step(faxtester_state_t *s)
+{
+ int delay;
+ int flags;
+ struct xml_node_parms_s parms;
+ uint8_t buf[1000];
+ uint8_t mask[1000];
+ char path[1024];
+ int i;
+ int j;
+ int hdlc;
+ int short_train;
+ int min_row_bits;
+ int ecm_frame_size;
+ int ecm_block;
+ int compression_type;
+ xmlChar *min;
+ xmlChar *max;
+ t4_tx_state_t t4_tx_state;
+ t30_stats_t t30_stats;
+
+ s->test_for_call_clear = false;
+ if (s->cur == NULL)
+ {
+ if (!s->final_delayed)
+ {
+ /* Add a bit of waiting at the end, to ensure everything gets flushed through,
+ any timers can expire, etc. */
+ faxtester_set_timeout(s, -1);
+ faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+ faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, 120000, false);
+ s->final_delayed = true;
+ return 1;
+ }
+ /* Finished */
+ printf("Test passed\n");
+ exit(0);
+ }
+ for (;;)
+ {
+ if (s->cur == NULL)
+ {
+ if (s->repeat_parent == NULL)
+ {
+ /* Finished */
+ printf("Test passed\n");
+ exit(0);
+ }
+ if (++s->repeat_count > s->repeat_max)
+ {
+ /* Finished */
+ printf("Too many repeats\n");
+ printf("Test failed\n");
+ exit(0);
+ }
+ if (s->repeat_count < s->repeat_min)
+ {
+ s->cur = s->repeat_start;
+ }
+ else
+ {
+ s->cur = s->repeat_parent->next;
+ s->repeat_parent = NULL;
+ }
+ }
+ if (xmlStrcmp(s->cur->name, (const xmlChar *) "step") == 0)
+ {
+ break;
+ }
+ if (s->repeat_parent == NULL && xmlStrcmp(s->cur->name, (const xmlChar *) "repeat") == 0)
+ {
+ min = xmlGetProp(s->cur, (const xmlChar *) "min");
+ max = xmlGetProp(s->cur, (const xmlChar *) "max");
+ s->repeat_min = min ? atoi((const char *) min) : 0;
+ s->repeat_max = max ? atoi((const char *) max) : INT_MAX;
+ s->repeat_count = 0;
+ if (min)
+ xmlFree(min);
+ if (max)
+ xmlFree(max);
+ if (s->repeat_min > 0)
+ {
+ s->repeat_parent = s->cur;
+ s->repeat_start =
+ s->cur = s->cur->xmlChildrenNode;
+ continue;
+ }
+ }
+ s->cur = s->cur->next;
+ }
+
+ get_node_parms(&parms, s->cur);
+
+ s->cur = s->cur->next;
+
+ span_log(&s->logging,
+ SPAN_LOG_FLOW,
+ "Dir - %s, type - %s, modem - %s, value - %s, timein - %s, timeout - %s, tag - %s\n",
+ (parms.dir) ? (const char *) parms.dir : " ",
+ (parms.type) ? (const char *) parms.type : "",
+ (parms.modem) ? (const char *) parms.modem : "",
+ (parms.value) ? (const char *) parms.value : "",
+ (parms.timein) ? (const char *) parms.timein : "",
+ (parms.timeout) ? (const char *) parms.timeout : "",
+ (parms.tag) ? (const char *) parms.tag : "");
+ if (parms.type == NULL)
+ {
+ free_node_parms(&parms);
+ return 1;
+ }
+ s->timein_x = (parms.timein) ? atoi((const char *) parms.timein) : -1;
+ s->timeout_x = (parms.timeout) ? atoi((const char *) parms.timeout) : -1;
+
+ if (parms.dir && strcasecmp((const char *) parms.dir, "R") == 0)
+ {
+ /* Receive always has a timeout applied. */
+ if (s->timeout_x < 0)
+ s->timeout_x = 7000;
+ faxtester_set_timeout(s, s->timeout_x);
+ if (parms.modem)
+ {
+ hdlc = (strcasecmp((const char *) parms.type, "PREAMBLE") == 0);
+ short_train = (strcasecmp((const char *) parms.type, "TCF") != 0);
+ faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
+ if (strcasecmp((const char *) parms.modem, "V.21") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V21, 300, false, true);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.17/14400") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V17, 14400, short_train, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.17/12000") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V17, 12000, short_train, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.17/9600") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V17, 9600, short_train, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.17/7200") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V17, 7200, short_train, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.29/9600") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V29, 9600, false, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.29/7200") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V29, 7200, false, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.27ter/4800") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V27TER, 4800, false, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.27ter/2400") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_V27TER, 2400, false, hdlc);
+ }
+ else
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n");
+ }
+ }
+
+ if (strcasecmp((const char *) parms.type, "SET") == 0)
+ {
+ if (strcasecmp((const char *) parms.tag, "IDENT") == 0)
+ strcpy(s->expected_rx_info.ident, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "SUB") == 0)
+ strcpy(s->expected_rx_info.sub_address, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "SEP") == 0)
+ strcpy(s->expected_rx_info.selective_polling_address, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "PSA") == 0)
+ strcpy(s->expected_rx_info.polled_sub_address, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "SID") == 0)
+ strcpy(s->expected_rx_info.sender_ident, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "PWD") == 0)
+ strcpy(s->expected_rx_info.password, (const char *) parms.value);
+ free_node_parms(&parms);
+ return 0;
+ }
+ else if (strcasecmp((const char *) parms.type, "CNG") == 0)
+ {
+ /* Look for CNG */
+ faxtester_set_rx_type(s, T30_MODEM_CNG, 0, false, false);
+ faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
+ }
+ else if (strcasecmp((const char *) parms.type, "CED") == 0)
+ {
+ /* Look for CED */
+ faxtester_set_rx_type(s, T30_MODEM_CED, 0, false, false);
+ faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
+ }
+ else if (strcasecmp((const char *) parms.type, "HDLC") == 0)
+ {
+ i = string_to_msg(buf, mask, (const char *) parms.value);
+ bit_reverse(s->awaited, buf, abs(i));
+ s->awaited_len = i;
+ }
+ else if (strcasecmp((const char *) parms.type, "TCF") == 0)
+ {
+ }
+ else if (strcasecmp((const char *) parms.type, "MSG") == 0)
+ {
+ }
+ else if (strcasecmp((const char *) parms.type, "PP") == 0)
+ {
+ }
+ else if (strcasecmp((const char *) parms.type, "SILENCE") == 0)
+ {
+ faxtest_set_rx_silence(s);
+ }
+ else if (strcasecmp((const char *) parms.type, "CLEAR") == 0)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Far end should drop the call\n");
+ s->test_for_call_clear = true;
+ s->call_clear_timer = 0;
+ }
+ else
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) parms.type);
+ free_node_parms(&parms);
+ return 0;
+ }
+ }
+ else
+ {
+ faxtester_set_timeout(s, s->timeout_x);
+ if (parms.modem)
+ {
+ hdlc = (strcasecmp((const char *) parms.type, "PREAMBLE") == 0);
+ short_train = (strcasecmp((const char *) parms.type, "TCF") != 0);
+ faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+ if (strcasecmp((const char *) parms.modem, "V.21") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V21, 300, false, true);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.17/14400") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V17, 14400, short_train, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.17/12000") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V17, 12000, short_train, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.17/9600") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V17, 9600, short_train, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.17/7200") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V17, 7200, short_train, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.29/9600") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V29, 9600, false, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.29/7200") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V29, 7200, false, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.27ter/4800") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V27TER, 4800, false, hdlc);
+ }
+ else if (strcasecmp((const char *) parms.modem, "V.27ter/2400") == 0)
+ {
+ faxtester_set_tx_type(s, T30_MODEM_V27TER, 2400, false, hdlc);
+ }
+ else
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n");
+ }
+ }
+
+ if (strcasecmp((const char *) parms.type, "SET") == 0)
+ {
+ if (strcasecmp((const char *) parms.tag, "IDENT") == 0)
+ t30_set_tx_ident(s->far_t30, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "SUB") == 0)
+ t30_set_tx_sub_address(s->far_t30, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "SEP") == 0)
+ t30_set_tx_selective_polling_address(s->far_t30, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "PSA") == 0)
+ t30_set_tx_polled_sub_address(s->far_t30, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "SID") == 0)
+ t30_set_tx_sender_ident(s->far_t30, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "PWD") == 0)
+ t30_set_tx_password(s->far_t30, (const char *) parms.value);
+ else if (strcasecmp((const char *) parms.tag, "RXFILE") == 0)
+ {
+ if (parms.value)
+ t30_set_rx_file(s->far_t30, (const char *) parms.value, -1);
+ else
+ t30_set_rx_file(s->far_t30, output_tiff_file_name, -1);
+ }
+ else if (strcasecmp((const char *) parms.tag, "TXFILE") == 0)
+ {
+ sprintf(s->next_tx_file, "%s/%s", s->image_path, (const char *) parms.value);
+ printf("Push '%s'\n", s->next_tx_file);
+ }
+ free_node_parms(&parms);
+ return 0;
+ }
+ else if (strcasecmp((const char *) parms.type, "CALL") == 0)
+ {
+ if (s->far_fax)
+ fax_restart(s->far_fax, false);
+ else
+ t38_terminal_restart(s->far_t38, false);
+ fax_prepare(s);
+ s->next_tx_file[0] = '\0';
+ t30_set_rx_file(s->far_t30, output_tiff_file_name, -1);
+ /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
+ t30_set_supported_output_compressions(s->far_t30, T4_COMPRESSION_T4_1D);
+ if (parms.value)
+ {
+ sprintf(path, "%s/%s", s->image_path, (const char *) parms.value);
+ t30_set_tx_file(s->far_t30, path, -1, -1);
+ }
+ free_node_parms(&parms);
+ return 0;
+ }
+ else if (strcasecmp((const char *) parms.type, "ANSWER") == 0)
+ {
+ if (s->far_fax)
+ fax_restart(s->far_fax, true);
+ else
+ t38_terminal_restart(s->far_t38, true);
+ fax_prepare(s);
+ s->next_tx_file[0] = '\0';
+ /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
+ t30_set_supported_output_compressions(s->far_t30, T4_COMPRESSION_T4_1D);
+ if (parms.value)
+ {
+ sprintf(path, "%s/%s", s->image_path, (const char *) parms.value);
+ t30_set_tx_file(s->far_t30, path, -1, -1);
+ }
+ free_node_parms(&parms);
+ return 0;
+ }
+ else if (strcasecmp((const char *) parms.type, "CNG") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+ faxtester_set_tx_type(s, T30_MODEM_CNG, 0, false, false);
+ }
+ else if (strcasecmp((const char *) parms.type, "CED") == 0)
+ {
+ faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+ faxtester_set_tx_type(s, T30_MODEM_CED, 0, false, false);
+ }
+ else if (strcasecmp((const char *) parms.type, "WAIT") == 0)
+ {
+ delay = (parms.value) ? atoi((const char *) parms.value) : 1;
+ faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
+ faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, delay, false);
+ }
+ else if (strcasecmp((const char *) parms.type, "PREAMBLE") == 0)
+ {
+ flags = (parms.value) ? atoi((const char *) parms.value) : 37;
+ faxtester_send_hdlc_flags(s, flags);
+ }
+ else if (strcasecmp((const char *) parms.type, "POSTAMBLE") == 0)
+ {
+ flags = (parms.value) ? atoi((const char *) parms.value) : 5;
+ faxtester_send_hdlc_flags(s, flags);
+ }
+ else if (strcasecmp((const char *) parms.type, "HDLC") == 0)
+ {
+ i = string_to_msg(buf, mask, (const char *) parms.value);
+ bit_reverse(buf, buf, abs(i));
+ if (parms.crc_error && strcasecmp((const char *) parms.crc_error, "0") == 0)
+ faxtester_send_hdlc_msg(s, buf, abs(i), false);
+ else
+ faxtester_send_hdlc_msg(s, buf, abs(i), true);
+ }
+ else if (strcasecmp((const char *) parms.type, "TCF") == 0)
+ {
+ i = (parms.value) ? atoi((const char *) parms.value) : 450;
+ if (parms.pattern)
+ {
+ /* TODO: implement proper patterns */
+ j = atoi((const char *) parms.pattern);
+ memset(s->image, 0x55, j);
+ if (i > j)
+ memset(s->image + j, 0, i - j);
+ }
+ else
+ {
+ memset(s->image, 0, i);
+ }
+ s->image_ptr = 0;
+ s->image_bit_ptr = 8;
+ s->image_buffer = s->image;
+ s->image_len = i;
+ }
+ else if (strcasecmp((const char *) parms.type, "MSG") == 0)
+ {
+ /* A non-ECM page */
+ min_row_bits = (parms.min_bits) ? atoi((const char *) parms.min_bits) : 0;
+ sprintf(path, "%s/%s", s->image_path, (const char *) parms.value);
+ if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n");
+ printf("Test failed\n");
+ exit(2);
+ }
+ t4_tx_set_header_info(&t4_tx_state, NULL);
+ compression_type = T4_COMPRESSION_T4_1D;
+ if (parms.compression)
+ {
+ if (strcasecmp((const char *) parms.compression, "T.4 1D") == 0)
+ compression_type = T4_COMPRESSION_T4_1D;
+ else if (strcasecmp((const char *) parms.compression, "T.4 2D") == 0)
+ compression_type = T4_COMPRESSION_T4_2D;
+ else if (strcasecmp((const char *) parms.compression, "T.6") == 0)
+ compression_type = T4_COMPRESSION_T6;
+ else if (strcasecmp((const char *) parms.compression, "T.85") == 0)
+ compression_type = T4_COMPRESSION_T85;
+ }
+ if (t4_tx_set_tx_image_format(&t4_tx_state,
+ compression_type,
+ T4_SUPPORT_WIDTH_215MM
+ | T4_SUPPORT_LENGTH_US_LETTER
+ | T4_SUPPORT_LENGTH_US_LEGAL
+ | T4_SUPPORT_LENGTH_UNLIMITED,
+ T4_RESOLUTION_R8_STANDARD
+ | T4_RESOLUTION_R8_FINE
+ | T4_RESOLUTION_R8_SUPERFINE
+ | T4_RESOLUTION_R16_SUPERFINE
+ | T4_RESOLUTION_200_100
+ | T4_RESOLUTION_200_200
+ | T4_RESOLUTION_200_400
+ | T4_RESOLUTION_300_300
+ | T4_RESOLUTION_300_600
+ | T4_RESOLUTION_400_400
+ | T4_RESOLUTION_400_800
+ | T4_RESOLUTION_600_600
+ | T4_RESOLUTION_600_1200
+ | T4_RESOLUTION_1200_1200,
+ T4_RESOLUTION_100_100
+ | T4_RESOLUTION_200_200
+ | T4_RESOLUTION_300_300
+ | T4_RESOLUTION_400_400
+ | T4_RESOLUTION_600_600
+ | T4_RESOLUTION_1200_1200) < 0)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n");
+ printf("Test failed\n");
+ exit(2);
+ }
+ t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits);
+ if (t4_tx_start_page(&t4_tx_state))
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n");
+ printf("Test failed\n");
+ exit(2);
+ }
+ s->image_len = t4_tx_get(&t4_tx_state, s->image, sizeof(s->image));
+ if (parms.bad_rows)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n");
+ corrupt_image(s, (const char *) parms.bad_rows);
+ }
+ t4_tx_release(&t4_tx_state);
+ span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM image is %d bytes (min row bits %d)\n", s->image_len, min_row_bits);
+ s->image_ptr = 0;
+ s->image_bit_ptr = 8;
+ s->image_buffer = s->image;
+ }
+ else if (strcasecmp((const char *) parms.type, "PP") == 0)
+ {
+ min_row_bits = (parms.min_bits) ? atoi((const char *) parms.min_bits) : 0;
+ ecm_block = (parms.block) ? atoi((const char *) parms.block) : 0;
+ ecm_frame_size = (parms.frame_size) ? atoi((const char *) parms.frame_size) : 64;
+ i = (parms.crc_error) ? atoi((const char *) parms.crc_error) : -1;
+ sprintf(path, "%s/%s", s->image_path, (const char *) parms.value);
+ if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n");
+ printf("Test failed\n");
+ exit(2);
+ }
+ t4_tx_set_header_info(&t4_tx_state, NULL);
+ compression_type = T4_COMPRESSION_T4_1D;
+ if (parms.compression)
+ {
+ if (strcasecmp((const char *) parms.compression, "T.4 1D") == 0)
+ compression_type = T4_COMPRESSION_T4_1D;
+ else if (strcasecmp((const char *) parms.compression, "T.4 2D") == 0)
+ compression_type = T4_COMPRESSION_T4_2D;
+ else if (strcasecmp((const char *) parms.compression, "T.6") == 0)
+ compression_type = T4_COMPRESSION_T6;
+ else if (strcasecmp((const char *) parms.compression, "T.85") == 0)
+ compression_type = T4_COMPRESSION_T85;
+ }
+ if (t4_tx_set_tx_image_format(&t4_tx_state,
+ compression_type,
+ T4_SUPPORT_WIDTH_215MM
+ | T4_SUPPORT_LENGTH_US_LETTER
+ | T4_SUPPORT_LENGTH_US_LEGAL
+ | T4_SUPPORT_LENGTH_UNLIMITED,
+ T4_RESOLUTION_R8_STANDARD
+ | T4_RESOLUTION_R8_FINE
+ | T4_RESOLUTION_R8_SUPERFINE
+ | T4_RESOLUTION_R16_SUPERFINE
+ | T4_RESOLUTION_200_100
+ | T4_RESOLUTION_200_200
+ | T4_RESOLUTION_200_400
+ | T4_RESOLUTION_300_300
+ | T4_RESOLUTION_300_600
+ | T4_RESOLUTION_400_400
+ | T4_RESOLUTION_400_800
+ | T4_RESOLUTION_600_600
+ | T4_RESOLUTION_600_1200
+ | T4_RESOLUTION_1200_1200,
+ T4_RESOLUTION_100_100
+ | T4_RESOLUTION_200_200
+ | T4_RESOLUTION_300_300
+ | T4_RESOLUTION_400_400
+ | T4_RESOLUTION_600_600
+ | T4_RESOLUTION_1200_1200) < 0)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n");
+ printf("Test failed\n");
+ exit(2);
+ }
+ t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits);
+ if (t4_tx_start_page(&t4_tx_state))
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n");
+ printf("Test failed\n");
+ exit(2);
+ }
+ /*endif*/
+ s->image_len = t4_tx_get(&t4_tx_state, s->image, sizeof(s->image));
+ if (parms.bad_rows)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n");
+ corrupt_image(s, (const char *) parms.bad_rows);
+ }
+ /*endif*/
+ t4_tx_release(&t4_tx_state);
+ span_log(&s->logging, SPAN_LOG_FLOW, "ECM image is %d bytes (min row bits %d)\n", s->image_len, min_row_bits);
+ faxtester_set_ecm_image_buffer(s, ecm_block, ecm_frame_size, i);
+ }
+ else if (strcasecmp((const char *) parms.type, "CLEAR") == 0)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Time to drop the call\n");
+ t30_terminate(s->far_t30);
+ free_node_parms(&parms);
+ return 0;
+ }
+ else if (strcasecmp((const char *) parms.type, "STATUS") == 0)
+ {
+ if (parms.value)
+ {
+ for (i = 0; t30_status[i].code >= 0; i++)
+ {
+ if (strcmp(t30_status[i].tag, (const char *) parms.value) == 0)
+ break;
+ }
+ if (t30_status[i].code >= 0)
+ delay = t30_status[i].code;
+ else
+ delay = atoi((const char *) parms.value);
+ t30_get_transfer_statistics(s->far_t30, &t30_stats);
+ if (delay == t30_stats.current_status)
+ span_log(&s->logging, SPAN_LOG_FLOW, "Expected status (%s) found\n", t30_status[i].tag);
+ else
+ span_log(&s->logging, SPAN_LOG_FLOW, "Expected status %s, but found %s (%d)\n", t30_status[i].tag, t30_status[t30_stats.current_status].tag, t30_stats.current_status);
+ if (delay != t30_stats.current_status)
+ {
+ printf("Test failed\n");
+ exit(2);
+ }
+ }
+ free_node_parms(&parms);
+ return 0;
+ }
+ else
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) parms.type);
+ free_node_parms(&parms);
+ return 0;
+ }
+ /*endif*/
+ }
+ /*endif*/
+ free_node_parms(&parms);
+ return 1;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int parse_config(faxtester_state_t *s, xmlNodePtr cur)
+{
+ xmlChar *x;
+ xmlChar *y;
+
+ while (cur)
+ {
+ if (xmlStrcmp(cur->name, (const xmlChar *) "path") == 0)
+ {
+ x = NULL;
+ y = NULL;
+ if ((x = xmlGetProp(cur, (const xmlChar *) "type"))
+ &&
+ (y = xmlGetProp(cur, (const xmlChar *) "value")))
+ {
+ if (strcasecmp((const char *) x, "IMAGE") == 0)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s' '%s'\n", (char *) x, (char *) y);
+ strcpy(s->image_path, (const char *) y);
+ }
+ /*endif*/
+ }
+ /*endif*/
+ if (x)
+ xmlFree(x);
+ /*endif*/
+ if (y)
+ xmlFree(y);
+ /*endif*/
+ }
+ /*endif*/
+ cur = cur->next;
+ }
+ /*endwhile*/
+ return -1;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int parse_test_group(faxtester_state_t *s, xmlNodePtr cur, const char *test)
+{
+ xmlChar *x;
+
+ while (cur)
+ {
+ if (xmlStrcmp(cur->name, (const xmlChar *) "test") == 0)
+ {
+ if ((x = xmlGetProp(cur, (const xmlChar *) "name")))
+ {
+ if (xmlStrcmp(x, (const xmlChar *) test) == 0)
+ {
+ span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s'\n", (char *) x);
+ s->cur = cur->xmlChildrenNode;
+ xmlFree(x);
+ return 0;
+ }
+ /*endif*/
+ xmlFree(x);
+ }
+ /*endif*/
+ }
+ /*endif*/
+ cur = cur->next;
+ }
+ /*endwhile*/
+ return -1;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int get_test_set(faxtester_state_t *s, const char *test_file, const char *test)
+{
+ xmlParserCtxtPtr ctxt;
+ xmlNodePtr cur;
+
+ if ((ctxt = xmlNewParserCtxt()) == NULL)
+ {
+ fprintf(stderr, "Failed to allocate XML parser context\n");
+ return -1;
+ }
+ /* parse the file, activating the DTD validation option */
+ if ((s->doc = xmlCtxtReadFile(ctxt, test_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL)
+ {
+ fprintf(stderr, "Failed to read the XML document\n");
+ return -1;
+ }
+ if (ctxt->valid == 0)
+ {
+ fprintf(stderr, "Failed to validate the XML document\n");
+ xmlFreeDoc(s->doc);
+ s->doc = NULL;
+ xmlFreeParserCtxt(ctxt);
+ return -1;
+ }
+ xmlFreeParserCtxt(ctxt);
+
+ /* Check the document is of the right kind */
+ if ((cur = xmlDocGetRootElement(s->doc)) == NULL)
+ {
+ xmlFreeDoc(s->doc);
+ s->doc = NULL;
+ fprintf(stderr, "Empty document\n");
+ return -1;
+ }
+ /*endif*/
+ if (xmlStrcmp(cur->name, (const xmlChar *) "fax-tests"))
+ {
+ xmlFreeDoc(s->doc);
+ s->doc = NULL;
+ fprintf(stderr, "Document of the wrong type, root node != fax-tests\n");
+ return -1;
+ }
+ /*endif*/
+ cur = cur->xmlChildrenNode;
+ while (cur && xmlIsBlankNode(cur))
+ cur = cur->next;
+ /*endwhile*/
+ if (cur == NULL)
+ {
+ fprintf(stderr, "XML test not found\n");
+ return -1;
+ }
+ /*endif*/
+ xmlCleanupParser();
+ while (cur)
+ {
+ if (xmlStrcmp(cur->name, (const xmlChar *) "config") == 0)
+ parse_config(s, cur->xmlChildrenNode);
+ /*endif*/
+ if (xmlStrcmp(cur->name, (const xmlChar *) "test-group") == 0)
+ {
+ if (parse_test_group(s, cur->xmlChildrenNode, test) == 0)
+ return 0;
+ /*endif*/
+ }
+ /*endif*/
+ cur = cur->next;
+ }
+ /*endwhile*/
+ fprintf(stderr, "XML test not found\n");
+ return -1;
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE(logging_state_t *) faxtester_get_logging_state(faxtester_state_t *s)
+{
+ return &s->logging;
+}
+/*- End of function --------------------------------------------------------*/
+
+faxtester_state_t *faxtester_init(faxtester_state_t *s, const char *test_file, const char *test)
{
if (s == NULL)
{
if ((s = (faxtester_state_t *) malloc(sizeof(*s))) == NULL)
return NULL;
}
+ /*endif*/
memset(s, 0, sizeof(*s));
span_log_init(&s->logging, SPAN_LOG_NONE, NULL);
@@ -656,29 +1864,38 @@ faxtester_state_t *faxtester_init(faxtester_state_t *s, int calling_party)
fax_modems_set_tep_mode(&s->modems, false);
fax_modems_set_rx_active(&s->modems, true);
faxtester_set_timeout(s, -1);
+ s->timein_x = -1;
+ s->timeout_x = -1;
faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
-
+ strcpy(s->image_path, ".");
+ s->next_tx_file[0] = '\0';
+ if (get_test_set(s, test_file, test) < 0)
+ {
+ /* TODO: free the state, if it was allocated. */
+ return NULL;
+ }
+ /*endif*/
+ memset(&s->expected_rx_info, 0, sizeof(s->expected_rx_info));
return s;
}
/*- End of function --------------------------------------------------------*/
int faxtester_release(faxtester_state_t *s)
{
+ if (s->doc)
+ {
+ xmlFreeDoc(s->doc);
+ s->doc = NULL;
+ }
return 0;
}
/*- End of function --------------------------------------------------------*/
int faxtester_free(faxtester_state_t *s)
{
+ faxtester_release(s);
free(s);
return 0;
}
/*- End of function --------------------------------------------------------*/
-
-void faxtester_set_flush_handler(faxtester_state_t *s, faxtester_flush_handler_t handler, void *user_data)
-{
- s->flush_handler = handler;
- s->flush_user_data = user_data;
-}
-/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/
diff --git a/libs/spandsp/tests/fax_tester.h b/libs/spandsp/tests/fax_tester.h
index 48308f7329..412c1fc340 100644
--- a/libs/spandsp/tests/fax_tester.h
+++ b/libs/spandsp/tests/fax_tester.h
@@ -39,23 +39,6 @@ typedef struct faxtester_state_s faxtester_state_t;
typedef void (*faxtester_flush_handler_t)(faxtester_state_t *s, void *user_data, int which);
-/*!
- FAX tester real time frame handler.
- \brief FAX tester real time frame handler.
- \param s The FAX tester context.
- \param user_data An opaque pointer.
- \param direction True for incoming, false for outgoing.
- \param msg The HDLC message.
- \param len The length of the message.
-*/
-typedef void (*faxtester_real_time_frame_handler_t)(faxtester_state_t *s,
- void *user_data,
- int direction,
- const uint8_t *msg,
- int len);
-
-typedef void (*faxtester_front_end_step_complete_handler_t)(faxtester_state_t *s, void *user_data);
-
/*!
FAX tester descriptor.
*/
@@ -63,9 +46,19 @@ struct faxtester_state_s
{
/*! \brief The far end FAX context */
fax_state_t *far_fax;
+ t38_terminal_state_t *far_t38;
+
+ int far_tag;
/*! \brief The far end T.38 terminal context */
t38_terminal_state_t *far_t38_fax;
+
+ t30_state_t *far_t30;
+
+ t30_exchanged_info_t expected_rx_info;
+
+ bool use_receiver_not_ready;
+ bool test_local_interrupt;
/*! \brief Path for the FAX image test files. */
char image_path[1024];
@@ -74,27 +67,23 @@ struct faxtester_state_s
xmlDocPtr doc;
/*! \brief Pointer to our current step in the test. */
xmlNodePtr cur;
+
+ int repeat_min;
+ int repeat_max;
+ int repeat_count;
+ xmlNodePtr repeat_start;
+ xmlNodePtr repeat_parent;
faxtester_flush_handler_t flush_handler;
void *flush_user_data;
- /*! \brief A pointer to a callback routine to be called when frames are
- exchanged. */
- faxtester_real_time_frame_handler_t real_time_frame_handler;
- /*! \brief An opaque pointer supplied in real time frame callbacks. */
- void *real_time_frame_user_data;
-
- faxtester_front_end_step_complete_handler_t front_end_step_complete_handler;
- void *front_end_step_complete_user_data;
-
- faxtester_front_end_step_complete_handler_t front_end_step_timeout_handler;
- void *front_end_step_timeout_user_data;
-
const uint8_t *image_buffer;
int image_len;
int image_ptr;
int image_bit_ptr;
+ uint8_t image[1000000];
+
int ecm_frame_size;
int corrupt_crc;
@@ -194,26 +183,24 @@ void faxtester_set_transmit_on_idle(faxtester_state_t *s, int transmit_on_idle);
*/
void faxtester_set_tep_mode(faxtester_state_t *s, int use_tep);
-void faxtester_set_real_time_frame_handler(faxtester_state_t *s, faxtester_real_time_frame_handler_t handler, void *user_data);
-
-void faxtester_set_front_end_step_complete_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data);
-
-void faxtester_set_front_end_step_timeout_handler(faxtester_state_t *s, faxtester_front_end_step_complete_handler_t handler, void *user_data);
-
void faxtester_set_timeout(faxtester_state_t *s, int timeout);
-void faxtester_set_non_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len);
+SPAN_DECLARE(int) faxtester_next_step(faxtester_state_t *s);
-void faxtester_set_ecm_image_buffer(faxtester_state_t *s, const uint8_t *buf, int len, int block, int frame_size, int crc_hit);
-
-/*! Initialise a FAX context.
- \brief Initialise a FAX context.
+/*! Get the logging context associated with a FAX tester context.
+ \brief Get the logging context associated with a FAX tester context.
\param s The FAX tester context.
- \param calling_party true if the context is for a calling party. FALSE if the
- context is for an answering party.
+ \return A pointer to the logging context */
+SPAN_DECLARE(logging_state_t *) faxtester_get_logging_state(faxtester_state_t *s);
+
+/*! Initialise a FAX tester context.
+ \brief Initialise a FAX tester context.
+ \param s The FAX tester context.
+ \param test_file The name of the file of XML test scripts.
+ \param test The name of the XML script test.
\return A pointer to the FAX context, or NULL if there was a problem.
*/
-faxtester_state_t *faxtester_init(faxtester_state_t *s, int calling_party);
+faxtester_state_t *faxtester_init(faxtester_state_t *s, const char *test_file, const char *test);
/*! Release a FAX context.
\brief Release a FAX context.
diff --git a/libs/spandsp/tests/fax_tests.c b/libs/spandsp/tests/fax_tests.c
index f3b34b91a3..57de0da361 100644
--- a/libs/spandsp/tests/fax_tests.c
+++ b/libs/spandsp/tests/fax_tests.c
@@ -99,48 +99,80 @@ The T.31 and TSB85 parts are incomplete right now.
#define INPUT_TIFF_FILE_NAME "../test-data/itu/fax/itutests.tif"
#define OUTPUT_TIFF_FILE_NAME "fax_tests.tif"
+#define INPUT_WAVE_FILE_NAME "fax_cap.wav"
#define OUTPUT_WAVE_FILE_NAME "fax_tests.wav"
enum
{
- AUDIO_FAX,
- T38_TERMINAL_FAX,
- T38_GATEWAY_FAX,
+ AUDIO_FAX = 1,
+ T38_FAX,
T31_AUDIO_FAX,
- T31_T38_TERMINAL_FAX,
- T31_T38_GATEWAY_FAX,
+ T31_T38_FAX,
TSB85_AUDIO_FAX,
- TSB85_T38_TERMINAL_FAX,
- TSB85_T38_GATEWAY_FAX
+ TSB85_T38_FAX,
+ REPLAY_AUDIO_FAX,
+ REPLAY_T38_FAX,
+ AUDIO_TO_T38_GATEWAY,
+ PASSTHROUGH,
+ AUDIO_CHAN,
+ T38_CHAN
};
-int mode[2] = {AUDIO_FAX, AUDIO_FAX};
+const char *output_tiff_file_name;
-t30_state_t *t30_state[2] = {NULL, NULL};
-fax_state_t *fax_state[2] = {NULL, NULL};
-t38_gateway_state_t *t38_gateway_state[2] = {NULL, NULL};
-t38_terminal_state_t *t38_state[2] = {NULL, NULL};
-t38_core_state_t *t38_core_state[2] = {NULL, NULL};
-faxtester_state_t *faxtester[2] = {NULL, NULL};
-g1050_state_t *g1050_path[2] = {NULL, NULL};
-awgn_state_t *awgn_state[2] = {NULL, NULL};
-int16_t audio_buffer[2*2][SAMPLES_PER_CHUNK];
+struct audio_buf_s
+{
+ int16_t amp[SAMPLES_PER_CHUNK];
+ int len;
+};
-int t38_subst_seq[2] = {0, 0};
+struct chain_element_s
+{
+ int node_type;
+ int left_chan_type;
+ int right_chan_type;
+ struct
+ {
+ fax_state_t *fax_state;
+ t38_terminal_state_t *t38_state;
+ faxtester_state_t *faxtester_state;
+ t38_gateway_state_t *t38_gateway_state;
+ SNDFILE *wave_handle;
+ } node;
+ struct
+ {
+ g1050_state_t *g1050_path;
+ both_ways_line_model_state_t *line_model;
+ struct audio_buf_s *audio_in_buf;
+ struct audio_buf_s *audio_out_buf;
+ } path;
+ t30_state_t *t30_state;
+ t38_core_state_t *t38_core_state;
+ int t38_subst_seq;
+ bool phase_e_reached;
+ bool completed;
+ bool succeeded;
+ t30_exchanged_info_t expected_rx_info;
-t30_exchanged_info_t expected_rx_info[2];
+ awgn_state_t *awgn_state;
+ struct audio_buf_s audio_buf[2];
+
+ int peer;
+ int t38_peer;
+
+ char tag[10];
+};
+
+struct chain_element_s chain[7];
+int chain_elements = 2;
+
+bool t38_simulate_incrementing_repeats = false;
bool use_receiver_not_ready = false;
bool test_local_interrupt = false;
double when = 0.0;
-bool phase_e_reached[2] = {false, false};
-bool completed[2] = {false, false};
-bool succeeded[2] = {false, false};
-
-bool t38_simulate_incrementing_repeats = false;
-
static int phase_b_handler(void *user_data, int result)
{
int i;
@@ -151,10 +183,12 @@ static int phase_b_handler(void *user_data, int result)
char tag[20];
const char *u;
const uint8_t *v;
+ t30_exchanged_info_t *info;
i = (int) (intptr_t) user_data;
- s = t30_state[i];
+ s = chain[i].t30_state;
ch = i + 'A';
+ info = &chain[i].expected_rx_info;
snprintf(tag, sizeof(tag), "%c: Phase B", ch);
printf("%c: Phase B handler - (0x%X) %s\n", ch, result, t30_frametype(result));
fax_log_rx_parameters(s, tag);
@@ -163,15 +197,15 @@ static int phase_b_handler(void *user_data, int result)
if ((u = t30_get_rx_ident(s)))
{
printf("%c: Phase B remote ident '%s'\n", ch, u);
- if (expected_rx_info[i].ident[0] && strcmp(expected_rx_info[i].ident, u))
+ if (info->ident[0] && strcmp(info->ident, u))
{
- printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, expected_rx_info[i].ident);
+ printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, info->ident);
status = T30_ERR_IDENT_UNACCEPTABLE;
}
}
else
{
- if (expected_rx_info[i].ident[0])
+ if (info->ident[0])
{
printf("%c: Phase B: remote ident missing!\n", ch);
status = T30_ERR_IDENT_UNACCEPTABLE;
@@ -180,15 +214,15 @@ static int phase_b_handler(void *user_data, int result)
if ((u = t30_get_rx_sub_address(s)))
{
printf("%c: Phase B: remote sub-address '%s'\n", ch, u);
- if (expected_rx_info[i].sub_address[0] && strcmp(expected_rx_info[i].sub_address, u))
+ if (info->sub_address[0] && strcmp(info->sub_address, u))
{
- printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, expected_rx_info[i].sub_address);
+ printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, info->sub_address);
status = T30_ERR_SUB_UNACCEPTABLE;
}
}
else
{
- if (expected_rx_info[i].sub_address[0])
+ if (info->sub_address[0])
{
printf("%c: Phase B: remote sub-address missing!\n", ch);
status = T30_ERR_SUB_UNACCEPTABLE;
@@ -197,15 +231,15 @@ static int phase_b_handler(void *user_data, int result)
if ((u = t30_get_rx_polled_sub_address(s)))
{
printf("%c: Phase B: remote polled sub-address '%s'\n", ch, u);
- if (expected_rx_info[i].polled_sub_address[0] && strcmp(expected_rx_info[i].polled_sub_address, u))
+ if (info->polled_sub_address[0] && strcmp(info->polled_sub_address, u))
{
- printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, expected_rx_info[i].polled_sub_address);
+ printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, info->polled_sub_address);
status = T30_ERR_PSA_UNACCEPTABLE;
}
}
else
{
- if (expected_rx_info[i].polled_sub_address[0])
+ if (info->polled_sub_address[0])
{
printf("%c: Phase B: remote polled sub-address missing!\n", ch);
status = T30_ERR_PSA_UNACCEPTABLE;
@@ -214,15 +248,15 @@ static int phase_b_handler(void *user_data, int result)
if ((u = t30_get_rx_selective_polling_address(s)))
{
printf("%c: Phase B: remote selective polling address '%s'\n", ch, u);
- if (expected_rx_info[i].selective_polling_address[0] && strcmp(expected_rx_info[i].selective_polling_address, u))
+ if (info->selective_polling_address[0] && strcmp(info->selective_polling_address, u))
{
- printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, expected_rx_info[i].selective_polling_address);
+ printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, info->selective_polling_address);
status = T30_ERR_SEP_UNACCEPTABLE;
}
}
else
{
- if (expected_rx_info[i].selective_polling_address[0])
+ if (info->selective_polling_address[0])
{
printf("%c: Phase B: remote selective polling address missing!\n", ch);
status = T30_ERR_SEP_UNACCEPTABLE;
@@ -231,15 +265,15 @@ static int phase_b_handler(void *user_data, int result)
if ((u = t30_get_rx_sender_ident(s)))
{
printf("%c: Phase B: remote sender ident '%s'\n", ch, u);
- if (expected_rx_info[i].sender_ident[0] && strcmp(expected_rx_info[i].sender_ident, u))
+ if (info->sender_ident[0] && strcmp(info->sender_ident, u))
{
- printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, expected_rx_info[i].sender_ident);
+ printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, info->sender_ident);
status = T30_ERR_SID_UNACCEPTABLE;
}
}
else
{
- if (expected_rx_info[i].sender_ident[0])
+ if (info->sender_ident[0])
{
printf("%c: Phase B: remote sender ident missing!\n", ch);
status = T30_ERR_SID_UNACCEPTABLE;
@@ -248,15 +282,15 @@ static int phase_b_handler(void *user_data, int result)
if ((u = t30_get_rx_password(s)))
{
printf("%c: Phase B: remote password '%s'\n", ch, u);
- if (expected_rx_info[i].password[0] && strcmp(expected_rx_info[i].password, u))
+ if (info->password[0] && strcmp(info->password, u))
{
- printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, expected_rx_info[i].password);
+ printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, info->password);
status = T30_ERR_PWD_UNACCEPTABLE;
}
}
else
{
- if (expected_rx_info[i].password[0])
+ if (info->password[0])
{
printf("%c: Phase B: remote password missing!\n", ch);
status = T30_ERR_PWD_UNACCEPTABLE;
@@ -265,46 +299,46 @@ static int phase_b_handler(void *user_data, int result)
if ((len = t30_get_rx_nsf(s, &v)))
{
printf("%c: Phase B: NSF %d bytes\n", ch, len);
- if (expected_rx_info[i].nsf_len && (expected_rx_info[i].nsf_len != len || memcmp(expected_rx_info[i].nsf, v, len)))
+ if (info->nsf_len && (info->nsf_len != len || memcmp(info->nsf, v, len)))
{
- printf("%c: Phase B: remote NSF incorrect! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsf_len);
+ printf("%c: Phase B: remote NSF incorrect! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
}
}
else
{
- if (expected_rx_info[i].nsf_len)
+ if (info->nsf_len)
{
- printf("%c: Phase B: remote NSF missing! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsf_len);
+ printf("%c: Phase B: remote NSF missing! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
}
}
if ((len = t30_get_rx_nsc(s, &v)))
{
printf("%c: Phase B: NSC %d bytes\n", ch, len);
- if (expected_rx_info[i].nsc_len && (expected_rx_info[i].nsc_len != len || memcmp(expected_rx_info[i].nsc, v, len)))
+ if (info->nsc_len && (info->nsc_len != len || memcmp(info->nsc, v, len)))
{
- printf("%c: Phase B: remote NSC incorrect! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsc_len);
+ printf("%c: Phase B: remote NSC incorrect! - expected %u bytes\n", ch, (unsigned int) info->nsc_len);
}
}
else
{
- if (expected_rx_info[i].nsc_len)
+ if (info->nsc_len)
{
- printf("%c: Phase B: remote NSC missing! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsc_len);
+ printf("%c: Phase B: remote NSC missing! - expected %u bytes\n", ch, (unsigned int) info->nsc_len);
}
}
if ((len = t30_get_rx_nss(s, &v)))
{
printf("%c: Phase B: NSS %d bytes\n", ch, len);
- if (expected_rx_info[i].nss_len && (expected_rx_info[i].nss_len != len || memcmp(expected_rx_info[i].nss, v, len)))
+ if (info->nss_len && (info->nss_len != len || memcmp(info->nss, v, len)))
{
- printf("%c: Phase B: remote NSS incorrect! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nss_len);
+ printf("%c: Phase B: remote NSS incorrect! - expected %u bytes\n", ch, (unsigned int) info->nss_len);
}
}
else
{
- if (expected_rx_info[i].nss_len)
+ if (info->nss_len)
{
- printf("%c: Phase B: remote NSS missing! - expected %u bytes\n", ch, (unsigned int) expected_rx_info[i].nsf_len);
+ printf("%c: Phase B: remote NSS missing! - expected %u bytes\n", ch, (unsigned int) info->nsf_len);
}
}
@@ -320,7 +354,7 @@ static int phase_d_handler(void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
- s = t30_state[i];
+ s = chain[i].t30_state;
ch = i + 'A';
snprintf(tag, sizeof(tag), "%c: Phase D", ch);
printf("%c: Phase D handler - (0x%X) %s\n", ch, result, t30_frametype(result));
@@ -367,7 +401,7 @@ static void phase_e_handler(void *user_data, int result)
char tag[20];
i = (int) (intptr_t) user_data;
- s = t30_state[i];
+ s = chain[i].t30_state;
ch = i + 'A';
snprintf(tag, sizeof(tag), "%c: Phase E", ch);
printf("%c: Phase E handler - (%d) %s\n", ch, result, t30_completion_code_to_str(result));
@@ -375,15 +409,15 @@ static void phase_e_handler(void *user_data, int result)
fax_log_tx_parameters(s, tag);
fax_log_rx_parameters(s, tag);
t30_get_transfer_statistics(s, &t);
- succeeded[i] = (result == T30_ERR_OK);
- phase_e_reached[i] = true;
+ chain[i].succeeded = (result == T30_ERR_OK);
+ chain[i].phase_e_reached = true;
}
/*- End of function --------------------------------------------------------*/
-static void real_time_frame_handler(void *user_data,
- bool incoming,
- const uint8_t *msg,
- int len)
+static void real_time_t30_frame_handler(void *user_data,
+ bool incoming,
+ const uint8_t *msg,
+ int len)
{
int i;
int ch;
@@ -415,7 +449,7 @@ static void set_t30_callbacks(t30_state_t *t30, int chan)
t30_set_phase_b_handler(t30, phase_b_handler, (void *) (intptr_t) chan);
t30_set_phase_d_handler(t30, phase_d_handler, (void *) (intptr_t) chan);
t30_set_phase_e_handler(t30, phase_e_handler, (void *) (intptr_t) chan);
- t30_set_real_time_frame_handler(t30, real_time_frame_handler, (void *) (intptr_t) chan);
+ t30_set_real_time_frame_handler(t30, real_time_t30_frame_handler, (void *) (intptr_t) chan);
t30_set_document_handler(t30, document_handler, (void *) (intptr_t) chan);
}
/*- End of function --------------------------------------------------------*/
@@ -447,11 +481,11 @@ static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t
{
for (i = 0; i < count; i++)
{
- span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", t38_subst_seq[chan], len);
+ span_log(&s->logging, SPAN_LOG_FLOW, "Send seq %d, len %d\n", chain[chan].t38_subst_seq, len);
- if (g1050_put(g1050_path[chan], buf, len, t38_subst_seq[chan], when) < 0)
- printf("Lost packet %d\n", t38_subst_seq[chan]);
- t38_subst_seq[chan] = (t38_subst_seq[chan] + 1) & 0xFFFF;
+ if (g1050_put(chain[chan].path.g1050_path, buf, len, chain[chan].t38_subst_seq, when) < 0)
+ printf("Lost packet %d\n", chain[chan].t38_subst_seq);
+ chain[chan].t38_subst_seq = (chain[chan].t38_subst_seq + 1) & 0xFFFF;
}
}
else
@@ -460,7 +494,7 @@ static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t
for (i = 0; i < count; i++)
{
- if (g1050_put(g1050_path[chan], buf, len, s->tx_seq_no, when) < 0)
+ if (g1050_put(chain[chan].path.g1050_path, buf, len, s->tx_seq_no, when) < 0)
printf("Lost packet %d\n", s->tx_seq_no);
}
}
@@ -468,36 +502,84 @@ static int tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t
}
/*- End of function --------------------------------------------------------*/
+static void t33_tests(void)
+{
+ int n;
+ int item_no;
+ int type;
+ uint8_t num[21];
+ uint8_t new_t33[133];
+ /* These patterns are from the T.33 spec */
+ static const uint8_t *pkts[] =
+ {
+ (const uint8_t *) "#1234567890#1234",
+ (const uint8_t *) "1234#5678#8910",
+ (const uint8_t *) "#6174444100#1234#567",
+ (const uint8_t *) "1234#5678##2032223",
+ (const uint8_t *) "#2037445555##6446666",
+ (const uint8_t *) "#2037445555#1234##6446666#5678",
+ //(const uint8_t *) "#123456789012345678901#1234##6446666#5678",
+ (const uint8_t *) ""
+ };
+
+ printf("T.33 sub-address packing/unpacking tests\n");
+ for (n = 0; pkts[n][0]; n++)
+ {
+ new_t33[0] = '\0';
+ printf("'%s'\n", pkts[n]);
+ for (item_no = 0; item_no < 100; item_no++)
+ {
+ if ((type = t33_sub_address_extract_field(num, pkts[n], item_no)) <= 0)
+ {
+ if (type == T33_NONE)
+ break;
+ printf("Bad sub-address field\n");
+ exit(2);
+ }
+ switch (type)
+ {
+ case T33_SST:
+ printf("SST '%s'\n", num);
+ t33_sub_address_add_field(new_t33, num, type);
+ break;
+ case T33_EXT:
+ printf(" EXT '%s'\n", num);
+ t33_sub_address_add_field(new_t33, num, type);
+ break;
+ }
+ }
+ if (strcmp((const char *) pkts[n], (const char *) new_t33))
+ {
+ printf("Re-encode mismatch '%s' '%s'\n", pkts[n], new_t33);
+ exit(2);
+ }
+ }
+}
+/*- End of function --------------------------------------------------------*/
+
int main(int argc, char *argv[])
{
int16_t silence[SAMPLES_PER_CHUNK];
- int16_t t30_amp[2][SAMPLES_PER_CHUNK];
- int16_t t38_amp[2][SAMPLES_PER_CHUNK];
int16_t t38_amp_hist_a[8][SAMPLES_PER_CHUNK];
int16_t t38_amp_hist_b[8][SAMPLES_PER_CHUNK];
- int16_t out_amp[SAMPLES_PER_CHUNK*4];
- int16_t *fax_rx_buf[2];
- int16_t *fax_tx_buf[2];
- int16_t *t38_gateway_rx_buf[2];
- int16_t *t38_gateway_tx_buf[2];
- int t30_len[2];
- int t38_len[2];
+ int16_t audio_log[SAMPLES_PER_CHUNK*4];
int hist_ptr;
int log_audio;
int msg_len;
uint8_t msg[1024];
int outframes;
SNDFILE *wave_handle;
- SNDFILE *input_wave_handle;
bool use_ecm;
bool use_tep;
- int feedback_audio;
- int use_transmit_on_idle;
+ bool use_polled_mode;
+ bool use_transmit_on_idle;
+ bool feedback_audio;
int t38_version;
const char *input_tiff_file_name;
- const char *decode_file_name;
+ const char *replay_file_name;
int i;
int j;
+ int k;
int seq_no;
int g1050_model_no;
int g1050_speed_pattern_no;
@@ -526,9 +608,13 @@ int main(int argc, char *argv[])
int expected_pages;
char *page_header_info;
char *page_header_tz;
- const char *tag;
const char *xml_file_name;
+ const char *xml_test_name[2];
+ int xml_step;
char buf[132 + 1];
+ int line_model_no;
+ int channel_codec;
+ int rbs_pattern;
#if defined(ENABLE_GUI)
int use_gui;
#endif
@@ -540,6 +626,7 @@ int main(int argc, char *argv[])
use_ecm = false;
t38_version = 1;
input_tiff_file_name = INPUT_TIFF_FILE_NAME;
+ output_tiff_file_name = OUTPUT_TIFF_FILE_NAME;
t38_simulate_incrementing_repeats = false;
g1050_model_no = 0;
g1050_speed_pattern_no = 1;
@@ -547,6 +634,7 @@ int main(int argc, char *argv[])
use_tep = false;
feedback_audio = false;
use_transmit_on_idle = true;
+ use_polled_mode = false;
supported_modems = T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17;
page_header_info = NULL;
page_header_tz = NULL;
@@ -557,16 +645,22 @@ int main(int argc, char *argv[])
signal_level = 0;
noise_level = -99;
scan_line_time = 0;
- decode_file_name = NULL;
+ replay_file_name = INPUT_WAVE_FILE_NAME;
code_to_look_up = -1;
allowed_bilevel_resolutions[0] = 0;
allowed_bilevel_resolutions[1] = 0;
allowed = 0;
+ line_model_no = 0;
+ channel_codec = MUNGE_CODEC_NONE;
+ rbs_pattern = 0;
colour_enabled = false;
t37_like_output = false;
t38_transport = T38_TRANSPORT_UDPTL;
xml_file_name = "../spandsp/tsb85.xml";
- while ((opt = getopt(argc, argv, "7b:c:Cd:D:efFgH:i:Ilm:M:n:p:s:S:tT:u:v:x:z:")) != -1)
+ xml_test_name[0] = "MRGN01";
+ xml_test_name[1] = "MRGN01";
+ xml_step = 0;
+ while ((opt = getopt(argc, argv, "7b:c:Cd:D:efFgH:i:Ilm:M:n:p:Ps:S:tT:u:v:x:X:z:")) != -1)
{
switch (opt)
{
@@ -584,7 +678,7 @@ int main(int argc, char *argv[])
colour_enabled = true;
break;
case 'd':
- decode_file_name = optarg;
+ replay_file_name = optarg;
break;
case 'D':
drop_frame_rate =
@@ -629,31 +723,75 @@ int main(int argc, char *argv[])
noise_level = atoi(optarg);
break;
case 'p':
- for (i = 0; i < 2; i++)
+ /*
+ -p FAX-audio-FAX
+ -p FAX-T38-FAX
+ -p FAX-audio-T38gateway-T38-T38gateway-audio-FAX
+ -p FAX-T38-T38gateway-audio-T38gateway-T38-FAX
+ -p FAX-T38-T38gateway-audio-FAX
+ -p FAX-audio-T38gateway-T38-FAX
+ -p tester-audio-FAX
+ -p tester-T38-FAX
+ -p tester-audio-T38gateway-T38-T38gateway-audio-FAX
+ -p tester-T38-T38gateway-audio-T38gateway-T38-FAX
+ -p tester-T38-T38gateway-audio-FAX
+ -p tester-audio-T38gateway-T38-FAX
+ */
+ for (i = 0, chain_elements = 0, k = 0; chain_elements < 7; i++)
{
- switch (optarg[i])
+ if (optarg[i] != '-' && optarg[i] != '\0')
+ continue;
+ j = optarg[i];
+ optarg[i] = '\0';
+ if (strcmp(&optarg[k], "FAX") == 0)
{
- case 'A':
- mode[i] = AUDIO_FAX;
- break;
- case 'G':
- mode[i] = T38_GATEWAY_FAX;
- break;
- case 'T':
- mode[i] = T38_TERMINAL_FAX;
- break;
- default:
- fprintf(stderr, "Unknown FAX path element %c\n", optarg[i]);
+ chain[chain_elements++].node_type = AUDIO_FAX;
+ }
+ else if (strcmp(&optarg[k], "T38") == 0)
+ {
+ chain[chain_elements++].node_type = T38_FAX;
+ }
+ else if (strcmp(&optarg[k], "T31") == 0)
+ {
+ chain[chain_elements++].node_type = T31_AUDIO_FAX;
+ }
+ else if (strcmp(&optarg[k], "tester") == 0)
+ {
+ chain[chain_elements++].node_type = TSB85_AUDIO_FAX;
+ }
+ else if (strcmp(&optarg[k], "replay") == 0)
+ {
+ chain[chain_elements++].node_type = REPLAY_AUDIO_FAX;
+ }
+ else if (strcmp(&optarg[k], "T38gateway") == 0)
+ {
+ chain[chain_elements++].node_type = AUDIO_TO_T38_GATEWAY;
+ }
+ else if (strcmp(&optarg[k], "passthrough") == 0)
+ {
+ chain[chain_elements++].node_type = PASSTHROUGH;
+ }
+ else
+ {
+ fprintf(stderr, "Unknown FAX path element %s\n", &optarg[k]);
exit(2);
}
+ k = i + 1;
+ if (j == '\0')
+ break;
}
- if ((mode[0] == AUDIO_FAX && mode[1] != AUDIO_FAX)
+#if 0
+ if ((chain[0].node_type == AUDIO_FAX && chain[chain_elements - 1].node_type != AUDIO_FAX)
||
- (mode[0] != AUDIO_FAX && mode[1] == AUDIO_FAX))
+ (chain[0].node_type != AUDIO_FAX && chain[chain_elements - 1].node_type == AUDIO_FAX))
{
- fprintf(stderr, "Invalid FAX path %s\n", optarg);
+ fprintf(stderr, "Invalid FAX path\n");
exit(2);
}
+#endif
+ break;
+ case 'P':
+ use_polled_mode = true;
break;
case 's':
g1050_speed_pattern_no = atoi(optarg);
@@ -692,6 +830,10 @@ int main(int argc, char *argv[])
t38_version = atoi(optarg);
break;
case 'x':
+ xml_test_name[xml_step] = optarg;
+ xml_step ^= 1;
+ break;
+ case 'X':
xml_file_name = optarg;
break;
case 'z':
@@ -726,336 +868,452 @@ int main(int argc, char *argv[])
memset(silence, 0, sizeof(silence));
srand48(0x1234567);
+
+ memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a));
+ memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b));
+
/* Set up the nodes */
- input_wave_handle = NULL;
- if (mode[0] == T38_TERMINAL_FAX)
+ chain[0].peer = chain_elements - 1;
+ chain[chain_elements - 1].peer = 0;
+
+ for (i = 0; i < chain_elements; i++)
{
- }
- else
- {
- if (decode_file_name)
+ chain[i].tag[0] = i + 'A';
+ chain[i].tag[1] = '\0';
+
+ memset(&chain[i].audio_buf[0], 0, sizeof(chain[i].audio_buf[0]));
+ memset(&chain[i].audio_buf[1], 0, sizeof(chain[i].audio_buf[1]));
+ memset(&chain[i].expected_rx_info, 0, sizeof(chain[i].expected_rx_info));
+
+ switch (chain[i].node_type)
{
- if ((input_wave_handle = sf_open_telephony_read(decode_file_name, 1)) == NULL)
- {
- fprintf(stderr, " Cannot open audio file '%s'\n", decode_file_name);
- exit(2);
- }
- }
- }
-
- for (i = 0; i < 2; i++)
- {
- tag = (i == 0) ? "A" : "B";
-
- memset(&expected_rx_info[i], 0, sizeof(expected_rx_info[i]));
- switch (mode[i])
- {
- case T38_TERMINAL_FAX:
- if ((t38_state[i] = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL)
- {
- fprintf(stderr, "Cannot start the T.38 terminal instance\n");
- exit(2);
- }
- t30_state[i] = t38_terminal_get_t30_state(t38_state[i]);
- t38_core_state[i] = t38_terminal_get_t38_core_state(t38_state[i]);
-
- logging = t38_terminal_get_logging_state(t38_state[i]);
- span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
-
- logging = t38_core_get_logging_state(t38_core_state[i]);
- span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
-
- logging = t30_get_logging_state(t30_state[i]);
- span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
- break;
case AUDIO_FAX:
- case T38_GATEWAY_FAX:
- if ((fax_state[i] = fax_init(NULL, (i == 0))) == NULL)
+ if ((chain[i].node.fax_state = fax_init(NULL, (i == 0))) == NULL)
{
- fprintf(stderr, "Cannot start FAX instance\n");
+ fprintf(stderr, " Cannot start FAX instance\n");
exit(2);
}
- t30_state[i] = fax_get_t30_state(fax_state[i]);
+ chain[i].t30_state = fax_get_t30_state(chain[i].node.fax_state);
- logging = fax_get_logging_state(fax_state[i]);
+ logging = fax_get_logging_state(chain[i].node.fax_state);
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
+ span_log_set_tag(logging, chain[i].tag);
- logging = fax_modems_get_logging_state(&fax_state[i]->modems);
+ logging = fax_modems_get_logging_state(&chain[i].node.fax_state->modems);
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
+ span_log_set_tag(logging, chain[i].tag);
- logging = t30_get_logging_state(t30_state[i]);
+ logging = t30_get_logging_state(chain[i].t30_state);
span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
+ span_log_set_tag(logging, chain[i].tag);
- if (mode[i] == T38_GATEWAY_FAX)
- {
- if ((t38_gateway_state[i] = t38_gateway_init(NULL, tx_packet_handler, (void *) (intptr_t) i)) == NULL)
- {
- fprintf(stderr, "Cannot start the T.38 gateway instance\n");
- exit(2);
- }
- t38_core_state[i] = t38_gateway_get_t38_core_state(t38_gateway_state[i]);
+ set_t30_callbacks(chain[i].t30_state, i);
- logging = t38_gateway_get_logging_state(t38_gateway_state[i]);
- span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
+ chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0];
+ chain[i].path.audio_out_buf = &chain[i].audio_buf[0];
- logging = fax_modems_get_logging_state(&t38_gateway_state[i]->audio.modems);
- span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
-
- logging = t38_core_get_logging_state(t38_core_state[i]);
- span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
- span_log_set_tag(logging, tag);
-
- fax_rx_buf[i] = t38_amp[i];
- fax_tx_buf[i] = t30_amp[i];
- t38_gateway_rx_buf[i] = t30_amp[i];
- t38_gateway_tx_buf[i] = t38_amp[i];
- }
- else
- {
- fax_rx_buf[i] = t30_amp[i];
- fax_tx_buf[i] = t30_amp[i ^ 1];
- t38_gateway_rx_buf[i] = NULL;
- t38_gateway_tx_buf[i] = NULL;
- }
- awgn_state[i] = NULL;
+ chain[i].awgn_state = NULL;
signal_scaling = 1.0f;
if (noise_level > -99)
{
- awgn_state[i] = awgn_init_dbm0(NULL, 1234567, noise_level);
+ chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level);
signal_scaling = powf(10.0f, signal_level/20.0f);
printf("Signal scaling %f\n", signal_scaling);
}
break;
+ case T38_FAX:
+ if ((chain[i].node.t38_state = t38_terminal_init(NULL, (i == 0), tx_packet_handler, (void *) (intptr_t) i)) == NULL)
+ {
+ fprintf(stderr, " Cannot start the T.38 terminal instance\n");
+ exit(2);
+ }
+ chain[i].t30_state = t38_terminal_get_t30_state(chain[i].node.t38_state);
+ chain[i].t38_core_state = t38_terminal_get_t38_core_state(chain[i].node.t38_state);
+
+ logging = t38_terminal_get_logging_state(chain[i].node.t38_state);
+ span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
+ span_log_set_tag(logging, chain[i].tag);
+
+ logging = t38_core_get_logging_state(chain[i].t38_core_state);
+ span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
+ span_log_set_tag(logging, chain[i].tag);
+
+ logging = t30_get_logging_state(chain[i].t30_state);
+ span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
+ span_log_set_tag(logging, chain[i].tag);
+
+ set_t30_callbacks(chain[i].t30_state, i);
+
+ if (i == 0)
+ {
+ chain[i].t38_peer = i + 1;
+ }
+ else
+ {
+ switch (chain[i - 1].node_type)
+ {
+ case T38_FAX:
+ case AUDIO_TO_T38_GATEWAY:
+ chain[i].t38_peer = i - 1;
+ break;
+ default:
+ chain[i].t38_peer = i + 1;
+ break;
+ }
+ }
+ break;
case T31_AUDIO_FAX:
break;
- case T31_T38_TERMINAL_FAX:
- case T31_T38_GATEWAY_FAX:
+ case T31_T38_FAX:
break;
case TSB85_AUDIO_FAX:
+ case TSB85_T38_FAX:
+ if ((chain[i].node.faxtester_state = faxtester_init(NULL, xml_file_name, xml_test_name[(i == 0) ? 0 : 1])) == NULL)
+ {
+ fprintf(stderr, " Cannot start FAX tester instance\n");
+ exit(2);
+ }
+ logging = faxtester_get_logging_state(chain[i].node.faxtester_state);
+ span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
+ span_log_set_tag(logging, chain[i].tag);
+
+ faxtester_set_transmit_on_idle(chain[i].node.faxtester_state, true);
+
+ chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0];
+ chain[i].path.audio_out_buf = &chain[i].audio_buf[0];
+
+ if (i == 0)
+ {
+ chain[i].t38_peer = i + 1;
+ }
+ else
+ {
+ switch (chain[i - 1].node_type)
+ {
+ case T38_FAX:
+ case AUDIO_TO_T38_GATEWAY:
+ chain[i].t38_peer = i - 1;
+ break;
+ default:
+ chain[i].t38_peer = i + 1;
+ break;
+ }
+ }
+
+ chain[i].awgn_state = NULL;
+ signal_scaling = 1.0f;
+ if (noise_level > -99)
+ {
+ chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level);
+ signal_scaling = powf(10.0f, signal_level/20.0f);
+ printf("Signal scaling %f\n", signal_scaling);
+ }
break;
- case TSB85_T38_TERMINAL_FAX:
- case TSB85_T38_GATEWAY_FAX:
+ case REPLAY_AUDIO_FAX:
+ if ((chain[i].node.wave_handle = sf_open_telephony_read(replay_file_name, 1)) == NULL)
+ {
+ fprintf(stderr, " Cannot open audio file '%s'\n", replay_file_name);
+ exit(2);
+ }
+
+ chain[i].path.audio_in_buf = &chain[i + ((i == 0) ? 1 : -1)].audio_buf[0];
+ chain[i].path.audio_out_buf = &chain[i].audio_buf[0];
break;
+ case AUDIO_TO_T38_GATEWAY:
+ if ((chain[i].node.t38_gateway_state = t38_gateway_init(NULL, tx_packet_handler, (void *) (intptr_t) i)) == NULL)
+ {
+ fprintf(stderr, " Cannot start T.38 gateway instance\n");
+ exit(2);
+ }
+ chain[i].t38_core_state = t38_gateway_get_t38_core_state(chain[i].node.t38_gateway_state);
+
+ logging = t38_gateway_get_logging_state(chain[i].node.t38_gateway_state);
+ span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
+ span_log_set_tag(logging, chain[i].tag);
+
+ logging = fax_modems_get_logging_state(&chain[i].node.t38_gateway_state->audio.modems);
+ span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
+ span_log_set_tag(logging, chain[i].tag);
+
+ logging = t38_core_get_logging_state(chain[i].t38_core_state);
+ span_log_set_level(logging, SPAN_LOG_DEBUG | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME);
+ span_log_set_tag(logging, chain[i].tag);
+
+ t38_gateway_set_transmit_on_idle(chain[i].node.t38_gateway_state, use_transmit_on_idle);
+ t38_gateway_set_supported_modems(chain[i].node.t38_gateway_state, supported_modems);
+ //t38_gateway_set_nsx_suppression(chain[i].node.t38_state, NULL, 0, NULL, 0);
+ t38_gateway_set_fill_bit_removal(chain[i].node.t38_gateway_state, remove_fill_bits);
+ t38_gateway_set_real_time_frame_handler(chain[i].node.t38_gateway_state, real_time_gateway_frame_handler, (void *) (intptr_t) i);
+ t38_gateway_set_ecm_capability(chain[i].node.t38_gateway_state, use_ecm);
+ t38_set_t38_version(chain[i].t38_core_state, t38_version);
+
+ if (i == 0)
+ {
+ chain[i].t38_peer = i + 1;
+ chain[i].path.audio_in_buf = NULL;
+ }
+ else
+ {
+ switch (chain[i - 1].node_type)
+ {
+ case T38_FAX:
+ case AUDIO_TO_T38_GATEWAY:
+ chain[i].t38_peer = i - 1;
+ chain[i].path.audio_in_buf = &chain[i + 1].audio_buf[0];
+ break;
+ default:
+ chain[i].t38_peer = i + 1;
+ chain[i].path.audio_in_buf = &chain[i - 1].audio_buf[0];
+ break;
+ }
+ }
+
+ chain[i].path.audio_out_buf = &chain[i].audio_buf[0];
+
+ chain[i].awgn_state = NULL;
+ signal_scaling = 1.0f;
+ if (noise_level > -99)
+ {
+ chain[i].awgn_state = awgn_init_dbm0(NULL, 1234567, noise_level);
+ signal_scaling = powf(10.0f, signal_level/20.0f);
+ printf("Signal scaling %f\n", signal_scaling);
+ }
}
- set_t30_callbacks(t30_state[i], i);
- }
- /* Set up the channels */
- for (i = 0; i < 2; i++)
- {
- if ((g1050_path[i] = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
+ if ((chain[i].path.g1050_path = g1050_init(g1050_model_no, g1050_speed_pattern_no, 100, 33)) == NULL)
{
- fprintf(stderr, "Failed to start IP network path model\n");
+ fprintf(stderr, " Failed to start IP network path model\n");
exit(2);
}
- memset(audio_buffer[2*i], 0, SAMPLES_PER_CHUNK*sizeof(int16_t));
- memset(audio_buffer[2*i + 1], 0, SAMPLES_PER_CHUNK*sizeof(int16_t));
- memset(t30_amp[i], 0, sizeof(t30_amp[i]));
- memset(t38_amp[i], 0, sizeof(t38_amp[i]));
}
- memset(t38_amp_hist_a, 0, sizeof(t38_amp_hist_a));
- memset(t38_amp_hist_b, 0, sizeof(t38_amp_hist_b));
- for (i = 0; i < 2; i++)
+ for (i = 0; i < chain_elements; i++)
{
j = i + 1;
- sprintf(buf, "%d%d%d%d%d%d%d%d", j, j, j, j, j, j, j, j);
- t30_set_tx_ident(t30_state[i], buf);
- strcpy(expected_rx_info[i ^ 1].ident, buf);
- sprintf(buf, "Sub-address %d", j);
- t30_set_tx_sub_address(t30_state[i], buf);
- //strcpy(expected_rx_info[i ^ 1].sub_address, buf);
- sprintf(buf, "Sender ID %d", j);
- t30_set_tx_sender_ident(t30_state[i], buf);
- //strcpy(expected_rx_info[i ^ 1].sender_ident, buf);
- sprintf(buf, "Password %d", j);
- t30_set_tx_password(t30_state[i], buf);
- //strcpy(expected_rx_info[i ^ 1].password, buf);
- sprintf(buf, "Polled sub-add %d", j);
- t30_set_tx_polled_sub_address(t30_state[i], buf);
- //strcpy(expected_rx_info[i ^ 1].polled_sub_address, buf);
- sprintf(buf, "Select poll add %d", j);
- t30_set_tx_selective_polling_address(t30_state[i], buf);
- //strcpy(expected_rx_info[i ^ 1].selective_polling_address, buf);
- t30_set_tx_page_header_info(t30_state[i], page_header_info);
- if (page_header_tz)
- t30_set_tx_page_header_tz(t30_state[i], page_header_tz);
-
- if ((i & 1) == 1)
+ if (chain[i].t30_state)
{
- t30_set_tx_nsf(t30_state[i], (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
- expected_rx_info[i ^ 1].nsf = (uint8_t *) "\x50\x00\x00\x00Spandsp\x00";
- expected_rx_info[i ^ 1].nsf_len = 12;
+ sprintf(buf, "%d%d%d%d%d%d%d%d", j, j, j, j, j, j, j, j);
+ t30_set_tx_ident(chain[i].t30_state, buf);
+ strcpy(chain[chain[i].peer].expected_rx_info.ident, buf);
+ sprintf(buf, "Sub-address %d", j);
+ t30_set_tx_sub_address(chain[i].t30_state, buf);
+ //strcpy(chain[chain[i].peer].expected_rx_info.sub_address, buf);
+ sprintf(buf, "Sender ID %d", j);
+ t30_set_tx_sender_ident(chain[i].t30_state, buf);
+ //strcpy(chain[chain[i].peer].expected_rx_info.sender_ident, buf);
+ sprintf(buf, "Password %d", j);
+ t30_set_tx_password(chain[i].t30_state, buf);
+ //strcpy(chain[chain[i].peer].expected_rx_info.password, buf);
+ sprintf(buf, "Polled sub-add %d", j);
+ t30_set_tx_polled_sub_address(chain[i].t30_state, buf);
+ //strcpy(chain[chain[i].peer].expected_rx_info.polled_sub_address, buf);
+ sprintf(buf, "Select poll add %d", j);
+ t30_set_tx_selective_polling_address(chain[i].t30_state, buf);
+ //strcpy(chain[chain[i].peer].expected_rx_info.selective_polling_address, buf);
+ t30_set_tx_page_header_info(chain[i].t30_state, page_header_info);
+ if (page_header_tz)
+ t30_set_tx_page_header_tz(chain[i].t30_state, page_header_tz);
+
+ if (i != 0)
+ {
+ t30_set_tx_nsf(chain[i].t30_state, (const uint8_t *) "\x50\x00\x00\x00Spandsp\x00", 12);
+ chain[chain[i].peer].expected_rx_info.nsf = (uint8_t *) "\x50\x00\x00\x00Spandsp\x00";
+ chain[chain[i].peer].expected_rx_info.nsf_len = 12;
+ }
+
+ t30_set_supported_modems(chain[i].t30_state, supported_modems);
+ t30_set_supported_t30_features(chain[i].t30_state,
+ T30_SUPPORT_IDENTIFICATION
+ | T30_SUPPORT_SELECTIVE_POLLING
+ | T30_SUPPORT_SUB_ADDRESSING);
+ t30_set_supported_image_sizes(chain[i].t30_state,
+ T4_SUPPORT_WIDTH_215MM
+ | T4_SUPPORT_WIDTH_255MM
+ | T4_SUPPORT_WIDTH_303MM
+ | T4_SUPPORT_LENGTH_US_LETTER
+ | T4_SUPPORT_LENGTH_US_LEGAL
+ | T4_SUPPORT_LENGTH_UNLIMITED);
+ switch (allowed_bilevel_resolutions[(i == 0) ? 0 : 1])
+ {
+ case 0:
+ /* Allow anything */
+ t30_set_supported_bilevel_resolutions(chain[i].t30_state,
+ T4_RESOLUTION_R8_STANDARD
+ | T4_RESOLUTION_R8_FINE
+ | T4_RESOLUTION_R8_SUPERFINE
+ | T4_RESOLUTION_R16_SUPERFINE
+ | T4_RESOLUTION_200_100
+ | T4_RESOLUTION_200_200
+ | T4_RESOLUTION_200_400
+ | T4_RESOLUTION_300_300
+ | T4_RESOLUTION_300_600
+ | T4_RESOLUTION_400_400
+ | T4_RESOLUTION_400_800
+ | T4_RESOLUTION_600_600
+ | T4_RESOLUTION_600_1200
+ | T4_RESOLUTION_1200_1200);
+ break;
+ case 1:
+ /* Allow anything metric */
+ t30_set_supported_bilevel_resolutions(chain[i].t30_state,
+ T4_RESOLUTION_R8_STANDARD
+ | T4_RESOLUTION_R8_FINE
+ | T4_RESOLUTION_R8_SUPERFINE
+ | T4_RESOLUTION_R16_SUPERFINE);
+ break;
+ case 2:
+ /* Allow anything inch based */
+ t30_set_supported_bilevel_resolutions(chain[i].t30_state,
+ T4_RESOLUTION_200_100
+ | T4_RESOLUTION_200_200
+ | T4_RESOLUTION_200_400
+ | T4_RESOLUTION_300_300
+ | T4_RESOLUTION_300_600
+ | T4_RESOLUTION_400_400
+ | T4_RESOLUTION_400_800
+ | T4_RESOLUTION_600_600
+ | T4_RESOLUTION_600_1200
+ | T4_RESOLUTION_1200_1200);
+ break;
+ case 3:
+ /* Allow only restricted length resolution */
+ t30_set_supported_bilevel_resolutions(chain[i].t30_state,
+ T4_RESOLUTION_R8_STANDARD
+ | T4_RESOLUTION_R8_FINE
+ | T4_RESOLUTION_200_100
+ | T4_RESOLUTION_200_200);
+ break;
+ case 4:
+ /* Allow only more restricted length resolution */
+ t30_set_supported_bilevel_resolutions(chain[i].t30_state,
+ T4_RESOLUTION_R8_STANDARD
+ | T4_RESOLUTION_200_100);
+ break;
+ }
+ if (colour_enabled)
+ {
+ t30_set_supported_colour_resolutions(chain[i].t30_state,
+ T4_RESOLUTION_100_100
+ | T4_RESOLUTION_200_200
+ | T4_RESOLUTION_300_300
+ | T4_RESOLUTION_400_400
+ | T4_RESOLUTION_600_600
+ | T4_RESOLUTION_1200_1200);
+ }
+ else
+ {
+ t30_set_supported_colour_resolutions(chain[i].t30_state, 0);
+ }
+ if (t37_like_output)
+ {
+ t30_set_supported_output_compressions(chain[i].t30_state,
+ T4_COMPRESSION_T85
+ | T4_COMPRESSION_T85_L0
+ | T4_COMPRESSION_T6
+ | T4_COMPRESSION_T42_T81);
+ }
+ else
+ {
+ t30_set_supported_output_compressions(chain[i].t30_state,
+ T4_COMPRESSION_T6
+ | T4_COMPRESSION_JPEG);
+ }
+
+ t30_set_ecm_capability(chain[i].t30_state, use_ecm);
+ t30_set_supported_compressions(chain[i].t30_state,
+ T4_COMPRESSION_T4_1D
+ | T4_COMPRESSION_T4_2D
+ | T4_COMPRESSION_T6
+ | T4_COMPRESSION_T85
+ | T4_COMPRESSION_T85_L0
+ //| T4_COMPRESSION_T88
+ | T4_COMPRESSION_T43
+ | T4_COMPRESSION_T45
+ | T4_COMPRESSION_T42_T81
+ | T4_COMPRESSION_SYCC_T81
+ | T4_COMPRESSION_GRAYSCALE
+ | T4_COMPRESSION_COLOUR
+ | T4_COMPRESSION_12BIT
+ | T4_COMPRESSION_COLOUR_TO_GRAY
+ | T4_COMPRESSION_GRAY_TO_BILEVEL
+ | T4_COMPRESSION_COLOUR_TO_BILEVEL
+ | T4_COMPRESSION_RESCALING
+ | 0);
+ t30_set_minimum_scan_line_time(chain[i].t30_state, scan_line_time);
}
- t30_set_supported_modems(t30_state[i], supported_modems);
- t30_set_supported_t30_features(t30_state[i],
- T30_SUPPORT_IDENTIFICATION
- | T30_SUPPORT_SELECTIVE_POLLING
- | T30_SUPPORT_SUB_ADDRESSING);
- t30_set_supported_image_sizes(t30_state[i],
- T4_SUPPORT_WIDTH_215MM
- | T4_SUPPORT_WIDTH_255MM
- | T4_SUPPORT_WIDTH_303MM
- | T4_SUPPORT_LENGTH_US_LETTER
- | T4_SUPPORT_LENGTH_US_LEGAL
- | T4_SUPPORT_LENGTH_UNLIMITED);
- switch (allowed_bilevel_resolutions[i])
+ switch (chain[i].node_type)
{
- case 0:
- /* Allow anything */
- t30_set_supported_bilevel_resolutions(t30_state[i],
- T4_RESOLUTION_R8_STANDARD
- | T4_RESOLUTION_R8_FINE
- | T4_RESOLUTION_R8_SUPERFINE
- | T4_RESOLUTION_R16_SUPERFINE
- | T4_RESOLUTION_200_100
- | T4_RESOLUTION_200_200
- | T4_RESOLUTION_200_400
- | T4_RESOLUTION_300_300
- | T4_RESOLUTION_300_600
- | T4_RESOLUTION_400_400
- | T4_RESOLUTION_400_800
- | T4_RESOLUTION_600_600
- | T4_RESOLUTION_600_1200
- | T4_RESOLUTION_1200_1200);
+ case AUDIO_FAX:
+ fax_set_transmit_on_idle(chain[i].node.fax_state, use_transmit_on_idle);
+ fax_set_tep_mode(chain[i].node.fax_state, use_tep);
break;
- case 1:
- /* Allow anything metric */
- t30_set_supported_bilevel_resolutions(t30_state[i],
- T4_RESOLUTION_R8_STANDARD
- | T4_RESOLUTION_R8_FINE
- | T4_RESOLUTION_R8_SUPERFINE
- | T4_RESOLUTION_R16_SUPERFINE);
- break;
- case 2:
- /* Allow anything inch based */
- t30_set_supported_bilevel_resolutions(t30_state[i],
- T4_RESOLUTION_200_100
- | T4_RESOLUTION_200_200
- | T4_RESOLUTION_200_400
- | T4_RESOLUTION_300_300
- | T4_RESOLUTION_300_600
- | T4_RESOLUTION_400_400
- | T4_RESOLUTION_400_800
- | T4_RESOLUTION_600_600
- | T4_RESOLUTION_600_1200
- | T4_RESOLUTION_1200_1200);
- break;
- case 3:
- /* Allow only restricted length resolution */
- t30_set_supported_bilevel_resolutions(t30_state[i],
- T4_RESOLUTION_R8_STANDARD
- | T4_RESOLUTION_R8_FINE
- | T4_RESOLUTION_200_100
- | T4_RESOLUTION_200_200);
- break;
- case 4:
- /* Allow only more restricted length resolution */
- t30_set_supported_bilevel_resolutions(t30_state[i],
- T4_RESOLUTION_R8_STANDARD
- | T4_RESOLUTION_200_100);
- break;
- }
- if (colour_enabled)
- {
- t30_set_supported_colour_resolutions(t30_state[i],
- T4_RESOLUTION_100_100
- | T4_RESOLUTION_200_200
- | T4_RESOLUTION_300_300
- | T4_RESOLUTION_400_400
- | T4_RESOLUTION_600_600
- | T4_RESOLUTION_1200_1200);
- }
- else
- {
- t30_set_supported_colour_resolutions(t30_state[i], 0);
- }
- if (t37_like_output)
- {
- t30_set_supported_output_compressions(t30_state[i],
- T4_COMPRESSION_T85
- | T4_COMPRESSION_T85_L0
- | T4_COMPRESSION_T6
- | T4_COMPRESSION_T42_T81);
- }
- else
- {
- t30_set_supported_output_compressions(t30_state[i],
- T4_COMPRESSION_T6
- | T4_COMPRESSION_JPEG);
- }
-
- t30_set_ecm_capability(t30_state[i], use_ecm);
- t30_set_supported_compressions(t30_state[i],
- T4_COMPRESSION_T4_1D
- | T4_COMPRESSION_T4_2D
- | T4_COMPRESSION_T6
- | T4_COMPRESSION_T85
- | T4_COMPRESSION_T85_L0
- //| T4_COMPRESSION_T88
- | T4_COMPRESSION_T43
- | T4_COMPRESSION_T45
- | T4_COMPRESSION_T42_T81
- | T4_COMPRESSION_SYCC_T81
- | T4_COMPRESSION_GRAYSCALE
- | T4_COMPRESSION_COLOUR
- | T4_COMPRESSION_12BIT
- | T4_COMPRESSION_COLOUR_TO_GRAY
- | T4_COMPRESSION_GRAY_TO_BILEVEL
- | T4_COMPRESSION_COLOUR_TO_BILEVEL
- | T4_COMPRESSION_RESCALING
- | 0);
- t30_set_minimum_scan_line_time(t30_state[i], scan_line_time);
-
- if (mode[i] == T38_GATEWAY_FAX)
- {
- t38_gateway_set_transmit_on_idle(t38_gateway_state[i], use_transmit_on_idle);
- t38_gateway_set_supported_modems(t38_gateway_state[i], supported_modems);
- //t38_gateway_set_nsx_suppression(t38_state[i], NULL, 0, NULL, 0);
- t38_gateway_set_fill_bit_removal(t38_gateway_state[i], remove_fill_bits);
- t38_gateway_set_real_time_frame_handler(t38_gateway_state[i], real_time_gateway_frame_handler, (void *) (intptr_t) i);
- t38_gateway_set_ecm_capability(t38_gateway_state[i], use_ecm);
- }
- if (mode[i] != AUDIO_FAX)
- {
- t38_set_t38_version(t38_core_state[i], t38_version);
- }
-
- if (mode[i] == T38_TERMINAL_FAX)
- {
- //t30_set_iaf_mode(t30_state[i], T30_IAF_MODE_NO_FILL_BITS);
+ case T38_FAX:
+ t38_set_t38_version(chain[i].t38_core_state, t38_version);
+ //t30_set_iaf_mode(chain[i].t30_state, T30_IAF_MODE_NO_FILL_BITS);
switch (t38_transport)
{
case T38_TRANSPORT_UDPTL:
case T38_TRANSPORT_RTP:
- t38_terminal_set_fill_bit_removal(t38_state[i], remove_fill_bits);
- t38_terminal_set_tep_mode(t38_state[i], use_tep);
+ t38_terminal_set_fill_bit_removal(chain[i].node.t38_state, remove_fill_bits);
+ t38_terminal_set_tep_mode(chain[i].node.t38_state, use_tep);
break;
case T38_TRANSPORT_TCP:
case T38_TRANSPORT_TCP_TPKT:
- t38_terminal_set_fill_bit_removal(t38_state[i], true);
- t38_terminal_set_config(t38_state[i], T38_TERMINAL_OPTION_NO_PACING | T38_TERMINAL_OPTION_NO_INDICATORS);
- t38_terminal_set_tep_mode(t38_state[i], false);
+ t38_terminal_set_fill_bit_removal(chain[i].node.t38_state, true);
+ t38_terminal_set_config(chain[i].node.t38_state, T38_TERMINAL_OPTION_NO_PACING | T38_TERMINAL_OPTION_NO_INDICATORS);
+ t38_terminal_set_tep_mode(chain[i].node.t38_state, false);
break;
}
- }
- else
- {
- fax_set_transmit_on_idle(fax_state[i], use_transmit_on_idle);
- fax_set_tep_mode(fax_state[i], use_tep);
+ break;
}
}
- t30_set_tx_file(t30_state[0], input_tiff_file_name, start_page, end_page);
- t30_set_rx_file(t30_state[1], OUTPUT_TIFF_FILE_NAME, -1);
+ for (i = 0; i < chain_elements; i++)
+ {
+ switch (chain[i].node_type)
+ {
+ case TSB85_AUDIO_FAX:
+ case TSB85_T38_FAX:
+ if (chain[chain[i].peer].node_type == AUDIO_FAX)
+ chain[i].node.faxtester_state->far_fax = chain[chain[i].peer].node.fax_state;
+ else
+ chain[i].node.faxtester_state->far_t38 = chain[chain[i].peer].node.t38_state;
+ chain[i].node.faxtester_state->far_t30 = chain[chain[i].peer].t30_state;
+ chain[i].node.faxtester_state->far_tag = chain[i].peer + 'A';
+
+ while (faxtester_next_step(chain[i].node.faxtester_state) == 0)
+ /*dummy loop*/;
+ /*endwhile*/
+ break;
+ case REPLAY_AUDIO_FAX:
+ break;
+ case PASSTHROUGH:
+ if (chain[i - 1].path.audio_in_buf == &chain[i].audio_buf[0])
+ chain[i - 1].path.audio_in_buf = &chain[i + 1].audio_buf[0];
+ if (chain[i + 1].path.audio_in_buf == &chain[i].audio_buf[0])
+ chain[i + 1].path.audio_in_buf = &chain[i - 1].audio_buf[0];
+ break;
+ }
+ }
+
+ switch (chain[chain_elements - 1].node_type)
+ {
+ case AUDIO_FAX:
+ case T38_FAX:
+ k = (use_polled_mode) ? (chain_elements - 1) : 0;
+ if (chain[k].t30_state)
+ t30_set_tx_file(chain[k].t30_state, input_tiff_file_name, start_page, end_page);
+ break;
+ }
+ switch (chain[0].node_type)
+ {
+ case AUDIO_FAX:
+ case T38_FAX:
+ k = (use_polled_mode) ? 0 : (chain_elements - 1);
+ if (chain[k].t30_state)
+ t30_set_rx_file(chain[k].t30_state, output_tiff_file_name, -1);
+ break;
+ }
#if defined(ENABLE_GUI)
if (use_gui)
@@ -1064,144 +1322,225 @@ int main(int argc, char *argv[])
hist_ptr = 0;
for (;;)
{
- memset(out_amp, 0, sizeof(out_amp));
+ memset(audio_log, 0, sizeof(audio_log));
- for (i = 0; i < 2; i++)
+ for (i = 0; i < chain_elements; i++)
{
/* Update T.30 timing */
- logging = t30_get_logging_state(t30_state[i]);
- span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
-
- if (mode[i] == T38_TERMINAL_FAX)
+ switch (chain[i].node_type)
{
- /* Update T.38 termination timing */
- logging = t38_terminal_get_logging_state(t38_state[i]);
+ case AUDIO_FAX:
+ /* Update timing */
+ logging = t30_get_logging_state(chain[i].t30_state);
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
- logging = t38_core_get_logging_state(t38_core_state[i]);
+ logging = fax_get_logging_state(chain[i].node.fax_state);
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
-
- completed[i] = t38_terminal_send_timeout(t38_state[i], SAMPLES_PER_CHUNK);
- }
- else
- {
- /* Update audio FAX timing */
- logging = fax_get_logging_state(fax_state[i]);
+ logging = fax_modems_get_logging_state(&chain[i].node.fax_state->modems);
span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
+#if 0
+ /* Probe inside the modems to update their logs */
+ span_log_bump_samples(chain[i].node.fax_state->modems.v27ter_rx.logging, len);
+ span_log_bump_samples(chain[i].node.fax_state->modems.v29_rx.logging, len);
+ span_log_bump_samples(chain[i].node.fax_state->modems.v17_rx.logging, len);
+#endif
#if 0
/* Mute the signal */
- vec_zeroi16(fax_rx_buf[i], SAMPLES_PER_CHUNK);
+ vec_zeroi16(chain[i].path.audio_in_buf->amp, SAMPLES_PER_CHUNK);
+ chain[i].path.audio_in_buf->len = SAMPLES_PER_CHUNK;
#endif
- fax_rx(fax_state[i], fax_rx_buf[i], SAMPLES_PER_CHUNK);
- if (!t30_call_active(t30_state[i]))
+ if (log_audio)
{
- completed[i] = true;
+ k = (i == 0) ? 0 : 2;
+ for (j = 0; j < chain[i].path.audio_in_buf->len; j++)
+ audio_log[4*j + k] = chain[i].path.audio_in_buf->amp[j];
+ }
+ fax_rx(chain[i].node.fax_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len);
+ if (!t30_call_active(chain[i].t30_state))
+ {
+ chain[i].completed = true;
continue;
}
- if (i == 0 && input_wave_handle)
+ chain[i].path.audio_out_buf->len = fax_tx(chain[i].node.fax_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
+ if (!use_transmit_on_idle)
{
- t30_len[i] = sf_readf_short(input_wave_handle, fax_tx_buf[i], SAMPLES_PER_CHUNK);
- if (t30_len[i] == 0)
- break;
+ /* The receive side always expects a full block of samples, but the
+ transmit side may not be sending any when it doesn't need to. We
+ may need to pad with some silence. */
+ if (chain[i].path.audio_out_buf->len < SAMPLES_PER_CHUNK)
+ {
+ vec_zeroi16(&chain[i].path.audio_out_buf->amp[chain[i].path.audio_out_buf->len], SAMPLES_PER_CHUNK - chain[i].path.audio_out_buf->len);
+ chain[i].path.audio_out_buf->len = SAMPLES_PER_CHUNK;
+ }
}
- else
+ if (chain[i].awgn_state)
{
- t30_len[i] = fax_tx(fax_state[i], fax_tx_buf[i], SAMPLES_PER_CHUNK);
- if (!use_transmit_on_idle)
- {
- /* The receive side always expects a full block of samples, but the
- transmit side may not be sending any when it doesn't need to. We
- may need to pad with some silence. */
- if (t30_len[i] < SAMPLES_PER_CHUNK)
- {
- memset(t30_amp[i] + t30_len[i], 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t30_len[i]));
- t30_len[i] = SAMPLES_PER_CHUNK;
- }
- }
- if (awgn_state[i])
- {
- for (j = 0; j < t30_len[i]; j++)
- fax_tx_buf[i][j] = ((int16_t) (fax_tx_buf[i][j]*signal_scaling)) + awgn(awgn_state[i]);
- }
+ for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
+ chain[i].path.audio_out_buf->amp[j] = ((int16_t) (chain[i].path.audio_out_buf->amp[j]*signal_scaling)) + awgn(chain[i].awgn_state);
}
if (log_audio)
{
- for (j = 0; j < t30_len[i]; j++)
- out_amp[4*j + 2*i] = t30_amp[i][j];
+ k = (i == 0) ? 1 : 3;
+ for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
+ audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j];
}
if (feedback_audio)
{
- for (j = 0; j < t30_len[i]; j++)
- t30_amp[i][j] += t38_amp_hist_a[hist_ptr][j] >> 1;
- memcpy(t38_amp_hist_a[hist_ptr], t38_amp[i], sizeof(int16_t)*SAMPLES_PER_CHUNK);
+ for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
+ chain[i].path.audio_out_buf->amp[j] += t38_amp_hist_a[hist_ptr][j] >> 1;
+ memcpy(t38_amp_hist_a[hist_ptr], chain[i].path.audio_out_buf->amp, sizeof(int16_t)*SAMPLES_PER_CHUNK);
}
+ break;
+ case T38_FAX:
+ /* Update timing */
+ logging = t30_get_logging_state(chain[i].t30_state);
+ span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
+ logging = t38_terminal_get_logging_state(chain[i].node.t38_state);
+ span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
+ logging = t38_core_get_logging_state(chain[i].t38_core_state);
+ span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
- if (mode[i] == T38_GATEWAY_FAX)
- {
- /* Update T.38 gateway timing */
- logging = t38_gateway_get_logging_state(t38_gateway_state[i]);
- span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
- logging = t38_core_get_logging_state(t38_core_state[i]);
- span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
+ chain[i].completed = t38_terminal_send_timeout(chain[i].node.t38_state, SAMPLES_PER_CHUNK);
- if (drop_frame_rate && --drop_frame == 0)
- {
- drop_frame = drop_frame_rate;
- if (t38_gateway_rx_fillin(t38_gateway_state[i], SAMPLES_PER_CHUNK))
- break;
- }
- else
- {
- if (t38_gateway_rx(t38_gateway_state[i], t38_gateway_rx_buf[i], SAMPLES_PER_CHUNK))
- break;
- }
-
- t38_len[i] = t38_gateway_tx(t38_gateway_state[i], t38_gateway_tx_buf[i], SAMPLES_PER_CHUNK);
- if (!use_transmit_on_idle)
- {
- if (t38_len[i] < SAMPLES_PER_CHUNK)
- {
- memset(t38_amp[i] + t38_len[i], 0, sizeof(int16_t)*(SAMPLES_PER_CHUNK - t38_len[i]));
- t38_len[i] = SAMPLES_PER_CHUNK;
- }
- }
- if (feedback_audio)
- {
- for (j = 0; j < t30_len[i]; j++)
- t30_amp[i][j] += t38_amp_hist_a[hist_ptr][j] >> 1;
- memcpy(t38_amp_hist_a[hist_ptr], t38_amp[i], sizeof(int16_t)*SAMPLES_PER_CHUNK);
- }
-
- if (log_audio)
- {
- for (j = 0; j < t38_len[i]; j++)
- out_amp[4*j + 2*i + 1] = t38_amp[i][j];
- }
- }
- }
- if (mode[i] != AUDIO_FAX)
- {
- while ((msg_len = g1050_get(g1050_path[i], msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
+ while ((msg_len = g1050_get(chain[i].path.g1050_path, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
{
#if defined(ENABLE_GUI)
if (use_gui)
media_monitor_rx(seq_no, tx_when, rx_when);
#endif
- t38_core_rx_ifp_packet(t38_core_state[i ^ 1], msg, msg_len, seq_no);
+ t38_core_rx_ifp_packet(chain[chain[i].t38_peer].t38_core_state, msg, msg_len, seq_no);
}
+ break;
+ case TSB85_AUDIO_FAX:
+ /* Update timing */
+ logging = faxtester_get_logging_state(chain[i].node.faxtester_state);
+ span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
+#if 0
+ /* Probe inside the modems to update their logs */
+ span_log_bump_samples(&chain[i].node.faxtester_state->modems.v27ter_rx.logging, len);
+ span_log_bump_samples(&chain[i].node.faxtester_state->modems.v29_rx.logging, len);
+ span_log_bump_samples(&chain[i].node.faxtester_state->modems.v17_rx.logging, len);
+#endif
+
+ if (log_audio)
+ {
+ k = (i == 0) ? 0 : 2;
+ for (j = 0; j < chain[i].path.audio_in_buf->len; j++)
+ audio_log[4*j + k] = chain[i].path.audio_in_buf->amp[j];
+ }
+ faxtester_rx(chain[i].node.faxtester_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len);
+ chain[i].path.audio_out_buf->len = faxtester_tx(chain[i].node.faxtester_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
+ if (chain[i].path.audio_out_buf->len == 0)
+ break;
+ if (log_audio)
+ {
+ k = (i == 0) ? 1 : 3;
+ for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
+ audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j];
+ }
+ if (chain[i].node.faxtester_state->test_for_call_clear && !chain[i].node.faxtester_state->far_end_cleared_call)
+ {
+ chain[i].node.faxtester_state->call_clear_timer += chain[i].path.audio_out_buf->len;
+ if (!t30_call_active(chain[i].node.faxtester_state->far_t30))
+ {
+ span_log(faxtester_get_logging_state(chain[i].node.faxtester_state),
+ SPAN_LOG_FLOW,
+ "Far end cleared after %dms (limits %dms to %dms)\n",
+ chain[i].node.faxtester_state->call_clear_timer/8,
+ chain[i].node.faxtester_state->timein_x,
+ chain[i].node.faxtester_state->timeout);
+ if (chain[i].node.faxtester_state->call_clear_timer/8 < chain[i].node.faxtester_state->timein_x || chain[i].node.faxtester_state->call_clear_timer/8 > chain[i].node.faxtester_state->timeout_x)
+ {
+ printf("Test failed\n");
+ exit(2);
+ }
+ span_log(faxtester_get_logging_state(chain[i].node.faxtester_state), SPAN_LOG_FLOW, "Clear time OK\n");
+ chain[i].node.faxtester_state->far_end_cleared_call = true;
+ chain[i].node.faxtester_state->test_for_call_clear = false;
+ while (faxtester_next_step(chain[i].node.faxtester_state) == 0)
+ /*dummy loop*/;
+ /*endwhile*/
+ }
+ /*endif*/
+ }
+ /*endif*/
+ break;
+ case REPLAY_AUDIO_FAX:
+ chain[i].path.audio_out_buf->len = sf_readf_short(chain[i].node.wave_handle, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
+ if (chain[i].path.audio_out_buf->len == 0)
+ break;
+ break;
+ case AUDIO_TO_T38_GATEWAY:
+ /* Update timing */
+ logging = t38_gateway_get_logging_state(chain[i].node.t38_gateway_state);
+ span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
+ logging = t38_core_get_logging_state(chain[i].t38_core_state);
+ span_log_bump_samples(logging, SAMPLES_PER_CHUNK);
+#if 0
+ /* Probe inside the modems to update their logs */
+ span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v27ter_rx.logging, len);
+ span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v29_rx.logging, len);
+ span_log_bump_samples(&chain[i].node.t38_gateway_state->modems.v17_rx.logging, len);
+#endif
+
+ if (drop_frame_rate && --drop_frame == 0)
+ {
+ drop_frame = drop_frame_rate;
+ if (t38_gateway_rx_fillin(chain[i].node.t38_gateway_state, SAMPLES_PER_CHUNK))
+ break;
+ }
+ else
+ {
+ if (t38_gateway_rx(chain[i].node.t38_gateway_state, chain[i].path.audio_in_buf->amp, chain[i].path.audio_in_buf->len))
+ break;
+ }
+
+ chain[i].path.audio_out_buf->len = t38_gateway_tx(chain[i].node.t38_gateway_state, chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
+ if (!use_transmit_on_idle)
+ {
+ if (chain[i].path.audio_out_buf->len < SAMPLES_PER_CHUNK)
+ {
+ vec_zeroi16(&chain[i].path.audio_out_buf->amp[chain[i].path.audio_out_buf->len], SAMPLES_PER_CHUNK - chain[i].path.audio_out_buf->len);
+ chain[i].path.audio_out_buf->len = SAMPLES_PER_CHUNK;
+ }
+ }
+ if (feedback_audio)
+ {
+ for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
+ chain[i].path.audio_out_buf->amp[j] += t38_amp_hist_a[hist_ptr][j] >> 1;
+ vec_movei16(t38_amp_hist_a[hist_ptr], chain[i].path.audio_out_buf->amp, SAMPLES_PER_CHUNK);
+ }
+
+#if 0
+ if (log_audio)
+ {
+ k = (i == 0) ? 1 : 3;
+ for (j = 0; j < chain[i].path.audio_out_buf->len; j++)
+ audio_log[4*j + k] = chain[i].path.audio_out_buf->amp[j];
+ }
+#endif
+ while ((msg_len = g1050_get(chain[i].path.g1050_path, msg, 1024, when, &seq_no, &tx_when, &rx_when)) >= 0)
+ {
+#if defined(ENABLE_GUI)
+ if (use_gui)
+ media_monitor_rx(seq_no, tx_when, rx_when);
+#endif
+ t38_core_rx_ifp_packet(chain[chain[i].t38_peer].t38_core_state, msg, msg_len, seq_no);
+ }
+ break;
}
}
if (log_audio)
{
- outframes = sf_writef_short(wave_handle, out_amp, SAMPLES_PER_CHUNK);
+ outframes = sf_writef_short(wave_handle, audio_log, SAMPLES_PER_CHUNK);
if (outframes != SAMPLES_PER_CHUNK)
break;
}
when += (float) SAMPLES_PER_CHUNK/(float) SAMPLE_RATE;
- if (completed[0] && completed[1])
+ if (chain[0].completed && chain[chain_elements - 1].completed)
break;
#if defined(ENABLE_GUI)
if (use_gui)
@@ -1210,24 +1549,19 @@ int main(int argc, char *argv[])
if (++hist_ptr > 3)
hist_ptr = 0;
}
- for (i = 0; i < 2; i++)
+
+ for (i = 0; i < chain_elements; i++)
{
- if (mode[i] == T38_GATEWAY_FAX)
+ switch (chain[i].node_type)
{
- t38_gateway_get_transfer_statistics(t38_gateway_state[i], &t38_stats);
+ case AUDIO_TO_T38_GATEWAY:
+ t38_gateway_get_transfer_statistics(chain[i].node.t38_gateway_state, &t38_stats);
printf("%c side exchanged %d pages at %dbps, in %s mode\n",
i + 'A',
t38_stats.pages_transferred,
t38_stats.bit_rate,
(t38_stats.error_correcting_mode) ? "ECM" : "non-ECM");
- }
- }
- if (input_wave_handle)
- {
- if (sf_close_telephony(input_wave_handle))
- {
- fprintf(stderr, " Cannot close audio file '%s'\n", decode_file_name);
- exit(2);
+ break;
}
}
if (log_audio)
@@ -1246,14 +1580,16 @@ int main(int argc, char *argv[])
if (start_page >= 0)
expected_pages -= start_page;
/* Check how many pages were transferred */
- for (i = 0; i < 2; i++)
+ for (j = 0; j < 2; j++)
{
- if (!phase_e_reached[i])
+ i = (j == 0) ? 0 : (chain_elements - 1);
+ if (!chain[i].phase_e_reached)
break;
- if (!succeeded[i])
+ if (!chain[i].succeeded)
break;
- t30_get_transfer_statistics(t30_state[i], &t30_stats);
- if (i & 1)
+
+ t30_get_transfer_statistics(chain[i].t30_state, &t30_stats);
+ if ((!use_polled_mode && i != 0) || (use_polled_mode && i == 0))
{
if (t30_stats.pages_tx != 0 || t30_stats.pages_rx != expected_pages)
break;
@@ -1263,23 +1599,45 @@ int main(int argc, char *argv[])
if (t30_stats.pages_tx != expected_pages || t30_stats.pages_rx != 0)
break;
}
- if (mode[i] == T38_TERMINAL_FAX)
- t38_terminal_free(t38_state[i]);
- else
- fax_free(fax_state[i]);
- if (mode[i] == T38_GATEWAY_FAX)
- t38_gateway_free(t38_gateway_state[i]);
- if (g1050_path[i])
+ }
+ for (i = 0; i < chain_elements; i++)
+ {
+ switch (chain[i].node_type)
{
- g1050_free(g1050_path[i]);
- g1050_path[i] = NULL;
+ case AUDIO_FAX:
+ fax_free(chain[i].node.fax_state);
+ break;
+ case T38_FAX:
+ t38_terminal_free(chain[i].node.t38_state);
+ break;
+ case TSB85_AUDIO_FAX:
+ case TSB85_T38_FAX:
+ faxtester_free(chain[i].node.faxtester_state);
+ break;
+ case REPLAY_AUDIO_FAX:
+ if (sf_close_telephony(chain[i].node.wave_handle))
+ {
+ fprintf(stderr, " Cannot close audio file '%s'\n", replay_file_name);
+ exit(2);
+ }
+ chain[i].node.wave_handle = NULL;
+ break;
+ case AUDIO_TO_T38_GATEWAY:
+ t38_gateway_free(chain[i].node.t38_gateway_state);
+ break;
+ }
+ if (chain[i].path.g1050_path)
+ {
+ g1050_free(chain[i].path.g1050_path);
+ chain[i].path.g1050_path = NULL;
}
}
- if (i < 2)
+ if (j < 2)
{
printf("Tests failed\n");
exit(2);
}
+ t33_tests();
printf("Tests passed\n");
return 0;
}
diff --git a/libs/spandsp/tests/fax_tests.sh b/libs/spandsp/tests/fax_tests.sh
index 0cacdcdd7b..140d8fddf9 100755
--- a/libs/spandsp/tests/fax_tests.sh
+++ b/libs/spandsp/tests/fax_tests.sh
@@ -94,7 +94,7 @@ LOCALTESTS_DIR=../test-data/local
TIFFCMP=tiffcmp
# Colour/gray -> bilevel by not allowing ECM
-#for OPTS in "-p AA" "-p TT" "-p GG" "-p TG" "-p GT"
+#for OPTS in "-p FAX-FAX" "-p T38-T38" "-p FAX-T38gateway-T38gateway-FAX" "-p T38-T38gateway-FAX" "-p FAX-T38gateway-T38"
#do
# IN_FILE="${LOCALTESTS_DIR}/lenna-colour.tif"
# OUT_FILE="${LOCALTESTS_DIR}/lenna-colour-bilevel.tif"
@@ -118,7 +118,7 @@ TIFFCMP=tiffcmp
#done
# Colour/gray -> colour/gray
-#for OPTS in "-p AA -C -e" "-p TT -C -e" "-p GG -C -e" "-p TG -C -e" "-p GT -C -e"
+#for OPTS in "-p FAX-FAX -C -e" "-p T38-T38 -C -e" "-p FAX-T38gateway-T38gateway-FAX -C -e" "-p T38-T38gateway-FAX -C -e" "-p FAX-T38gateway-T38 -C -e"
#do
# IN_FILE="${LOCALTESTS_DIR}/lenna-colour.tif"
# OUT_FILE="${LOCALTESTS_DIR}/lenna-colour-out.tif"
@@ -142,7 +142,7 @@ TIFFCMP=tiffcmp
#done
# Bi-level tests with image squashing
-for OPTS in "-p AA" "-p AA -e" "-p TT" "-p TT -e" "-p GG" "-p GG -e" "-p TG" "-p TG -e" "-p GT" "-p GT -e"
+for OPTS in "-p FAX-FAX" "-p FAX-FAX -e" "-p T38-T38" "-p T38-T38 -e" "-p FAX-T38gateway-T38gateway-FAX" "-p FAX-T38gateway-T38gateway-FAX -e" "-p T38-T38gateway-FAX" "-p T38-T38gateway-FAX -e" "-p FAX-T38gateway-T38" "-p FAX-T38gateway-T38 -e"
do
IN_FILE="${ITUTESTS_DIR}/bilevel_R8_77_A4.tif"
OUT_FILE="${ITUTESTS_DIR}/bilevel_R8_77SQ_A4.tif"
@@ -241,7 +241,7 @@ do
done
# Bi-level tests
-for OPTS in "-p AA" "-p AA -e" "-p TT" "-p TT -e" "-p GG" "-p GG -e" "-p TG" "-p TG -e" "-p GT" "-p GT -e"
+for OPTS in "-p FAX-FAX" "-p FAX-FAX -e" "-p T38-T38" "-p T38-T38 -e" "-p FAX-T38gateway-T38gateway-FAX" "-p FAX-T38gateway-T38gateway-FAX -e" "-p T38-T38gateway-FAX" "-p T38-T38gateway-FAX -e" "-p FAX-T38gateway-T38" "-p FAX-T38gateway-T38 -e"
do
FILE="${ITUTESTS_DIR}/itutests.tif"
run_fax_test
diff --git a/libs/spandsp/tests/pcap_parse.c b/libs/spandsp/tests/pcap_parse.c
index 56d8d288e8..bc3805af2a 100644
--- a/libs/spandsp/tests/pcap_parse.c
+++ b/libs/spandsp/tests/pcap_parse.c
@@ -113,7 +113,7 @@ typedef struct _null_hdr
typedef struct _ipv6_hdr
{
char dontcare[6];
- uint8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */
+ u_int8_t nxt_header; /* we only need the next header, so we can determine, if the next header is UDP or not */
char dontcare2[33];
} ipv6_hdr;
#endif
diff --git a/libs/spandsp/tests/tsb85_tests.c b/libs/spandsp/tests/tsb85_tests.c
index 624dcb1f6c..5b199491f1 100644
--- a/libs/spandsp/tests/tsb85_tests.c
+++ b/libs/spandsp/tests/tsb85_tests.c
@@ -71,1179 +71,11 @@
SNDFILE *out_handle;
-bool use_receiver_not_ready = false;
-bool test_local_interrupt = false;
-
const char *output_tiff_file_name;
bool log_audio = false;
-fax_state_t *fax;
-faxtester_state_t state;
-
-uint8_t image[1000000];
-
-uint8_t awaited[1000];
-int awaited_len = 0;
-
-char image_path[1024];
-
-t30_exchanged_info_t expected_rx_info;
-
-char next_tx_file[1000];
-
-static int timein_x = -1;
-static int timeout_x = -1;
-
-static int next_step(faxtester_state_t *s);
-
-static bool test_for_call_clear = false;
-static int call_clear_timer = 0;
-
-static bool far_end_cleared_call = false;
-
-struct
-{
- const char *tag;
- int code;
-} t30_status[] =
-{
- {"OK", T30_ERR_OK},
- {"CEDTONE", T30_ERR_CEDTONE},
- {"T0_EXPIRED", T30_ERR_T0_EXPIRED},
- {"T1_EXPIRED", T30_ERR_T1_EXPIRED},
- {"T3_EXPIRED", T30_ERR_T3_EXPIRED},
- {"HDLC_CARRIER", T30_ERR_HDLC_CARRIER},
- {"CANNOT_TRAIN", T30_ERR_CANNOT_TRAIN},
- {"OPER_INT_FAIL", T30_ERR_OPER_INT_FAIL},
- {"INCOMPATIBLE", T30_ERR_INCOMPATIBLE},
- {"RX_INCAPABLE", T30_ERR_RX_INCAPABLE},
- {"TX_INCAPABLE", T30_ERR_TX_INCAPABLE},
- {"NORESSUPPORT", T30_ERR_NORESSUPPORT},
- {"NOSIZESUPPORT", T30_ERR_NOSIZESUPPORT},
- {"UNEXPECTED", T30_ERR_UNEXPECTED},
- {"TX_BADDCS", T30_ERR_TX_BADDCS},
- {"TX_BADPG", T30_ERR_TX_BADPG},
- {"TX_ECMPHD", T30_ERR_TX_ECMPHD},
- {"TX_GOTDCN", T30_ERR_TX_GOTDCN},
- {"TX_INVALRSP", T30_ERR_TX_INVALRSP},
- {"TX_NODIS", T30_ERR_TX_NODIS},
- {"TX_PHBDEAD", T30_ERR_TX_PHBDEAD},
- {"TX_PHDDEAD", T30_ERR_TX_PHDDEAD},
- {"TX_T5EXP", T30_ERR_TX_T5EXP},
- {"RX_ECMPHD", T30_ERR_RX_ECMPHD},
- {"RX_GOTDCS", T30_ERR_RX_GOTDCS},
- {"RX_INVALCMD", T30_ERR_RX_INVALCMD},
- {"RX_NOCARRIER", T30_ERR_RX_NOCARRIER},
- {"RX_NOEOL", T30_ERR_RX_NOEOL},
- {"RX_NOFAX", T30_ERR_RX_NOFAX},
- {"RX_T2EXPDCN", T30_ERR_RX_T2EXPDCN},
- {"RX_T2EXPD", T30_ERR_RX_T2EXPD},
- {"RX_T2EXPFAX", T30_ERR_RX_T2EXPFAX},
- {"RX_T2EXPMPS", T30_ERR_RX_T2EXPMPS},
- {"RX_T2EXPRR", T30_ERR_RX_T2EXPRR},
- {"RX_T2EXP", T30_ERR_RX_T2EXP},
- {"RX_DCNWHY", T30_ERR_RX_DCNWHY},
- {"RX_DCNDATA", T30_ERR_RX_DCNDATA},
- {"RX_DCNFAX", T30_ERR_RX_DCNFAX},
- {"RX_DCNPHD", T30_ERR_RX_DCNPHD},
- {"RX_DCNRRD", T30_ERR_RX_DCNRRD},
- {"RX_DCNNORTN", T30_ERR_RX_DCNNORTN},
- {"FILEERROR", T30_ERR_FILEERROR},
- {"NOPAGE", T30_ERR_NOPAGE},
- {"BADTIFF", T30_ERR_BADTIFF},
- {"BADPAGE", T30_ERR_BADPAGE},
- {"BADTAG", T30_ERR_BADTAG},
- {"BADTIFFHDR", T30_ERR_BADTIFFHDR},
- {"NOMEM", T30_ERR_NOMEM},
- {"RETRYDCN", T30_ERR_RETRYDCN},
- {"CALLDROPPED", T30_ERR_CALLDROPPED},
- {"NOPOLL", T30_ERR_NOPOLL},
- {"IDENT_UNACCEPTABLE", T30_ERR_IDENT_UNACCEPTABLE},
- {"SUB_UNACCEPTABLE", T30_ERR_SUB_UNACCEPTABLE},
- {"SEP_UNACCEPTABLE", T30_ERR_SEP_UNACCEPTABLE},
- {"PSA_UNACCEPTABLE", T30_ERR_PSA_UNACCEPTABLE},
- {"SID_UNACCEPTABLE", T30_ERR_SID_UNACCEPTABLE},
- {"PWD_UNACCEPTABLE", T30_ERR_PWD_UNACCEPTABLE},
- {"TSA_UNACCEPTABLE", T30_ERR_TSA_UNACCEPTABLE},
- {"IRA_UNACCEPTABLE", T30_ERR_IRA_UNACCEPTABLE},
- {"CIA_UNACCEPTABLE", T30_ERR_CIA_UNACCEPTABLE},
- {"ISP_UNACCEPTABLE", T30_ERR_ISP_UNACCEPTABLE},
- {"CSA_UNACCEPTABLE", T30_ERR_CSA_UNACCEPTABLE},
- {NULL, -1}
-};
-
-static int phase_b_handler(void *user_data, int result)
-{
- int ch;
- int status;
- t30_state_t *s;
- const char *u;
-
- s = (t30_state_t *) user_data;
- ch = 'A';
- status = T30_ERR_OK;
- if ((u = t30_get_rx_ident(s)))
- {
- printf("%c: Phase B: remote ident '%s'\n", ch, u);
- if (expected_rx_info.ident[0] && strcmp(expected_rx_info.ident, u))
- {
- printf("%c: Phase B: remote ident incorrect! - expected '%s'\n", ch, expected_rx_info.ident);
- status = T30_ERR_IDENT_UNACCEPTABLE;
- }
- }
- else
- {
- if (expected_rx_info.ident[0])
- {
- printf("%c: Phase B: remote ident missing!\n", ch);
- status = T30_ERR_IDENT_UNACCEPTABLE;
- }
- }
- if ((u = t30_get_rx_sub_address(s)))
- {
- printf("%c: Phase B: remote sub-address '%s'\n", ch, u);
- if (expected_rx_info.sub_address[0] && strcmp(expected_rx_info.sub_address, u))
- {
- printf("%c: Phase B: remote sub-address incorrect! - expected '%s'\n", ch, expected_rx_info.sub_address);
- status = T30_ERR_SUB_UNACCEPTABLE;
- }
- }
- else
- {
- if (expected_rx_info.sub_address[0])
- {
- printf("%c: Phase B: remote sub-address missing!\n", ch);
- status = T30_ERR_SUB_UNACCEPTABLE;
- }
- }
- if ((u = t30_get_rx_polled_sub_address(s)))
- {
- printf("%c: Phase B: remote polled sub-address '%s'\n", ch, u);
- if (expected_rx_info.polled_sub_address[0] && strcmp(expected_rx_info.polled_sub_address, u))
- {
- printf("%c: Phase B: remote polled sub-address incorrect! - expected '%s'\n", ch, expected_rx_info.polled_sub_address);
- status = T30_ERR_PSA_UNACCEPTABLE;
- }
- }
- else
- {
- if (expected_rx_info.polled_sub_address[0])
- {
- printf("%c: Phase B: remote polled sub-address missing!\n", ch);
- status = T30_ERR_PSA_UNACCEPTABLE;
- }
- }
- if ((u = t30_get_rx_selective_polling_address(s)))
- {
- printf("%c: Phase B: remote selective polling address '%s'\n", ch, u);
- if (expected_rx_info.selective_polling_address[0] && strcmp(expected_rx_info.selective_polling_address, u))
- {
- printf("%c: Phase B: remote selective polling address incorrect! - expected '%s'\n", ch, expected_rx_info.selective_polling_address);
- status = T30_ERR_SEP_UNACCEPTABLE;
- }
- }
- else
- {
- if (expected_rx_info.selective_polling_address[0])
- {
- printf("%c: Phase B: remote selective polling address missing!\n", ch);
- status = T30_ERR_SEP_UNACCEPTABLE;
- }
- }
- if ((u = t30_get_rx_sender_ident(s)))
- {
- printf("%c: Phase B: remote sender ident '%s'\n", ch, u);
- if (expected_rx_info.sender_ident[0] && strcmp(expected_rx_info.sender_ident, u))
- {
- printf("%c: Phase B: remote sender ident incorrect! - expected '%s'\n", ch, expected_rx_info.sender_ident);
- status = T30_ERR_SID_UNACCEPTABLE;
- }
- }
- else
- {
- if (expected_rx_info.sender_ident[0])
- {
- printf("%c: Phase B: remote sender ident missing!\n", ch);
- status = T30_ERR_SID_UNACCEPTABLE;
- }
- }
- if ((u = t30_get_rx_password(s)))
- {
- printf("%c: Phase B: remote password '%s'\n", ch, u);
- if (expected_rx_info.password[0] && strcmp(expected_rx_info.password, u))
- {
- printf("%c: Phase B: remote password incorrect! - expected '%s'\n", ch, expected_rx_info.password);
- status = T30_ERR_PWD_UNACCEPTABLE;
- }
- }
- else
- {
- if (expected_rx_info.password[0])
- {
- printf("%c: Phase B: remote password missing!\n", ch);
- status = T30_ERR_PWD_UNACCEPTABLE;
- }
- }
- printf("%c: Phase B handler on channel %d - (0x%X) %s\n", ch, ch, result, t30_frametype(result));
- return status;
-}
-/*- End of function --------------------------------------------------------*/
-
-static int phase_d_handler(void *user_data, int result)
-{
- int i;
- int ch;
- t30_state_t *s;
- char tag[20];
-
- i = 0;
- s = (t30_state_t *) user_data;
- ch = i + 'A';
- snprintf(tag, sizeof(tag), "%c: Phase D", ch);
- printf("%c: Phase D handler on channel %c - (0x%X) %s\n", ch, ch, result, t30_frametype(result));
- fax_log_page_transfer_statistics(s, tag);
- fax_log_tx_parameters(s, tag);
- fax_log_rx_parameters(s, tag);
-
- if (use_receiver_not_ready)
- t30_set_receiver_not_ready(s, 3);
-
- if (test_local_interrupt)
- {
- if (i == 0)
- {
- printf("%c: Initiating interrupt request\n", ch);
- t30_local_interrupt_request(s, true);
- }
- else
- {
- switch (result)
- {
- case T30_PIP:
- case T30_PRI_MPS:
- case T30_PRI_EOM:
- case T30_PRI_EOP:
- printf("%c: Accepting interrupt request\n", ch);
- t30_local_interrupt_request(s, true);
- break;
- case T30_PIN:
- break;
- }
- }
- }
- return T30_ERR_OK;
-}
-/*- End of function --------------------------------------------------------*/
-
-static void phase_e_handler(void *user_data, int result)
-{
- int ch;
- t30_state_t *s;
- char tag[20];
-
- ch = 'A';
- s = (t30_state_t *) user_data;
- snprintf(tag, sizeof(tag), "%c: Phase E", ch);
- printf("%c: Phase E handler on channel %c - (%d) %s\n", ch, ch, result, t30_completion_code_to_str(result));
- fax_log_final_transfer_statistics(s, tag);
- fax_log_tx_parameters(s, tag);
- fax_log_rx_parameters(s, tag);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void t30_real_time_frame_handler(void *user_data,
- bool incoming,
- const uint8_t *msg,
- int len)
-{
- if (msg == NULL)
- {
- }
- else
- {
- fprintf(stderr,
- "T.30: Real time frame handler - %s, %s, length = %d\n",
- (incoming) ? "line->T.30" : "T.30->line",
- t30_frametype(msg[2]),
- len);
- }
-}
-/*- End of function --------------------------------------------------------*/
-
-static int document_handler(void *user_data, int event)
-{
- int ch;
- t30_state_t *s;
-
- ch = 'A';
- s = (t30_state_t *) user_data;
- fprintf(stderr, "%c: Document handler on channel %c - event %d\n", ch, ch, event);
- if (next_tx_file[0])
- {
- t30_set_tx_file(s, next_tx_file, -1, -1);
- next_tx_file[0] = '\0';
- return true;
- }
- return false;
-}
-/*- End of function --------------------------------------------------------*/
-
-static void faxtester_real_time_frame_handler(faxtester_state_t *s,
- void *user_data,
- int direction,
- const uint8_t *msg,
- int len)
-{
- if (msg == NULL)
- {
- while (next_step(s) == 0)
- ;
- /*endwhile*/
- }
- else
- {
- fprintf(stderr,
- "TST: Real time frame handler - %s, %s, length = %d\n",
- (direction) ? "line->tester" : "tester->line",
- t30_frametype(msg[2]),
- len);
- if (direction && msg[1] == awaited[1])
- {
- if ((awaited_len >= 0 && len != abs(awaited_len))
- ||
- (awaited_len < 0 && len < abs(awaited_len))
- ||
- memcmp(msg, awaited, abs(awaited_len)) != 0)
- {
- span_log_buf(&s->logging, SPAN_LOG_FLOW, "Expected", awaited, abs(awaited_len));
- span_log_buf(&s->logging, SPAN_LOG_FLOW, "Received", msg, len);
- printf("Test failed\n");
- exit(2);
- }
- }
- if (msg[1] == awaited[1])
- {
- while (next_step(s) == 0)
- ;
- /*endwhile*/
- }
- }
-}
-/*- End of function --------------------------------------------------------*/
-
-static void faxtester_front_end_step_complete_handler(faxtester_state_t *s, void *user_data)
-{
- while (next_step(s) == 0)
- ;
- /*endwhile*/
-}
-/*- End of function --------------------------------------------------------*/
-
-static void faxtester_front_end_step_timeout_handler(faxtester_state_t *s, void *user_data)
-{
- span_log(&s->logging, SPAN_LOG_FLOW, "FAX tester step timed out\n");
- printf("Test failed\n");
- exit(2);
-}
-/*- End of function --------------------------------------------------------*/
-
-static void fax_prepare(void)
-{
- t30_state_t *t30;
- logging_state_t *logging;
-
- t30 = fax_get_t30_state(fax);
- fax_set_transmit_on_idle(fax, true);
- fax_set_tep_mode(fax, true);
-#if 0
- t30_set_tx_ident(t30, "1234567890");
- t30_set_tx_sub_address(t30, "Sub-address");
- t30_set_tx_sender_ident(t30, "Sender ID");
- t30_set_tx_password(t30, "Password");
- t30_set_tx_polled_sub_address(t30, "Polled sub-address");
- t30_set_tx_selective_polling_address(t30, "Sel polling address");
-#endif
- t30_set_tx_nsf(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSF\x00", 16);
- //t30_set_tx_nss(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSS\x00", 16);
- t30_set_tx_nsc(t30, (const uint8_t *) "\x50\x00\x00\x00Spandsp NSC\x00", 16);
- t30_set_ecm_capability(t30, true);
- t30_set_supported_t30_features(t30,
- T30_SUPPORT_IDENTIFICATION
- | T30_SUPPORT_SELECTIVE_POLLING
- | T30_SUPPORT_SUB_ADDRESSING);
- t30_set_supported_image_sizes(t30,
- T4_SUPPORT_WIDTH_215MM
- | T4_SUPPORT_WIDTH_255MM
- | T4_SUPPORT_WIDTH_303MM
- | T4_SUPPORT_LENGTH_US_LETTER
- | T4_SUPPORT_LENGTH_US_LEGAL
- | T4_SUPPORT_LENGTH_UNLIMITED);
- t30_set_supported_bilevel_resolutions(t30,
- T4_RESOLUTION_R8_STANDARD
- | T4_RESOLUTION_R8_FINE
- | T4_RESOLUTION_R8_SUPERFINE
- | T4_RESOLUTION_R16_SUPERFINE
- | T4_RESOLUTION_100_100
- | T4_RESOLUTION_200_100
- | T4_RESOLUTION_200_200
- | T4_RESOLUTION_200_400
- | T4_RESOLUTION_300_300
- | T4_RESOLUTION_300_600
- | T4_RESOLUTION_400_400
- | T4_RESOLUTION_400_800
- | T4_RESOLUTION_600_600
- | T4_RESOLUTION_600_1200
- | T4_RESOLUTION_1200_1200);
- t30_set_supported_colour_resolutions(t30, 0);
- t30_set_supported_modems(t30, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
- t30_set_supported_compressions(t30, T4_COMPRESSION_T4_1D | T4_COMPRESSION_T4_2D | T4_COMPRESSION_T6);
- t30_set_phase_b_handler(t30, phase_b_handler, (void *) t30);
- t30_set_phase_d_handler(t30, phase_d_handler, (void *) t30);
- t30_set_phase_e_handler(t30, phase_e_handler, (void *) t30);
- t30_set_real_time_frame_handler(t30, t30_real_time_frame_handler, (void *) t30);
- t30_set_document_handler(t30, document_handler, (void *) t30);
-
- logging = fax_get_logging_state(fax);
- span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
- span_log_set_tag(logging, "A");
-
- logging = t30_get_logging_state(t30);
- span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
- span_log_set_tag(logging, "A");
-
-#if 0
- span_log_set_level(&fax.modems.v27ter_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
- span_log_set_tag(&fax.modems.v27ter_rx.logging, "A");
- span_log_set_level(&fax.modems.v29_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
- span_log_set_tag(&fax.modems.v29_rx.logging, "A");
- span_log_set_level(&fax.modems.v17_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
- span_log_set_tag(&fax.modems.v17_rx.logging, "A");
-#endif
-}
-/*- End of function --------------------------------------------------------*/
-
-static int string_to_msg(uint8_t msg[], uint8_t mask[], const char buf[])
-{
- int i;
- int x;
- const char *t;
-
- msg[0] = 0;
- mask[0] = 0xFF;
- i = 0;
- t = (char *) buf;
- while (*t)
- {
- /* Skip white space */
- while (isspace((int) *t))
- t++;
- /* If we find ... we allow arbitrary addition info beyond this point in the message */
- if (t[0] == '.' && t[1] == '.' && t[2] == '.')
- {
- return -i;
- }
- else if (isxdigit((int) *t))
- {
- for ( ; isxdigit((int) *t); t++)
- {
- x = *t;
- if (x >= 'a')
- x -= 0x20;
- if (x >= 'A')
- x -= ('A' - 10);
- else
- x -= '0';
- msg[i] = (msg[i] << 4) | x;
- }
- mask[i] = 0xFF;
- if (*t == '/')
- {
- /* There is a mask following the byte */
- mask[i] = 0;
- for (t++; isxdigit((int) *t); t++)
- {
- x = *t;
- if (x >= 'a')
- x -= 0x20;
- if (x >= 'A')
- x -= ('A' - 10);
- else
- x -= '0';
- mask[i] = (mask[i] << 4) | x;
- }
- }
- if (*t && !isspace((int) *t))
- {
- /* Bad string */
- return 0;
- }
- i++;
- }
- }
- return i;
-}
-/*- End of function --------------------------------------------------------*/
-
-#if 0
-static void string_test2(const uint8_t msg[], int len)
-{
- int i;
-
- if (len > 0)
- {
- for (i = 0; i < len - 1; i++)
- printf("%02X ", msg[i]);
- printf("%02X", msg[i]);
- }
-}
-/*- End of function --------------------------------------------------------*/
-
-static void string_test3(const char buf[])
-{
- uint8_t msg[1000];
- uint8_t mask[1000];
- int len;
- int i;
-
- len = string_to_msg(msg, mask, buf);
- printf("Len = %d: ", len);
- string_test2(msg, abs(len));
- printf("/");
- string_test2(mask, abs(len));
- printf("\n");
-}
-/*- End of function --------------------------------------------------------*/
-
-static int string_test(void)
-{
- string_test3("FF C8 12 34 56 78");
- string_test3("FF C8 12/55 34 56/aA 78 ");
- string_test3("FF C8 12/55 34 56/aA 78 ...");
- string_test3("FF C8 12/55 34 56/aA 78...");
- string_test3("FF C8 12/55 34 56/aA 78 ... 99 88 77");
- exit(0);
-}
-/*- End of function --------------------------------------------------------*/
-#endif
-
-static void corrupt_image(faxtester_state_t *s, uint8_t image[], int len, const char *bad_rows)
-{
- int i;
- int j;
- int k;
- uint32_t bits;
- uint32_t bitsx;
- int list[1000];
- int x;
- int row;
- const char *t;
-
- /* Form the list of rows to be hit */
- x = 0;
- t = bad_rows;
- while (*t)
- {
- while (isspace((int) *t))
- t++;
- if (sscanf(t, "%d", &list[x]) < 1)
- break;
- x++;
- while (isdigit((int) *t))
- t++;
- if (*t == ',')
- t++;
- }
-
- /* Go through the image, and corrupt the first bit of every listed row */
- bits = 0x7FF;
- bitsx = 0x7FF;
- row = 0;
- for (i = 0; i < len; i++)
- {
- bits ^= (image[i] << 11);
- bitsx ^= (image[i] << 11);
- for (j = 0; j < 8; j++)
- {
- if ((bits & 0xFFF) == 0x800)
- {
- /* We are at an EOL. Is this row in the list of rows to be corrupted? */
- row++;
- for (k = 0; k < x; k++)
- {
- if (list[k] == row)
- {
- /* Corrupt this row. TSB85 says to hit the first bit after the EOL */
- bitsx ^= 0x1000;
- }
- }
- }
- bits >>= 1;
- bitsx >>= 1;
- }
- image[i] = (bitsx >> 3) & 0xFF;
- }
- span_log(&s->logging, SPAN_LOG_FLOW, "%d rows found. %d corrupted\n", row, x);
-}
-/*- End of function --------------------------------------------------------*/
-
-static int next_step(faxtester_state_t *s)
-{
- int delay;
- int flags;
- xmlChar *dir;
- xmlChar *type;
- xmlChar *modem;
- xmlChar *value;
- xmlChar *tag;
- xmlChar *bad_rows;
- xmlChar *crc_error;
- xmlChar *pattern;
- xmlChar *timein;
- xmlChar *timeout;
- xmlChar *min_bits;
- xmlChar *frame_size;
- xmlChar *block;
- xmlChar *compression;
- uint8_t buf[1000];
- uint8_t mask[1000];
- char path[1024];
- int i;
- int j;
- int hdlc;
- int short_train;
- int min_row_bits;
- int ecm_frame_size;
- int ecm_block;
- int compression_type;
- int len;
- t4_tx_state_t t4_tx_state;
- t30_state_t *t30;
- t30_stats_t t30_stats;
-
- test_for_call_clear = false;
- if (s->cur == NULL)
- {
- if (!s->final_delayed)
- {
- /* Add a bit of waiting at the end, to ensure everything gets flushed through,
- any timers can expire, etc. */
- faxtester_set_timeout(s, -1);
- faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
- faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, 120000, false);
- s->final_delayed = true;
- return 1;
- }
- /* Finished */
- printf("Test passed\n");
- exit(0);
- }
- while (s->cur && xmlStrcmp(s->cur->name, (const xmlChar *) "step") != 0)
- s->cur = s->cur->next;
- if (s->cur == NULL)
- {
- /* Finished */
- printf("Test passed\n");
- exit(0);
- }
-
- dir = xmlGetProp(s->cur, (const xmlChar *) "dir");
- type = xmlGetProp(s->cur, (const xmlChar *) "type");
- modem = xmlGetProp(s->cur, (const xmlChar *) "modem");
- value = xmlGetProp(s->cur, (const xmlChar *) "value");
- tag = xmlGetProp(s->cur, (const xmlChar *) "tag");
- bad_rows = xmlGetProp(s->cur, (const xmlChar *) "bad_rows");
- crc_error = xmlGetProp(s->cur, (const xmlChar *) "crc_error");
- pattern = xmlGetProp(s->cur, (const xmlChar *) "pattern");
- timein = xmlGetProp(s->cur, (const xmlChar *) "timein");
- timeout = xmlGetProp(s->cur, (const xmlChar *) "timeout");
- min_bits = xmlGetProp(s->cur, (const xmlChar *) "min_bits");
- frame_size = xmlGetProp(s->cur, (const xmlChar *) "frame_size");
- block = xmlGetProp(s->cur, (const xmlChar *) "block");
- compression = xmlGetProp(s->cur, (const xmlChar *) "compression");
-
- s->cur = s->cur->next;
-
- span_log(&s->logging,
- SPAN_LOG_FLOW,
- "Dir - %s, type - %s, modem - %s, value - %s, timein - %s, timeout - %s, tag - %s\n",
- (dir) ? (const char *) dir : "",
- (type) ? (const char *) type : "",
- (modem) ? (const char *) modem : "",
- (value) ? (const char *) value : "",
- (timein) ? (const char *) timein : "",
- (timeout) ? (const char *) timeout : "",
- (tag) ? (const char *) tag : "");
- if (type == NULL)
- return 1;
- if (timein)
- timein_x = atoi((const char *) timein);
- else
- timein_x = -1;
- if (timeout)
- timeout_x = atoi((const char *) timeout);
- else
- timeout_x = -1;
-
- if (dir && strcasecmp((const char *) dir, "R") == 0)
- {
- /* Receive always has a timeout applied. */
- if (timeout_x < 0)
- timeout_x = 7000;
- faxtester_set_timeout(s, timeout_x);
- if (modem)
- {
- hdlc = (strcasecmp((const char *) type, "PREAMBLE") == 0);
- short_train = (strcasecmp((const char *) type, "TCF") != 0);
- faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
- if (strcasecmp((const char *) modem, "V.21") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V21, 300, false, true);
- }
- else if (strcasecmp((const char *) modem, "V.17/14400") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V17, 14400, short_train, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.17/12000") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V17, 12000, short_train, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.17/9600") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V17, 9600, short_train, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.17/7200") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V17, 7200, short_train, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.29/9600") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V29, 9600, false, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.29/7200") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V29, 7200, false, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.27ter/4800") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V27TER, 4800, false, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.27ter/2400") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_V27TER, 2400, false, hdlc);
- }
- else
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n");
- }
- }
-
- if (strcasecmp((const char *) type, "SET") == 0)
- {
- if (strcasecmp((const char *) tag, "IDENT") == 0)
- strcpy(expected_rx_info.ident, (const char *) value);
- else if (strcasecmp((const char *) tag, "SUB") == 0)
- strcpy(expected_rx_info.sub_address, (const char *) value);
- else if (strcasecmp((const char *) tag, "SEP") == 0)
- strcpy(expected_rx_info.selective_polling_address, (const char *) value);
- else if (strcasecmp((const char *) tag, "PSA") == 0)
- strcpy(expected_rx_info.polled_sub_address, (const char *) value);
- else if (strcasecmp((const char *) tag, "SID") == 0)
- strcpy(expected_rx_info.sender_ident, (const char *) value);
- else if (strcasecmp((const char *) tag, "PWD") == 0)
- strcpy(expected_rx_info.password, (const char *) value);
- return 0;
- }
- else if (strcasecmp((const char *) type, "CNG") == 0)
- {
- /* Look for CNG */
- faxtester_set_rx_type(s, T30_MODEM_CNG, 0, false, false);
- faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
- }
- else if (strcasecmp((const char *) type, "CED") == 0)
- {
- /* Look for CED */
- faxtester_set_rx_type(s, T30_MODEM_CED, 0, false, false);
- faxtester_set_tx_type(s, T30_MODEM_NONE, 0, false, false);
- }
- else if (strcasecmp((const char *) type, "HDLC") == 0)
- {
- i = string_to_msg(buf, mask, (const char *) value);
- bit_reverse(awaited, buf, abs(i));
- awaited_len = i;
- }
- else if (strcasecmp((const char *) type, "TCF") == 0)
- {
- }
- else if (strcasecmp((const char *) type, "MSG") == 0)
- {
- }
- else if (strcasecmp((const char *) type, "PP") == 0)
- {
- }
- else if (strcasecmp((const char *) type, "SILENCE") == 0)
- {
- faxtest_set_rx_silence(s);
- }
- else if (strcasecmp((const char *) type, "CLEAR") == 0)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Far end should drop the call\n");
- test_for_call_clear = true;
- call_clear_timer = 0;
- }
- else
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) type);
- return 0;
- }
- }
- else
- {
- faxtester_set_timeout(s, timeout_x);
- if (modem)
- {
- hdlc = (strcasecmp((const char *) type, "PREAMBLE") == 0);
- short_train = (strcasecmp((const char *) type, "TCF") != 0);
- faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
- if (strcasecmp((const char *) modem, "V.21") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V21, 300, false, true);
- }
- else if (strcasecmp((const char *) modem, "V.17/14400") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V17, 14400, short_train, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.17/12000") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V17, 12000, short_train, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.17/9600") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V17, 9600, short_train, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.17/7200") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V17, 7200, short_train, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.29/9600") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V29, 9600, false, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.29/7200") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V29, 7200, false, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.27ter/4800") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V27TER, 4800, false, hdlc);
- }
- else if (strcasecmp((const char *) modem, "V.27ter/2400") == 0)
- {
- faxtester_set_tx_type(s, T30_MODEM_V27TER, 2400, false, hdlc);
- }
- else
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised modem\n");
- }
- }
-
- if (strcasecmp((const char *) type, "SET") == 0)
- {
- t30 = fax_get_t30_state(fax);
- if (strcasecmp((const char *) tag, "IDENT") == 0)
- t30_set_tx_ident(t30, (const char *) value);
- else if (strcasecmp((const char *) tag, "SUB") == 0)
- t30_set_tx_sub_address(t30, (const char *) value);
- else if (strcasecmp((const char *) tag, "SEP") == 0)
- t30_set_tx_selective_polling_address(t30, (const char *) value);
- else if (strcasecmp((const char *) tag, "PSA") == 0)
- t30_set_tx_polled_sub_address(t30, (const char *) value);
- else if (strcasecmp((const char *) tag, "SID") == 0)
- t30_set_tx_sender_ident(t30, (const char *) value);
- else if (strcasecmp((const char *) tag, "PWD") == 0)
- t30_set_tx_password(t30, (const char *) value);
- else if (strcasecmp((const char *) tag, "RXFILE") == 0)
- {
- if (value)
- t30_set_rx_file(t30, (const char *) value, -1);
- else
- t30_set_rx_file(t30, output_tiff_file_name, -1);
- }
- else if (strcasecmp((const char *) tag, "TXFILE") == 0)
- {
- sprintf(next_tx_file, "%s/%s", image_path, (const char *) value);
- printf("Push '%s'\n", next_tx_file);
- }
- return 0;
- }
- else if (strcasecmp((const char *) type, "CALL") == 0)
- {
- fax = fax_init(NULL, false);
- fax_prepare();
- next_tx_file[0] = '\0';
- t30 = fax_get_t30_state(fax);
- t30_set_rx_file(t30, output_tiff_file_name, -1);
- /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
- t30_set_supported_output_compressions(t30, T4_COMPRESSION_T4_1D);
- if (value)
- {
- sprintf(path, "%s/%s", image_path, (const char *) value);
- t30_set_tx_file(t30, path, -1, -1);
- }
- return 0;
- }
- else if (strcasecmp((const char *) type, "ANSWER") == 0)
- {
- fax = fax_init(NULL, true);
- fax_prepare();
- next_tx_file[0] = '\0';
- t30 = fax_get_t30_state(fax);
- /* Avoid libtiff 3.8.2 and earlier bug on complex 2D lines. */
- t30_set_supported_output_compressions(t30, T4_COMPRESSION_T4_1D);
- if (value)
- {
- sprintf(path, "%s/%s", image_path, (const char *) value);
- t30_set_tx_file(t30, path, -1, -1);
- }
- return 0;
- }
- else if (strcasecmp((const char *) type, "CNG") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
- faxtester_set_tx_type(s, T30_MODEM_CNG, 0, false, false);
- }
- else if (strcasecmp((const char *) type, "CED") == 0)
- {
- faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
- faxtester_set_tx_type(s, T30_MODEM_CED, 0, false, false);
- }
- else if (strcasecmp((const char *) type, "WAIT") == 0)
- {
- delay = (value) ? atoi((const char *) value) : 1;
- faxtester_set_rx_type(s, T30_MODEM_NONE, 0, false, false);
- faxtester_set_tx_type(s, T30_MODEM_PAUSE, 0, delay, false);
- }
- else if (strcasecmp((const char *) type, "PREAMBLE") == 0)
- {
- flags = (value) ? atoi((const char *) value) : 37;
- faxtester_send_hdlc_flags(s, flags);
- }
- else if (strcasecmp((const char *) type, "POSTAMBLE") == 0)
- {
- flags = (value) ? atoi((const char *) value) : 5;
- faxtester_send_hdlc_flags(s, flags);
- }
- else if (strcasecmp((const char *) type, "HDLC") == 0)
- {
- i = string_to_msg(buf, mask, (const char *) value);
- bit_reverse(buf, buf, abs(i));
- if (crc_error && strcasecmp((const char *) crc_error, "0") == 0)
- faxtester_send_hdlc_msg(s, buf, abs(i), false);
- else
- faxtester_send_hdlc_msg(s, buf, abs(i), true);
- }
- else if (strcasecmp((const char *) type, "TCF") == 0)
- {
- if (value)
- i = atoi((const char *) value);
- else
- i = 450;
- if (pattern)
- {
- /* TODO: implement proper patterns */
- j = atoi((const char *) pattern);
- memset(image, 0x55, j);
- if (i > j)
- memset(image + j, 0, i - j);
- }
- else
- {
- memset(image, 0, i);
- }
- faxtester_set_non_ecm_image_buffer(s, image, i);
- }
- else if (strcasecmp((const char *) type, "MSG") == 0)
- {
- /* A non-ECM page */
- min_row_bits = (min_bits) ? atoi((const char *) min_bits) : 0;
- sprintf(path, "%s/%s", image_path, (const char *) value);
- if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n");
- printf("Test failed\n");
- exit(2);
- }
- t4_tx_set_header_info(&t4_tx_state, NULL);
- compression_type = T4_COMPRESSION_T4_1D;
- if (compression)
- {
- if (strcasecmp((const char *) compression, "T.4 2D") == 0)
- compression_type = T4_COMPRESSION_T4_2D;
- else if (strcasecmp((const char *) compression, "T.6") == 0)
- compression_type = T4_COMPRESSION_T6;
- }
- if (t4_tx_set_tx_image_format(&t4_tx_state,
- compression_type,
- T4_SUPPORT_WIDTH_215MM
- | T4_SUPPORT_LENGTH_US_LETTER
- | T4_SUPPORT_LENGTH_US_LEGAL
- | T4_SUPPORT_LENGTH_UNLIMITED,
- T4_RESOLUTION_R8_STANDARD
- | T4_RESOLUTION_R8_FINE
- | T4_RESOLUTION_R8_SUPERFINE
- | T4_RESOLUTION_R16_SUPERFINE
- | T4_RESOLUTION_200_100
- | T4_RESOLUTION_200_200
- | T4_RESOLUTION_200_400
- | T4_RESOLUTION_300_300
- | T4_RESOLUTION_300_600
- | T4_RESOLUTION_400_400
- | T4_RESOLUTION_400_800
- | T4_RESOLUTION_600_600
- | T4_RESOLUTION_600_1200
- | T4_RESOLUTION_1200_1200,
- T4_RESOLUTION_100_100
- | T4_RESOLUTION_200_200
- | T4_RESOLUTION_300_300
- | T4_RESOLUTION_400_400
- | T4_RESOLUTION_600_600
- | T4_RESOLUTION_1200_1200) < 0)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n");
- printf("Test failed\n");
- exit(2);
- }
- t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits);
- if (t4_tx_start_page(&t4_tx_state))
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n");
- printf("Test failed\n");
- exit(2);
- }
- len = t4_tx_get(&t4_tx_state, image, sizeof(image));
- if (bad_rows)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n");
- corrupt_image(s, image, len, (const char *) bad_rows);
- }
- t4_tx_release(&t4_tx_state);
- span_log(&s->logging, SPAN_LOG_FLOW, "Non-ECM image is %d bytes (min row bits %d)\n", len, min_row_bits);
- faxtester_set_non_ecm_image_buffer(s, image, len);
- }
- else if (strcasecmp((const char *) type, "PP") == 0)
- {
- min_row_bits = (min_bits) ? atoi((const char *) min_bits) : 0;
- ecm_block = (block) ? atoi((const char *) block) : 0;
- ecm_frame_size = (frame_size) ? atoi((const char *) frame_size) : 64;
- i = (crc_error) ? atoi((const char *) crc_error) : -1;
- sprintf(path, "%s/%s", image_path, (const char *) value);
- if (t4_tx_init(&t4_tx_state, path, -1, -1) == NULL)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Failed to init T.4 send\n");
- printf("Test failed\n");
- exit(2);
- }
- t4_tx_set_header_info(&t4_tx_state, NULL);
- compression_type = T4_COMPRESSION_T4_1D;
- if (compression)
- {
- if (strcasecmp((const char *) compression, "T.4 2D") == 0)
- compression_type = T4_COMPRESSION_T4_2D;
- else if (strcasecmp((const char *) compression, "T.6") == 0)
- compression_type = T4_COMPRESSION_T6;
- }
- if (t4_tx_set_tx_image_format(&t4_tx_state,
- compression_type,
- T4_SUPPORT_WIDTH_215MM
- | T4_SUPPORT_LENGTH_US_LETTER
- | T4_SUPPORT_LENGTH_US_LEGAL
- | T4_SUPPORT_LENGTH_UNLIMITED,
- T4_RESOLUTION_R8_STANDARD
- | T4_RESOLUTION_R8_FINE
- | T4_RESOLUTION_R8_SUPERFINE
- | T4_RESOLUTION_R16_SUPERFINE
- | T4_RESOLUTION_200_100
- | T4_RESOLUTION_200_200
- | T4_RESOLUTION_200_400
- | T4_RESOLUTION_300_300
- | T4_RESOLUTION_300_600
- | T4_RESOLUTION_400_400
- | T4_RESOLUTION_400_800
- | T4_RESOLUTION_600_600
- | T4_RESOLUTION_600_1200
- | T4_RESOLUTION_1200_1200,
- T4_RESOLUTION_100_100
- | T4_RESOLUTION_200_200
- | T4_RESOLUTION_300_300
- | T4_RESOLUTION_400_400
- | T4_RESOLUTION_600_600
- | T4_RESOLUTION_1200_1200) < 0)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Failed to set T.4 compression\n");
- printf("Test failed\n");
- exit(2);
- }
- t4_tx_set_min_bits_per_row(&t4_tx_state, min_row_bits);
- if (t4_tx_start_page(&t4_tx_state))
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Failed to start T.4 send\n");
- printf("Test failed\n");
- exit(2);
- }
- /*endif*/
- len = t4_tx_get(&t4_tx_state, image, sizeof(image));
- if (bad_rows)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "We need to corrupt the image\n");
- corrupt_image(s, image, len, (const char *) bad_rows);
- }
- /*endif*/
- t4_tx_release(&t4_tx_state);
- span_log(&s->logging, SPAN_LOG_FLOW, "ECM image is %d bytes (min row bits %d)\n", len, min_row_bits);
- faxtester_set_ecm_image_buffer(s, image, len, ecm_block, ecm_frame_size, i);
- }
- else if (strcasecmp((const char *) type, "CLEAR") == 0)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Time to drop the call\n");
- t30 = fax_get_t30_state(fax);
- t30_terminate(t30);
- return 0;
- }
- else if (strcasecmp((const char *) type, "STATUS") == 0)
- {
- if (value)
- {
- for (i = 0; t30_status[i].code >= 0; i++)
- {
- if (strcmp(t30_status[i].tag, (const char *) value) == 0)
- break;
- }
- if (t30_status[i].code >= 0)
- delay = t30_status[i].code;
- else
- delay = atoi((const char *) value);
- t30 = fax_get_t30_state(fax);
- t30_get_transfer_statistics(t30, &t30_stats);
- span_log(&s->logging, SPAN_LOG_FLOW, "Expect status %d. Got %d\n", delay, t30_stats.current_status);
- if (delay != t30_stats.current_status)
- {
- printf("Test failed\n");
- exit(2);
- }
- }
- return 0;
- }
- else
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) type);
- return 0;
- }
- /*endif*/
- }
- /*endif*/
- return 1;
-}
-/*- End of function --------------------------------------------------------*/
+faxtester_state_t *state;
static void exchange(faxtester_state_t *s)
{
@@ -1270,21 +102,37 @@ static void exchange(faxtester_state_t *s)
total_audio_time = 0;
- faxtester_set_transmit_on_idle(&state, true);
- faxtester_set_real_time_frame_handler(&state, faxtester_real_time_frame_handler, NULL);
- faxtester_set_front_end_step_complete_handler(&state, faxtester_front_end_step_complete_handler, NULL);
- faxtester_set_front_end_step_timeout_handler(&state, faxtester_front_end_step_timeout_handler, NULL);
+ faxtester_set_transmit_on_idle(s, true);
- fax = fax_init(NULL, false);
- fax_prepare();
- next_tx_file[0] = '\0';
+ s->far_fax = fax_init(NULL, false);
+ s->far_t30 = fax_get_t30_state(s->far_fax);
+ s->far_tag = 'A';
- while (next_step(s) == 0)
+ if (s->far_fax)
+ logging = fax_get_logging_state(s->far_fax);
+ else
+ logging = t38_terminal_get_logging_state(s->far_t38);
+ span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+ span_log_set_tag(logging, "A");
+
+ logging = t30_get_logging_state(s->far_t30);
+ span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+ span_log_set_tag(logging, "A");
+
+#if 0
+ span_log_set_level(&fax.modems.v27ter_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+ span_log_set_tag(&fax.modems.v27ter_rx.logging, "A");
+ span_log_set_level(&fax.modems.v29_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+ span_log_set_tag(&fax.modems.v29_rx.logging, "A");
+ span_log_set_level(&fax.modems.v17_rx.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+ span_log_set_tag(&fax.modems.v17_rx.logging, "A");
+#endif
+ while (faxtester_next_step(s) == 0)
;
/*endwhile*/
for (;;)
{
- len = fax_tx(fax, amp, SAMPLES_PER_CHUNK);
+ len = fax_tx(s->far_fax, amp, SAMPLES_PER_CHUNK);
faxtester_rx(s, amp, len);
if (log_audio)
{
@@ -1296,20 +144,21 @@ static void exchange(faxtester_state_t *s)
total_audio_time += SAMPLES_PER_CHUNK;
- logging = t30_get_logging_state(fax_get_t30_state(fax));
+ logging = t30_get_logging_state(s->far_t30);
span_log_bump_samples(logging, len);
#if 0
span_log_bump_samples(&fax.modems.v27ter_rx.logging, len);
span_log_bump_samples(&fax.modems.v29_rx.logging, len);
span_log_bump_samples(&fax.modems.v17_rx.logging, len);
#endif
- logging = fax_get_logging_state(fax);
+ logging = fax_get_logging_state(s->far_fax);
span_log_bump_samples(logging, len);
- span_log_bump_samples(&s->logging, len);
+ logging = faxtester_get_logging_state(s);
+ span_log_bump_samples(logging, len);
len = faxtester_tx(s, amp, SAMPLES_PER_CHUNK);
- if (fax_rx(fax, amp, len))
+ if (fax_rx(s->far_fax, amp, len))
break;
/*endif*/
if (log_audio)
@@ -1322,21 +171,21 @@ static void exchange(faxtester_state_t *s)
/*endif*/
}
/*endif*/
- if (test_for_call_clear && !far_end_cleared_call)
+ if (s->test_for_call_clear && !s->far_end_cleared_call)
{
- call_clear_timer += len;
- if (!t30_call_active(fax_get_t30_state(fax)))
+ s->call_clear_timer += len;
+ if (!t30_call_active(s->far_t30))
{
- span_log(&s->logging, SPAN_LOG_FLOW, "Far end cleared after %dms (limits %dms to %dms)\n", call_clear_timer/8, timein_x, timeout_x);
- if (call_clear_timer/8 < timein_x || call_clear_timer/8 > timeout_x)
+ span_log(faxtester_get_logging_state(s), SPAN_LOG_FLOW, "Far end cleared after %dms (limits %dms to %dms)\n", s->call_clear_timer/8, s->timein_x, s->timeout);
+ if (s->call_clear_timer/8 < s->timein_x || s->call_clear_timer/8 > s->timeout_x)
{
printf("Test failed\n");
exit(2);
}
- span_log(&s->logging, SPAN_LOG_FLOW, "Clear time OK\n");
- far_end_cleared_call = true;
- test_for_call_clear = false;
- while (next_step(s) == 0)
+ span_log(faxtester_get_logging_state(s), SPAN_LOG_FLOW, "Clear time OK\n");
+ s->far_end_cleared_call = true;
+ s->test_for_call_clear = false;
+ while (faxtester_next_step(s) == 0)
;
/*endwhile*/
}
@@ -1359,154 +208,11 @@ static void exchange(faxtester_state_t *s)
}
/*- End of function --------------------------------------------------------*/
-static int parse_config(faxtester_state_t *s, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur)
-{
- xmlChar *x;
- xmlChar *y;
-
- while (cur)
- {
- if (xmlStrcmp(cur->name, (const xmlChar *) "path") == 0)
- {
- if ((x = xmlGetProp(cur, (const xmlChar *) "type"))
- &&
- (y = xmlGetProp(cur, (const xmlChar *) "value")))
- {
- if (strcasecmp((const char *) x, "IMAGE") == 0)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s' '%s'\n", (char *) x, (char *) y);
- strcpy(image_path, (const char *) y);
- }
- /*endif*/
- }
- /*endif*/
- }
- /*endif*/
- cur = cur->next;
- }
- /*endwhile*/
- return -1;
-}
-/*- End of function --------------------------------------------------------*/
-
-static int parse_test_group(faxtester_state_t *s, xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur, const char *test)
-{
- xmlChar *x;
-
- while (cur)
- {
- if (xmlStrcmp(cur->name, (const xmlChar *) "test") == 0)
- {
- if ((x = xmlGetProp(cur, (const xmlChar *) "name")))
- {
- if (xmlStrcmp(x, (const xmlChar *) test) == 0)
- {
- span_log(&s->logging, SPAN_LOG_FLOW, "Found '%s'\n", (char *) x);
- s->cur = cur->xmlChildrenNode;
- return 0;
- }
- /*endif*/
- }
- /*endif*/
- }
- /*endif*/
- cur = cur->next;
- }
- /*endwhile*/
- return -1;
-}
-/*- End of function --------------------------------------------------------*/
-
-static int get_test_set(faxtester_state_t *s, const char *test_file, const char *test)
-{
- xmlParserCtxtPtr ctxt;
- xmlNsPtr ns;
- xmlNodePtr cur;
-
- ns = NULL;
- xmlKeepBlanksDefault(0);
- xmlCleanupParser();
-
- if ((ctxt = xmlNewParserCtxt()) == NULL)
- {
- fprintf(stderr, "Failed to allocate parser context\n");
- printf("Test failed\n");
- exit(2);
- }
- /* parse the file, activating the DTD validation option */
- if ((s->doc = xmlCtxtReadFile(ctxt, test_file, NULL, XML_PARSE_XINCLUDE | XML_PARSE_DTDVALID)) == NULL)
- {
- fprintf(stderr, "Failed to read the XML document\n");
- printf("Test failed\n");
- exit(2);
- }
- if (ctxt->valid == 0)
- {
- fprintf(stderr, "Failed to validate the XML document\n");
- xmlFreeDoc(s->doc);
- xmlFreeParserCtxt(ctxt);
- printf("Test failed\n");
- exit(2);
- }
- xmlFreeParserCtxt(ctxt);
-
- /* Check the document is of the right kind */
- if ((cur = xmlDocGetRootElement(s->doc)) == NULL)
- {
- xmlFreeDoc(s->doc);
- fprintf(stderr, "Empty document\n");
- printf("Test failed\n");
- exit(2);
- }
- /*endif*/
- if (xmlStrcmp(cur->name, (const xmlChar *) "fax-tests"))
- {
- xmlFreeDoc(s->doc);
- fprintf(stderr, "Document of the wrong type, root node != fax-tests");
- printf("Test failed\n");
- exit(2);
- }
- /*endif*/
- cur = cur->xmlChildrenNode;
- while (cur && xmlIsBlankNode(cur))
- cur = cur->next;
- /*endwhile*/
- if (cur == NULL)
- {
- printf("Test failed\n");
- exit(2);
- }
- /*endif*/
- while (cur)
- {
- if (xmlStrcmp(cur->name, (const xmlChar *) "config") == 0)
- {
- parse_config(s, s->doc, ns, cur->xmlChildrenNode);
- }
- /*endif*/
- if (xmlStrcmp(cur->name, (const xmlChar *) "test-group") == 0)
- {
- if (parse_test_group(s, s->doc, ns, cur->xmlChildrenNode, test) == 0)
- {
- /* We found the test we want, so run it. */
- exchange(s);
- break;
- }
- /*endif*/
- }
- /*endif*/
- cur = cur->next;
- }
- /*endwhile*/
- xmlFreeDoc(s->doc);
- return 0;
-}
-/*- End of function --------------------------------------------------------*/
-
int main(int argc, char *argv[])
{
const char *xml_file_name;
const char *test_name;
+ logging_state_t *logging;
int opt;
#if 0
@@ -1537,13 +243,18 @@ int main(int argc, char *argv[])
if (argc > 0)
test_name = argv[0];
- strcpy(image_path, ".");
- faxtester_init(&state, true);
- memset(&expected_rx_info, 0, sizeof(expected_rx_info));
- span_log_set_level(&state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
- span_log_set_tag(&state.logging, "B");
- get_test_set(&state, xml_file_name, test_name);
- faxtester_release(&state);
+ if ((state = faxtester_init(NULL, xml_file_name, test_name)) == NULL)
+ {
+ fprintf(stderr, "Cannot start FAX tester instance\n");
+ printf("Test failed\n");
+ exit(2);
+ }
+ logging = faxtester_get_logging_state(state);
+ span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
+ span_log_set_tag(logging, "B");
+ /* We found the test we want, so run it. */
+ exchange(state);
+ faxtester_free(state);
printf("Done\n");
return 0;
}
diff --git a/src/include/switch_core.h b/src/include/switch_core.h
index 75172cff6e..f6472be2f3 100644
--- a/src/include/switch_core.h
+++ b/src/include/switch_core.h
@@ -2243,6 +2243,12 @@ SWITCH_DECLARE(switch_core_flag_t) switch_core_flags(void);
*/
SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen);
+/*!
+ \brief Switch on the privilege awareness for the process and request required privileges
+ \return 0 on success
+*/
+
+SWITCH_DECLARE(int32_t) switch_core_set_process_privileges(void);
/*!
\brief Set the maximum priority the process can obtain
diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h
index 412cb63757..ca0c710273 100644
--- a/src/include/switch_ivr.h
+++ b/src/include/switch_ivr.h
@@ -122,6 +122,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_events(switch_core_session_
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_next_event(switch_core_session_t *session);
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_messages(switch_core_session_t *session);
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_signal_data(switch_core_session_t *session);
+SWITCH_DECLARE(switch_status_t) switch_ivr_parse_signal_data(switch_core_session_t *session, switch_bool_t all, switch_bool_t only_session_thread);
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_next_signal_data(switch_core_session_t *session);
SWITCH_DECLARE(switch_status_t) switch_ivr_process_indications(switch_core_session_t *session, switch_core_session_message_t *message);
diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h
index feb9337d54..1d31bc8b88 100644
--- a/src/include/switch_module_interfaces.h
+++ b/src/include/switch_module_interfaces.h
@@ -305,6 +305,12 @@ typedef enum {
SWITCH_VIDEO_ENCODE_SPEED_FAST
} switch_video_encode_speed_t;
+typedef enum {
+ SWITCH_VIDEO_PROFILE_BASELINE,
+ SWITCH_VIDEO_PROFILE_MAIN,
+ SWITCH_VIDEO_PROFILE_HIGH
+} switch_video_profile_t;
+
typedef struct switch_mm_s {
int samplerate;
int channels;
@@ -314,7 +320,9 @@ typedef struct switch_mm_s {
int vw;
int vh;
float fps;
+ float source_fps;
int vbuf;
+ switch_video_profile_t vprofile;
switch_video_encode_speed_t vencspd;
} switch_mm_t;
diff --git a/src/include/switch_types.h b/src/include/switch_types.h
index 126f722ce2..ef4b9eb077 100644
--- a/src/include/switch_types.h
+++ b/src/include/switch_types.h
@@ -1170,6 +1170,7 @@ typedef enum {
SWITCH_STATUS_CONTINUE,
SWITCH_STATUS_TERM,
SWITCH_STATUS_NOT_INITALIZED,
+ SWITCH_STATUS_TOO_LATE,
SWITCH_STATUS_XBREAK = 35,
SWITCH_STATUS_WINBREAK = 730035
} switch_status_t;
diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c
index 5d4a0e1a16..3589eb3389 100644
--- a/src/mod/applications/mod_av/avcodec.c
+++ b/src/mod/applications/mod_av/avcodec.c
@@ -866,7 +866,7 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt
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 = 30;
+ 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);
diff --git a/src/mod/applications/mod_av/avformat.c b/src/mod/applications/mod_av/avformat.c
index e3f4ed6cd2..3e60049915 100644
--- a/src/mod/applications/mod_av/avformat.c
+++ b/src/mod/applications/mod_av/avformat.c
@@ -41,7 +41,7 @@
#include
#define SCALE_FLAGS SWS_BICUBIC
-#define DFT_RECORD_OFFSET 350
+#define DFT_RECORD_OFFSET 0
static switch_status_t av_file_close(switch_file_handle_t *handle);
SWITCH_MODULE_LOAD_FUNCTION(mod_avformat_load);
@@ -139,7 +139,6 @@ typedef struct record_helper_s {
AVFormatContext *fc;
MediaStream *video_st;
switch_timer_t *timer;
- switch_timer_t *other_timer;
int in_callback;
switch_queue_t *video_queue;
switch_thread_t *video_thread;
@@ -259,11 +258,6 @@ static switch_status_t add_stream(MediaStream *mst, AVFormatContext *fc, AVCodec
c->channels = mst->channels;
c->channel_layout = av_get_default_channel_layout(c->channels);
- mst->st->time_base.den = 1000;
- mst->st->time_base.num = 1;
- c->time_base.den = 1000;
- c->time_base.num = 1;
-
if (mm) {
if (mm->ab) {
c->bit_rate = mm->ab * 1024;
@@ -312,18 +306,34 @@ static switch_status_t add_stream(MediaStream *mst, AVFormatContext *fc, AVCodec
if (codec_id == AV_CODEC_ID_H264) {
c->ticks_per_frame = 2;
+ switch (mm->vprofile) {
+ case SWITCH_VIDEO_PROFILE_BASELINE:
+ av_opt_set(c->priv_data, "profile", "baseline", 0);
+ c->level = 41;
+ break;
+ case SWITCH_VIDEO_PROFILE_MAIN:
+ av_opt_set(c->priv_data, "profile", "main", 0);
+ av_opt_set(c->priv_data, "level", "5", 0);
+ break;
+ case SWITCH_VIDEO_PROFILE_HIGH:
+ av_opt_set(c->priv_data, "profile", "high", 0);
+ av_opt_set(c->priv_data, "level", "52", 0);
+ break;
+ }
+
switch (mm->vencspd) {
- case SWITCH_VIDEO_ENCODE_SPEED_SLOW:
- av_opt_set(c->priv_data, "preset", "veryslow", 0);
- break;
- case SWITCH_VIDEO_ENCODE_SPEED_MEDIUM:
- av_opt_set(c->priv_data, "preset", "medium", 0);
- break;
- case SWITCH_VIDEO_ENCODE_SPEED_FAST:
- av_opt_set(c->priv_data, "preset", "ultrafast", 0);
- break;
- default:
- break;
+ case SWITCH_VIDEO_ENCODE_SPEED_SLOW:
+ av_opt_set(c->priv_data, "preset", "veryslow", 0);
+ break;
+ case SWITCH_VIDEO_ENCODE_SPEED_MEDIUM:
+ av_opt_set(c->priv_data, "preset", "medium", 0);
+ break;
+ case SWITCH_VIDEO_ENCODE_SPEED_FAST:
+ av_opt_set(c->priv_data, "preset", "veryfast", 0);
+ av_opt_set(c->priv_data, "tune", "zerolatency", 0);
+ break;
+ default:
+ break;
}
}
@@ -481,62 +491,86 @@ static switch_status_t open_audio(AVFormatContext *fc, AVCodec *codec, MediaStre
return SWITCH_STATUS_SUCCESS;
}
+static int flush_video_queue(switch_queue_t *q, int min)
+{
+ void *pop;
+
+ if (switch_queue_size(q) > min) {
+ while (switch_queue_trypop(q, &pop) == SWITCH_STATUS_SUCCESS) {
+ switch_image_t *img = (switch_image_t *) pop;
+ switch_img_free(&img);
+ if (min && switch_queue_size(q) <= min) {
+ break;
+ }
+ }
+ }
+
+ return switch_queue_size(q);
+}
+
static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *obj)
{
record_helper_t *eh = (record_helper_t *) obj;
- void *pop;
- switch_image_t *img, *last_img = NULL, *tmp_img = NULL;
- switch_size_t size;
+ void *pop = NULL;
+ switch_image_t *img = NULL, *tmp_img = NULL;
+ int d_w = 0, d_h = 0;
+ int size = 0, skip = 0, skip_freq = 0, skip_count = 0, skip_total = 0, skip_total_count = 0;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "video thread start\n");
for(;;) {
AVPacket pkt = { 0 };
int got_packet;
- int ret = -1, popped = 0;
+ int ret = -1;
- do {
- switch_status_t status;
- img = NULL;
-
- if (!popped) {
- status = switch_queue_pop(eh->video_queue, &pop);
- popped++;
- } else {
- status = switch_queue_trypop(eh->video_queue, &pop);
+ top:
+
+ if (switch_queue_pop(eh->video_queue, &pop) == SWITCH_STATUS_SUCCESS) {
+ switch_img_free(&img);
+
+ if (!pop) {
+ goto endfor;
}
-
- if (status == SWITCH_STATUS_SUCCESS) {
+ img = (switch_image_t *) pop;
+
+ if (!d_w) d_w = img->d_w;
+ if (!d_h) d_h = img->d_h;
+
+ if (d_w && d_h && (d_w != img->d_w || d_h != img->d_h)) {
+ /* scale to match established stream */
+ switch_img_scale(img, &tmp_img, d_w, d_h);
switch_img_free(&img);
-
- if (!pop) {
- goto endfor;
- }
- img = (switch_image_t *)pop;
- } else {
- if (img) {
- break;
+ img = tmp_img;
+ tmp_img = NULL;
+ }
+ } else {
+ continue;
+ }
+
+ if (skip) {
+ if ((skip_total_count > 0 && !--skip_total_count) || ++skip_count >= skip_freq) {
+ skip_total_count = skip_total;
+ skip_count = 0;
+ skip--;
+ goto top;
+ }
+ } else {
+
+ size = switch_queue_size(eh->video_queue);
+
+ if (size > 5) {
+ skip = size;
+
+ if (size > 10) {
+ skip_freq = 3;
+ skip_total = 1;
} else {
- popped = 0;
- continue;
+ skip_freq = 2;
+ skip_total = 1;
}
}
-
- size = switch_queue_size(eh->video_queue);
- } while(img && size > 1);
-
-
- if (last_img && (last_img->d_w != img->d_w || last_img->d_h != img->d_h)) {
- /* scale to match established stream */
- switch_img_scale(img, &tmp_img, last_img->d_w, last_img->d_h);
- switch_img_free(&img);
- img = tmp_img;
- tmp_img = NULL;
}
- switch_img_free(&last_img);
- last_img = img;
-
//switch_mutex_lock(eh->mutex);
eh->in_callback = 1;
@@ -552,14 +586,6 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
fill_avframe(eh->video_st->frame, img);
switch_core_timer_sync(eh->timer);
- if (eh->other_timer) {
- if (eh->timer->samplecount > eh->other_timer->samplecount) {
- int sleepfor = (eh->timer->samplecount - eh->other_timer->samplecount) * 1000;
- switch_yield(sleepfor);
- 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++;
@@ -590,8 +616,6 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
endfor:
- switch_img_free(&last_img);
-
while(switch_queue_trypop(eh->video_queue, &pop) == SWITCH_STATUS_SUCCESS) {
if (!pop) break;
img = (switch_image_t *) pop;
@@ -614,7 +638,7 @@ static switch_status_t video_read_callback(switch_core_session_t *session, switc
switch_queue_push(eh->video_queue, img);
}
- return SWITCH_STATUS_SUCCESS;;
+ return SWITCH_STATUS_SUCCESS;
}
static void close_stream(AVFormatContext *fc, MediaStream *mst)
@@ -1077,7 +1101,6 @@ struct av_file_context {
switch_buffer_t *buf;
switch_buffer_t *audio_buffer;
switch_timer_t video_timer;
- switch_timer_t audio_timer;
int offset;
int audio_start;
int vid_ready;
@@ -1097,6 +1120,7 @@ struct av_file_context {
int file_read_thread_running;
switch_time_t video_start_time;
switch_image_t *last_img;
+ int read_fps;
};
typedef struct av_file_context av_file_context_t;
@@ -1117,7 +1141,7 @@ static void mod_avformat_destroy_output_context(av_file_context_t *context)
static switch_status_t open_input_file(av_file_context_t *context, switch_file_handle_t *handle, const char *filename)
{
AVCodec *audio_codec = NULL;
- AVCodec *video_codec;
+ AVCodec *video_codec = NULL;
int error;
int i;
switch_status_t status = SWITCH_STATUS_SUCCESS;
@@ -1146,6 +1170,8 @@ static switch_status_t open_input_file(av_file_context_t *context, switch_file_h
if (switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO)) {
context->has_video = 1;
}
+ handle->mm.source_fps = ceil(av_q2d(context->video_st.st->avg_frame_rate));
+ context->read_fps = (int)handle->mm.source_fps;
}
}
@@ -1231,6 +1257,7 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
AVPacket pkt = { 0 };
int got_data = 0;
int error;
+ int sync = 0;
context->file_read_thread_running = 1;
@@ -1238,10 +1265,10 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
while (context->file_read_thread_running) {
if (switch_buffer_inuse(context->audio_buffer) > AUDIO_BUF_SEC * context->audio_st.sample_rate * context->audio_st.channels * 2) {
- switch_yield(100000);
+ switch_yield(10000);
continue;
}
-
+
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
@@ -1257,7 +1284,10 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
if (context->has_video && pkt.stream_index == context->video_st.st->index) {
AVFrame *vframe = av_frame_alloc();
switch_image_t *img;
-
+ if (!sync) {
+ switch_buffer_zero(context->audio_buffer);
+ sync = 1;
+ }
switch_assert(vframe);
if ((error = avcodec_decode_video2(context->video_st.st->codec, vframe, &got_data, &pkt)) < 0) {
@@ -1270,11 +1300,11 @@ static void *SWITCH_THREAD_FUNC file_read_thread_run(switch_thread_t *thread, vo
// 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);
- if (switch_queue_size(context->eh.video_queue) > 300) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Dropping frames\n");
- av_frame_free(&vframe);
- continue;
- }
+ //if (switch_queue_size(context->eh.video_queue) > 300) {
+ // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Dropping frames\n");
+ // av_frame_free(&vframe);
+ // continue;
+ //}
if (got_data && error > 0) {
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got picture %dx%d fmt: %d pktpts:%lld pktdts:%lld\n", vframe->width, vframe->height, vframe->format, vframe->pkt_pts, vframe->pkt_dts);
@@ -1508,6 +1538,8 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
handle->samplerate = 44100;
handle->mm.samplerate = 44100;
handle->mm.ab = 128;
+ //handle->mm.vencspd = SWITCH_VIDEO_ENCODE_SPEED_FAST;
+ handle->mm.vprofile = SWITCH_VIDEO_PROFILE_BASELINE;
if (!handle->mm.vb && handle->mm.vw && handle->mm.vh) {
switch(handle->mm.vh) {
@@ -1563,9 +1595,6 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
handle->pos = 0;
- switch_core_timer_init(&context->audio_timer, "soft", 1, 1, /*handle->samplerate / 1000,*/ context->pool);
- switch_core_timer_init(&context->video_timer, "soft", 1, 1, context->pool);
-
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening File [%s] %dhz %s\n",
file, handle->samplerate, switch_test_flag(handle, SWITCH_FILE_FLAG_VIDEO) ? " with VIDEO" : "");
@@ -1581,10 +1610,6 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
switch_core_timer_destroy(&context->video_timer);
}
- if (context->audio_timer.interval) {
- switch_core_timer_destroy(&context->audio_timer);
- }
-
if (context->audio_buffer) {
switch_buffer_destroy(&context->audio_buffer);
}
@@ -1597,19 +1622,104 @@ static switch_status_t av_file_truncate(switch_file_handle_t *handle, int64_t of
return SWITCH_STATUS_FALSE;
}
-static void flush_video_queue(switch_queue_t *q)
+
+static switch_status_t av_file_write(switch_file_handle_t *handle, void *data, size_t *len)
{
- void *pop;
- if (switch_queue_size(q) == 0) {
- return;
+ uint32_t datalen = 0;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ // uint8_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }, *bp = buf;
+ // uint32_t encoded_rate;
+ av_file_context_t *context = (av_file_context_t *)handle->private_info;
+ // uint32_t size = 0;
+ uint32_t bytes;
+ int inuse;
+
+ if (!context->vid_ready) {
+ return status;
}
- while (switch_queue_trypop(q, &pop) == SWITCH_STATUS_SUCCESS) {
- switch_image_t *img = (switch_image_t *) pop;
- switch_img_free(&img);
+ if (data && len) {
+ datalen = *len * 2 * handle->channels;
+
+ if (context->offset) {
+ char buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
+ switch_size_t samples = *len;
+ int fps = handle->samplerate / samples;
+ int lead_frames = (context->offset * fps) / 1000;
+
+ for (int x = 0; x < lead_frames; x++) {
+ switch_buffer_write(context->audio_buffer, buf, datalen);
+ }
+ context->offset = 0;
+ }
+
+ switch_buffer_write(context->audio_buffer, data, datalen);
+ }
+
+ bytes = context->audio_st.frame->nb_samples * 2 * context->audio_st.st->codec->channels;
+
+
+ //inuse = switch_buffer_inuse(context->audio_buffer);
+ //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "inuse: %d samples: %d bytes: %d\n", inuse, context->audio_st.frame->nb_samples, bytes);
+
+
+ while ((inuse = switch_buffer_inuse(context->audio_buffer)) >= bytes) {
+ AVPacket pkt = { 0 };
+ int got_packet = 0;
+ int ret;
+
+ av_init_packet(&pkt);
+
+ if (context->audio_st.resample_ctx) { // need resample
+ int out_samples = avresample_get_out_samples(context->audio_st.resample_ctx, context->audio_st.frame->nb_samples);
+
+ av_frame_make_writable(context->audio_st.frame);
+ av_frame_make_writable(context->audio_st.tmp_frame);
+ switch_buffer_read(context->audio_buffer, context->audio_st.frame->data[0], bytes);
+ /* convert to destination format */
+ ret = avresample_convert(context->audio_st.resample_ctx,
+ (uint8_t **)context->audio_st.frame->data, 0, out_samples,
+ context->audio_st.tmp_frame->data, 0, context->audio_st.frame->nb_samples);
+
+ if (ret < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error while converting %d samples, error text: %s\n",
+ context->audio_st.frame->nb_samples, get_error_text(ret));
+ continue;
+ }
+
+ context->audio_st.tmp_frame->pts = context->audio_st.next_pts;
+ context->audio_st.next_pts += context->audio_st.frame->nb_samples;
+ ret = avcodec_encode_audio2(context->audio_st.st->codec, &pkt, context->audio_st.tmp_frame, &got_packet);
+ } else {
+ av_frame_make_writable(context->audio_st.frame);
+ switch_buffer_read(context->audio_buffer, context->audio_st.frame->data[0], bytes);
+ context->audio_st.frame->pts = context->audio_st.next_pts;
+ context->audio_st.next_pts += context->audio_st.frame->nb_samples;
+
+ ret = avcodec_encode_audio2(context->audio_st.st->codec, &pkt, context->audio_st.frame, &got_packet);
+ }
+
+ if (ret < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Error encoding audio frame: %d\n", ret);
+ continue;
+ }
+
+ if (got_packet) {
+ if (context->mutex) switch_mutex_lock(context->mutex);
+ ret = write_frame(context->fc, &context->audio_st.st->codec->time_base, context->audio_st.st, &pkt);
+ if (context->mutex) switch_mutex_unlock(context->mutex);
+ if (ret < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error while writing audio frame: %s\n", get_error_text(ret));
+ //switch_goto_status(SWITCH_STATUS_FALSE, end);
+ }
+ }
+ if (data) {
+ break;
+ }
}
+ return status;
}
static switch_status_t av_file_close(switch_file_handle_t *handle)
@@ -1624,6 +1734,8 @@ static switch_status_t av_file_close(switch_file_handle_t *handle)
if (context->eh.video_thread) {
switch_thread_join(&status, context->eh.video_thread);
}
+
+ av_file_write(handle, NULL, NULL);
if (context->file_read_thread_running && context->file_read_thread) {
context->file_read_thread_running = 0;
@@ -1631,7 +1743,7 @@ static switch_status_t av_file_close(switch_file_handle_t *handle)
}
if (context->eh.video_queue) {
- flush_video_queue(context->eh.video_queue);
+ flush_video_queue(context->eh.video_queue, 0);
}
if (context->fc) {
@@ -1644,10 +1756,6 @@ static switch_status_t av_file_close(switch_file_handle_t *handle)
switch_core_timer_destroy(&context->video_timer);
}
- if (context->audio_timer.interval) {
- switch_core_timer_destroy(&context->audio_timer);
- }
-
switch_img_free(&context->last_img);
switch_buffer_destroy(&context->audio_buffer);
@@ -1701,103 +1809,6 @@ static switch_status_t av_file_read(switch_file_handle_t *handle, void *data, si
return *len == 0 ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS;
}
-static switch_status_t av_file_write(switch_file_handle_t *handle, void *data, size_t *len)
-{
-
- uint32_t datalen = *len * 2 * handle->channels;
- switch_status_t status = SWITCH_STATUS_SUCCESS;
- // uint8_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }, *bp = buf;
- // uint32_t encoded_rate;
- av_file_context_t *context = (av_file_context_t *)handle->private_info;
- // uint32_t size = 0;
- uint32_t bytes;
- int inuse;
-
- if (!context->vid_ready) {
- return status;
- }
-
- if (context->offset) {
- char buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
- switch_size_t samples = *len;
- int fps = handle->samplerate / samples;
- int lead_frames = (context->offset * fps) / 1000;
-
- for (int x = 0; x < lead_frames; x++) {
- switch_buffer_write(context->audio_buffer, buf, datalen);
- }
- context->offset = 0;
- }
-
- switch_buffer_write(context->audio_buffer, data, datalen);
- bytes = context->audio_st.frame->nb_samples * 2 * context->audio_st.st->codec->channels;
-
- //inuse = switch_buffer_inuse(context->audio_buffer);
- //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "inuse: %d samples: %d bytes: %d\n", inuse, context->audio_st.frame->nb_samples, bytes);
-
- while ((inuse = switch_buffer_inuse(context->audio_buffer)) >= bytes) {
- AVPacket pkt = { 0 };
- int got_packet = 0;
- int ret;
-
- av_init_packet(&pkt);
-
- if (context->audio_st.resample_ctx) { // need resample
- int out_samples = avresample_get_out_samples(context->audio_st.resample_ctx, context->audio_st.frame->nb_samples);
-
- av_frame_make_writable(context->audio_st.frame);
- av_frame_make_writable(context->audio_st.tmp_frame);
- switch_buffer_read(context->audio_buffer, context->audio_st.frame->data[0], bytes);
- /* convert to destination format */
- ret = avresample_convert(context->audio_st.resample_ctx,
- (uint8_t **)context->audio_st.frame->data, 0, out_samples,
- context->audio_st.tmp_frame->data, 0, context->audio_st.frame->nb_samples);
-
- if (ret < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error while converting %d samples, error text: %s\n",
- context->audio_st.frame->nb_samples, get_error_text(ret));
- continue;
- }
-
- context->audio_st.tmp_frame->pts = context->audio_st.next_pts;
- context->audio_st.next_pts += context->audio_st.frame->nb_samples;
- ret = avcodec_encode_audio2(context->audio_st.st->codec, &pkt, context->audio_st.tmp_frame, &got_packet);
- } else {
- av_frame_make_writable(context->audio_st.frame);
- switch_buffer_read(context->audio_buffer, context->audio_st.frame->data[0], bytes);
-
- switch_core_timer_sync(&context->audio_timer);
- context->audio_st.frame->pts = context->audio_timer.samplecount;
- //context->audio_st.frame->pts = context->audio_st.next_pts;
- //context->audio_st.next_pts += context->audio_st.frame->nb_samples;
-
- ret = avcodec_encode_audio2(context->audio_st.st->codec, &pkt, context->audio_st.frame, &got_packet);
- }
-
- if (ret < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Error encoding audio frame: %d\n", ret);
- continue;
- }
-
- if (got_packet) {
- if (context->mutex) switch_mutex_lock(context->mutex);
- ret = write_frame(context->fc, &context->audio_st.st->codec->time_base, context->audio_st.st, &pkt);
- if (context->mutex) switch_mutex_unlock(context->mutex);
- if (ret < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error while writing audio frame: %s\n", get_error_text(ret));
- switch_goto_status(SWITCH_STATUS_FALSE, end);
- }
- }
-
- break;
- }
-
-
-
-end:
- return status;
-}
-
static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_frame_t *frame, switch_video_read_flag_t flags)
{
av_file_context_t *context = (av_file_context_t *)handle->private_info;
@@ -1807,14 +1818,21 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
int ticks = 0;
int max_delta = 1 * AV_TIME_BASE; // 1 second
switch_status_t status = SWITCH_STATUS_SUCCESS;
-
+ double fl_to = 0.02;
+ int do_fl = 0;
+
if (!context->has_video) return SWITCH_STATUS_FALSE;
if ((flags & SVR_CHECK)) {
return SWITCH_STATUS_BREAK;
}
- if (flags & SVR_FLUSH) max_delta = 0.02 * AV_TIME_BASE;
+ fl_to = (1000 / context->read_fps) * 1000;
+ //printf("WTF %d (%f)\n",switch_queue_size(context->eh.video_queue), fl_to);
+ if (flags & SVR_FLUSH) {
+ max_delta = fl_to * AV_TIME_BASE;
+ do_fl = 1;
+ }
if (context->last_img) {
if (mst->next_pts && (switch_time_now() - mst->next_pts > max_delta)) {
@@ -1825,7 +1843,7 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
return SWITCH_STATUS_SUCCESS;
}
- if (!(flags & SVR_BLOCK)) return SWITCH_STATUS_BREAK;
+ if (!(flags & SVR_BLOCK) && !do_fl) return SWITCH_STATUS_BREAK;
}
if (!context->file_read_thread_running && switch_queue_size(context->eh.video_queue) == 0) {
@@ -1845,7 +1863,7 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
again:
- if (flags & SVR_BLOCK) {
+ if ((flags & SVR_BLOCK)) {
status = switch_queue_pop(context->eh.video_queue, &pop);
} else {
status = switch_queue_trypop(context->eh.video_queue, &pop);
@@ -1853,14 +1871,6 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
if (pop && status == SWITCH_STATUS_SUCCESS) {
switch_image_t *img = (switch_image_t *)pop;
-
- // #define YIELD 40000 // use a constant FPS
-#ifdef YIELD
- switch_yield(YIELD);
- frame->img = img;
- if (0) goto again;
-#else
-
uint64_t pts;
uint64_t now = switch_time_now();
@@ -1884,35 +1894,33 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
if ((mst->next_pts && switch_time_now() - mst->next_pts > max_delta)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG3, "picture is too late, off: %" SWITCH_INT64_T_FMT " queue size:%u\n", (int64_t)(switch_time_now() - mst->next_pts), switch_queue_size(context->eh.video_queue));
switch_img_free(&img);
-
+ max_delta = AV_TIME_BASE;
if (switch_queue_size(context->eh.video_queue) > 0) {
goto again;
- } else {
+ } else if (!(flags & SVR_BLOCK) && !do_fl) {
mst->next_pts = 0;
return SWITCH_STATUS_BREAK;
}
}
- if (flags & SVR_BLOCK) {
- while (switch_time_now() - mst->next_pts < -10000 / 2) {
- switch_cond_next();
+ if ((flags & SVR_BLOCK) || do_fl) {
+ while (switch_micro_time_now() - mst->next_pts < -10000 / 2) {
+ // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "yield\n");
+ switch_yield(10000);
}
frame->img = img;
+ do_fl = 0;
} else {
- if (switch_time_now() - mst->next_pts > -10000 / 2) {
+ if (switch_micro_time_now() - mst->next_pts > -10000 / 2) {
frame->img = img;
} else {
context->last_img = img;
return SWITCH_STATUS_BREAK;
}
}
-#endif
-
+
} else {
- if ((flags & SVR_BLOCK)) {
- switch_yield(10000);
- }
return SWITCH_STATUS_BREAK;
}
@@ -1965,13 +1973,16 @@ static switch_status_t av_file_write_video(switch_file_handle_t *handle, switch_
context->eh.fc = context->fc;
context->eh.mm = &handle->mm;
context->eh.timer = &context->video_timer;
- context->eh.other_timer = &context->audio_timer;
switch_queue_create(&context->eh.video_queue, SWITCH_CORE_QUEUE_LEN, handle->memory_pool);
switch_threadattr_create(&thd_attr, handle->memory_pool);
//switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&context->eh.video_thread, thd_attr, video_thread_run, &context->eh, handle->memory_pool);
+ switch_core_timer_init(&context->video_timer, "soft", 1, 1, context->pool);
+ switch_buffer_zero(context->audio_buffer);
+ context->audio_st.frame->pts = 0;
+ context->audio_st.next_pts = 0;
}
if (context->has_video) {
@@ -1987,6 +1998,7 @@ end:
return status;
}
+
static switch_status_t av_file_set_string(switch_file_handle_t *handle, switch_audio_col_t col, const char *string)
{
av_file_context_t *context = (av_file_context_t *)handle->private_info;
diff --git a/src/mod/applications/mod_conference/conference_file.c b/src/mod/applications/mod_conference/conference_file.c
index e720d46d8e..45a7913d3f 100644
--- a/src/mod/applications/mod_conference/conference_file.c
+++ b/src/mod/applications/mod_conference/conference_file.c
@@ -56,6 +56,11 @@ switch_status_t conference_file_close(conference_obj_t *conference, conference_f
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "milliseconds", "%ld", (long) node->fh.samples_in / (node->fh.native_rate / 1000));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "samples", "%ld", (long) node->fh.samples_in);
+ if (node->layer_id && node->layer_id > -1) {
+ if (node->canvas_id < 0) node->canvas_id = 0;
+ conference_video_canvas_del_fnode_layer(conference, node);
+ }
+
if (node->fh.params) {
switch_event_merge(event, node->fh.params);
}
@@ -86,11 +91,13 @@ switch_status_t conference_file_close(conference_obj_t *conference, conference_f
conference_al_close(node->al);
}
#endif
- if (switch_core_file_has_video(&node->fh) && conference->canvases[0] && node->canvas_id > -1) {
- conference->canvases[node->canvas_id]->timer.interval = conference->video_fps.ms;
- conference->canvases[node->canvas_id]->timer.samples = conference->video_fps.samples;
- switch_core_timer_sync(&conference->canvases[node->canvas_id]->timer);
- conference->canvases[node->canvas_id]->send_keyframe = 1;
+ if (conference->playing_video_file && switch_core_file_has_video(&node->fh) && conference->canvases[0] && node->canvas_id > -1) {
+ if (conference->canvases[node->canvas_id]->timer.timer_interface) {
+ conference->canvases[node->canvas_id]->timer.interval = conference->video_fps.ms;
+ conference->canvases[node->canvas_id]->timer.samples = conference->video_fps.samples;
+ switch_core_timer_sync(&conference->canvases[node->canvas_id]->timer);
+ conference->canvases[node->canvas_id]->send_keyframe = 1;
+ }
conference->playing_video_file = 0;
}
return switch_core_file_close(&node->fh);
@@ -239,6 +246,7 @@ switch_status_t conference_file_play(conference_obj_t *conference, char *file, u
/* Open the file */
fnode->fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
+ fnode->fh.mm.fps = conference->video_fps.fps;
if (switch_core_file_open(&fnode->fh, file, channels, conference->rate, flags, pool) != SWITCH_STATUS_SUCCESS) {
switch_event_t *event;
@@ -299,7 +307,7 @@ switch_status_t conference_file_play(conference_obj_t *conference, char *file, u
fnode->file = switch_core_strdup(fnode->pool, file);
if (!conference->fnode || (async && !conference->async_fnode)) {
- conference_video_fnode_check(fnode);
+ conference_video_fnode_check(fnode, -1);
}
/* Queue the node */
diff --git a/src/mod/applications/mod_conference/conference_member.c b/src/mod/applications/mod_conference/conference_member.c
index 8d5af7fa62..5d60dcd16c 100644
--- a/src/mod/applications/mod_conference/conference_member.c
+++ b/src/mod/applications/mod_conference/conference_member.c
@@ -1422,7 +1422,7 @@ switch_status_t conference_member_say(conference_member_t *member, char *text, u
fp = switch_core_strdup(pool, text);
switch_assert(fp);
- if (!switch_event_create_brackets(fp, '{', '}', ',', ¶ms, &new_fp, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+ if (switch_event_create_brackets(fp, '{', '}', ',', ¶ms, &new_fp, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
new_fp = fp;
}
diff --git a/src/mod/applications/mod_conference/conference_video.c b/src/mod/applications/mod_conference/conference_video.c
index e78aa25700..bf469577ca 100644
--- a/src/mod/applications/mod_conference/conference_video.c
+++ b/src/mod/applications/mod_conference/conference_video.c
@@ -789,7 +789,7 @@ void conference_video_layer_set_banner(conference_member_t *member, mcu_layer_t
switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h,
&layer->canvas->letterbox_bgcolor);
- if (!strcasecmp(text, "allclear")) {
+ if (zstr(text) || !strcasecmp(text, "allclear")) {
switch_channel_set_variable(member->channel, "video_banner_text", NULL);
}
@@ -1380,8 +1380,8 @@ void conference_video_canvas_set_fnode_layer(mcu_canvas_t *canvas, conference_fi
if (canvas->layout_floor_id > -1) {
idx = canvas->layout_floor_id;
xlayer = &canvas->layers[idx];
-
- if (xlayer->fnode) {
+
+ if (xlayer->fnode && xlayer->fnode != fnode) {
idx = -1;
}
}
@@ -1492,8 +1492,8 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_write_thread_run(switch_thread_
if (last) {
int delta = now - last;
- if (delta > member->conference->video_fps.ms * 2) {
- switch_core_session_request_video_refresh(member->session);
+ if (delta > member->conference->video_fps.ms * 5000) {
+ switch_core_session_request_video_refresh(member->session);
}
}
@@ -1659,18 +1659,27 @@ void conference_video_patch_fnode(mcu_canvas_t *canvas, conference_file_node_t *
} else if (status == SWITCH_STATUS_IGNORE) {
if (canvas && fnode->layer_id > -1 ) {
conference_video_canvas_del_fnode_layer(canvas->conference, fnode);
+ fnode->canvas_id = canvas->canvas_id;
}
}
}
}
-void conference_video_fnode_check(conference_file_node_t *fnode) {
- mcu_canvas_t *canvas = fnode->conference->canvases[fnode->canvas_id];
-
+void conference_video_fnode_check(conference_file_node_t *fnode, int canvas_id) {
+ mcu_canvas_t *canvas = NULL;
+
if (switch_core_file_has_video(&fnode->fh) && switch_core_file_read_video(&fnode->fh, NULL, SVR_CHECK) == SWITCH_STATUS_BREAK) {
int full_screen = 0;
char *res_id = NULL;
+ if (fnode->canvas_id == -1) {
+ if (canvas_id == -1) {
+ return;
+ }
+ fnode->canvas_id = canvas_id;
+ }
+
+ canvas = fnode->conference->canvases[fnode->canvas_id];
if (fnode->fh.params && fnode->conference->canvas_count == 1) {
full_screen = switch_true(switch_event_get_header(fnode->fh.params, "full-screen"));
}
@@ -2296,7 +2305,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
}
if (check_async_file) {
- if (switch_core_file_read_video(&conference->async_fnode->fh, &file_frame, SVR_BLOCK | SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
+ if (switch_core_file_read_video(&conference->async_fnode->fh, &file_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
if ((async_file_img = file_frame.img)) {
file_imgs[j++] = async_file_img;
}
@@ -2304,7 +2313,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
}
if (check_file) {
- if (switch_core_file_read_video(&conference->fnode->fh, &file_frame, SVR_BLOCK | SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
+ if (switch_core_file_read_video(&conference->fnode->fh, &file_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
if ((normal_file_img = file_frame.img)) {
file_imgs[j++] = normal_file_img;
}
@@ -2456,19 +2465,19 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
switch_mutex_unlock(conference->member_mutex);
} else {
- if (conference->async_fnode && conference->async_fnode->canvas_id == canvas->canvas_id) {
+ if (conference->async_fnode && (conference->async_fnode->canvas_id == canvas->canvas_id || conference->async_fnode->canvas_id == -1)) {
if (conference->async_fnode->layer_id > -1) {
conference_video_patch_fnode(canvas, conference->async_fnode);
} else {
- conference_video_fnode_check(conference->async_fnode);
+ conference_video_fnode_check(conference->async_fnode, canvas->canvas_id);
}
}
- if (conference->fnode && conference->fnode->canvas_id == canvas->canvas_id) {
+ if (conference->fnode && (conference->fnode->canvas_id == canvas->canvas_id || conference->fnode->canvas_id == -1)) {
if (conference->fnode->layer_id > -1) {
conference_video_patch_fnode(canvas, conference->fnode);
} else {
- conference_video_fnode_check(conference->fnode);
+ conference_video_fnode_check(conference->fnode, canvas->canvas_id);
}
}
@@ -2540,7 +2549,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
timestamp = canvas->timer.samplecount;
if (conference->playing_video_file) {
- if (switch_core_file_read_video(&conference->fnode->fh, &write_frame, SVR_BLOCK | SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
+ if (switch_core_file_read_video(&conference->fnode->fh, &write_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
switch_img_free(&file_img);
if (canvas->play_file) {
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index 0802b95987..963ae9aa15 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -667,7 +667,7 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
conference->fnode = conference->fnode->next;
if (conference->fnode) {
- conference_video_fnode_check(conference->fnode);
+ conference_video_fnode_check(conference->fnode, -1);
}
@@ -899,7 +899,7 @@ switch_status_t conference_say(conference_obj_t *conference, const char *text, u
fp = switch_core_strdup(pool, text);
switch_assert(fp);
- if (!switch_event_create_brackets(fp, '{', '}', ',', ¶ms, &new_fp, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+ if (switch_event_create_brackets(fp, '{', '}', ',', ¶ms, &new_fp, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
new_fp = fp;
}
diff --git a/src/mod/applications/mod_conference/mod_conference.h b/src/mod/applications/mod_conference/mod_conference.h
index ff19ff44f5..3adb7f49a2 100644
--- a/src/mod/applications/mod_conference/mod_conference.h
+++ b/src/mod/applications/mod_conference/mod_conference.h
@@ -930,7 +930,7 @@ video_layout_t *conference_video_get_layout(conference_obj_t *conference, const
void conference_video_check_avatar(conference_member_t *member, switch_bool_t force);
void conference_video_find_floor(conference_member_t *member, switch_bool_t entering);
void conference_video_destroy_canvas(mcu_canvas_t **canvasP);
-void conference_video_fnode_check(conference_file_node_t *fnode);
+void conference_video_fnode_check(conference_file_node_t *fnode, int canvas_id);
switch_status_t conference_video_set_canvas_bgimg(mcu_canvas_t *canvas, const char *img_path);
switch_status_t conference_al_parse_position(al_handle_t *al, const char *data);
switch_status_t conference_video_thread_callback(switch_core_session_t *session, switch_frame_t *frame, void *user_data);
diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c
index 310aa302e4..cf31deea75 100644
--- a/src/mod/applications/mod_dptools/mod_dptools.c
+++ b/src/mod/applications/mod_dptools/mod_dptools.c
@@ -2424,15 +2424,30 @@ static void att_xfer_set_result(switch_channel_t *channel, switch_status_t statu
switch_channel_set_variable(channel, SWITCH_ATT_XFER_RESULT_VARIABLE, status == SWITCH_STATUS_SUCCESS ? "success" : "failure");
}
-SWITCH_STANDARD_APP(att_xfer_function)
+struct att_obj {
+ switch_core_session_t *session;
+ const char *data;
+ int running;
+};
+
+void *SWITCH_THREAD_FUNC att_thread_run(switch_thread_t *thread, void *obj)
{
+ struct att_obj *att = (struct att_obj *) obj;
+ switch_core_session_t *session = att->session;
switch_core_session_t *peer_session = NULL;
+ const char *data = att->data;
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
switch_channel_t *channel = switch_core_session_get_channel(session), *peer_channel = NULL;
const char *bond = NULL;
switch_core_session_t *b_session = NULL;
switch_bool_t follow_recording = switch_true(switch_channel_get_variable(channel, "recording_follow_attxfer"));
-
+
+ att->running = 1;
+
+ if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
+ return NULL;
+ }
+
bond = switch_channel_get_partner_uuid(channel);
switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, bond);
switch_core_event_hook_add_state_change(session, tmp_hanguphook);
@@ -2505,6 +2520,35 @@ SWITCH_STANDARD_APP(att_xfer_function)
switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL);
switch_channel_clear_flag(channel, CF_XFER_ZOMBIE);
+
+ switch_core_session_rwunlock(session);
+ att->running = 0;
+
+ return NULL;
+}
+
+SWITCH_STANDARD_APP(att_xfer_function)
+{
+ switch_thread_t *thread;
+ switch_threadattr_t *thd_attr = NULL;
+ switch_memory_pool_t *pool = switch_core_session_get_pool(session);
+ struct att_obj *att;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ switch_threadattr_create(&thd_attr, pool);
+ switch_threadattr_detach_set(thd_attr, 1);
+ switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+ switch_threadattr_detach_set(thd_attr, 1);
+
+ att = switch_core_session_alloc(session, sizeof(*att));
+ att->running = -1;
+ att->session = session;
+ att->data = switch_core_session_strdup(session, data);
+ switch_thread_create(&thread, thd_attr, att_thread_run, att, pool);
+
+ while(att->running && switch_channel_up(channel)) {
+ switch_yield(100000);
+ }
}
SWITCH_STANDARD_APP(read_function)
@@ -3146,6 +3190,8 @@ static void *SWITCH_THREAD_FUNC camp_music_thread(switch_thread_t *thread, void
}
while (stake->running && switch_channel_ready(channel)) {
+ switch_ivr_parse_signal_data(session, SWITCH_TRUE, SWITCH_FALSE);
+
if (status != SWITCH_STATUS_BREAK) {
if (!strcasecmp(moh, "silence")) {
status = switch_ivr_collect_digits_callback(session, &args, 0, 0);
diff --git a/src/mod/applications/mod_easyroute/mod_easyroute.c b/src/mod/applications/mod_easyroute/mod_easyroute.c
index 5fdbf3abb2..e039c86e38 100644
--- a/src/mod/applications/mod_easyroute/mod_easyroute.c
+++ b/src/mod/applications/mod_easyroute/mod_easyroute.c
@@ -357,7 +357,7 @@ SWITCH_STANDARD_API(easyroute_function)
}
}
- if (!route_lookup(destnum, &results, noat, separator) == SWITCH_STATUS_SUCCESS) {
+ if (route_lookup(destnum, &results, noat, separator) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "No Match!\n");
status = SWITCH_STATUS_SUCCESS;
goto done;
diff --git a/src/mod/applications/mod_enum/mod_enum.c b/src/mod/applications/mod_enum/mod_enum.c
index 42126f3009..efa3fe3125 100644
--- a/src/mod/applications/mod_enum/mod_enum.c
+++ b/src/mod/applications/mod_enum/mod_enum.c
@@ -838,7 +838,7 @@ SWITCH_STANDARD_API(enum_function)
}
- if (!enum_lookup(root, dest, &results, NULL, session) == SWITCH_STATUS_SUCCESS) {
+ if (enum_lookup(root, dest, &results, NULL, session) != SWITCH_STATUS_SUCCESS) {
stream->write_function(stream, "No Match!\n");
return SWITCH_STATUS_SUCCESS;
}
diff --git a/src/mod/applications/mod_voicemail/mod_voicemail.c b/src/mod/applications/mod_voicemail/mod_voicemail.c
index 994ec33cce..18583bf181 100644
--- a/src/mod/applications/mod_voicemail/mod_voicemail.c
+++ b/src/mod/applications/mod_voicemail/mod_voicemail.c
@@ -3290,7 +3290,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS);
status =
deliver_vm(profile, ux, domain, path, 0, read_flags, my_params, pool, cid_name, cid_num, forwarded_by,
- SWITCH_TRUE, session ? switch_core_session_get_uuid(session) : NULL, NULL);
+ SWITCH_TRUE, session ? switch_core_session_get_uuid(session) : NULL, session);
switch_event_destroy(&my_params);
}
continue;
@@ -3300,7 +3300,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS);
status = deliver_vm(profile, ut, domain, path, 0, read_flags,
my_params, pool, cid_name, cid_num, forwarded_by, SWITCH_TRUE,
- session ? switch_core_session_get_uuid(session) : NULL, NULL);
+ session ? switch_core_session_get_uuid(session) : NULL, session);
switch_event_destroy(&my_params);
}
}
@@ -3324,7 +3324,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS);
status = deliver_vm(profile, ut, domain, path, 0, read_flags,
my_params, pool, cid_name, cid_num, forwarded_by, SWITCH_TRUE,
- session ? switch_core_session_get_uuid(session) : NULL, NULL);
+ session ? switch_core_session_get_uuid(session) : NULL, session);
switch_event_destroy(&my_params);
}
}
@@ -3339,7 +3339,7 @@ static switch_status_t voicemail_inject(const char *data, switch_core_session_t
switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS);
status = deliver_vm(profile, ut, domain, path, 0, read_flags,
my_params, pool, cid_name, cid_num, forwarded_by, SWITCH_TRUE,
- session ? switch_core_session_get_uuid(session) : NULL, NULL);
+ session ? switch_core_session_get_uuid(session) : NULL, session);
switch_event_destroy(&my_params);
} else {
status = SWITCH_STATUS_FALSE;
diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c
index 159a50c22b..9b9ec670e0 100644
--- a/src/mod/codecs/mod_opus/mod_opus.c
+++ b/src/mod/codecs/mod_opus/mod_opus.c
@@ -63,8 +63,23 @@ static opus_codec_settings_t default_codec_settings = {
/*.cbr*/ 0,
/*.sprop_maxcapturerate*/ 0,
/*.sprop_stereo*/ 0,
- /*.maxptime*/ 0,
- /*.minptime*/ 0,
+ /*.maxptime*/ 40,
+ /*.minptime*/ 10,
+ /*.ptime*/ 0,
+ /*.samplerate*/ 0
+};
+
+static opus_codec_settings_t default_codec_settings_8k = {
+ /*.useinbandfec */ 1,
+ /*.usedtx */ 1,
+ /*.maxaveragebitrate */ 14000,
+ /*.maxplaybackrate */ 8000,
+ /*.stereo*/ 0,
+ /*.cbr*/ 0,
+ /*.sprop_maxcapturerate*/ 8000,
+ /*.sprop_stereo*/ 0,
+ /*.maxptime*/ 120,
+ /*.minptime*/ 10,
/*.ptime*/ 0,
/*.samplerate*/ 0
};
@@ -78,6 +93,8 @@ struct opus_context {
uint32_t debug;
uint32_t use_jb_lookahead;
opus_codec_settings_t codec_settings;
+ int look_check;
+ int look_ts;
};
struct {
@@ -90,6 +107,7 @@ struct {
int plpct;
int asymmetric_samplerates;
int keep_fec;
+ int fec_decode;
int debuginfo;
uint32_t use_jb_lookahead;
switch_mutex_t *mutex;
@@ -107,6 +125,57 @@ static switch_bool_t switch_opus_acceptable_rate(int rate)
return SWITCH_TRUE;
}
+static uint32_t switch_opus_encoder_set_audio_bandwidth(OpusEncoder *encoder_object,int enc_samplerate)
+{
+ if (enc_samplerate == 8000) { /* Audio Bandwidth: 0-4000Hz Sampling Rate: 8000Hz */
+ opus_encoder_ctl(encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
+ return OPUS_BANDWIDTH_NARROWBAND;
+ } else if (enc_samplerate == 12000) { /* Audio Bandwidth: 0-6000Hz Sampling Rate: 12000Hz */
+ opus_encoder_ctl(encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
+ return OPUS_BANDWIDTH_MEDIUMBAND;
+ } else if (enc_samplerate == 16000) { /* Audio Bandwidth: 0-8000Hz Sampling Rate: 16000Hz */
+ opus_encoder_ctl(encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
+ return OPUS_BANDWIDTH_WIDEBAND;
+ } else if (enc_samplerate == 24000) { /* Audio Bandwidth: 0-12000Hz Sampling Rate: 24000Hz */
+ opus_encoder_ctl(encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_SIGNAL(OPUS_AUTO));
+ return OPUS_BANDWIDTH_SUPERWIDEBAND;
+ }
+ /* Audio Bandwidth: 0-20000Hz Sampling Rate: 48000Hz */
+ opus_encoder_ctl(encoder_object, OPUS_SET_BANDWIDTH(OPUS_AUTO));
+ opus_encoder_ctl(encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
+ opus_encoder_ctl(encoder_object, OPUS_SET_SIGNAL(OPUS_AUTO));
+ return OPUS_BANDWIDTH_FULLBAND;
+}
+
+static switch_bool_t switch_opus_show_audio_bandwidth(int audiobandwidth,char *audiobandwidth_str)
+{
+ if (audiobandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ strncpy(audiobandwidth_str, "NARROWBAND",10);
+ return SWITCH_TRUE;
+ } else if (audiobandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ strncpy(audiobandwidth_str, "MEDIUMBAND",10);
+ return SWITCH_TRUE;
+ } else if (audiobandwidth == OPUS_BANDWIDTH_WIDEBAND) {
+ strncpy(audiobandwidth_str,"WIDEBAND",8);
+ return SWITCH_TRUE;
+ } else if (audiobandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND) {
+ strncpy(audiobandwidth_str, "SUPERWIDEBAND",13);
+ return SWITCH_TRUE;
+ } else if (audiobandwidth == OPUS_BANDWIDTH_FULLBAND) {
+ strncpy(audiobandwidth_str, "FULLBAND",8);
+ return SWITCH_TRUE;
+ }
+ return SWITCH_FALSE;
+}
+
static switch_status_t switch_opus_fmtp_parse(const char *fmtp, switch_codec_fmtp_t *codec_fmtp)
{
if (codec_fmtp) {
@@ -165,11 +234,6 @@ static switch_status_t switch_opus_fmtp_parse(const char *fmtp, switch_codec_fmt
codec_fmtp->microseconds_per_packet = codec_settings->ptime * 1000;
}
- if (!strcasecmp(data, "samplerate")) {
- codec_settings->samplerate = atoi(arg);
- codec_fmtp->actual_samples_per_second = codec_settings->samplerate;
- }
-
if (!strcasecmp(data, "stereo")) {
codec_settings->stereo = atoi(arg);
codec_fmtp->stereo = codec_settings->stereo;
@@ -212,9 +276,7 @@ static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *poo
{
char buf[256] = { 0 };
- if (settings->useinbandfec) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "useinbandfec=1; ");
- }
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "useinbandfec=%d; ", settings->useinbandfec);
if (settings->usedtx) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "usedtx=1; ");
@@ -248,12 +310,7 @@ static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *poo
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxptime=%d; ", settings->maxptime);
}
- if (settings->samplerate) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "samplerate=%d; ", settings->samplerate);
- }
-
if (settings->stereo) {
- settings->sprop_stereo = settings->stereo;
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "stereo=%d; ", settings->stereo);
}
@@ -271,26 +328,50 @@ static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *poo
static switch_bool_t switch_opus_has_fec(const uint8_t* payload,int payload_length_bytes)
{
- int frames, payload_length_ms;
- int n;
+ int nb_silk_frames, nb_opus_frames, n, i;
opus_int16 frame_sizes[48];
const unsigned char *frame_data[48];
+ int frames;
- if (payload == NULL || payload_length_bytes <= 0){
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "corrupted packet\n");
+ if (payload == NULL || payload_length_bytes <= 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "corrupted packet (invalid size)\n");
+ return SWITCH_FALSE;
+ }
+ if (payload[0] & 0x80) {
+ /* this scares users and its harmless so commenting it */
+ //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FEC in CELT_ONLY mode ?!\n");
+ return SWITCH_FALSE;
+ }
+
+ if ((nb_opus_frames = opus_packet_parse(payload, payload_length_bytes, NULL, frame_data, frame_sizes, NULL)) < 0 ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OPUS_INVALID_PACKET ! nb_opus_frames: %d\n", nb_opus_frames);
return SWITCH_FALSE;
}
- if (payload[0] & 0x80){
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FEC in CELT_ONLY mode ?!\n");
- return SWITCH_FALSE;
+ nb_silk_frames = 0;
+
+ if ((payload[0] >> 3 ) < 12) { /* config in silk-only : NB,MB,WB */
+ nb_silk_frames = (payload[0] >> 3) & 0x3;
+ if(nb_silk_frames == 0) {
+ nb_silk_frames = 1;
+ }
+ if (nb_silk_frames == 1) {
+ for (n = 0; n <= (payload[0]&0x4) ; n++) { /* mono or stereo */
+ if (frame_data[0][0] & (0x80 >> ((n + 1) * (nb_silk_frames + 1) - 1))) {
+ return SWITCH_TRUE; /* 1st 20ms (or 10 ms) frame has FEC */
+ }
+ }
+ } else {
+ opus_int16 LBRR_flag = 0 ;
+ for (i=0 ; i < nb_opus_frames; i++ ) { /* only mono */
+ LBRR_flag = (frame_data[i][0] >> (7 - nb_silk_frames)) & 0x1;
+ if (LBRR_flag) {
+ return SWITCH_TRUE; /* one of the silk frames has FEC */
+ }
+ }
+ }
}
-
- payload_length_ms = opus_packet_get_samples_per_frame(payload, 48000) / 48;
- if (10 > payload_length_ms) {
- payload_length_ms = 10;
- }
-
+
frames = opus_packet_parse(payload, payload_length_bytes, NULL, frame_data, frame_sizes, NULL);
if (frames < 0) {
@@ -310,50 +391,96 @@ static switch_bool_t switch_opus_has_fec(const uint8_t* payload,int payload_leng
return SWITCH_FALSE;
}
+/* this is only useful for fs = 8000 hz, the map is only used
+ * at the beginning of the call. */
+static int switch_opus_get_fec_bitrate(int fs, int loss)
+{
+ int threshold_bitrates[25] = {
+ 15600,15200,15200,15200,14800,
+ 14800,14800,14800,14400,14400,
+ 14400,14000,14000,14000,13600,
+ 13600,13600,13600,13200,13200,
+ 13200,12800,12800,12800,12400
+ };
+
+ if (loss <= 0){
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (fs == 8000) {
+ if (loss >=25) {
+ return threshold_bitrates[24];
+ } else {
+ return threshold_bitrates[loss-1];
+ }
+ }
+
+ return SWITCH_STATUS_FALSE ;
+}
+
static switch_status_t switch_opus_info(void * encoded_data, uint32_t len, uint32_t samples_per_second, char *print_text)
{
- int nb_samples;
- int nb_frames;
+ /* nb_silk_frames: number of silk-frames (10 or 20 ms) in an opus frame: 0, 1, 2 or 3 */
+ /* computed from the 5 MSB (configuration) of the TOC byte (encoded_data[0]) */
+ /* nb_opus_frames: number of opus frames in the packet */
+ /* computed from the 2 LSB (p0p1) of the TOC byte */
+ /* p0p1 = 0 => nb_opus_frames= 1 */
+ /* p0p1 = 1 or 2 => nb_opus_frames= 2 */
+ /* p0p1 = 3 => given by the 6 LSB of encoded_data[1] */
+
+ int nb_samples, nb_silk_frames, nb_opus_frames, n, i;
int audiobandwidth;
- const char *audiobandwidth_str = "UNKNOWN";
+ char audiobandwidth_str[32] = {0};
opus_int16 frame_sizes[48];
const unsigned char *frame_data[48];
char has_fec = 0;
+ uint8_t * payload = encoded_data ;
if (!encoded_data) {
return SWITCH_STATUS_FALSE;
}
- nb_frames = opus_packet_get_nb_frames(encoded_data, len);
- nb_samples = opus_packet_get_samples_per_frame(encoded_data, samples_per_second) * nb_frames;
audiobandwidth = opus_packet_get_bandwidth(encoded_data);
- if (audiobandwidth == OPUS_BANDWIDTH_NARROWBAND) {
- audiobandwidth_str = "NARROWBAND";
- } else if (audiobandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
- audiobandwidth_str = "MEDIUMBAND";
- } else if (audiobandwidth == OPUS_BANDWIDTH_WIDEBAND) {
- audiobandwidth_str = "WIDEBAND";
- } else if (audiobandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND) {
- audiobandwidth_str = "SUPERWIDEBAND";
- } else if (audiobandwidth == OPUS_BANDWIDTH_FULLBAND) {
- audiobandwidth_str = "FULLBAND";
- } else if (audiobandwidth == OPUS_INVALID_PACKET) {
+ if (!switch_opus_show_audio_bandwidth(audiobandwidth,audiobandwidth_str)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: OPUS_INVALID_PACKET !\n", print_text);
}
- if (opus_packet_parse(encoded_data, len, NULL, frame_data, frame_sizes, NULL)) {
- if (frame_data[0]) {
- /*check only 1st frame*/
- has_fec = frame_data[0][0] & (0x80 >> 1);
+ if ((nb_opus_frames = opus_packet_parse(encoded_data, len, NULL, frame_data, frame_sizes, NULL)) < 0 ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: OPUS_INVALID_PACKET ! frames: %d\n", print_text, nb_opus_frames);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ nb_samples = opus_packet_get_samples_per_frame(encoded_data, samples_per_second) * nb_opus_frames;
+ nb_silk_frames = 0;
+
+ if ((payload[0] >> 3 ) < 12) { /* config in silk-only : NB,MB,WB */
+ nb_silk_frames = (payload[0] >> 3) & 0x3;
+ if(nb_silk_frames == 0) {
+ nb_silk_frames = 1;
+ }
+ if (nb_silk_frames == 1) {
+ for (n = 0; n <= (payload[0]&0x4) ; n++) { /* mono or stereo */
+ if (frame_data[0][0] & (0x80 >> ((n + 1) * (nb_silk_frames + 1) - 1))){
+ has_fec = 1 ; /* 1st 20ms (or 10 ms) frame has fec */
+ }
+ }
+ } else {
+ opus_int16 LBRR_flag = 0 ;
+ for (i=0 ; i < nb_opus_frames; i++ ) { /* only mono */
+ LBRR_flag = (frame_data[i][0] >> (7 - nb_silk_frames)) & 0x1;
+ if (LBRR_flag) {
+ has_fec = 1;
+ }
+ }
}
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: frames [%d] samples [%d] audio bandwidth [%s] bytes [%d] FEC[%s]\n",
- print_text, nb_frames, nb_samples, audiobandwidth_str, len, has_fec ? "yes" : "no");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: nb_opus_frames [%d] nb_silk_frames [%d] samples [%d] audio bandwidth [%s] bytes [%d] FEC[%s]\n",
+ print_text, nb_opus_frames, nb_silk_frames, nb_samples, audiobandwidth_str, len, has_fec ? "yes" : "no" );
return SWITCH_STATUS_SUCCESS;
-}
+}
static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag_t flags, const switch_codec_settings_t *codec_settings)
{
@@ -402,6 +529,8 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
opus_codec_settings.sprop_maxcapturerate = opus_codec_settings_remote.sprop_maxcapturerate;
}
+ opus_codec_settings.useinbandfec = opus_prefs.fec_decode;
+
opus_codec_settings.cbr = !opus_prefs.use_vbr;
opus_codec_settings.usedtx = opus_prefs.use_dtx;
@@ -445,36 +574,27 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
return SWITCH_STATUS_GENERR;
}
- /* Setting documented in "RTP Payload Format for Opus Speech and Audio Codec" draft-spittka-payload-rtp-opus-03 */
- if (opus_codec_settings.maxaveragebitrate) { /* Remote codec settings found in SDP "fmtp", we accept to tune the Encoder */
+ /* https://tools.ietf.org/html/rfc7587 */
+ if (opus_codec_settings.maxaveragebitrate) {
opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(opus_codec_settings.maxaveragebitrate));
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bitrate based on maxaveragebitrate found in SDP [%dbps]\n", opus_codec_settings.maxaveragebitrate);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder: set bitrate based on maxaveragebitrate value found in SDP or local config [%dbps]\n", opus_codec_settings.maxaveragebitrate);
} else {
- /* Default codec settings used, may have been modified by SDP "samplerate" */
- opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps));
- if (codec->implementation->actual_samples_per_second == 8000) {
- opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
- opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
- } else {
- opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
- }
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bitrate to local settings [%dbps]\n", bitrate_bps);
+ opus_encoder_ctl(context->encoder_object, OPUS_SET_BANDWIDTH(OPUS_AUTO));
+ opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(bitrate_bps)); /* OPUS_AUTO */
+ opus_encoder_ctl(context->encoder_object, OPUS_GET_BITRATE(&bitrate_bps)); /* return average bps for this audio bandwidth */
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder: set bitrate to local settings [%dbps]\n", bitrate_bps);
}
-
- /* Another setting from "RTP Payload Format for Opus Speech and Audio Codec" */
+ /* Another fmtp setting from https://tools.ietf.org/html/rfc7587 - "RTP Payload Format for the Opus Speech and Audio Codec" */
if (opus_codec_settings.maxplaybackrate) {
- if (opus_codec_settings.maxplaybackrate == 8000) { /* Audio Bandwidth: 0-4000Hz Sampling Rate: 8000Hz */
- opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
- } else if (opus_codec_settings.maxplaybackrate == 12000) { /* Audio Bandwidth: 0-6000Hz Sampling Rate: 12000Hz */
- opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_MEDIUMBAND));
- } else if (opus_codec_settings.maxplaybackrate == 16000) { /* Audio Bandwidth: 0-8000Hz Sampling Rate: 16000Hz */
- opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
- } else if (opus_codec_settings.maxplaybackrate == 24000) { /* Audio Bandwidth: 0-12000Hz Sampling Rate: 24000Hz */
- opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
- } else if (opus_codec_settings.maxplaybackrate == 48000) { /* Audio Bandwidth: 0-20000Hz Sampling Rate: 48000Hz */
- opus_encoder_ctl(context->encoder_object, OPUS_SET_MAX_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
+ opus_int32 audiobandwidth;
+ char audiobandwidth_str[32] = {0};
+
+ audiobandwidth = switch_opus_encoder_set_audio_bandwidth(context->encoder_object,opus_codec_settings.maxplaybackrate);
+ if (!switch_opus_show_audio_bandwidth(audiobandwidth,audiobandwidth_str)) {
+ memset(audiobandwidth_str,0,sizeof(audiobandwidth_str));
+ strncpy(audiobandwidth_str, "OPUS_AUTO",sizeof(audiobandwidth_str)-1);
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder set bandwidth based on maxplaybackrate found in SDP [%dHz]\n", opus_codec_settings.maxplaybackrate);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opus encoder: set audio bandwidth to [%s] based on maxplaybackrate value found in SDP or local config [%dHz]\n",audiobandwidth_str,opus_codec_settings.maxplaybackrate);
}
if (use_vbr) {
@@ -494,7 +614,20 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag
}
if (opus_codec_settings.useinbandfec) {
+ /* FEC on the encoder: start the call with a preconfigured packet loss percentage */
+ int fec_bitrate = opus_codec_settings.maxaveragebitrate;
+ int loss_percent = opus_prefs.plpct ;
opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(opus_codec_settings.useinbandfec));
+ opus_encoder_ctl(context->encoder_object, OPUS_SET_PACKET_LOSS_PERC(loss_percent));
+ if (opus_prefs.keep_fec){
+ fec_bitrate = switch_opus_get_fec_bitrate(enc_samplerate,loss_percent);
+ /* keep a bitrate for which the encoder will always add FEC */
+ if (fec_bitrate != SWITCH_STATUS_FALSE) {
+ opus_encoder_ctl(context->encoder_object, OPUS_SET_BITRATE(fec_bitrate));
+ /* will override the maxaveragebitrate set in opus.conf.xml */
+ opus_codec_settings.maxaveragebitrate = fec_bitrate;
+ }
+ }
}
if (opus_codec_settings.usedtx) {
@@ -608,7 +741,7 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
struct opus_context *context = codec->private_info;
int samples = 0;
int fec = 0, plc = 0;
- int32_t frame_size;
+ int32_t frame_size = 0, last_frame_size = 0;
uint32_t frame_samples;
if (!context) {
@@ -620,47 +753,66 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
if (*flag & SFF_PLC) {
switch_core_session_t *session = codec->session;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
switch_jb_t *jb = NULL;
- int got_frame = 0;
plc = 1;
encoded_data = NULL;
if ((opus_prefs.use_jb_lookahead || context->use_jb_lookahead) && context->codec_settings.useinbandfec && session) {
- if (opus_packet_get_bandwidth(codec->cur_frame->data) != OPUS_BANDWIDTH_FULLBAND &&
- codec->cur_frame && (jb = switch_core_session_get_jb(session, SWITCH_MEDIA_TYPE_AUDIO))) {
+ if (!context->look_check) {
+ context->look_ts = switch_true(switch_channel_get_variable_dup(channel, "jb_use_timestamps", SWITCH_FALSE, -1));
+ context->look_check = 1;
+ }
+ if (codec->cur_frame && (jb = switch_core_session_get_jb(session, SWITCH_MEDIA_TYPE_AUDIO))) {
switch_frame_t frame = { 0 };
uint8_t buf[SWITCH_RTP_MAX_BUF_LEN];
+ uint32_t ts = 0;
+ uint16_t seq = 0;
+
+ if (context->look_ts) {
+ ts = codec->cur_frame->timestamp;
+ } else {
+ seq = codec->cur_frame->seq;
+ }
+
frame.data = buf;
frame.buflen = sizeof(buf);
-
- if (switch_jb_peek_frame(jb, codec->cur_frame->timestamp, 0, 1, &frame)) {
- got_frame = 1;
- fec = 1;
- encoded_data = frame.data;
- encoded_data_len = frame.datalen;
+
+ if (globals.debug || context->debug) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Missing %s %u Checking JB\n", seq ? "SEQ" : "TS", seq ? seq : ts);
+ }
+
+ if (switch_jb_peek_frame(jb, ts, seq, 1, &frame) == SWITCH_STATUS_SUCCESS) {
if (globals.debug || context->debug) {
- if (switch_opus_has_fec(frame.data, frame.datalen)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FEC info available in packet with SEQ[%d] encoded_data_len: %d\n",
- codec->cur_frame->seq, encoded_data_len);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Lookahead frame found: %u:%u\n",
+ frame.timestamp, frame.seq);
+ }
+
+
+ if ((fec = switch_opus_has_fec(frame.data, frame.datalen))) {
+ encoded_data = frame.data;
+ encoded_data_len = frame.datalen;
+ }
+
+ if (globals.debug || context->debug) {
+ if (fec) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FEC info available in packet with SEQ: %d LEN: %d\n",
+ frame.seq, frame.datalen);
} else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NO FEC info in this packet with SEQ[%d] encoded_data_len: %d\n",
- codec->cur_frame->seq, encoded_data_len );
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NO FEC info in this packet with SEQ: %d LEN: %d\n",
+ frame.seq, frame.datalen);
}
}
- }
+ }
}
}
- if (!got_frame) {
- opus_decoder_ctl(context->decoder_object, OPUS_GET_LAST_PACKET_DURATION(&frame_size));
-
- if (!frame_size) {
- frame_size = frame_samples - (frame_samples % (codec->implementation->actual_samples_per_second / 400));
- }
- }
+ opus_decoder_ctl(context->decoder_object, OPUS_GET_LAST_PACKET_DURATION(&last_frame_size));
+ if (last_frame_size) frame_size = last_frame_size;
+
if (globals.debug || context->debug) {
if (opus_prefs.use_jb_lookahead || context->use_jb_lookahead) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "MISSING FRAME: %s\n", fec ? "Look-ahead FEC" : "PLC");
@@ -675,7 +827,8 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
if (globals.debug || context->debug > 1) {
int samplerate = context->dec_frame_size * 1000 / (codec->implementation->microseconds_per_packet / 1000);
switch_opus_info(encoded_data, encoded_data_len,
- samplerate ? samplerate : codec->implementation->actual_samples_per_second, "decode");
+ samplerate ? samplerate : codec->implementation->actual_samples_per_second,
+ !encoded_data ? "PLC correction" : fec ? "FEC correction" : "decode");
}
samples = opus_decode(context->decoder_object, encoded_data, encoded_data_len, decoded_data, frame_size, fec);
@@ -794,6 +947,14 @@ static switch_status_t opus_load_config(switch_bool_t reload)
return status;
}
+ memset(&opus_prefs, 0, sizeof(opus_prefs));
+ opus_prefs.use_jb_lookahead = 1;
+ opus_prefs.keep_fec = 1;
+ opus_prefs.use_dtx = 0;
+ opus_prefs.plpct = 20;
+ opus_prefs.use_vbr = 0;
+ //opus_prefs.fec_decode = 1;
+
if ((settings = switch_xml_child(cfg, "settings"))) {
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
char *key = (char *) switch_xml_attr_soft(param, "name");
@@ -811,8 +972,10 @@ static switch_status_t opus_load_config(switch_bool_t reload)
opus_prefs.asymmetric_samplerates = atoi(val);
} else if (!strcasecmp(key, "use-jb-lookahead")) {
opus_prefs.use_jb_lookahead = switch_true(val);
- } else if (!strcasecmp(key, "keep-fec-enabled")) {
+ } else if (!strcasecmp(key, "keep-fec-enabled")) { /* encoder */
opus_prefs.keep_fec = atoi(val);
+ } else if (!strcasecmp(key, "advertise_useinbandfec")) { /*decoder, has meaning only for FMTP: useinbandfec=1 by default */
+ opus_prefs.fec_decode = atoi(val);
} else if (!strcasecmp(key, "maxaveragebitrate")) {
opus_prefs.maxaveragebitrate = atoi(val);
if (opus_prefs.maxaveragebitrate < 6000 || opus_prefs.maxaveragebitrate > 510000) {
@@ -955,18 +1118,21 @@ static switch_status_t switch_opus_control(switch_codec_t *codec,
plpct = 100;
}
- calc = plpct % 10;
- plpct = plpct - calc + ( calc ? 10 : 0);
-
- if (opus_prefs.plpct > 0 && plpct < opus_prefs.plpct) {
- plpct = opus_prefs.plpct;
- }
-
- if (plpct != context->old_plpct) {
+ if (opus_prefs.keep_fec) {
opus_encoder_ctl(context->encoder_object, OPUS_SET_PACKET_LOSS_PERC(plpct));
-
+ } else {
+ calc = plpct % 10;
+ plpct = plpct - calc + ( calc ? 10 : 0);
+ }
+ if (plpct != context->old_plpct) {
if (opus_prefs.keep_fec) {
- switch_opus_keep_fec_enabled(codec);
+ if (plpct > 10) {
+ /* this will increase bitrate a little bit, just to keep FEC enabled */
+ switch_opus_keep_fec_enabled(codec);
+ }
+ } else {
+ /* this can have no effect because FEC is F(bitrate,packetloss), let the codec decide if FEC is to be used or not */
+ opus_encoder_ctl(context->encoder_object, OPUS_SET_PACKET_LOSS_PERC(plpct));
}
if (globals.debug || context->debug) {
@@ -992,6 +1158,7 @@ SWITCH_STANDARD_API(mod_opus_debug)
if (!strcasecmp(cmd, "on")) {
globals.debug = 1;
stream->write_function(stream, "OPUS Debug: on\n");
+ stream->write_function(stream, "Library version: %s\n",opus_get_version_string());
} else if (!strcasecmp(cmd, "off")) {
globals.debug = 0;
stream->write_function(stream, "OPUS Debug: off\n");
@@ -1035,6 +1202,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
settings = default_codec_settings;
+ settings.useinbandfec = opus_prefs.fec_decode;
+
+ settings.cbr = !opus_prefs.use_vbr;
+
+ settings.usedtx = opus_prefs.use_dtx;
+
if (opus_prefs.maxaveragebitrate) {
settings.maxaveragebitrate = opus_prefs.maxaveragebitrate;
}
@@ -1050,8 +1223,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
for (x = 0; x < 3; x++) {
settings.ptime = mss / 1000;
- settings.maxptime = settings.ptime;
- settings.minptime = settings.ptime;
settings.samplerate = rate;
settings.stereo = 0;
dft_fmtp = gen_fmtp(&settings, pool);
@@ -1109,11 +1280,27 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
mss = 10000;
rate = 8000;
+ settings = default_codec_settings_8k;
+
+ settings.useinbandfec = opus_prefs.fec_decode;
+
+ settings.cbr = !opus_prefs.use_vbr;
+
+ settings.usedtx = opus_prefs.use_dtx;
+
+ if (opus_prefs.maxaveragebitrate) {
+ settings.maxaveragebitrate = opus_prefs.maxaveragebitrate;
+ }
+ if (opus_prefs.maxplaybackrate) {
+ settings.maxplaybackrate = opus_prefs.maxplaybackrate;
+ }
+ if (opus_prefs.sprop_maxcapturerate) {
+ settings.sprop_maxcapturerate = opus_prefs.sprop_maxcapturerate;
+ }
+
for (x = 0; x < 3; x++) {
settings.stereo = 0;
settings.ptime = mss / 1000;
- settings.maxptime = settings.ptime;
- settings.minptime = settings.ptime;
settings.samplerate = rate;
dft_fmtp = gen_fmtp(&settings, pool);
@@ -1158,6 +1345,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
if (x == 1) { /*20 ms * 3 = 60 ms */
int nb_frames;
settings.stereo = 0;
+ settings.ptime = mss * 3 / 1000;
dft_fmtp = gen_fmtp(&settings, pool);
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
116, /* the IANA code number */
@@ -1181,6 +1369,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load)
for (nb_frames = 4; nb_frames <= 6; nb_frames++) {
/*20 ms * nb_frames = 80 ms , 100 ms , 120 ms */
settings.stereo = 0;
+ settings.ptime = mss * nb_frames / 1000;
dft_fmtp = gen_fmtp(&settings, pool);
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
116, /* the IANA code number */
diff --git a/src/mod/endpoints/mod_gsmopen/mobigater b/src/mod/endpoints/mod_gsmopen/mobigater
deleted file mode 120000
index cfea4c01b2..0000000000
--- a/src/mod/endpoints/mod_gsmopen/mobigater
+++ /dev/null
@@ -1 +0,0 @@
-alsa_nogsmlib_nocplusplus
\ No newline at end of file
diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c
index 28b68ab8fd..85673df525 100644
--- a/src/mod/endpoints/mod_skinny/skinny_server.c
+++ b/src/mod/endpoints/mod_skinny/skinny_server.c
@@ -150,12 +150,12 @@ switch_status_t skinny_create_incoming_session(listener_t *listener, uint32_t *l
}
/* First create the caller profile in the patterns Dialplan */
if (!(tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(nsession),
- NULL, listener->profile->patterns_dialplan,
- button->displayname, button->shortname,
+ NULL, listener->profile->patterns_dialplan,
+ button->displayname, button->shortname,
listener->remote_ip, NULL, NULL, NULL,
"skinny" /* modname */,
- listener->profile->patterns_context,
- "")) != 0) {
+ listener->profile->patterns_context,
+ ""))) {
skinny_log_ls_msg(listener, nsession, SWITCH_LOG_CRIT, "Error Creating Session caller profile\n");
goto error;
}
diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c
index e979618a8a..d69a5bd291 100644
--- a/src/mod/endpoints/mod_sofia/sofia.c
+++ b/src/mod/endpoints/mod_sofia/sofia.c
@@ -6969,6 +6969,7 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status,
NUTAG_MEDIA_ENABLE(0),
TAG_IF(!zstr(other_tech_pvt->user_via), SIPTAG_VIA_STR(other_tech_pvt->user_via)),
SIPTAG_CONTACT_STR(other_tech_pvt->reply_contact),
+ SIPTAG_CONTENT_TYPE_STR("application/sdp"),
SIPTAG_PAYLOAD_STR(r_sdp),
TAG_END());
diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c
index 69ef7ac767..86afb899d8 100644
--- a/src/mod/endpoints/mod_verto/mod_verto.c
+++ b/src/mod/endpoints/mod_verto/mod_verto.c
@@ -3125,6 +3125,7 @@ static switch_bool_t verto__attach_func(const char *method, cJSON *params, jsock
if (tech_pvt) {
switch_channel_clear_flag(tech_pvt->channel, CF_REINVITE);
+ switch_channel_clear_flag(tech_pvt->channel, CF_RECOVERING);
switch_clear_flag(tech_pvt, TFLAG_ATTACH_REQ);
if (switch_channel_test_flag(tech_pvt->channel, CF_CONFERENCE)) {
switch_channel_set_flag(tech_pvt->channel, CF_CONFERENCE_ADV);
diff --git a/src/mod/event_handlers/mod_json_cdr/conf/autoload_configs/json_cdr.conf.xml b/src/mod/event_handlers/mod_json_cdr/conf/autoload_configs/json_cdr.conf.xml
index 374ec8d2e2..a51a6518cf 100644
--- a/src/mod/event_handlers/mod_json_cdr/conf/autoload_configs/json_cdr.conf.xml
+++ b/src/mod/event_handlers/mod_json_cdr/conf/autoload_configs/json_cdr.conf.xml
@@ -31,8 +31,8 @@
-
-
+
+
diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c
index 9c9eedd8dd..a8a530bd46 100644
--- a/src/mod/formats/mod_local_stream/mod_local_stream.c
+++ b/src/mod/formats/mod_local_stream/mod_local_stream.c
@@ -89,6 +89,7 @@ struct local_stream_source {
char *timer_name;
local_stream_context_t *context_list;
int total;
+ int first;
switch_dir_t *dir_handle;
switch_mutex_t *mutex;
switch_memory_pool_t *pool;
@@ -117,6 +118,41 @@ struct local_stream_source {
typedef struct local_stream_source local_stream_source_t;
+switch_status_t list_streams_full(const char *line, const char *cursor, switch_console_callback_match_t **matches, switch_bool_t show_aliases)
+{
+ local_stream_source_t *source;
+ switch_hash_index_t *hi;
+ void *val;
+ const void *vvar;
+ switch_console_callback_match_t *my_matches = NULL;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+ switch_mutex_lock(globals.mutex);
+ for (hi = switch_core_hash_first(globals.source_hash); hi; hi = switch_core_hash_next(&hi)) {
+ switch_core_hash_this(hi, &vvar, NULL, &val);
+
+ source = (local_stream_source_t *) val;
+ if (!show_aliases && strcmp((char *)vvar, source->name)) {
+ continue;
+ }
+
+ switch_console_push_match(&my_matches, (const char *) vvar);
+ }
+ switch_mutex_unlock(globals.mutex);
+
+ if (my_matches) {
+ *matches = my_matches;
+ status = SWITCH_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
+switch_status_t list_streams(const char *line, const char *cursor, switch_console_callback_match_t **matches)
+{
+ return list_streams_full(line, cursor, matches, SWITCH_TRUE);
+}
+
static int do_rand(uint32_t count)
{
double r;
@@ -279,6 +315,8 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
flush_video_queue(source->video_q);
}
+ switch_buffer_zero(audio_buffer);
+
if (switch_core_timer_init(&timer, source->timer_name, source->interval, (int)source->samples, temp_pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n");
switch_dir_close(source->dir_handle);
@@ -325,7 +363,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
if (source->chime_counter > 0) {
source->chime_counter -= (int32_t)source->samples;
}
-
+
if (!switch_test_flag((&source->chime_fh), SWITCH_FILE_OPEN) && source->chime_counter <= 0) {
char *val;
@@ -376,22 +414,26 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
}
}
- if (is_open) {
+ if (!is_open) {
+ switch_buffer_zero(audio_buffer);
+ break;
+ } else {
+ int svr = 0;
+
if (switch_core_has_video() && switch_core_file_has_video(use_fh)) {
switch_frame_t vid_frame = { 0 };
if (use_fh == &source->chime_fh && switch_core_file_has_video(&fh)) {
- if (switch_core_file_read_video(&fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
+ if (switch_core_file_read_video(&fh, &vid_frame, svr) == SWITCH_STATUS_SUCCESS) {
switch_img_free(&vid_frame.img);
}
}
- if (switch_core_file_read_video(use_fh, &vid_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) {
+ while (switch_core_file_read_video(use_fh, &vid_frame, svr) == SWITCH_STATUS_SUCCESS) {
if (vid_frame.img) {
int flush = 1;
source->has_video = 1;
-
if (source->total) {
if (switch_queue_trypush(source->video_q, vid_frame.img) == SWITCH_STATUS_SUCCESS) {
flush = 0;
@@ -413,7 +455,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
switch_core_file_read(&fh, abuf, &olen);
olen = source->samples;
}
-
+
if (switch_core_file_read(use_fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) {
switch_core_file_close(use_fh);
flush_video_queue(source->video_q);
@@ -451,67 +493,70 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
break;
}
- if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2 * source->channels)) {
- void *pop;
+ source->prebuf = source->samples * 2 * source->channels;
+ if (!source->total) {
+ flush_video_queue(source->video_q);
+ switch_buffer_zero(audio_buffer);
+ } else if (used > source->samples * 2 * source->channels) {
+ //if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2 * source->channels)) {
+ void *pop;
+ uint32_t bused;
+
used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2 * source->channels);
- if (!source->total) {
- flush_video_queue(source->video_q);
- } else {
- uint32_t bused = 0;
+ bused = 0;
- switch_mutex_lock(source->mutex);
- for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
+ switch_mutex_lock(source->mutex);
+ for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
- if (source->has_video) {
- switch_set_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO);
- } else {
- switch_clear_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO);
- }
-
- if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) {
- continue;
- }
-
- switch_mutex_lock(cp->audio_mutex);
- bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer);
- if (bused > source->samples * 768) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n",
- cp->func, cp->file, cp->line, bused, (long)source->samples);
- switch_buffer_zero(cp->audio_buffer);
- } else {
- switch_buffer_write(cp->audio_buffer, dist_buf, used);
- }
- switch_mutex_unlock(cp->audio_mutex);
+ if (source->has_video) {
+ switch_set_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO);
+ } else {
+ switch_clear_flag(cp->handle, SWITCH_FILE_FLAG_VIDEO);
}
- switch_mutex_unlock(source->mutex);
+
+ if (switch_test_flag(cp->handle, SWITCH_FILE_CALLBACK)) {
+ continue;
+ }
+
+ switch_mutex_lock(cp->audio_mutex);
+ bused = (uint32_t)switch_buffer_inuse(cp->audio_buffer);
+ if (bused > source->samples * 768) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Flushing Stream Handle Buffer [%s() %s:%d] size: %u samples: %ld\n",
+ cp->func, cp->file, cp->line, bused, (long)source->samples);
+ switch_buffer_zero(cp->audio_buffer);
+ } else {
+ switch_buffer_write(cp->audio_buffer, dist_buf, used);
+ }
+ switch_mutex_unlock(cp->audio_mutex);
+ }
+ switch_mutex_unlock(source->mutex);
- while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) {
- switch_image_t *img = (switch_image_t *) pop;
- switch_image_t *imgcp = NULL;
+ while (switch_queue_trypop(source->video_q, &pop) == SWITCH_STATUS_SUCCESS) {
+ switch_image_t *img = (switch_image_t *) pop;
+ switch_image_t *imgcp = NULL;
- if (source->total == 1) {
- switch_queue_push(source->context_list->video_q, img);
- } else {
- if (source->context_list) {
- switch_mutex_lock(source->mutex);
- for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
- if (cp->video_q) {
- imgcp = NULL;
- switch_img_copy(img, &imgcp);
- if (imgcp) {
- if (switch_queue_trypush(cp->video_q, imgcp) != SWITCH_STATUS_SUCCESS) {
- flush_video_queue(cp->video_q);
- }
+ if (source->total == 1) {
+ switch_queue_push(source->context_list->video_q, img);
+ } else {
+ if (source->context_list) {
+ switch_mutex_lock(source->mutex);
+ for (cp = source->context_list; cp && RUNNING; cp = cp->next) {
+ if (cp->video_q) {
+ imgcp = NULL;
+ switch_img_copy(img, &imgcp);
+ if (imgcp) {
+ if (switch_queue_trypush(cp->video_q, imgcp) != SWITCH_STATUS_SUCCESS) {
+ flush_video_queue(cp->video_q);
}
}
}
- switch_mutex_unlock(source->mutex);
}
- switch_img_free(&img);
+ switch_mutex_unlock(source->mutex);
}
+ switch_img_free(&img);
}
}
}
@@ -709,6 +754,9 @@ static switch_status_t local_stream_file_open(switch_file_handle_t *handle, cons
context->next = source->context_list;
source->context_list = context;
source->total++;
+ if (source->total == 1) {
+ source->first = 1;
+ }
switch_mutex_unlock(source->mutex);
end:
@@ -758,7 +806,9 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle
local_stream_context_t *context = handle->private_info;
switch_status_t status;
switch_time_t now;
-
+ int fps = (int)ceil(handle->mm.fps);
+ int min_qsize = fps;
+
if (!(context->ready && context->source->ready)) {
return SWITCH_STATUS_FALSE;
}
@@ -796,7 +846,7 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle
return SWITCH_STATUS_BREAK;
}
- while(context->ready && context->source->ready && (flags & SVR_FLUSH) && switch_queue_size(context->video_q) > 1) {
+ while(context->ready && context->source->ready && (flags & SVR_FLUSH) && switch_queue_size(context->video_q) > min_qsize / 2) {
if (switch_queue_trypop(context->video_q, &pop) == SWITCH_STATUS_SUCCESS) {
switch_image_t *img = (switch_image_t *) pop;
switch_img_free(&img);
@@ -807,6 +857,10 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle
return SWITCH_STATUS_FALSE;
}
+ while (switch_queue_size(context->video_q) < 5) {
+ return SWITCH_STATUS_BREAK;
+ }
+
if ((flags & SVR_BLOCK)) {
status = switch_queue_pop(context->video_q, &pop);
} else {
@@ -869,7 +923,7 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle
//switch_img_overlay(frame->img, context->banner_img, 0, frame->img->d_h - context->banner_img->d_h, 100);
switch_img_patch(frame->img, context->banner_img, 0, frame->img->d_h - context->banner_img->d_h);
}
-
+
return SWITCH_STATUS_SUCCESS;
}
@@ -1031,197 +1085,11 @@ static void event_handler(switch_event_t *event)
RUNNING = 0;
}
-#define RELOAD_LOCAL_STREAM_SYNTAX ""
-SWITCH_STANDARD_API(reload_local_stream_function)
+#define LOCAL_STREAM_SYNTAX " "
+SWITCH_STANDARD_API(local_stream_function)
{
local_stream_source_t *source = NULL;
- char *mycmd = NULL, *argv[1] = { 0 };
- char *local_stream_name = NULL;
- int argc = 0;
-
-
- if (zstr(cmd)) {
- goto usage;
- }
-
- if (!(mycmd = strdup(cmd))) {
- goto usage;
- }
-
- if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 1) {
- goto usage;
- }
-
- local_stream_name = argv[0];
- if (zstr(local_stream_name)) {
- goto usage;
- }
-
- switch_mutex_lock(globals.mutex);
- source = switch_core_hash_find(globals.source_hash, local_stream_name);
- switch_mutex_unlock(globals.mutex);
-
- if (!source) {
- stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
- goto done;
- }
-
- source->full_reload = 1;
- source->part_reload = 1;
- stream->write_function(stream, "+OK");
- goto done;
-
- usage:
- stream->write_function(stream, "-USAGE: %s\n", RELOAD_LOCAL_STREAM_SYNTAX);
- switch_safe_free(mycmd);
-
- done:
-
- switch_safe_free(mycmd);
- return SWITCH_STATUS_SUCCESS;
-}
-
-#define STOP_LOCAL_STREAM_SYNTAX ""
-SWITCH_STANDARD_API(stop_local_stream_function)
-{
- local_stream_source_t *source = NULL;
- char *mycmd = NULL, *argv[1] = { 0 };
- char *local_stream_name = NULL;
- int argc = 0;
-
-
- if (zstr(cmd)) {
- goto usage;
- }
-
- if (!(mycmd = strdup(cmd))) {
- goto usage;
- }
-
- if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 1) {
- goto usage;
- }
-
- local_stream_name = argv[0];
- if (zstr(local_stream_name)) {
- goto usage;
- }
-
- switch_mutex_lock(globals.mutex);
- source = switch_core_hash_find(globals.source_hash, local_stream_name);
- switch_mutex_unlock(globals.mutex);
-
- if (!source) {
- stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
- goto done;
- }
-
- source->stopped = 1;
- stream->write_function(stream, "+OK");
- goto done;
-
- usage:
- stream->write_function(stream, "-USAGE: %s\n", STOP_LOCAL_STREAM_SYNTAX);
- switch_safe_free(mycmd);
-
- done:
-
- switch_safe_free(mycmd);
- return SWITCH_STATUS_SUCCESS;
-}
-
-#define SHOW_LOCAL_STREAM_SYNTAX "[local_stream_name [xml]]"
-SWITCH_STANDARD_API(show_local_stream_function)
-{
- local_stream_source_t *source = NULL;
- char *mycmd = NULL, *argv[2] = { 0 };
- char *local_stream_name = NULL;
- int argc = 0;
- switch_hash_index_t *hi;
- const void *var;
- void *val;
- switch_bool_t xml = SWITCH_FALSE;
-
- switch_mutex_lock(globals.mutex);
-
- if (zstr(cmd)) {
- for (hi = switch_core_hash_first(globals.source_hash); hi; hi = switch_core_hash_next(&hi)) {
- switch_core_hash_this(hi, &var, NULL, &val);
- if ((source = (local_stream_source_t *) val)) {
- stream->write_function(stream, "%s,%s\n", source->name, source->location);
- }
- }
- } else {
- if (!(mycmd = strdup(cmd))) {
- goto usage;
- }
-
- if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
- local_stream_name = argv[0];
- if (argc > 1 && !strcasecmp("xml", argv[1])) {
- xml = SWITCH_TRUE;
- }
- }
-
- if (!local_stream_name) {
- goto usage;
- }
-
- source = switch_core_hash_find(globals.source_hash, local_stream_name);
- if (source) {
- if (xml) {
- stream->write_function(stream, "\n\n", source->name);
- stream->write_function(stream, " %s\n", source->location);
- stream->write_function(stream, " %d\n", source->channels);
- stream->write_function(stream, " %d\n", source->rate);
- stream->write_function(stream, " %d\n", source->interval);
- stream->write_function(stream, " %d\n", source->samples);
- stream->write_function(stream, " %d\n", source->prebuf);
- stream->write_function(stream, " %s\n", source->timer_name);
- stream->write_function(stream, " %d\n", source->total);
- stream->write_function(stream, " %s\n", (source->shuffle) ? "true" : "false");
- stream->write_function(stream, " %s\n", (source->ready) ? "true" : "false");
- stream->write_function(stream, " %s\n", (source->stopped) ? "true" : "false");
- stream->write_function(stream, "\n");
- } else {
- stream->write_function(stream, "%s\n", source->name);
- stream->write_function(stream, " location: %s\n", source->location);
- stream->write_function(stream, " channels: %d\n", source->channels);
- stream->write_function(stream, " rate: %d\n", source->rate);
- stream->write_function(stream, " interval: %d\n", source->interval);
- stream->write_function(stream, " samples: %d\n", source->samples);
- stream->write_function(stream, " prebuf: %d\n", source->prebuf);
- stream->write_function(stream, " timer: %s\n", source->timer_name);
- stream->write_function(stream, " total: %d\n", source->total);
- stream->write_function(stream, " shuffle: %s\n", (source->shuffle) ? "true" : "false");
- stream->write_function(stream, " ready: %s\n", (source->ready) ? "true" : "false");
- stream->write_function(stream, " stopped: %s\n", (source->stopped) ? "true" : "false");
- stream->write_function(stream, " reloading: %s\n", (source->full_reload) ? "true" : "false");
- }
- } else {
- stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
- goto done;
- }
- }
-
- stream->write_function(stream, "+OK");
- goto done;
-
- usage:
- stream->write_function(stream, "-USAGE: %s\n", SHOW_LOCAL_STREAM_SYNTAX);
-
- done:
-
- switch_mutex_unlock(globals.mutex);
- switch_safe_free(mycmd);
- return SWITCH_STATUS_SUCCESS;
-}
-
-#define START_LOCAL_STREAM_SYNTAX ""
-SWITCH_STANDARD_API(start_local_stream_function)
-{
- local_stream_source_t *source = NULL;
- char *mycmd = NULL, *argv[8] = { 0 };
+ char *mycmd = NULL, *argv[5] = { 0 };
char *local_stream_name = NULL;
int argc = 0;
int ok = 0;
@@ -1238,68 +1106,124 @@ SWITCH_STANDARD_API(start_local_stream_function)
goto usage;
}
- local_stream_name = argv[0];
+ local_stream_name = argv[1];
+
+ if (!strcasecmp(argv[0], "hup")) {
+ switch_mutex_lock(globals.mutex);
+ source = switch_core_hash_find(globals.source_hash, local_stream_name);
+ switch_mutex_unlock(globals.mutex);
+
+ if (source) {
+ source->hup = 1;
+ stream->write_function(stream, "+OK hup stream: %s", source->name);
+ goto done;
+ }
+ } else if (!strcasecmp(argv[0], "stop")) {
+ switch_mutex_lock(globals.mutex);
+ source = switch_core_hash_find(globals.source_hash, local_stream_name);
+ switch_mutex_unlock(globals.mutex);
+
+ if (!source) {
+ stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
+ goto done;
+ }
+
+ source->stopped = 1;
+ stream->write_function(stream, "+OK");
+ } else if (!strcasecmp(argv[0], "reload")) {
+ switch_mutex_lock(globals.mutex);
+ source = switch_core_hash_find(globals.source_hash, local_stream_name);
+ switch_mutex_unlock(globals.mutex);
+
+ if (!source) {
+ stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
+ goto done;
+ }
+
+ source->full_reload = 1;
+ source->part_reload = 1;
+ stream->write_function(stream, "+OK");
+ } else if (!strcasecmp(argv[0], "start")) {
+ switch_mutex_lock(globals.mutex);
+ source = switch_core_hash_find(globals.source_hash, local_stream_name);
+ switch_mutex_unlock(globals.mutex);
+
+ if (source) {
+ source->stopped = 0;
+ stream->write_function(stream, "+OK stream: %s", source->name);
+ goto done;
+ }
+
+ if ((ok = launch_streams(local_stream_name))) {
+ stream->write_function(stream, "+OK stream: %s", local_stream_name);
+ goto done;
+ }
+
+ } else if (!strcasecmp(argv[0], "show")) {
+ switch_hash_index_t *hi;
+ const void *var;
+ void *val;
+ switch_bool_t xml = SWITCH_FALSE;
+
+ switch_mutex_lock(globals.mutex);
+ if (argc == 1) {
+ for (hi = switch_core_hash_first(globals.source_hash); hi; hi = switch_core_hash_next(&hi)) {
+ switch_core_hash_this(hi, &var, NULL, &val);
+ if ((source = (local_stream_source_t *) val)) {
+ stream->write_function(stream, "%s,%s\n", source->name, source->location);
+ }
+ }
+ } else {
+ if (argc == 4 && !strcasecmp("xml", argv[3])) {
+ xml = SWITCH_TRUE;
+ }
+
+ source = switch_core_hash_find(globals.source_hash, local_stream_name);
+
+ if (source) {
+ if (xml) {
+ stream->write_function(stream, "\n\n", source->name);
+ stream->write_function(stream, " %s\n", source->location);
+ stream->write_function(stream, " %d\n", source->channels);
+ stream->write_function(stream, " %d\n", source->rate);
+ stream->write_function(stream, " %d\n", source->interval);
+ stream->write_function(stream, " %d\n", source->samples);
+ stream->write_function(stream, " %d\n", source->prebuf);
+ stream->write_function(stream, " %s\n", source->timer_name);
+ stream->write_function(stream, " %d\n", source->total);
+ stream->write_function(stream, " %s\n", (source->shuffle) ? "true" : "false");
+ stream->write_function(stream, " %s\n", (source->ready) ? "true" : "false");
+ stream->write_function(stream, " %s\n", (source->stopped) ? "true" : "false");
+ stream->write_function(stream, "\n");
+ } else {
+ stream->write_function(stream, "%s\n", source->name);
+ stream->write_function(stream, " location: %s\n", source->location);
+ stream->write_function(stream, " channels: %d\n", source->channels);
+ stream->write_function(stream, " rate: %d\n", source->rate);
+ stream->write_function(stream, " interval: %d\n", source->interval);
+ stream->write_function(stream, " samples: %d\n", source->samples);
+ stream->write_function(stream, " prebuf: %d\n", source->prebuf);
+ stream->write_function(stream, " timer: %s\n", source->timer_name);
+ stream->write_function(stream, " total: %d\n", source->total);
+ stream->write_function(stream, " shuffle: %s\n", (source->shuffle) ? "true" : "false");
+ stream->write_function(stream, " ready: %s\n", (source->ready) ? "true" : "false");
+ stream->write_function(stream, " stopped: %s\n", (source->stopped) ? "true" : "false");
+ stream->write_function(stream, " reloading: %s\n", (source->full_reload) ? "true" : "false");
+ }
+ } else {
+ stream->write_function(stream, "-ERR Cannot locate local_stream %s!\n", local_stream_name);
+ }
+ }
+ switch_mutex_unlock(globals.mutex);
- switch_mutex_lock(globals.mutex);
- source = switch_core_hash_find(globals.source_hash, local_stream_name);
- switch_mutex_unlock(globals.mutex);
- if (source) {
- source->stopped = 0;
- stream->write_function(stream, "+OK stream: %s", source->name);
goto done;
}
-
- if ((ok = launch_streams(local_stream_name))) {
- stream->write_function(stream, "+OK stream: %s", local_stream_name);
- goto done;
- }
-
- usage:
- stream->write_function(stream, "-USAGE: %s\n", START_LOCAL_STREAM_SYNTAX);
-
- done:
-
- switch_safe_free(mycmd);
- return SWITCH_STATUS_SUCCESS;
-}
-
-#define HUP_LOCAL_STREAM_SYNTAX ""
-SWITCH_STANDARD_API(hup_local_stream_function)
-{
- local_stream_source_t *source = NULL;
- char *mycmd = NULL, *argv[8] = { 0 };
- char *local_stream_name = NULL;
- int argc = 0;
-
- if (zstr(cmd)) {
- goto usage;
- }
-
- if (!(mycmd = strdup(cmd))) {
- goto usage;
- }
-
- if ((argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) < 1) {
- goto usage;
- }
-
- local_stream_name = argv[0];
-
- switch_mutex_lock(globals.mutex);
- source = switch_core_hash_find(globals.source_hash, local_stream_name);
- switch_mutex_unlock(globals.mutex);
-
- if (source) {
- source->hup = 1;
- stream->write_function(stream, "+OK hup stream: %s", source->name);
- goto done;
- }
-
+
goto done;
-
- usage:
- stream->write_function(stream, "-USAGE: %s\n", START_LOCAL_STREAM_SYNTAX);
-
+
+ usage:
+ stream->write_function(stream, "-USAGE: %s\n", LOCAL_STREAM_SYNTAX);
+
done:
switch_safe_free(mycmd);
@@ -1337,15 +1261,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_local_stream_load)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind event handler!\n");
}
-
-
- SWITCH_ADD_API(commands_api_interface, "hup_local_stream", "Skip to next file in local_stream", hup_local_stream_function, RELOAD_LOCAL_STREAM_SYNTAX);
- SWITCH_ADD_API(commands_api_interface, "reload_local_stream", "Reloads a local_stream", reload_local_stream_function, RELOAD_LOCAL_STREAM_SYNTAX);
- SWITCH_ADD_API(commands_api_interface, "stop_local_stream", "Stops and unloads a local_stream", stop_local_stream_function, STOP_LOCAL_STREAM_SYNTAX);
- SWITCH_ADD_API(commands_api_interface, "start_local_stream", "Starts a new local_stream", start_local_stream_function, START_LOCAL_STREAM_SYNTAX);
- SWITCH_ADD_API(commands_api_interface, "show_local_stream", "Shows a local stream", show_local_stream_function, SHOW_LOCAL_STREAM_SYNTAX);
-
+ SWITCH_ADD_API(commands_api_interface, "local_stream", "manage local streams", local_stream_function, LOCAL_STREAM_SYNTAX);
+ // switch_console_set_complete("add sofia profile ::sofia::list_profiles start");
+ switch_console_set_complete("add local_stream show ::console::list_streams as xml");
+ switch_console_set_complete("add local_stream start");
+ switch_console_set_complete("add local_stream reload ::console::list_streams");
+ switch_console_set_complete("add local_stream stop ::console::list_streams");
+ switch_console_set_complete("add local_stream hup ::console::list_streams");
+ switch_console_add_complete_func("::console::list_streams", list_streams);
/* indicate that the module should continue to be loaded */
+
return SWITCH_STATUS_SUCCESS;
}
diff --git a/src/switch.c b/src/switch.c
index bd8c73ae91..942b5cd763 100644
--- a/src/switch.c
+++ b/src/switch.c
@@ -1089,6 +1089,10 @@ int main(int argc, char *argv[])
reincarnate_protect(reincarnate_reexec ? argv : NULL);
#endif
+ if (switch_core_set_process_privileges() < 0) {
+ return 255;
+ }
+
switch (priority) {
case 2:
set_realtime_priority();
diff --git a/src/switch_core.c b/src/switch_core.c
index e0c800e2bf..7e79a92f42 100644
--- a/src/switch_core.c
+++ b/src/switch_core.c
@@ -53,7 +53,9 @@
#ifdef HAVE_SYS_PRCTL_H
#include
#endif
-
+#ifdef SOLARIS_PRIVILEGES
+#include
+#endif
SWITCH_DECLARE_DATA switch_directories SWITCH_GLOBAL_dirs = { 0 };
SWITCH_DECLARE_DATA switch_filenames SWITCH_GLOBAL_filenames = { 0 };
@@ -888,20 +890,54 @@ SWITCH_DECLARE(void) switch_core_set_globals(void)
}
+SWITCH_DECLARE(int32_t) switch_core_set_process_privileges(void)
+{
+#ifdef SOLARIS_PRIVILEGES
+ priv_set_t *basicset;
+
+ /* make the process privilege-aware */
+ setpflags(PRIV_AWARE, 1);
+
+ /* reset the privileges to basic */
+ basicset = priv_str_to_set("basic", ",", NULL);
+ if (setppriv(PRIV_SET, PRIV_EFFECTIVE, basicset) != 0) {
+ fprintf(stderr, "ERROR: Failed to acquire basic privileges (%s)\n", strerror(errno));
+ }
+
+ /* we need high-resolution clock, and this requires a non-basic privilege */
+ if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_CLOCK_HIGHRES, NULL) < 0) {
+ fprintf(stderr, "ERROR: Failed to acquire proc_clock_highres privilege (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ /* need this for setrlimit */
+ if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_SYS_RESOURCE, NULL) < 0) {
+ fprintf(stderr, "ERROR: Failed to acquire sys_resource privilege (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ /* we need to read directories belonging to other uid */
+ if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_SEARCH, NULL) < 0) {
+ fprintf(stderr, "ERROR: Failed to acquire file_dac_search privilege (%s)\n", strerror(errno));
+ return -1;
+ }
+#endif
+ return 0;
+}
+
SWITCH_DECLARE(int32_t) set_low_priority(void)
{
-
-
#ifdef WIN32
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
#else
-#ifdef USE_SCHED_SETSCHEDULER
+#if defined(USE_SCHED_SETSCHEDULER) && ! defined(SOLARIS_PRIVILEGES)
/*
* Try to use a normal scheduler
*/
struct sched_param sched = { 0 };
sched.sched_priority = 0;
- if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
+ if (sched_setscheduler(0, SCHED_OTHER, &sched) < 0) {
+ fprintf(stderr, "ERROR: Failed to set SCHED_OTHER scheduler (%s)\n", strerror(errno));
return -1;
}
#endif
@@ -911,12 +947,12 @@ SWITCH_DECLARE(int32_t) set_low_priority(void)
* setpriority() works on FreeBSD (6.2), nice() doesn't
*/
if (setpriority(PRIO_PROCESS, getpid(), 19) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
+ fprintf(stderr, "ERROR: Could not set nice level\n");
return -1;
}
#else
if (nice(19) != 19) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
+ fprintf(stderr, "ERROR: Could not set nice level\n");
return -1;
}
#endif
@@ -937,32 +973,60 @@ SWITCH_DECLARE(int32_t) set_realtime_priority(void)
*/
struct sched_param sched = { 0 };
sched.sched_priority = SWITCH_PRI_LOW;
- if (sched_setscheduler(0, SCHED_FIFO, &sched)) {
+#endif
+
+#ifdef SOLARIS_PRIVILEGES
+ /* request the privileges to elevate the priority */
+ if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_PRIOCNTL, NULL) < 0) {
+ fprintf(stderr, "WARN: Failed to acquire proc_priocntl privilege (%s)\n", strerror(errno));
+ } else {
+ if (sched_setscheduler(0, SCHED_FIFO, &sched) < 0) {
+ fprintf(stderr, "ERROR: Failed to set SCHED_FIFO scheduler (%s)\n", strerror(errno));
+ } else {
+ return 0;
+ }
+ }
+
+ if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_PRIOUP, NULL) < 0) {
+ fprintf(stderr, "ERROR: Failed to acquire proc_prioup privilege (%s)\n", strerror(errno));
+ return -1;
+ } else {
+ if (setpriority(PRIO_PROCESS, 0, -10) < 0) {
+ fprintf(stderr, "ERROR: Could not set nice level\n");
+ return -1;
+ }
+ }
+ return 0;
+#else
+
+#ifdef USE_SCHED_SETSCHEDULER
+ if (sched_setscheduler(0, SCHED_FIFO, &sched) < 0) {
+ fprintf(stderr, "ERROR: Failed to set SCHED_FIFO scheduler (%s)\n", strerror(errno));
sched.sched_priority = 0;
- if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
+ if (sched_setscheduler(0, SCHED_OTHER, &sched) < 0 ) {
+ fprintf(stderr, "ERROR: Failed to set SCHED_OTHER scheduler (%s)\n", strerror(errno));
return -1;
}
}
#endif
-
-
#ifdef HAVE_SETPRIORITY
/*
* setpriority() works on FreeBSD (6.2), nice() doesn't
*/
if (setpriority(PRIO_PROCESS, getpid(), -10) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
+ fprintf(stderr, "ERROR: Could not set nice level\n");
return -1;
}
#else
if (nice(-10) != -10) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
+ fprintf(stderr, "ERROR: Could not set nice level\n");
return -1;
}
#endif
#endif
return 0;
+#endif
}
SWITCH_DECLARE(uint32_t) switch_core_cpu_count(void)
@@ -1006,7 +1070,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
*/
runas_pw = getpwnam(user);
if (!runas_pw) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unknown user \"%s\"\n", user);
+ fprintf(stderr, "ERROR: Unknown user \"%s\"\n", user);
return -1;
}
runas_uid = runas_pw->pw_uid;
@@ -1020,7 +1084,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
*/
gr = getgrnam(group);
if (!gr) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unknown group \"%s\"\n", group);
+ fprintf(stderr, "ERROR: Unknown group \"%s\"\n", group);
return -1;
}
runas_gid = gr->gr_gid;
@@ -1032,6 +1096,13 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
}
if (runas_uid) {
+#ifdef SOLARIS_PRIVILEGES
+ /* request the privilege to set the UID */
+ if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_SETID, NULL) < 0) {
+ fprintf(stderr, "ERROR: Failed to acquire proc_setid privilege (%s)\n", strerror(errno));
+ return -1;
+ }
+#endif
#ifdef HAVE_SETGROUPS
/*
* Drop all group memberships prior to changing anything
@@ -1039,7 +1110,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* (which is not what we want...)
*/
if (setgroups(0, NULL) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to drop group access list\n");
+ fprintf(stderr, "ERROR: Failed to drop group access list\n");
return -1;
}
#endif
@@ -1049,7 +1120,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* (without loading the user's other groups)
*/
if (setgid(runas_gid) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n");
+ fprintf(stderr, "ERROR: Failed to change gid!\n");
return -1;
}
} else {
@@ -1057,7 +1128,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* No group has been passed, use the user's primary group in this case
*/
if (setgid(runas_pw->pw_gid) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n");
+ fprintf(stderr, "ERROR: Failed to change gid!\n");
return -1;
}
#ifdef HAVE_INITGROUPS
@@ -1066,7 +1137,7 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* (This can be really useful for fine-grained access control)
*/
if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to set group access list for user\n");
+ fprintf(stderr, "ERROR: Failed to set group access list for user\n");
return -1;
}
#endif
@@ -1076,12 +1147,12 @@ SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
* Finally drop all privileges by switching to the new userid
*/
if (setuid(runas_uid) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change uid!\n");
+ fprintf(stderr, "ERROR: Failed to change uid!\n");
return -1;
}
#ifdef HAVE_SYS_PRCTL_H
if (prctl(PR_SET_DUMPABLE, 1) < 0) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to enable core dumps!\n");
+ fprintf(stderr, "ERROR: Failed to enable core dumps!\n");
return -1;
}
#endif
diff --git a/src/switch_core_file.c b/src/switch_core_file.c
index 69433dbdb2..c6d92ded06 100644
--- a/src/switch_core_file.c
+++ b/src/switch_core_file.c
@@ -85,6 +85,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file,
fh->mm.keyint = 60;
fh->mm.ab = 128;
fh->mm.vencspd = SWITCH_VIDEO_ENCODE_SPEED_DEFAULT;
+ fh->mm.vprofile = SWITCH_VIDEO_PROFILE_BASELINE;
if (*file_path == '{') {
char *timeout;
@@ -199,6 +200,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file,
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid video encode speed: %s\n", val);
}
}
+
+ if ((val = switch_event_get_header(fh->params, "vprofile"))) {
+ if (!strcasecmp(val, "baseline")) {
+ fh->mm.vprofile = SWITCH_VIDEO_PROFILE_BASELINE;
+ } else if (!strcasecmp(val, "main")) {
+ fh->mm.vprofile = SWITCH_VIDEO_PROFILE_MAIN;
+ } else if (!strcasecmp(val, "high")) {
+ fh->mm.vprofile = SWITCH_VIDEO_PROFILE_HIGH;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid video profile: %s\n", val);
+ }
+ }
}
if (switch_directory_exists(file_path, fh->memory_pool) == SWITCH_STATUS_SUCCESS) {
diff --git a/src/switch_core_media.c b/src/switch_core_media.c
index c0163f07e6..d2846fa637 100644
--- a/src/switch_core_media.c
+++ b/src/switch_core_media.c
@@ -1429,7 +1429,7 @@ SWITCH_DECLARE(void) switch_core_session_check_outgoing_crypto(switch_core_sessi
switch_media_handle_t *smh;
int i;
- if (!switch_core_session_media_handle_ready(session) == SWITCH_STATUS_SUCCESS) {
+ if (switch_core_session_media_handle_ready(session) != SWITCH_STATUS_SUCCESS) {
return;
}
@@ -1748,7 +1748,7 @@ SWITCH_DECLARE(switch_core_media_params_t *) switch_core_media_get_mparams(switc
SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *session, switch_bool_t force)
{
const char *abs, *codec_string = NULL;
- const char *ocodec = NULL;
+ const char *ocodec = NULL, *val;
switch_media_handle_t *smh;
switch_assert(session);
@@ -1778,6 +1778,14 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses
goto ready;
}
+ val = switch_channel_get_variable_dup(session->channel, "media_mix_inbound_outbound_codecs", SWITCH_FALSE, -1);
+ if (!val || !switch_true(val)) {
+ if ((ocodec = switch_channel_get_variable(session->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
+ codec_string = ocodec;
+ goto ready;
+ }
+ }
+
if (!(codec_string = switch_channel_get_variable(session->channel, "codec_string"))) {
codec_string = switch_core_media_get_codec_string(smh->session);
}
@@ -1787,7 +1795,7 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses
goto ready;
}
- if ((ocodec = switch_channel_get_variable(session->channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
+ if (ocodec) {
if (!codec_string || (smh->media_flags[SCMF_DISABLE_TRANSCODING])) {
codec_string = ocodec;
} else {
@@ -4053,6 +4061,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
if (!best_te || map->rm_rate == a_engine->cur_payload_map->rm_rate) {
best_te = (switch_payload_t) map->rm_pt;
best_te_rate = map->rm_rate;
+ smh->mparams->recv_te = best_te;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set telephone-event payload to %u@%ld\n", best_te, best_te_rate);
}
continue;
@@ -4396,6 +4405,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
if (!best_te || map->rm_rate == a_engine->cur_payload_map->adv_rm_rate) {
best_te = (switch_payload_t) map->rm_pt;
best_te_rate = map->rm_rate;
+ smh->mparams->recv_te = best_te;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set telephone-event payload to %u@%lu\n", best_te, best_te_rate);
}
continue;
@@ -4432,9 +4442,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
}
if (best_te) {
- if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
+ if (sdp_type == SDP_TYPE_RESPONSE) {
te = smh->mparams->te = (switch_payload_t) best_te;
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", best_te);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Set 2833 dtmf send payload to %u\n",
+ switch_channel_get_name(session->channel), best_te);
switch_channel_set_variable(session->channel, "dtmf_type", "rfc2833");
smh->mparams->dtmf_type = DTMF_2833;
if (a_engine->rtp_session) {
@@ -4444,7 +4455,8 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
} else {
te = smh->mparams->recv_te = smh->mparams->te = (switch_payload_t) best_te;
smh->mparams->te_rate = best_te_rate;
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send/recv payload to %u\n", te);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Set 2833 dtmf send/recv payload to %u\n",
+ switch_channel_get_name(session->channel), te);
switch_channel_set_variable(session->channel, "dtmf_type", "rfc2833");
smh->mparams->dtmf_type = DTMF_2833;
if (a_engine->rtp_session) {
@@ -5116,9 +5128,9 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi
if (switch_channel_test_flag(channel, CF_VIDEO_READY)) {
switch_mutex_lock(mh->file_mutex);
if (smh->video_write_fh && switch_channel_ready(session->channel) && switch_test_flag(smh->video_write_fh, SWITCH_FILE_OPEN)) {
- switch_status_t wstatus = switch_core_file_read_video(smh->video_write_fh, &fr, SVR_FLUSH);
+ switch_status_t wstatus = switch_core_file_read_video(smh->video_write_fh, &fr, 0);
if (wstatus == SWITCH_STATUS_SUCCESS) {
- switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_NONE, 0);
+ switch_core_session_write_video_frame(session, &fr, SWITCH_IO_FLAG_NONE, SVR_FLUSH);
switch_img_free(&fr.img);
} else if (wstatus != SWITCH_STATUS_BREAK && wstatus != SWITCH_STATUS_IGNORE) {
smh->video_write_fh = NULL;
@@ -6303,13 +6315,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi
}
if (smh->mparams->te) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf send payload to %u\n", smh->mparams->te);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Set 2833 dtmf send payload to %u\n",
+ switch_channel_get_name(session->channel), smh->mparams->te);
switch_rtp_set_telephony_event(a_engine->rtp_session, smh->mparams->te);
switch_channel_set_variable_printf(session->channel, "rtp_2833_send_payload", "%d", smh->mparams->te);
}
if (smh->mparams->recv_te) {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set 2833 dtmf receive payload to %u\n", smh->mparams->recv_te);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Set 2833 dtmf receive payload to %u\n",
+ switch_channel_get_name(session->channel), smh->mparams->recv_te);
switch_rtp_set_telephony_recv_event(a_engine->rtp_session, smh->mparams->recv_te);
switch_channel_set_variable_printf(session->channel, "rtp_2833_recv_payload", "%d", smh->mparams->recv_te);
}
@@ -7925,8 +7939,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess
if (ov_fmtp) {
pass_fmtp = ov_fmtp;
- } else { //if (switch_true(switch_channel_get_variable_dup(session->channel, "rtp_mirror_fmtp", SWITCH_FALSE, -1))) {
- // seems to break eyebeam at least...
+ } else if (switch_true(switch_channel_get_variable_dup(session->channel, "rtp_mirror_fmtp", SWITCH_FALSE, -1))) {
pass_fmtp = switch_channel_get_variable(session->channel, "rtp_video_fmtp");
}
}
@@ -8306,13 +8319,13 @@ SWITCH_DECLARE(void) switch_core_media_set_udptl_image_sdp(switch_core_session_t
uint32_t port;
const char *family = "IP4";
const char *username;
- const char *bit_removal_on = "a=T38FaxFillBitRemoval\n";
+ const char *bit_removal_on = "a=T38FaxFillBitRemoval\r\n";
const char *bit_removal_off = "";
- const char *mmr_on = "a=T38FaxTranscodingMMR\n";
+ const char *mmr_on = "a=T38FaxTranscodingMMR\r\n";
const char *mmr_off = "";
- const char *jbig_on = "a=T38FaxTranscodingJBIG\n";
+ const char *jbig_on = "a=T38FaxTranscodingJBIG\r\n";
const char *jbig_off = "";
const char *var;
int broken_boolean;
@@ -8375,46 +8388,46 @@ SWITCH_DECLARE(void) switch_core_media_set_udptl_image_sdp(switch_core_session_t
switch_snprintf(buf, sizeof(buf),
- "v=0\n"
- "o=%s %010u %010u IN %s %s\n"
- "s=%s\n" "c=IN %s %s\n" "t=0 0\n", username, smh->owner_id, smh->session_id, family, ip, username, family, ip);
+ "v=0\r\n"
+ "o=%s %010u %010u IN %s %s\r\n"
+ "s=%s\r\n" "c=IN %s %s\r\n" "t=0 0\r\n", username, smh->owner_id, smh->session_id, family, ip, username, family, ip);
if (t38_options->T38FaxMaxBuffer) {
- switch_snprintf(max_buf, sizeof(max_buf), "a=T38FaxMaxBuffer:%d\n", t38_options->T38FaxMaxBuffer);
+ switch_snprintf(max_buf, sizeof(max_buf), "a=T38FaxMaxBuffer:%d\r\n", t38_options->T38FaxMaxBuffer);
};
if (t38_options->T38FaxMaxDatagram) {
- switch_snprintf(max_data, sizeof(max_data), "a=T38FaxMaxDatagram:%d\n", t38_options->T38FaxMaxDatagram);
+ switch_snprintf(max_data, sizeof(max_data), "a=T38FaxMaxDatagram:%d\r\n", t38_options->T38FaxMaxDatagram);
};
if (broken_boolean) {
- bit_removal_on = "a=T38FaxFillBitRemoval:1\n";
- bit_removal_off = "a=T38FaxFillBitRemoval:0\n";
+ bit_removal_on = "a=T38FaxFillBitRemoval:1\r\n";
+ bit_removal_off = "a=T38FaxFillBitRemoval:0\r\n";
- mmr_on = "a=T38FaxTranscodingMMR:1\n";
- mmr_off = "a=T38FaxTranscodingMMR:0\n";
+ mmr_on = "a=T38FaxTranscodingMMR:1\r\n";
+ mmr_off = "a=T38FaxTranscodingMMR:0\r\n";
- jbig_on = "a=T38FaxTranscodingJBIG:1\n";
- jbig_off = "a=T38FaxTranscodingJBIG:0\n";
+ jbig_on = "a=T38FaxTranscodingJBIG:1\r\n";
+ jbig_off = "a=T38FaxTranscodingJBIG:0\r\n";
}
switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- "m=image %d udptl t38\n"
- "a=T38FaxVersion:%d\n"
- "a=T38MaxBitRate:%d\n"
+ "m=image %d udptl t38\r\n"
+ "a=T38FaxVersion:%d\r\n"
+ "a=T38MaxBitRate:%d\r\n"
"%s"
"%s"
"%s"
- "a=T38FaxRateManagement:%s\n"
+ "a=T38FaxRateManagement:%s\r\n"
"%s"
"%s"
- "a=T38FaxUdpEC:%s\n",
- //"a=T38VendorInfo:%s\n",
+ "a=T38FaxUdpEC:%s\r\n",
+ //"a=T38VendorInfo:%s\r\n",
port,
t38_options->T38FaxVersion,
t38_options->T38MaxBitRate,
@@ -8431,7 +8444,7 @@ SWITCH_DECLARE(void) switch_core_media_set_udptl_image_sdp(switch_core_session_t
if (insist) {
- switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "m=audio 0 RTP/AVP 19\n");
+ switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "m=audio 0 RTP/AVP 19\r\n");
}
switch_core_media_set_local_sdp(session, buf, SWITCH_TRUE);
@@ -8943,11 +8956,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_se
break;
case SWITCH_MESSAGE_INDICATE_HARD_MUTE:
- {
- if (session->bugs) {
+ if (a_engine->rtp_session) {
+ if (session->bugs && msg->numeric_arg) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
"%s has a media bug, hard mute not allowed.\n", switch_channel_get_name(session->channel));
- } else if (a_engine->rtp_session) {
+ } else {
if (msg->numeric_arg) {
switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_MUTE);
} else {
diff --git a/src/switch_core_media_bug.c b/src/switch_core_media_bug.c
index 681bd4d173..3a02f2f441 100644
--- a/src/switch_core_media_bug.c
+++ b/src/switch_core_media_bug.c
@@ -854,6 +854,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t
switch_event_fire(&event);
}
+ switch_core_media_hard_mute(session, SWITCH_FALSE);
+
return SWITCH_STATUS_SUCCESS;
}
diff --git a/src/switch_core_video.c b/src/switch_core_video.c
index eaa6c9fe74..4ea9669d6c 100644
--- a/src/switch_core_video.c
+++ b/src/switch_core_video.c
@@ -48,7 +48,9 @@
#include
#endif
+#ifdef SWITCH_HAVE_YUV
static inline void switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_color_t *yuv, int x, int y);
+#endif
static inline void switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_color_t *rgb, int x, int y);
@@ -58,14 +60,18 @@ static inline void switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_colo
* \param[in] rgb RGB color pointer
* \param[out] yuv YUV color pointer
*/
+#ifdef SWITCH_HAVE_YUV
static inline void switch_color_rgb2yuv(switch_rgb_color_t *rgb, switch_yuv_color_t *yuv);
+#endif
/*!\brief Convert YUV color to RGB
*
* \param[in] yuv YUV color pointer
* \param[out] rgb RGB color pointer
*/
+#ifdef SWITCH_HAVE_YUV
static inline void switch_color_yuv2rgb(switch_yuv_color_t *yuv, switch_rgb_color_t *rgb);
+#endif
/*!\brief Draw a pixel on an image
*
@@ -542,17 +548,17 @@ SWITCH_DECLARE(void) switch_img_fill(switch_image_t *img, int x, int y, int w, i
#endif
}
+#ifdef SWITCH_HAVE_YUV
static inline void switch_img_get_yuv_pixel(switch_image_t *img, switch_yuv_color_t *yuv, int x, int y)
{
-#ifdef SWITCH_HAVE_YUV
// switch_assert(img->fmt == SWITCH_IMG_FMT_I420);
if (x < 0 || y < 0 || x >= img->d_w || y >= img->d_h) return;
yuv->y = *(img->planes[SWITCH_PLANE_Y] + img->stride[SWITCH_PLANE_Y] * y + x);
yuv->u = *(img->planes[SWITCH_PLANE_U] + img->stride[SWITCH_PLANE_U] * y / 2 + x / 2);
yuv->v = *(img->planes[SWITCH_PLANE_V] + img->stride[SWITCH_PLANE_V] * y / 2 + x / 2);
-#endif
}
+#endif
static inline void switch_img_get_rgb_pixel(switch_image_t *img, switch_rgb_color_t *rgb, int x, int y)
{
@@ -699,20 +705,20 @@ SWITCH_DECLARE(void) switch_color_set_rgb(switch_rgb_color_t *color, const char
}
}
+#ifdef SWITCH_HAVE_YUV
static inline void switch_color_rgb2yuv(switch_rgb_color_t *rgb, switch_yuv_color_t *yuv)
{
-#ifdef SWITCH_HAVE_YUV
yuv->y = (uint8_t)(((rgb->r * 4897) >> 14) + ((rgb->g * 9611) >> 14) + ((rgb->b * 1876) >> 14));
yuv->u = (uint8_t)(- ((rgb->r * 2766) >> 14) - ((5426 * rgb->g) >> 14) + rgb->b / 2 + 128);
yuv->v = (uint8_t)(rgb->r / 2 -((6855 * rgb->g) >> 14) - ((rgb->b * 1337) >> 14) + 128);
-#endif
}
+#endif
#define CLAMP(val) MAX(0, MIN(val, 255))
+#ifdef SWITCH_HAVE_YUV
static inline void switch_color_yuv2rgb(switch_yuv_color_t *yuv, switch_rgb_color_t *rgb)
{
-#ifdef SWITCH_HAVE_YUV
#if 0
int C = yuv->y - 16;
int D = yuv->u - 128;
@@ -727,8 +733,8 @@ static inline void switch_color_yuv2rgb(switch_yuv_color_t *yuv, switch_rgb_colo
rgb->r = CLAMP( yuv->y + ((22457 * (yuv->v-128)) >> 14));
rgb->g = CLAMP((yuv->y - ((715 * (yuv->v-128)) >> 10) - ((5532 * (yuv->u-128)) >> 14)));
rgb->b = CLAMP((yuv->y + ((28384 * (yuv->u-128)) >> 14)));
-#endif
}
+#endif
SWITCH_DECLARE(void) switch_color_set_yuv(switch_yuv_color_t *color, const char *str)
{
diff --git a/src/switch_ivr.c b/src/switch_ivr.c
index f1995c52ee..766aa0d8ad 100644
--- a/src/switch_ivr.c
+++ b/src/switch_ivr.c
@@ -159,7 +159,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
if (!switch_channel_media_ready(channel)) {
- for (elapsed=0; switch_channel_up(channel) && elapsed<(ms/20); elapsed++) {
+ for (elapsed=0; switch_channel_ready(channel) && elapsed<(ms/20); elapsed++) {
if (switch_channel_test_flag(channel, CF_BREAK)) {
switch_channel_clear_flag(channel, CF_BREAK);
switch_goto_status(SWITCH_STATUS_BREAK, end);
@@ -820,14 +820,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_messages(switch_core_sessio
}
-static switch_status_t switch_ivr_parse_signal_data(switch_core_session_t *session, switch_bool_t all)
+SWITCH_DECLARE(switch_status_t) switch_ivr_parse_signal_data(switch_core_session_t *session, switch_bool_t all, switch_bool_t only_session_thread)
{
void *data;
switch_core_session_message_t msg = { 0 };
int i = 0;
switch_channel_t *channel = switch_core_session_get_channel(session);
- if (!switch_core_session_in_thread(session)) {
+ if (only_session_thread && !switch_core_session_in_thread(session)) {
return SWITCH_STATUS_FALSE;
}
@@ -857,11 +857,11 @@ static switch_status_t switch_ivr_parse_signal_data(switch_core_session_t *sessi
}
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_signal_data(switch_core_session_t *session) {
- return switch_ivr_parse_signal_data(session, SWITCH_TRUE);
+ return switch_ivr_parse_signal_data(session, SWITCH_TRUE, SWITCH_FALSE);
}
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_next_signal_data(switch_core_session_t *session) {
- return switch_ivr_parse_signal_data(session, SWITCH_FALSE);
+ return switch_ivr_parse_signal_data(session, SWITCH_FALSE, SWITCH_FALSE);
}
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_events(switch_core_session_t *session)
diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c
index 9f5b472b19..d55b8ac29b 100644
--- a/src/switch_ivr_async.c
+++ b/src/switch_ivr_async.c
@@ -1113,11 +1113,14 @@ static void *SWITCH_THREAD_FUNC recording_thread(switch_thread_t *thread, void *
switch_size_t bsize = SWITCH_RECOMMENDED_BUFFER_SIZE, samples = 0, inuse = 0;
unsigned char *data;
int channels = 1;
+ switch_codec_implementation_t read_impl = { 0 };
if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) {
return NULL;
}
+ switch_core_session_get_read_impl(session, &read_impl);
+ bsize = read_impl.decoded_bytes_per_packet;
rh = switch_core_media_bug_get_user_data(bug);
switch_buffer_create_dynamic(&rh->thread_buffer, 1024 * 512, 1024 * 64, 0);
rh->thread_ready = 1;
diff --git a/src/switch_jitterbuffer.c b/src/switch_jitterbuffer.c
index cf6bf6dd69..530db657e3 100644
--- a/src/switch_jitterbuffer.c
+++ b/src/switch_jitterbuffer.c
@@ -65,6 +65,7 @@ struct switch_jb_s {
uint32_t target_ts;
uint32_t last_target_ts;
uint16_t psuedo_seq;
+ uint16_t last_psuedo_seq;
uint32_t visible_nodes;
uint32_t complete_frames;
uint32_t frame_len;
@@ -581,6 +582,8 @@ static inline void increment_ts(switch_jb_t *jb)
{
if (!jb->target_ts) return;
+ jb->last_psuedo_seq = jb->psuedo_seq;
+ jb->last_target_ts = jb->target_ts;
jb->target_ts = htonl((ntohl(jb->target_ts) + jb->samples_per_frame));
jb->psuedo_seq++;
}
@@ -589,6 +592,7 @@ static inline void set_read_ts(switch_jb_t *jb, uint32_t ts)
{
if (!ts) return;
+ jb->last_psuedo_seq = jb->psuedo_seq;
jb->last_target_ts = ts;
jb->target_ts = htonl((ntohl(jb->last_target_ts) + jb->samples_per_frame));
jb->psuedo_seq++;
@@ -597,6 +601,7 @@ static inline void set_read_ts(switch_jb_t *jb, uint32_t ts)
static inline void increment_seq(switch_jb_t *jb)
{
+ jb->last_target_seq = jb->target_seq;
jb->target_seq = htons((ntohs(jb->target_seq) + 1));
}
@@ -828,13 +833,12 @@ SWITCH_DECLARE(void) switch_jb_reset(switch_jb_t *jb)
SWITCH_DECLARE(switch_status_t) switch_jb_peek_frame(switch_jb_t *jb, uint32_t ts, uint16_t seq, int peek, switch_frame_t *frame)
{
switch_jb_node_t *node = NULL;
-
if (seq) {
uint16_t want_seq = seq + peek;
- node = switch_core_inthash_find(jb->node_hash, want_seq);
+ node = switch_core_inthash_find(jb->node_hash, htons(want_seq));
} else if (ts && jb->samples_per_frame) {
uint32_t want_ts = ts + (peek * jb->samples_per_frame);
- node = switch_core_inthash_find(jb->node_hash_ts, want_ts);
+ node = switch_core_inthash_find(jb->node_hash_ts, htonl(want_ts));
}
if (node) {
@@ -842,6 +846,7 @@ SWITCH_DECLARE(switch_status_t) switch_jb_peek_frame(switch_jb_t *jb, uint32_t t
frame->timestamp = ntohl(node->packet.header.ts);
frame->m = node->packet.header.m;
frame->datalen = node->len;
+
if (frame->data && frame->buflen > node->len) {
memcpy(frame->data, node->packet.body, node->len);
}
@@ -1129,9 +1134,14 @@ SWITCH_DECLARE(switch_status_t) switch_jb_get_packet(switch_jb_t *jb, switch_rtp
{
switch_jb_node_t *node = NULL;
switch_status_t status;
-
+ int plc = 0;
+
switch_mutex_lock(jb->mutex);
+ if (jb->complete_frames == 0) {
+ switch_goto_status(SWITCH_STATUS_BREAK, end);
+ }
+
if (jb->complete_frames < jb->frame_len) {
jb_debug(jb, 2, "BUFFERING %u/%u\n", jb->complete_frames , jb->frame_len);
switch_goto_status(SWITCH_STATUS_MORE_DATA, end);
@@ -1230,6 +1240,7 @@ SWITCH_DECLARE(switch_status_t) switch_jb_get_packet(switch_jb_t *jb, switch_rtp
switch_goto_status(SWITCH_STATUS_RESTART, end);
} else {
jb_debug(jb, 2, "%s", "Frame not found suggest PLC\n");
+ plc = 1;
switch_goto_status(SWITCH_STATUS_NOTFOUND, end);
}
}
@@ -1253,6 +1264,21 @@ SWITCH_DECLARE(switch_status_t) switch_jb_get_packet(switch_jb_t *jb, switch_rtp
end:
+ if (plc) {
+ uint16_t seq;
+ uint32_t ts = 0;
+
+ if (jb->samples_per_frame) {
+ seq = htons(jb->last_psuedo_seq);
+ ts = jb->last_target_ts;
+ } else {
+ seq = jb->last_target_seq;
+ }
+
+ packet->header.seq = seq;
+ packet->header.ts = ts;
+ }
+
switch_mutex_unlock(jb->mutex);
if (status == SWITCH_STATUS_SUCCESS && jb->type == SJB_AUDIO) {
diff --git a/src/switch_rtp.c b/src/switch_rtp.c
index bc3ca09fc9..ea5fc24504 100644
--- a/src/switch_rtp.c
+++ b/src/switch_rtp.c
@@ -71,6 +71,7 @@
#define WARN_SRTP_ERRS 10
#define MAX_SRTP_ERRS 100
#define NTP_TIME_OFFSET 2208988800UL
+#define ZRTP_MAGIC_COOKIE 0x5a525450
static const switch_payload_t INVALID_PT = 255;
#define DTMF_SANITY (rtp_session->one_second * 30)
@@ -80,7 +81,7 @@ static const switch_payload_t INVALID_PT = 255;
static switch_port_t START_PORT = RTP_START_PORT;
static switch_port_t END_PORT = RTP_END_PORT;
static switch_mutex_t *port_lock = NULL;
-static void do_flush(switch_rtp_t *rtp_session, int force);
+static switch_size_t do_flush(switch_rtp_t *rtp_session, int force, switch_size_t bytes_in);
typedef srtp_hdr_t rtp_hdr_t;
@@ -434,6 +435,12 @@ struct switch_rtp {
switch_core_session_t *session;
payload_map_t **pmaps;
payload_map_t *pmap_tail;
+ int ice_adj;
+ uint8_t has_rtp;
+ uint8_t has_rtcp;
+ uint8_t has_ice;
+ uint8_t punts;
+ uint8_t clean;
#ifdef ENABLE_ZRTP
zrtp_session_t *zrtp_session;
zrtp_profile_t *zrtp_profile;
@@ -552,7 +559,7 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_
*/
if (bytes > rtp_header_len && !rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] &&
- rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
+ rtp_session->last_rtp_hdr.pt == rtp_session->recv_te) {
switch_size_t len = bytes - rtp_header_len;
unsigned char *packet = (unsigned char *) RTP_BODY(rtp_session);
int end;
@@ -580,8 +587,8 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_
end = packet[1] & 0x80 ? 1 : 0;
duration = (packet[2] << 8) + packet[3];
key = switch_rfc2833_to_char(packet[0]);
- in_digit_seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
- ts = htonl(rtp_session->recv_msg.header.ts);
+ in_digit_seq = ntohs((uint16_t) rtp_session->last_rtp_hdr.seq);
+ ts = htonl(rtp_session->last_rtp_hdr.ts);
if (rtp_session->flags[SWITCH_RTP_FLAG_PASS_RFC2833]) {
@@ -610,7 +617,7 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "read: %c %u %u %u %u %d %d %s\n",
key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq,
- ts, duration, rtp_session->recv_msg.header.m, end, end && !rtp_session->dtmf_data.in_digit_ts ? "ignored" : "");
+ ts, duration, rtp_session->last_rtp_hdr.m, end, end && !rtp_session->dtmf_data.in_digit_ts ? "ignored" : "");
#endif
if (!rtp_session->dtmf_data.in_digit_queued && rtp_session->dtmf_data.in_digit_ts) {
@@ -702,7 +709,7 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_
} else {
#ifdef DEBUG_2833
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "drop: %c %u %u %u %u %d %d\n",
- key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq, ts, duration, rtp_session->recv_msg.header.m, end);
+ key, in_digit_seq, rtp_session->dtmf_data.in_digit_seq, ts, duration, rtp_session->last_rtp_hdr.m, end);
#endif
switch_cond_next();
return RESULT_GOTO_RECVFROM;
@@ -714,13 +721,13 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_
return RESULT_GOTO_END;
}
- if (!rtp_session->dtmf_data.in_interleaved && rtp_session->recv_msg.header.pt != rtp_session->recv_te) {
+ if (!rtp_session->dtmf_data.in_interleaved && rtp_session->last_rtp_hdr.pt != rtp_session->recv_te) {
/* Drat, they are sending audio still as well as DTMF ok fine..... *sigh* */
rtp_session->dtmf_data.in_interleaved = 1;
}
if (rtp_session->dtmf_data.in_interleaved || (rtp_session->rtp_bugs & RTP_BUG_IGNORE_DTMF_DURATION)) {
- if (rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
+ if (rtp_session->last_rtp_hdr.pt == rtp_session->recv_te) {
return RESULT_GOTO_RECVFROM;
}
} else {
@@ -1184,9 +1191,12 @@ static void handle_ice(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice, void *d
ice->last_ok = now;
rtp_session->wrong_addrs = 0;
} else {
- if ((rtp_session->dtls->state != DS_READY || !ice->ready || !ice->rready)) {
+ if (((rtp_session->dtls && rtp_session->dtls->state != DS_READY) || !ice->ready || !ice->rready) &&
+ rtp_session->wrong_addrs > 2 && rtp_session->ice_adj == 0) {
do_adj++;
- } else if (rtp_session->wrong_addrs > 5 || elapsed >= 3000) {
+ rtp_session->ice_adj = 1;
+ rtp_session->wrong_addrs = 0;
+ } else if (rtp_session->wrong_addrs > 10 || elapsed >= 10000) {
do_adj++;
}
@@ -2715,7 +2725,8 @@ SWITCH_DECLARE(void) switch_rtp_reset(switch_rtp_t *rtp_session)
rtp_session->wrong_addrs = 0;
rtp_session->rtcp_sent_packets = 0;
rtp_session->rtcp_last_sent = 0;
-
+ rtp_session->ice_adj = 0;
+
//switch_rtp_del_dtls(rtp_session, DTLS_TYPE_RTP|DTLS_TYPE_RTCP);
switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_PAUSE);
switch_rtp_set_flag(rtp_session, SWITCH_RTP_FLAG_MUTE);
@@ -3994,7 +4005,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_video_buffer_size(switch_rtp_t *r
}
if (!max_frames) {
- max_frames = 30;
+ max_frames = 50;
}
if (!rtp_session->vb) {
@@ -4052,18 +4063,22 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *
max_queue_frames = queue_frames * 3;
}
- READ_INC(rtp_session);
+
if (rtp_session->jb) {
status = switch_jb_set_frames(rtp_session->jb, queue_frames, max_queue_frames);
} else {
+ READ_INC(rtp_session);
status = switch_jb_create(&rtp_session->jb, SJB_AUDIO, queue_frames, max_queue_frames, rtp_session->pool);
switch_jb_set_session(rtp_session->jb, rtp_session->session);
- switch_jb_ts_mode(rtp_session->jb, samples_per_packet, samples_per_second);
+ if (switch_true(switch_channel_get_variable_dup(switch_core_session_get_channel(rtp_session->session), "jb_use_timestamps", SWITCH_FALSE, -1))) {
+ switch_jb_ts_mode(rtp_session->jb, samples_per_packet, samples_per_second);
+ }
//switch_jb_debug_level(rtp_session->jb, 10);
+ READ_DEC(rtp_session);
}
- READ_DEC(rtp_session);
+
return status;
}
@@ -4844,14 +4859,15 @@ static int jb_valid(switch_rtp_t *rtp_session)
}
-static void do_flush(switch_rtp_t *rtp_session, int force)
+static switch_size_t do_flush(switch_rtp_t *rtp_session, int force, switch_size_t bytes_in)
{
int was_blocking = 0;
switch_size_t bytes;
uint32_t flushed = 0;
-
+ switch_size_t bytes_out = 0;
+
if (!switch_rtp_ready(rtp_session)) {
- return;
+ return 0;
}
reset_jitter_seq(rtp_session);
@@ -4861,7 +4877,7 @@ static void do_flush(switch_rtp_t *rtp_session, int force)
rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] ||
rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON]
) {
- return;
+ return 0;
}
}
@@ -4870,16 +4886,20 @@ static void do_flush(switch_rtp_t *rtp_session, int force)
if (switch_rtp_ready(rtp_session) ) {
if (rtp_session->jb && !rtp_session->pause_jb && jb_valid(rtp_session)) {
- switch_jb_reset(rtp_session->jb);
+ //switch_jb_reset(rtp_session->jb);
+ bytes_out = bytes_in;
+ goto end;
}
- //if (rtp_session->vb) {
- // switch_jb_reset(rtp_session->vb);
- //}
-
if (rtp_session->vbw) {
switch_jb_reset(rtp_session->vbw);
}
+
+ if (rtp_session->vb) {
+ //switch_jb_reset(rtp_session->vb);
+ bytes_out = bytes_in;
+ goto end;
+ }
if (rtp_session->flags[SWITCH_RTP_FLAG_DEBUG_RTP_READ]) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session),
@@ -4903,7 +4923,7 @@ static void do_flush(switch_rtp_t *rtp_session, int force)
int do_cng = 0;
/* Make sure to handle RFC2833 packets, even if we're flushing the packets */
- if (bytes > rtp_header_len && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
+ if (bytes > rtp_header_len && rtp_session->last_rtp_hdr.pt == rtp_session->recv_te) {
handle_rfc2833(rtp_session, bytes, &do_cng);
#ifdef DEBUG_2833
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "*** RTP packet handled in flush loop %d ***\n", do_cng);
@@ -4933,8 +4953,12 @@ static void do_flush(switch_rtp_t *rtp_session, int force)
switch_core_session_request_video_refresh(rtp_session->session);
}
}
+
+ end:
READ_DEC(rtp_session);
+
+ return bytes_out;
}
static int check_recv_payload(switch_rtp_t *rtp_session)
@@ -4952,7 +4976,7 @@ static int check_recv_payload(switch_rtp_t *rtp_session)
continue;
}
- if (rtp_session->recv_msg.header.pt == pmap->pt) {
+ if (rtp_session->last_rtp_hdr.pt == pmap->pt) {
ok = 1;
}
}
@@ -4962,6 +4986,27 @@ static int check_recv_payload(switch_rtp_t *rtp_session)
return ok;
}
+static int get_recv_payload(switch_rtp_t *rtp_session)
+{
+ int r = -1;
+
+ if (rtp_session->pmaps && *rtp_session->pmaps) {
+ payload_map_t *pmap;
+
+ switch_mutex_lock(rtp_session->flag_mutex);
+
+ for (pmap = *rtp_session->pmaps; pmap && pmap->allocated; pmap = pmap->next) {
+ if (pmap->negotiated) {
+ r = pmap->pt;
+ break;
+ }
+ }
+ switch_mutex_unlock(rtp_session->flag_mutex);
+ }
+
+ return r;
+}
+
#define return_cng_frame() do_cng = 1; goto timer_check
static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes, switch_frame_flag_t *flags,
@@ -4973,13 +5018,57 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
int sync = 0;
switch_time_t now;
switch_size_t xcheck_jitter = 0;
-
+ int tries = 0;
+ int block = 0;
+
switch_assert(bytes);
more:
+ tries++;
+
+ if (tries > 20) {
+ if (rtp_session->jb && !rtp_session->pause_jb && jb_valid(rtp_session)) {
+ switch_jb_reset(rtp_session->jb);
+ }
+ rtp_session->punts++;
+ rtp_session->clean = 0;
+ *bytes = 0;
+ return SWITCH_STATUS_BREAK;
+ }
+
+ if (block) {
+ int to = 20000;
+ int fdr = 0;
+
+ if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
+ to = 100000;
+ } else {
+ if (rtp_session->flags[SWITCH_RTP_FLAG_USE_TIMER] && rtp_session->timer.interval) {
+ to = rtp_session->timer.interval * 1000;
+ }
+ }
+
+ poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, to);
+
+ if (rtp_session->flags[SWITCH_RTP_FLAG_USE_TIMER] && rtp_session->timer.interval) {
+ switch_core_timer_sync(&rtp_session->timer);
+ }
+
+ block = 0;
+ }
+
*bytes = sizeof(rtp_msg_t);
sync = 0;
+ rtp_session->has_rtp = 0;
+ rtp_session->has_ice = 0;
+ rtp_session->has_rtcp = 0;
+ if (rtp_session->dtls) {
+ rtp_session->dtls->bytes = 0;
+ rtp_session->dtls->data = NULL;
+ }
+ memset(&rtp_session->last_rtp_hdr, 0, sizeof(rtp_session->last_rtp_hdr));
+
if (poll_status == SWITCH_STATUS_SUCCESS) {
status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes);
} else {
@@ -4987,15 +5076,58 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
if (*bytes) {
- rtp_session->missed_count = 0;
- if (rtp_session->recv_msg.header.version == 2) {
+ b = (unsigned char *) &rtp_session->recv_msg;
+
+ /* version 2 probably rtp, zrtp cookie present means zrtp */
+ rtp_session->has_rtp = (rtp_session->recv_msg.header.version == 2 || ntohl(*(int *)(b+4)) == ZRTP_MAGIC_COOKIE);
+
+ if ((*b >= 20) && (*b <= 64)) {
+ rtp_session->dtls->bytes = *bytes;
+ rtp_session->dtls->data = (void *) &rtp_session->recv_msg;
+ rtp_session->has_ice = 0;
+ rtp_session->has_rtp = 0;
+ rtp_session->has_rtcp = 0;
+ } else if (*b == 0 || *b == 1) {
+ rtp_session->has_ice = 1;
+ rtp_session->has_rtp = 0;
+ rtp_session->has_rtcp = 0;
+ } else {
+ if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
+ switch(rtp_session->recv_msg.header.pt) {
+ case 64: // 192 Full INTRA-frame request.
+ case 72: // 200 Sender report.
+ case 73: // 201 Receiver report.
+ case 74: // 202 Source description.
+ case 75: // 203 Goodbye.
+ case 76: // 204 Application-defined.
+ case 77: // 205 Transport layer FB message.
+ case 78: // 206 Payload-specific FB message.
+ case 79: // 207 Extended report.
+ rtp_session->has_rtcp = 1;
+ rtp_session->has_rtp = 0;
+ rtp_session->has_ice = 0;
+ break;
+ default:
+ if (rtp_session->rtcp_recv_msg_p->header.version == 2 &&
+ rtp_session->rtcp_recv_msg_p->header.type > 199 && rtp_session->rtcp_recv_msg_p->header.type < 208) {
+ rtp_session->has_rtcp = 1;
+ rtp_session->has_rtp = 0;
+ rtp_session->has_ice = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ if (rtp_session->has_rtp) {
+ rtp_session->missed_count = 0;
switch_cp_addr(rtp_session->rtp_from_addr, rtp_session->from_addr);
rtp_session->last_rtp_hdr = rtp_session->recv_msg.header;
}
}
if (!rtp_session->vb && (!rtp_session->jb || rtp_session->pause_jb || !jb_valid(rtp_session))) {
- if (*bytes > rtp_header_len && (rtp_session->recv_msg.header.version == 2 && check_recv_payload(rtp_session))) {
+ if (*bytes > rtp_header_len && (rtp_session->has_rtp && check_recv_payload(rtp_session))) {
xcheck_jitter = *bytes;
check_jitter(rtp_session);
}
@@ -5014,8 +5146,6 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
if (*bytes) {
- b = (unsigned char *) &rtp_session->recv_msg;
-
*flags &= ~SFF_PROXY_PACKET;
//if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
@@ -5023,7 +5153,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
//}
- if (*b == 0 || *b == 1) {
+ if (rtp_session->has_ice) {
if (rtp_session->ice.ice_user) {
handle_ice(rtp_session, &rtp_session->ice, (void *) &rtp_session->recv_msg, *bytes);
}
@@ -5040,27 +5170,6 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
do_dtls(rtp_session, rtp_session->rtcp_dtls);
}
- rtp_session->dtls->bytes = 0;
-
- if (*bytes) {
- char *b = (char *) &rtp_session->recv_msg;
-
- if ((*b >= 20) && (*b <= 64)) {
- rtp_session->dtls->bytes = *bytes;
- rtp_session->dtls->data = (void *) &rtp_session->recv_msg;
- } else {
- rtp_session->dtls->bytes = 0;
- rtp_session->dtls->data = NULL;
-
- if (*b != 0 && *b != 1 && rtp_session->dtls->state != DS_READY) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1,
- "Drop %s packet %ld bytes (dtls not ready!) b=%u\n", rtp_type(rtp_session), (long)*bytes, *b);
- *bytes = 0;
- }
-
- }
- }
-
do_dtls(rtp_session, rtp_session->dtls);
if (rtp_session->dtls && rtp_session->dtls->bytes) {
@@ -5072,11 +5181,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
if (status == SWITCH_STATUS_SUCCESS && *bytes) {
if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX]) {
*flags &= ~SFF_RTCP;
- if (!check_recv_payload(rtp_session) &&
- rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
- rtp_session->recv_msg.header.pt != rtp_session->cng_pt &&
- rtp_session->rtcp_recv_msg_p->header.version == 2 &&
- rtp_session->rtcp_recv_msg_p->header.type > 199 && rtp_session->rtcp_recv_msg_p->header.type < 208) { //rtcp muxed
+ if (rtp_session->has_rtcp) {
*flags |= SFF_RTCP;
if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV]) {
@@ -5099,7 +5204,11 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
}
- if (*bytes && !rtp_write_ready(rtp_session, *bytes, __LINE__)) {
+
+
+ if ((*bytes && (!rtp_write_ready(rtp_session, *bytes, __LINE__) || !rtp_session->has_rtp || rtp_session->has_rtcp)) || sync) {
+ rtp_session->hot_hits = 0;
+ block = 1;
*bytes = 0;
goto more;
}
@@ -5123,8 +5232,8 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
my_host, switch_sockaddr_get_port(rtp_session->local_addr),
old_host, rtp_session->remote_port,
tx_host, switch_sockaddr_get_port(rtp_session->rtp_from_addr),
- rtp_session->recv_msg.header.pt, ntohl(rtp_session->recv_msg.header.ts), ntohs(rtp_session->recv_msg.header.seq),
- rtp_session->recv_msg.header.m);
+ rtp_session->last_rtp_hdr.pt, ntohl(rtp_session->last_rtp_hdr.ts), ntohs(rtp_session->last_rtp_hdr.seq),
+ rtp_session->last_rtp_hdr.m);
}
@@ -5133,22 +5242,12 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
int r = (rand() % 10000) + 1;
if (r <= 200) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ALERT,
- "Simulate dropped packet ......... ts: %u seq: %u\n", ntohl(rtp_session->recv_msg.header.ts), ntohs(rtp_session->recv_msg.header.seq));
+ "Simulate dropped packet ......... ts: %u seq: %u\n", ntohl(rtp_session->last_rtp_hdr.ts), ntohs(rtp_session->last_rtp_hdr.seq));
*bytes = 0;
}
}
#endif
-
- if (sync) {
- if (!rtp_session->flags[SWITCH_RTP_FLAG_USE_TIMER] && rtp_session->timer.interval) {
- switch_core_timer_sync(&rtp_session->timer);
- reset_jitter_seq(rtp_session);
- }
- rtp_session->hot_hits = 0;
-
- goto more;
- }
udptl:
@@ -5158,8 +5257,8 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
now = switch_micro_time_now();
if (*bytes) {
- uint16_t seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
- ts = ntohl(rtp_session->recv_msg.header.ts);
+ uint16_t seq = ntohs((uint16_t) rtp_session->last_rtp_hdr.seq);
+ ts = ntohl(rtp_session->last_rtp_hdr.ts);
#ifdef DEBUG_MISSED_SEQ
if (rtp_session->last_seq && rtp_session->last_seq+1 != seq) {
@@ -5213,7 +5312,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
if (!rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] && !rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] && !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] &&
- *bytes && rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
+ *bytes && rtp_session->last_rtp_hdr.pt != rtp_session->recv_te &&
ts && !rtp_session->jb && !rtp_session->pause_jb && jb_valid(rtp_session) && ts == rtp_session->last_cng_ts) {
/* we already sent this frame..... */
*bytes = 0;
@@ -5249,11 +5348,11 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
#endif
#ifdef ENABLE_SRTP
- if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] && rtp_session->recv_msg.header.version == 2 &&
+ if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] && rtp_session->has_rtp &&
(check_recv_payload(rtp_session) ||
- rtp_session->recv_msg.header.pt == rtp_session->recv_te ||
- rtp_session->recv_msg.header.pt == rtp_session->cng_pt)) {
- //if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] && (!rtp_session->ice.ice_user || rtp_session->recv_msg.header.version == 2)) {
+ rtp_session->last_rtp_hdr.pt == rtp_session->recv_te ||
+ rtp_session->last_rtp_hdr.pt == rtp_session->cng_pt)) {
+ //if (rtp_session->flags[SWITCH_RTP_FLAG_SECURE_RECV] && (!rtp_session->ice.ice_user || rtp_session->has_rtp)) {
int sbytes = (int) *bytes;
err_status_t stat = 0;
@@ -5319,17 +5418,21 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
- if (rtp_session->recv_msg.header.version == 2) {
+ if (rtp_session->has_rtp) {
+ if (rtp_session->recv_msg.header.cc > 0) { /* Contributing Source Identifiers (4 bytes = sizeof CSRC header)*/
+ rtp_session->recv_msg.ebody = RTP_BODY(rtp_session) + (rtp_session->recv_msg.header.cc * 4);
+ }
+
/* recalculate body length in case rtp extension used */
if (!rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] && !rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] &&
- rtp_session->recv_msg.header.version == 2 && rtp_session->recv_msg.header.x) { /* header extensions */
+ rtp_session->has_rtp && rtp_session->recv_msg.header.x) { /* header extensions */
uint16_t length;
- rtp_session->recv_msg.ext = (switch_rtp_hdr_ext_t *) rtp_session->recv_msg.body;
+ rtp_session->recv_msg.ext = (switch_rtp_hdr_ext_t *) RTP_BODY(rtp_session);
length = ntohs((uint16_t)rtp_session->recv_msg.ext->length);
if (length < SWITCH_RTP_MAX_BUF_LEN_WORDS) {
- rtp_session->recv_msg.ebody = rtp_session->recv_msg.body + (length * 4) + 4;
+ rtp_session->recv_msg.ebody = (char *)rtp_session->recv_msg.ext + (length * 4) + 4;
if (*bytes > (length * 4 + 4)) {
*bytes -= (length * 4 + 4);
} else {
@@ -5341,17 +5444,17 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
#ifdef DEBUG_CHROME
- if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && rtp_session->recv_msg.header.version == 2) {
+ if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && rtp_session->has_rtp) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
"VIDEO: seq: %d ts: %u len: %ld %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x mark: %d\n",
- ntohs(rtp_session->recv_msg.header.seq), ntohl(rtp_session->recv_msg.header.ts), *bytes,
+ ntohs(rtp_session->last_rtp_hdr.seq), ntohl(rtp_session->last_rtp_hdr.ts), *bytes,
*((uint8_t *)RTP_BODY(rtp_session)), *((uint8_t *)RTP_BODY(rtp_session) + 1),
*((uint8_t *)RTP_BODY(rtp_session) + 2), *((uint8_t *)RTP_BODY(rtp_session) + 3),
*((uint8_t *)RTP_BODY(rtp_session) + 4), *((uint8_t *)RTP_BODY(rtp_session) + 5),
*((uint8_t *)RTP_BODY(rtp_session) + 6), *((uint8_t *)RTP_BODY(rtp_session) + 7),
*((uint8_t *)RTP_BODY(rtp_session) + 8), *((uint8_t *)RTP_BODY(rtp_session) + 9),
- *((uint8_t *)RTP_BODY(rtp_session) + 10), rtp_session->recv_msg.header.m);
+ *((uint8_t *)RTP_BODY(rtp_session) + 10), rtp_session->last_rtp_hdr.m);
}
#endif
@@ -5366,9 +5469,9 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
rtp_session->stats.inbound.raw_bytes += *bytes;
- if (rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
+ if (rtp_session->last_rtp_hdr.pt == rtp_session->recv_te) {
rtp_session->stats.inbound.dtmf_packet_count++;
- } else if (rtp_session->recv_msg.header.pt == rtp_session->cng_pt || rtp_session->recv_msg.header.pt == 13) {
+ } else if (rtp_session->last_rtp_hdr.pt == rtp_session->cng_pt || rtp_session->last_rtp_hdr.pt == 13) {
rtp_session->stats.inbound.cng_packet_count++;
} else {
rtp_session->stats.inbound.media_packet_count++;
@@ -5378,7 +5481,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
rtp_session->stats.inbound.packet_count++;
}
- if (rtp_session->recv_msg.header.pt == rtp_session->recv_te ||
+ if (rtp_session->last_rtp_hdr.pt == rtp_session->recv_te ||
(*bytes < rtp_header_len && *bytes > 0) ||
rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] || rtp_session->flags[SWITCH_RTP_FLAG_UDPTL]) {
return SWITCH_STATUS_SUCCESS;
@@ -5404,10 +5507,15 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
}
- if (rtp_session->recv_msg.header.version == 2 && *bytes) {
+ if (rtp_session->has_rtp && *bytes) {
if (rtp_session->vb && jb_valid(rtp_session)) {
- switch_jb_put_packet(rtp_session->vb, (switch_rtp_packet_t *) &rtp_session->recv_msg, *bytes);
+ status = switch_jb_put_packet(rtp_session->vb, (switch_rtp_packet_t *) &rtp_session->recv_msg, *bytes);
+
+ if (status == SWITCH_STATUS_TOO_LATE) {
+ goto more;
+ }
+
status = SWITCH_STATUS_FALSE;
*bytes = 0;
@@ -5419,7 +5527,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
if (rtp_session->jb && !rtp_session->pause_jb && jb_valid(rtp_session)) {
uint32_t read_ssrc = ntohl(rtp_session->last_rtp_hdr.ssrc);
- if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
+ if (rtp_session->last_rtp_hdr.m && rtp_session->last_rtp_hdr.pt != rtp_session->recv_te &&
!rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && !(rtp_session->rtp_bugs & RTP_BUG_IGNORE_MARK_BIT)) {
switch_jb_reset(rtp_session->jb);
} else if (rtp_session->last_jb_read_ssrc && rtp_session->last_jb_read_ssrc != read_ssrc) {
@@ -5433,8 +5541,12 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
reset_jitter_seq(rtp_session);
}
- switch_jb_put_packet(rtp_session->jb, (switch_rtp_packet_t *) &rtp_session->recv_msg, *bytes);
+ status = switch_jb_put_packet(rtp_session->jb, (switch_rtp_packet_t *) &rtp_session->recv_msg, *bytes);
+ if (status == SWITCH_STATUS_TOO_LATE) {
+ goto more;
+ }
+
status = SWITCH_STATUS_FALSE;
*bytes = 0;
@@ -5444,7 +5556,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
}
- if (!*bytes || rtp_session->recv_msg.header.version == 2) {
+ if (!*bytes || rtp_session->has_rtp) {
if (rtp_session->jb && !rtp_session->pause_jb && jb_valid(rtp_session)) {
switch_status_t jstatus = switch_jb_get_packet(rtp_session->jb, (switch_rtp_packet_t *) &rtp_session->recv_msg, bytes);
@@ -5453,14 +5565,22 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
switch(jstatus) {
case SWITCH_STATUS_MORE_DATA:
- status = SWITCH_STATUS_BREAK;
+ if (rtp_session->punts < 4) {
+ block = 1;
+ goto more;
+ }
+ *bytes = 0;
break;
case SWITCH_STATUS_NOTFOUND:
{
+ int pt = get_recv_payload(rtp_session);
(*flags) |= SFF_PLC;
status = SWITCH_STATUS_SUCCESS;
- rtp_session->recv_msg.header = rtp_session->last_rtp_hdr;
*bytes = switch_jb_get_last_read_len(rtp_session->jb);
+ rtp_session->last_rtp_hdr = rtp_session->recv_msg.header;
+ if (pt > -1) {
+ rtp_session->last_rtp_hdr.pt = pt;
+ }
}
break;
case SWITCH_STATUS_SUCCESS:
@@ -5469,7 +5589,9 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
rtp_session->stats.inbound.jb_packet_count++;
status = SWITCH_STATUS_SUCCESS;
rtp_session->last_rtp_hdr = rtp_session->recv_msg.header;
-
+ if (++rtp_session->clean > 200) {
+ rtp_session->punts = 0;
+ }
if (!xcheck_jitter) {
check_jitter(rtp_session);
xcheck_jitter = *bytes;
@@ -6112,9 +6234,9 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
ret = -1;
goto end;
}
-
+
if (rtp_session->max_missed_packets && read_loops == 1 && !rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
- if (bytes) {
+ if (bytes && status == SWITCH_STATUS_SUCCESS) {
rtp_session->missed_count = 0;
} else if (++rtp_session->missed_count >= rtp_session->max_missed_packets) {
ret = -2;
@@ -6298,11 +6420,11 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
}
- if (bytes && rtp_session->recv_msg.header.version == 2 &&
+ if (bytes && rtp_session->has_rtp &&
!rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] && !rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] &&
- rtp_session->recv_msg.header.pt != 13 &&
- rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
- rtp_session->recv_msg.header.pt != rtp_session->cng_pt) {
+ rtp_session->last_rtp_hdr.pt != 13 &&
+ rtp_session->last_rtp_hdr.pt != rtp_session->recv_te &&
+ rtp_session->last_rtp_hdr.pt != rtp_session->cng_pt) {
int accept_packet = 1;
@@ -6317,7 +6439,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
continue;
}
- if (rtp_session->recv_msg.header.pt == pmap->pt) {
+ if (rtp_session->last_rtp_hdr.pt == pmap->pt) {
accept_packet = 1;
if (pmapP) {
*pmapP = pmap;
@@ -6345,8 +6467,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
check = !bytes;
if (rtp_session->flags[SWITCH_RTP_FLAG_FLUSH]) {
- do_flush(rtp_session, SWITCH_FALSE);
- bytes = 0;
+ bytes = do_flush(rtp_session, SWITCH_FALSE, bytes);
switch_rtp_clear_flag(rtp_session, SWITCH_RTP_FLAG_FLUSH);
}
@@ -6370,14 +6491,14 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
goto recvfrom;
}
- if (bytes && rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
+ if (bytes && rtp_session->last_rtp_hdr.m && rtp_session->last_rtp_hdr.pt != rtp_session->recv_te &&
!rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] &&
!(rtp_session->rtp_bugs & RTP_BUG_IGNORE_MARK_BIT)) {
rtp_flush_read_buffer(rtp_session, SWITCH_RTP_FLUSH_ONCE);
}
- if (rtp_session->recv_msg.header.pt == rtp_session->cng_pt || rtp_session->recv_msg.header.pt == 13) {
+ if (rtp_session->last_rtp_hdr.pt == rtp_session->cng_pt || rtp_session->last_rtp_hdr.pt == 13) {
*flags |= SFF_NOT_AUDIO;
} else {
*flags &= ~SFF_NOT_AUDIO; /* If this flag was already set, make sure to remove it when we get real audio */
@@ -6386,7 +6507,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
/* ignore packets not meant for us unless the auto-adjust window is open (ice mode has its own alternatives to this) */
if (!using_ice(rtp_session) && bytes) {
if (rtp_session->flags[SWITCH_RTP_FLAG_AUTOADJ]) {
- if (rtp_session->recv_msg.header.pt == rtp_session->cng_pt || rtp_session->recv_msg.header.pt == 13) {
+ if (rtp_session->last_rtp_hdr.pt == rtp_session->cng_pt || rtp_session->last_rtp_hdr.pt == 13) {
goto recvfrom;
}
@@ -6465,7 +6586,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
if (rtp_session->flags[SWITCH_RTP_FLAG_UDPTL]) {
#if 0
- if (rtp_session->recv_msg.header.version == 2 && check_recv_payload(rtp_session)) {
+ if (rtp_session->has_rtp && check_recv_payload(rtp_session)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING,
"Ignoring udptl packet of size of %ld bytes that looks strikingly like a RTP packet.\n", (long)bytes);
bytes = 0;
@@ -6488,7 +6609,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
goto do_continue;
}
- if (rtp_session->recv_msg.header.pt && (rtp_session->recv_msg.header.pt == rtp_session->cng_pt || rtp_session->recv_msg.header.pt == 13)) {
+ if (rtp_session->last_rtp_hdr.pt && (rtp_session->last_rtp_hdr.pt == rtp_session->cng_pt || rtp_session->last_rtp_hdr.pt == 13)) {
return_cng_frame();
}
}
@@ -6500,12 +6621,12 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
if (bytes && rtp_session->recv_msg.header.version != 2) {
uint8_t *data = (uint8_t *) RTP_BODY(rtp_session);
- if (rtp_session->recv_msg.header.version == 0) {
- if (rtp_session->ice.ice_user) {
- handle_ice(rtp_session, &rtp_session->ice, (void *) &rtp_session->recv_msg, bytes);
- goto recvfrom;
- }
- }
+ //if (rtp_session->recv_msg.header.version == 0) {
+ // if (rtp_session->ice.ice_user) {
+ // handle_ice(rtp_session, &rtp_session->ice, (void *) &rtp_session->recv_msg, bytes);
+ // goto recvfrom;
+ // }
+ //}
if (rtp_session->invalid_handler) {
rtp_session->invalid_handler(rtp_session, rtp_session->sock_input, (void *) &rtp_session->recv_msg, bytes, rtp_session->rtp_from_addr);
@@ -6514,9 +6635,9 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
memset(data, 0, 2);
data[0] = 65;
- rtp_session->recv_msg.header.pt = rtp_session->cng_pt != INVALID_PT ? rtp_session->cng_pt : SWITCH_RTP_CNG_PAYLOAD;
+ rtp_session->last_rtp_hdr.pt = rtp_session->cng_pt != INVALID_PT ? rtp_session->cng_pt : SWITCH_RTP_CNG_PAYLOAD;
*flags |= SFF_CNG;
- *payload_type = (switch_payload_t) rtp_session->recv_msg.header.pt;
+ *payload_type = (switch_payload_t) rtp_session->last_rtp_hdr.pt;
ret = 2 + rtp_header_len;
goto end;
} else if (bytes) {
@@ -6556,9 +6677,9 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
memset(data, 0, 2);
data[0] = 65;
- rtp_session->recv_msg.header.pt = rtp_session->cng_pt != INVALID_PT ? rtp_session->cng_pt : SWITCH_RTP_CNG_PAYLOAD;
+ rtp_session->last_rtp_hdr.pt = rtp_session->cng_pt != INVALID_PT ? rtp_session->cng_pt : SWITCH_RTP_CNG_PAYLOAD;
*flags |= SFF_CNG;
- *payload_type = (switch_payload_t) rtp_session->recv_msg.header.pt;
+ *payload_type = (switch_payload_t) rtp_session->last_rtp_hdr.pt;
ret = 2 + rtp_header_len;
rtp_session->stats.inbound.skip_packet_count++;
goto end;
@@ -6598,8 +6719,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
return_cng_frame();
}
- if (rtp_session->flags[SWITCH_RTP_FLAG_GOOGLEHACK] && rtp_session->recv_msg.header.pt == 102) {
- rtp_session->recv_msg.header.pt = 97;
+ if (rtp_session->flags[SWITCH_RTP_FLAG_GOOGLEHACK] && rtp_session->last_rtp_hdr.pt == 102) {
+ rtp_session->last_rtp_hdr.pt = 97;
}
break;
@@ -6613,7 +6734,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
}
if (switch_rtp_ready(rtp_session)) {
- *payload_type = (switch_payload_t) rtp_session->recv_msg.header.pt;
+ *payload_type = (switch_payload_t) rtp_session->last_rtp_hdr.pt;
if (*payload_type == SWITCH_RTP_CNG_PAYLOAD) {
*flags |= SFF_CNG;
@@ -6803,10 +6924,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
if (frame->payload == rtp_session->recv_te) {
switch_set_flag(frame, SFF_RFC2833);
}
- frame->timestamp = ntohl(rtp_session->recv_msg.header.ts);
- frame->seq = (uint16_t) ntohs((uint16_t) rtp_session->recv_msg.header.seq);
+ frame->timestamp = ntohl(rtp_session->last_rtp_hdr.ts);
+ frame->seq = (uint16_t) ntohs((uint16_t) rtp_session->last_rtp_hdr.seq);
frame->ssrc = ntohl(rtp_session->last_rtp_hdr.ssrc);
- frame->m = rtp_session->recv_msg.header.m ? SWITCH_TRUE : SWITCH_FALSE;
+ frame->m = rtp_session->last_rtp_hdr.m ? SWITCH_TRUE : SWITCH_FALSE;
}
#ifdef ENABLE_ZRTP
@@ -7073,11 +7194,11 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
send_msg->header.ssrc = htonl(rtp_session->ssrc);
if (rtp_session->flags[SWITCH_RTP_FLAG_GOOGLEHACK] && rtp_session->send_msg.header.pt == 97) {
- rtp_session->recv_msg.header.pt = 102;
+ rtp_session->last_rtp_hdr.pt = 102;
}
if (rtp_session->flags[SWITCH_RTP_FLAG_VAD] &&
- rtp_session->recv_msg.header.pt == rtp_session->vad_data.read_codec->implementation->ianacode) {
+ rtp_session->last_rtp_hdr.pt == rtp_session->vad_data.read_codec->implementation->ianacode) {
int16_t decoded[SWITCH_RECOMMENDED_BUFFER_SIZE / sizeof(int16_t)] = { 0 };
uint32_t rate = 0;
diff --git a/support-d/.bashrc b/support-d/.bashrc
index 4b21b517da..4b917c3b5c 100644
--- a/support-d/.bashrc
+++ b/support-d/.bashrc
@@ -5,6 +5,9 @@ export UNAME=`uname -s`
if [ "`id -u`" = "0" ]; then
if [ "${UNAME}" = "Linux" ]; then
+ if [ -d /usr/lib/ccache ]; then
+ export PATH="/usr/lib/ccache:$PATH"
+ fi
export PATH="$PATH:/opt/bin:/usr/local/bin:/usr/local/sbin:/usr/local/freeswitch/bin"
if [ -d /usr/src/freeswitch.git/support-d/utils ]; then
export PATH="/usr/src/freeswitch.git/support-d/utils:$PATH"
diff --git a/support-d/utils/fixbug.pl b/support-d/utils/fixbug.pl
index de3891bf6f..573ef06ee2 100755
--- a/support-d/utils/fixbug.pl
+++ b/support-d/utils/fixbug.pl
@@ -34,11 +34,16 @@ if ($prog =~ /wget/) {
}
my $xml = `$cmd $url 2>/dev/null`;
+if ($opts{debug}) {
+ print "URL $url\n";
+ print $xml;
+}
my $xs= new XML::Simple;
my $r = $xs->XMLin($xml);
my $sum = $r->{channel}->{item}->{summary};
+$sum =~ s/\"/\\"/g;
if ($opts{msg} eq "edit") {
$auto = 0;
diff --git a/support-d/utils/hashfinder b/support-d/utils/hashfinder
index 88df4ce5cc..b402f6552b 100755
--- a/support-d/utils/hashfinder
+++ b/support-d/utils/hashfinder
@@ -35,9 +35,9 @@
# hashfinder - Find origin of a particular line of code
#
-
my $file = shift;
my $regex = shift;
+my $alt_file = shift;
my $delim = " ";
$file and $regex or die "missing params. Syntax: ";
@@ -58,7 +58,9 @@ sub doit($$) {
$linematch = 1;
}
- open GIT, "git blame -n $file $rev|";
+ retry:
+
+ open GIT, "git blame -n $file $rev 2>&1|";
my $mc = 0;
my @matches = ();
@@ -66,6 +68,14 @@ sub doit($$) {
while () {
my $matched = 0;
+ if (/fatal:/) {
+ if ($alt_file) {
+ $file = $alt_file;
+ $alt_file = undef;
+ goto retry;
+ }
+ }
+
if ($linematch) {
$matched = (/^\S+\s+$pattern\s+/);
} else {
@@ -81,7 +91,6 @@ sub doit($$) {
close(GIT);
-
if ($mc > 5) {
print $delim x $loops;
print "$mc matches; Maybe more specific?\n";
@@ -100,10 +109,11 @@ sub doit($$) {
my ($hash, $lno, $author, $line);
my $done = 0;
- if (/$file/) {
+ if (/\//) {
($hash, $lno, $author, $line) = /(\S+)\s+\S+\s+(\S+)\s+(\([^\)]+\))\s*(.*)/;
$done = 1;
} else {
+ die $_;
($hash, $lno, $author, $line) = /(\S+)\s+(\S+)\s+(\([^\)]+\))\s*(.*)/;
}
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
deleted file mode 100644
index d290dd506d..0000000000
--- a/tests/unit/Makefile.am
+++ /dev/null
@@ -1,30 +0,0 @@
-AUTOMAKE_OPTIONS = foreign
-FSLD = $(top_builddir)/libfreeswitch.la $(top_builddir)/libs/apr/libapr-1.la $(top_builddir)/libs/apr-util/libaprutil-1.la
-
-TESTS =
-check_PROGRAMS =
-
-
-if HAVE_TAP
-TESTS += switch_event
-check_PROGRAMS += switch_event
-
-switch_event_SOURCES = switch_event.c
-switch_event_CFLAGS = $(SWITCH_AM_CFLAGS)
-switch_event_LDADD = $(FSLD)
-switch_event_LDFLAGS = $(SWITCH_AM_LDFLAGS) -ltap
-
-TESTS += switch_hash
-check_PROGRAMS += switch_hash
-
-switch_hash_SOURCES = switch_hash.c
-switch_hash_CFLAGS = $(SWITCH_AM_CFLAGS)
-switch_hash_LDADD = $(FSLD)
-switch_hash_LDFLAGS = $(SWITCH_AM_LDFLAGS) -ltap
-
-else
-check: error
-error:
- $(error You must install libtap-dev to build these unit tests)
-endif
-
diff --git a/tests/unit/switch_event.c b/tests/unit/switch_event.c
index 9b19879d67..a893d493fb 100644
--- a/tests/unit/switch_event.c
+++ b/tests/unit/switch_event.c
@@ -9,7 +9,7 @@ int main () {
switch_bool_t verbose = SWITCH_TRUE;
const char *err = NULL;
switch_time_t start_ts, end_ts;
- int rc = 0, loops = 10;
+ int rc = 0, loops = 10, x = 0;
switch_status_t status = SWITCH_STATUS_SUCCESS;
char **index = NULL;
unsigned long long micro_total = 0;
@@ -31,7 +31,7 @@ int main () {
}
index = calloc(loops, sizeof(char *));
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
index[x] = switch_mprintf("%d", x);
}
@@ -42,13 +42,13 @@ int main () {
ok( status == SWITCH_STATUS_SUCCESS,"Create Event");
#ifndef BENCHMARK
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
status = switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, index[x], index[x]);
ok( status == SWITCH_STATUS_SUCCESS,"Add header to event");
}
#else
small_start_ts = switch_time_now();
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
if ( switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, index[x], index[x]) != SWITCH_STATUS_SUCCESS) {
fail("Failed to add header to event");
}
@@ -64,12 +64,12 @@ int main () {
#ifndef BENCHMARK
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
is(switch_event_get_header(event, index[x]), index[x], "correct header value returned");
}
#else
small_start_ts = switch_time_now();
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
if ( !switch_event_get_header(event, index[x])) {
fail("Failed to lookup event header value");
}
@@ -89,7 +89,7 @@ int main () {
end_ts = switch_time_now();
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
free(index[x]);
}
free(index);
@@ -97,7 +97,7 @@ int main () {
micro_total = end_ts - start_ts;
micro_per = micro_total / (double) loops;
rate_per_sec = 1000000 / micro_per;
- note("switch_event Total %ldus / %d loops, %.2f us per loop, %.0f loops per second\n",
+ diag("switch_event Total %ldus / %d loops, %.2f us per loop, %.0f loops per second\n",
micro_total, loops, micro_per, rate_per_sec);
switch_core_destroy();
diff --git a/tests/unit/switch_hash.c b/tests/unit/switch_hash.c
index c3997301d5..522ca6ea1c 100644
--- a/tests/unit/switch_hash.c
+++ b/tests/unit/switch_hash.c
@@ -13,7 +13,8 @@ int main () {
unsigned long long micro_total = 0;
double micro_per = 0;
double rate_per_sec = 0;
-
+ int x = 0;
+
#ifdef BENCHMARK
switch_time_t small_start_ts, small_end_ts;
#endif
@@ -42,7 +43,7 @@ int main () {
}
index = calloc(loops, sizeof(char *));
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
index[x] = switch_mprintf("%d", x);
}
@@ -51,13 +52,13 @@ int main () {
/* Insertion */
#ifndef BENCHMARK
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
status = switch_core_hash_insert(hash, index[x], (void *) index[x]);
ok(status == SWITCH_STATUS_SUCCESS, "Insert into the hash");
}
#else
small_start_ts = switch_time_now();
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
switch_core_hash_insert(hash, index[x], (void *) index[x]);
}
small_end_ts = switch_time_now();
@@ -72,7 +73,7 @@ int main () {
/* Lookup */
#ifndef BENCHMARK
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
char *data = NULL;
data = switch_core_hash_find(hash, index[x]);
ok(data != NULL, "Successful lookup");
@@ -80,7 +81,7 @@ int main () {
}
#else
small_start_ts = switch_time_now();
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
if ( ! switch_core_hash_find(hash, index[x])) {
fail("Failed to properly locate one of the values");
}
@@ -97,7 +98,7 @@ int main () {
/* Delete */
#ifndef BENCHMARK
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
char *data = NULL;
data = switch_core_hash_delete(hash, index[x]);
ok(data != NULL, "Create a new hash");
@@ -105,7 +106,7 @@ int main () {
}
#else
small_start_ts = switch_time_now();
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
if ( !switch_core_hash_delete(hash, index[x])) {
fail("Failed to delete and return the value");
}
@@ -124,7 +125,7 @@ int main () {
/* END LOOPS */
switch_core_hash_destroy(&hash);
- for ( int x = 0; x < loops; x++) {
+ for ( x = 0; x < loops; x++) {
free(index[x]);
}
free(index);
@@ -132,7 +133,7 @@ int main () {
micro_total = end_ts - start_ts;
micro_per = micro_total / (double) loops;
rate_per_sec = 1000000 / micro_per;
- note("switch_hash Total %ldus / %d loops, %.2f us per loop, %.0f loops per second\n",
+ diag("switch_hash Total %ldus / %d loops, %.2f us per loop, %.0f loops per second\n",
micro_total, loops, micro_per, rate_per_sec);
switch_core_destroy();
diff --git a/tests/unit/unit.mk b/tests/unit/unit.mk
new file mode 100644
index 0000000000..68cd2e5d39
--- /dev/null
+++ b/tests/unit/unit.mk
@@ -0,0 +1,17 @@
+AUTOMAKE_OPTIONS = foreign
+FSLD = $(top_builddir)/libfreeswitch.la $(top_builddir)/libs/apr/libapr-1.la $(top_builddir)/libs/apr-util/libaprutil-1.la
+
+check_PROGRAMS += tests/unit/switch_event
+
+tests_unit_switch_event_SOURCES = tests/unit/switch_event.c
+tests_unit_switch_event_CFLAGS = $(SWITCH_AM_CFLAGS)
+tests_unit_switch_event_LDADD = $(FSLD)
+tests_unit_switch_event_LDFLAGS = $(SWITCH_AM_LDFLAGS) -ltap
+
+check_PROGRAMS += tests/unit/switch_hash
+
+tests_unit_switch_hash_SOURCES = tests/unit/switch_hash.c
+tests_unit_switch_hash_CFLAGS = $(SWITCH_AM_CFLAGS)
+tests_unit_switch_hash_LDADD = $(FSLD)
+tests_unit_switch_hash_LDFLAGS = $(SWITCH_AM_LDFLAGS) -ltap
+