This commit is contained in:
Phil Ringnalda 2017-01-20 19:16:11 -08:00
Родитель 706dc45dd8 68b37a46e8
Коммит 72dfd3bd3f
493 изменённых файлов: 5606 добавлений и 3854 удалений

Просмотреть файл

@ -34,7 +34,10 @@ USE_LIBS += [
]
if CONFIG['LIBFUZZER']:
USE_LIBS += [ 'fuzzer' ]
USE_LIBS += [ 'fuzzer' ]
LOCAL_INCLUDES += [
'/tools/fuzzing/libfuzzer',
]
if CONFIG['_MSC_VER']:
# Always enter a Windows program through wmain, whether or not we're

Просмотреть файл

@ -43,6 +43,10 @@
#include "mozilla/Telemetry.h"
#include "mozilla/WindowsDllBlocklist.h"
#ifdef LIBFUZZER
#include "FuzzerDefs.h"
#endif
#ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
#include <cpuid.h>
#include "mozilla/Unused.h"
@ -163,17 +167,6 @@ static bool IsArg(const char* arg, const char* s)
Bootstrap::UniquePtr gBootstrap;
#ifdef LIBFUZZER
int libfuzzer_main(int argc, char **argv);
/* This wrapper is used by the libFuzzer main to call into libxul */
void libFuzzerGetFuncs(const char* moduleName, LibFuzzerInitFunc* initFunc,
LibFuzzerTestingFunc* testingFunc) {
return gBootstrap->XRE_LibFuzzerGetFuncs(moduleName, initFunc, testingFunc);
}
#endif
static int do_main(int argc, char* argv[], char* envp[])
{
// Allow firefox.exe to launch XULRunner apps via -app <application.ini>
@ -235,7 +228,7 @@ static int do_main(int argc, char* argv[], char* envp[])
#ifdef LIBFUZZER
if (getenv("LIBFUZZER"))
gBootstrap->XRE_LibFuzzerSetMain(argc, argv, libfuzzer_main);
gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
#endif
return gBootstrap->XRE_main(argc, argv, config);

Просмотреть файл

@ -855,10 +855,18 @@ pref("places.frecency.embedVisitBonus", 0);
pref("places.frecency.framedLinkVisitBonus", 0);
pref("places.frecency.linkVisitBonus", 100);
pref("places.frecency.typedVisitBonus", 2000);
// The bookmarks bonus is always added on top of any other bonus, including
// the redirect source and the typed ones.
pref("places.frecency.bookmarkVisitBonus", 75);
// The redirect source bonus overwrites any transition bonus.
// 0 would hide these pages, instead we want them low ranked. Thus we use
// linkVisitBonus - bookmarkVisitBonus, so that a bookmarked source is in par
// with a common link.
pref("places.frecency.redirectSourceVisitBonus", 25);
pref("places.frecency.downloadVisitBonus", 0);
pref("places.frecency.permRedirectVisitBonus", 0);
pref("places.frecency.tempRedirectVisitBonus", 0);
// The perm/temp redirects here relate to redirect targets, not sources.
pref("places.frecency.permRedirectVisitBonus", 50);
pref("places.frecency.tempRedirectVisitBonus", 40);
pref("places.frecency.reloadVisitBonus", 0);
pref("places.frecency.defaultVisitBonus", 0);
@ -1574,4 +1582,4 @@ pref("browser.formautofill.experimental", false);
#ifdef NIGHTLY_BUILD
pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,goog-malware-proto,goog-unwanted-proto,test-malware-simple,test-unwanted-simple");
pref("urlclassifier.phishTable", "goog-phish-shavar,goog-phish-proto,test-phish-simple");
#endif
#endif

Просмотреть файл

@ -516,7 +516,6 @@ const gExtensionsNotifications = {
container.firstChild.remove();
}
// Strings below to be properly localized in bug 1316996
const DEFAULT_EXTENSION_ICON =
"chrome://mozapps/skin/extensions/extensionGeneric.svg";
let items = 0;
@ -524,8 +523,10 @@ const gExtensionsNotifications = {
if (++items > 4) {
break;
}
let button = document.createElement("toolbarbutton");
button.setAttribute("label", `"${update.addon.name}" requires new permissions`);
let text = gNavigatorBundle.getFormattedString("webextPerms.updateMenuItem", [update.addon.name]);
button.setAttribute("label", text);
let icon = update.addon.iconURL || DEFAULT_EXTENSION_ICON;
button.setAttribute("image", icon);
@ -537,12 +538,19 @@ const gExtensionsNotifications = {
container.appendChild(button);
}
let appName;
for (let addon of sideloaded) {
if (++items > 4) {
break;
}
if (!appName) {
let brandBundle = document.getElementById("bundle_brand");
appName = brandBundle.getString("brandShortName");
}
let button = document.createElement("toolbarbutton");
button.setAttribute("label", `"${addon.name}" added to Firefox`);
let text = gNavigatorBundle.getFormattedString("webextPerms.sideloadMenuItem", [addon.name, appName]);
button.setAttribute("label", text);
let icon = addon.iconURL || DEFAULT_EXTENSION_ICON;
button.setAttribute("image", icon);

Просмотреть файл

@ -3091,7 +3091,11 @@
<parameter name="aTab"/>
<body>
<![CDATA[
this.getBrowserForTab(aTab).reload();
let browser = this.getBrowserForTab(aTab);
// Reset temporary permissions on the current tab. This is done here
// because we only want to reset permissions on user reload.
SitePermissions.clearTemporaryPermissions(browser);
browser.reload();
]]>
</body>
</method>

Просмотреть файл

@ -35,9 +35,36 @@ add_task(function* testTempPermissionOnReload() {
scope: SitePermissions.SCOPE_TEMPORARY,
});
reloaded = BrowserTestUtils.browserLoaded(browser, false, uri.spec);
// Reload as a user (should remove the temp permission).
EventUtils.synthesizeMouseAtCenter(reloadButton, {});
yield reloaded;
Assert.deepEqual(SitePermissions.get(uri, id, browser), {
state: SitePermissions.UNKNOWN,
scope: SitePermissions.SCOPE_PERSISTENT,
});
// Set the permission again.
SitePermissions.set(uri, id, SitePermissions.BLOCK, SitePermissions.SCOPE_TEMPORARY, browser);
// Open the tab context menu.
let contextMenu = document.getElementById("tabContextMenu");
let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(gBrowser.selectedTab, {type: "contextmenu", button: 2});
yield popupShownPromise;
let reloadMenuItem = document.getElementById("context_reloadTab");
reloaded = BrowserTestUtils.browserLoaded(browser, false, uri.spec);
// Reload as a user through the context menu (should remove the temp permission).
EventUtils.synthesizeMouseAtCenter(reloadMenuItem, {});
yield reloaded;
Assert.deepEqual(SitePermissions.get(uri, id, browser), {
state: SitePermissions.UNKNOWN,
scope: SitePermissions.SCOPE_PERSISTENT,

Просмотреть файл

@ -50,4 +50,25 @@ var tests = [
this.notification.remove();
}
},
// Test that the space key on an anchor element focuses an active notification
{ id: "Test#3",
*run() {
this.notifyObj = new BasicNotification(this.id);
this.notifyObj.anchorID = "geo-notification-icon";
this.notifyObj.addOptions({
persistent: true
});
this.notification = showNotification(this.notifyObj);
},
*onShown(popup) {
checkPopup(popup, this.notifyObj);
let anchor = document.getElementById(this.notifyObj.anchorID);
anchor.focus();
is(document.activeElement, anchor);
EventUtils.synthesizeKey(" ", {});
is(document.activeElement, popup.childNodes[0].button);
this.notification.remove();
},
onHidden(popup) { }
},
];

Просмотреть файл

@ -33,6 +33,93 @@ xpinstallDisabledMessage=Software installation is currently disabled. Click Enab
xpinstallDisabledButton=Enable
xpinstallDisabledButton.accesskey=n
# LOCALIZATION NOTE (webextPerms.header)
# This string is used as a header in the webextension permissions dialog,
# %S is replaced with the localized name of the extension being installed.
# See https://bug1308309.bmoattachments.org/attachment.cgi?id=8814612
# for an example of the full dialog.
# Note, this string will be used as raw markup. Avoid characters like <, >, &
webextPerms.header=Add %S?
# LOCALIZATION NOTE (webextPerms.listIntro)
# This string will be followed by a list of permissions requested
# by the webextension.
webextPerms.listIntro=It requires your permission to:
webextPerms.add.label=Add
webextPerms.add.accessKey=A
webextPerms.cancel.label=Cancel
webextPerms.cancel.accessKey=C
# LOCALIZATION NOTE (webextPerms.sideloadMenuItem)
# %1$S will be replaced with the localized name of the sideloaded add-on.
# %2$S will be replace with the name of the application (e.g., Firefox, Nightly)
webextPerms.sideloadMenuItem=%1$S added to %2$S
# LOCALIZATION NOTE (webextPerms.sideloadHeader)
# This string is used as a header in the webextension permissions dialog
# when the extension is side-loaded.
# %S is replaced with the localized name of the extension being installed.
# Note, this string will be used as raw markup. Avoid characters like <, >, &
webextPerms.sideloadHeader=%S added
webextPerms.sideloadText=Another program on your computer installed an add-on that may affect your browser. Please review this add-ons permissions requests and choose to Enable or Disable.
webextPerms.sideloadEnable.label=Enable
webextPerms.sideloadEnable.accessKey=E
webextPerms.sideloadDisable.label=Disable
webextPerms.sideloadDisable.accessKey=D
# LOCALIZATION NOTE (webextPerms.updateMenuItem)
# %S will be replaced with the localized name of the extension which
# has been updated.
webextPerms.updateMenuItem=%S requires new permissions
# LOCALIZATION NOTE (webextPerms.updateText)
# %S is replaced with the localized name of the updated extension.
# Note, this string will be used as raw markup. Avoid characters like <, >, &
webextPerms.updateText=%S has been updated. You must approve new permissions before the updated version will install. Choosing “Cancel” will maintain your current add-on version.
webextPerms.updateAccept.label=Update
webextPerms.updateAccept.accessKey=U
webextPerms.description.bookmarks=Read and modify bookmarks
webextPerms.description.downloads=Download files and read and modify the browsers download history
webextPerms.description.history=Access browsing history
# LOCALIZATION NOTE (webextPerms.description.nativeMessaging)
# %S will be replaced with the name of the application
webextPerms.description.nativeMessaging=Exchange messages with programs other than %S
webextPerms.description.notifications=Display notifications to you
webextPerms.description.sessions=Access browser recently closed tabs
webextPerms.description.tabs=Access browser tabs
webextPerms.description.topSites=Access browsing history
webextPerms.description.webNavigation=Access browser activity during navigation
webextPerms.hostDescription.allUrls=Access your data for all websites
# LOCALIZATION NOTE (webextPerms.hostDescription.wildcard)
# %S will be replaced by the DNS domain for which a webextension
# is requesting access (e.g., mozilla.org)
webextPerms.hostDescription.wildcard=Access your data for sites in the %S domain
# LOCALIZATION NOTE (webextPerms.hostDescription.tooManyWildcards):
# Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 will be replaced by an integer indicating the number of additional
# domains for which this webextension is requesting permission.
webextPerms.hostDescription.tooManyWildcards=Access your data in #1 other domain;Access your data in #1 other domains
# LOCALIZATION NOTE (webextPerms.hostDescription.oneSite)
# %S will be replaced by the DNS host name for which a webextension
# is requesting access (e.g., www.mozilla.org)
webextPerms.hostDescription.oneSite=Access your data for %S
# LOCALIZATION NOTE (webextPerms.hostDescription.tooManySites)
# Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 will be replaced by an integer indicating the number of additional
# hosts for which this webextension is requesting permission.
webextPerms.hostDescription.tooManySites=Access your data on #1 other site;Access your data on #1 other sites
# LOCALIZATION NOTE (addonDownloadingAndVerifying):
# Semicolon-separated list of plural forms. See:
# http://developer.mozilla.org/en/docs/Localization_and_Plurals

Просмотреть файл

@ -12,6 +12,8 @@ Cu.import("resource://devtools/shared/event-emitter.js");
XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
"resource://gre/modules/AddonManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services",
@ -154,74 +156,98 @@ this.ExtensionsUI = {
if (name.length > 50) {
name = name.slice(0, 49) + "…";
}
name = name.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");
// The strings below are placeholders, they will switch over to the
// bundle.get*String() calls as part of bug 1316996.
let addonLabel = `<label class="addon-webext-name">${name}</label>`;
let bundle = win.gNavigatorBundle;
// let bundle = win.gNavigatorBundle;
// let header = bundle.getFormattedString("webextPerms.header", [name])
// let listHeader = bundle.getString("webextPerms.listHeader");
let header = "Add ADDON?".replace("ADDON", name);
let header = bundle.getFormattedString("webextPerms.header", [addonLabel]);
let text = "";
let listHeader = "It can:";
let listIntro = bundle.getString("webextPerms.listIntro");
// let acceptText = bundle.getString("webextPerms.accept.label");
// let acceptKey = bundle.getString("webextPerms.accept.accessKey");
// let cancelText = bundle.getString("webextPerms.cancel.label");
// let cancelKey = bundle.getString("webextPerms.cancel.accessKey");
let acceptText = "Add extension";
let acceptKey = "A";
let cancelText = "Cancel";
let cancelKey = "C";
let acceptText = bundle.getString("webextPerms.add.label");
let acceptKey = bundle.getString("webextPerms.add.accessKey");
let cancelText = bundle.getString("webextPerms.cancel.label");
let cancelKey = bundle.getString("webextPerms.cancel.accessKey");
if (info.type == "sideload") {
header = `${name} added`;
text = "Another program on your computer installed an add-on that may affect your browser. Please review this add-on's permission requests and choose to Enable or Disable";
acceptText = "Enable";
acceptKey = "E";
cancelText = "Disable";
cancelKey = "D";
header = bundle.getFormattedString("webextPerms.sideloadHeader", [addonLabel]);
text = bundle.getString("webextPerms.sideloadText");
acceptText = bundle.getString("webextPerms.sideloadEnable.label");
acceptKey = bundle.getString("webextPerms.sideloadEnable.accessKey");
cancelText = bundle.getString("webextPerms.sideloadDisable.label");
cancelKey = bundle.getString("webextPerms.sideloadDisable.accessKey");
} else if (info.type == "update") {
header = "";
text = `${name} has been updated. You must approve new permissions before the updated version will install.`;
acceptText = "Update";
acceptKey = "U";
text = bundle.getFormattedString("webextPerms.updateText", [addonLabel]);
acceptText = bundle.getString("webextPerms.updateAccept.label");
acceptKey = bundle.getString("webextPerms.updateAccept.accessKey");
}
let formatPermission = perm => {
try {
// return bundle.getString(`webextPerms.description.${perm}`);
return `localized description of permission ${perm}`;
} catch (err) {
// return bundle.getFormattedString("webextPerms.description.unknown",
// [perm]);
return `localized description of unknown permission ${perm}`;
let msgs = [];
for (let permission of perms.permissions) {
let key = `webextPerms.description.${permission}`;
if (permission == "nativeMessaging") {
let brandBundle = win.document.getElementById("bundle_brand");
let appName = brandBundle.getString("brandShortName");
msgs.push(bundle.getFormattedString(key, [appName]));
} else {
try {
msgs.push(bundle.getString(key));
} catch (err) {
// We deliberately do not include all permissions in the prompt.
// So if we don't find one then just skip it.
}
}
};
}
let formatHostPermission = perm => {
if (perm == "<all_urls>") {
// return bundle.getString("webextPerms.hostDescription.allUrls");
return "localized description of <all_urls> host permission";
let allUrls = false, wildcards = [], sites = [];
for (let permission of perms.hosts) {
if (permission == "<all_urls>") {
allUrls = true;
break;
}
let match = /^[htps*]+:\/\/([^/]+)\//.exec(perm);
let match = /^[htps*]+:\/\/([^/]+)\//.exec(permission);
if (!match) {
throw new Error("Unparseable host permission");
}
if (match[1].startsWith("*.")) {
let domain = match[1].slice(2);
// return bundle.getFormattedString("webextPerms.hostDescription.wildcard", [domain]);
return `localized description of wildcard host permission for ${domain}`;
if (match[1] == "*") {
allUrls = true;
} else if (match[1].startsWith("*.")) {
wildcards.push(match[1].slice(2));
} else {
sites.push(match[1]);
}
}
if (allUrls) {
msgs.push(bundle.getString("webextPerms.hostDescription.allUrls"));
} else {
// Formats a list of host permissions. If we have 4 or fewer, display
// them all, otherwise display the first 3 followed by an item that
// says "...plus N others"
function format(list, itemKey, moreKey) {
function formatItems(items) {
msgs.push(...items.map(item => bundle.getFormattedString(itemKey, [item])));
}
if (list.length < 5) {
formatItems(list);
} else {
formatItems(list.slice(0, 3));
let remaining = list.length - 3;
msgs.push(PluralForm.get(remaining, bundle.getString(moreKey))
.replace("#1", remaining));
}
}
// return bundle.getFormattedString("webextPerms.hostDescription.oneSite", [match[1]]);
return `localized description of single host permission for ${match[1]}`;
};
let msgs = [
...perms.permissions.map(formatPermission),
...perms.hosts.map(formatHostPermission),
];
format(wildcards, "webextPerms.hostDescription.wildcard",
"webextPerms.hostDescription.tooManyWildcards");
format(sites, "webextPerms.hostDescription.oneSite",
"webextPerms.hostDescription.tooManySites");
}
let popupOptions = {
hideClose: true,
@ -231,21 +257,21 @@ this.ExtensionsUI = {
eventCallback(topic) {
if (topic == "showing") {
let doc = this.browser.ownerDocument;
doc.getElementById("addon-webext-perm-header").textContent = header;
doc.getElementById("addon-webext-perm-header").innerHTML = header;
if (text) {
doc.getElementById("addon-webext-perm-text").innerHTML = text;
}
let listIntroEl = doc.getElementById("addon-webext-perm-intro");
listIntroEl.value = listIntro;
listIntroEl.hidden = (msgs.length == 0);
let list = doc.getElementById("addon-webext-perm-list");
while (list.firstChild) {
list.firstChild.remove();
}
if (text) {
doc.getElementById("addon-webext-perm-text").textContent = text;
}
let listHeaderEl = doc.getElementById("addon-webext-perm-intro");
listHeaderEl.value = listHeader;
listHeaderEl.hidden = (msgs.length == 0);
for (let msg of msgs) {
let item = doc.createElementNS(HTML_NS, "li");
item.textContent = msg;

Просмотреть файл

@ -834,10 +834,14 @@ menuitem.bookmark-item {
}
.addon-webext-perm-header {
font-weight: bold;
font-size: 1.3em;
}
.addon-webext-name {
font-weight: bold;
margin: 0;
}
/* Notification icon box */
.notification-anchor-icon:-moz-focusring {

Просмотреть файл

@ -3092,10 +3092,14 @@ menulist.translate-infobar-element > .menulist-dropmarker {
}
.addon-webext-perm-header {
font-weight: bold;
font-size: 1.3em;
}
.addon-webext-name {
font-weight: bold;
margin: 0;
}
/* Status panel */
.statuspanel-label {

Просмотреть файл

@ -2137,10 +2137,14 @@ toolbarbutton.bookmark-item[dragover="true"][open="true"] {
}
.addon-webext-perm-header {
font-weight: bold;
font-size: 1.3em;
}
.addon-webext-name {
font-weight: bold;
margin: 0;
}
/* Notification icon box */
.notification-anchor-icon:-moz-focusring {

Просмотреть файл

@ -146,7 +146,10 @@ var gDevToolsBrowser = exports.gDevToolsBrowser = {
devtoolsTheme = "light";
}
win.document.documentElement.setAttribute("devtoolstheme", devtoolsTheme);
// Style gcli and the splitter between the toolbox and page content. This used to
// set the attribute on the browser's root node but that regressed tpaint: bug 1331449.
win.document.getElementById("browser-bottombox").setAttribute("devtoolstheme", devtoolsTheme);
win.document.getElementById("content").setAttribute("devtoolstheme", devtoolsTheme);
// If the toolbox color changes and we have the opposite compact theme applied,
// change it to match. For example:

Просмотреть файл

@ -17,16 +17,22 @@ registerCleanupFunction(() => {
add_task(function* testDevtoolsTheme() {
info("Checking stylesheet and :root attributes based on devtools theme.");
Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "light");
is(document.documentElement.getAttribute("devtoolstheme"), "light",
"The documentElement has an attribute based on devtools theme.");
is(document.getElementById("browser-bottombox").getAttribute("devtoolstheme"), "light",
"The element has an attribute based on devtools theme.");
is(document.getElementById("content").getAttribute("devtoolstheme"), "light",
"The element has an attribute based on devtools theme.");
Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "dark");
is(document.documentElement.getAttribute("devtoolstheme"), "dark",
"The documentElement has an attribute based on devtools theme.");
is(document.getElementById("browser-bottombox").getAttribute("devtoolstheme"), "dark",
"The element has an attribute based on devtools theme.");
is(document.getElementById("content").getAttribute("devtoolstheme"), "dark",
"The element has an attribute based on devtools theme.");
Services.prefs.setCharPref(PREF_DEVTOOLS_THEME, "firebug");
is(document.documentElement.getAttribute("devtoolstheme"), "light",
"The documentElement has 'light' as a default for the devtoolstheme attribute");
is(document.getElementById("browser-bottombox").getAttribute("devtoolstheme"), "light",
"The element has 'light' as a default for the devtoolstheme attribute.");
is(document.getElementById("content").getAttribute("devtoolstheme"), "light",
"The element has 'light' as a default for the devtoolstheme attribute.");
});
add_task(function* testDevtoolsAndCompactThemeSyncing() {

Просмотреть файл

@ -64,6 +64,13 @@ function swapToInnerBrowser({ tab, containerURL, getInnerBrowser }) {
gBrowser.hideTab(containerTab);
let containerBrowser = containerTab.linkedBrowser;
// Copy tab listener state flags to container tab. Each tab gets its own tab
// listener and state flags which cache document loading progress. The state flags
// are checked when switching tabs to update the browser UI. The later step of
// `swapBrowsersAndCloseOther` will fold the state back into the main tab.
let stateFlags = gBrowser._tabListeners.get(tab).mStateFlags;
gBrowser._tabListeners.get(containerTab).mStateFlags = stateFlags;
// 2. Mark the tool tab browser's docshell as active so the viewport frame
// is created eagerly and will be ready to swap.
// This line is crucial when the tool UI is loaded into a background tab.
@ -147,11 +154,17 @@ function swapToInnerBrowser({ tab, containerURL, getInnerBrowser }) {
gBrowser._swapBrowserDocShells(contentTab, innerBrowser);
innerBrowser = null;
// Copy tab listener state flags to content tab. See similar comment in `start`
// above for more details.
let stateFlags = gBrowser._tabListeners.get(tab).mStateFlags;
gBrowser._tabListeners.get(contentTab).mStateFlags = stateFlags;
// 5. Force the original browser tab to be remote since web content is
// loaded in the child process, and we're about to swap the content
// into this tab.
gBrowser.updateBrowserRemoteness(tab.linkedBrowser, true,
contentBrowser.remoteType);
gBrowser.updateBrowserRemoteness(tab.linkedBrowser, true, {
remoteType: contentBrowser.remoteType,
});
// 6. Swap the content into the original browser tab and close the
// temporary tab used to hold the content via

Просмотреть файл

@ -192,8 +192,8 @@ function dragElementBy(selector, x, y, win) {
let { Simulate } = React.addons.TestUtils;
let rect = getElRect(selector, win);
let startPoint = {
clientX: rect.left + Math.floor(rect.width / 2),
clientY: rect.top + Math.floor(rect.height / 2),
clientX: Math.floor(rect.left + rect.width / 2),
clientY: Math.floor(rect.top + rect.height / 2),
};
let endPoint = [ startPoint.clientX + x, startPoint.clientY + y ];

Просмотреть файл

@ -933,8 +933,8 @@ OutputPanel.prototype._init = function (devtoolbar) {
so it can be styled correctly. */
OutputPanel.prototype._copyTheme = function () {
if (this.document) {
let theme =
this._devtoolbar._doc.documentElement.getAttribute("devtoolstheme");
let theme = this._devtoolbar._doc.getElementById("browser-bottombox")
.getAttribute("devtoolstheme");
this.document.documentElement.setAttribute("devtoolstheme", theme);
}
};
@ -1253,8 +1253,8 @@ TooltipPanel.prototype._init = function (devtoolbar) {
so it can be styled correctly. */
TooltipPanel.prototype._copyTheme = function () {
if (this.document) {
let theme =
this._devtoolbar._doc.documentElement.getAttribute("devtoolstheme");
let theme = this._devtoolbar._doc.getElementById("browser-bottombox")
.getAttribute("devtoolstheme");
this.document.documentElement.setAttribute("devtoolstheme", theme);
}
};

Просмотреть файл

@ -9,7 +9,7 @@
/* NOTE: THESE NEED TO STAY IN SYNC WITH LIGHT-THEME.CSS AND DARK-THEME.CSS.
We are copy/pasting variables from light-theme and dark-theme,
since they aren't loaded in this context (within browser.css). */
:root[devtoolstheme="light"] #developer-toolbar {
#browser-bottombox[devtoolstheme="light"] #developer-toolbar {
--gcli-background-color: #fcfcfc; /* --theme-tab-toolbar-background */
--gcli-input-background: #fcfcfc; /* --theme-toolbar-background */
--gcli-input-focused-background: #ffffff; /* --theme-sidebar-background */
@ -21,7 +21,7 @@
--command-line-image-focus: url(chrome://devtools/skin/images/commandline-icon.svg#light-theme-focus); /* --theme-command-line-image-focus */
}
:root[devtoolstheme="dark"] #developer-toolbar {
#browser-bottombox[devtoolstheme="dark"] #developer-toolbar {
--gcli-background-color: #272b35; /* --theme-toolbar-background */
--gcli-input-background: #272b35; /* --theme-tab-toolbar-background */
--gcli-input-focused-background: #272b35; /* --theme-tab-toolbar-background */
@ -54,8 +54,8 @@
margin: auto 10px;
}
:root[devtoolstheme="light"] #developer-toolbar > .developer-toolbar-button:not([checked=true]) > image,
:root[devtoolstheme="light"] .gclitoolbar-input-node:not([focused=true])::before {
#browser-bottombox[devtoolstheme="light"] #developer-toolbar > .developer-toolbar-button:not([checked=true]) > image,
#browser-bottombox[devtoolstheme="light"] .gclitoolbar-input-node:not([focused=true])::before {
filter: invert(1);
}
@ -65,7 +65,7 @@
}
/* The toolkit close button is low contrast in the dark theme so invert it. */
:root[devtoolstheme="dark"] #developer-toolbar > .close-icon:not(:hover) > image {
#browser-bottombox[devtoolstheme="dark"] #developer-toolbar > .close-icon:not(:hover) > image {
filter: invert(1);
}

Просмотреть файл

@ -20,13 +20,12 @@
--devtools-splitter-inline-end-width: 4px;
}
:root[devtoolstheme="light"] {
#content[devtoolstheme="light"] {
/* These variables are used in browser.xul but inside the toolbox they are overridden by --theme-splitter-color */
--devtools-splitter-color: #dde1e4;
}
:root[devtoolstheme="dark"],
:root[devtoolstheme="firebug"] {
#content[devtoolstheme="dark"] {
--devtools-splitter-color: #42484f;
}

Просмотреть файл

@ -354,6 +354,11 @@ AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
return NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR;
}
cubeb_channel_layout layout;
int r = cubeb_get_preferred_channel_layout(cubebContext, &layout);
MOZ_ASSERT(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
params.layout = (r == CUBEB_OK) ? layout : CUBEB_LAYOUT_UNDEFINED;
return OpenCubeb(cubebContext, params, startTime, CubebUtils::GetFirstStream());
}

Просмотреть файл

@ -639,6 +639,11 @@ AudioCallbackDriver::Init()
output.format = CUBEB_SAMPLE_FLOAT32NE;
}
cubeb_channel_layout layout;
int r = cubeb_get_preferred_channel_layout(cubebContext, &layout);
MOZ_ASSERT(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
output.layout = (r == CUBEB_OK) ? layout : CUBEB_LAYOUT_UNDEFINED;
Maybe<uint32_t> latencyPref = CubebUtils::GetCubebMSGLatencyInFrames();
if (latencyPref) {
latency_frames = latencyPref.value();
@ -658,6 +663,7 @@ AudioCallbackDriver::Init()
input = output;
input.channels = mInputChannels; // change to support optional stereo capture
input.layout = CUBEB_LAYOUT_MONO;
cubeb_stream* stream = nullptr;
CubebUtils::AudioDeviceID input_id = nullptr, output_id = nullptr;

Просмотреть файл

@ -0,0 +1,22 @@
// |jit-test| test-also-wasm-baseline; exitstatus: 3
load(libdir + "asserts.js");
if (!wasmIsSupported())
quit(3);
var g = newGlobal();
g.parent = this;
g.eval("new Debugger(parent).onExceptionUnwind = function () { some_error; };");
var module = new WebAssembly.Module(wasmTextToBinary(`
(module
(import $imp "a" "b" (result i32))
(func $call (result i32) (call 0))
(export "call" $call)
)`));
var instance = new WebAssembly.Instance(module, { a: { b: () => {
some_other_error;
}}});
instance.exports.call();

Просмотреть файл

@ -151,12 +151,16 @@ WasmHandleThrow()
DebugFrame* frame = iter.debugFrame();
JSTrapStatus status = Debugger::onExceptionUnwind(cx, frame);
if (status == JSTRAP_RETURN) {
// Unexpected trap return -- raising error since throw recovery
// is not yet implemented in the wasm baseline.
// TODO properly handle JSTRAP_RETURN and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected resumption value from onExceptionUnwind");
// Assume JSTRAP_ERROR status if no exception is pending --
// no onExceptionUnwind handlers must be fired.
if (cx->isExceptionPending()) {
JSTrapStatus status = Debugger::onExceptionUnwind(cx, frame);
if (status == JSTRAP_RETURN) {
// Unexpected trap return -- raising error since throw recovery
// is not yet implemented in the wasm baseline.
// TODO properly handle JSTRAP_RETURN and resume wasm execution.
JS_ReportErrorASCII(cx, "Unexpected resumption value from onExceptionUnwind");
}
}
bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, false);

Просмотреть файл

@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
The git commit ID used was 051cd8478dd48a18e2e91e5f07837640f40618c1.
The git commit ID used was d96e35f02dbb9a093e5bfdff4f2948b7a6e9d3f9.

Просмотреть файл

@ -16,6 +16,13 @@
#include <unistd.h>
#endif
template<typename T, size_t N>
constexpr size_t
ARRAY_LENGTH(T(&)[N])
{
return N;
}
void delay(unsigned int ms)
{
#if defined(_WIN32)
@ -30,6 +37,34 @@ void delay(unsigned int ms)
#define M_PI 3.14159265358979323846
#endif
typedef struct {
char const * name;
unsigned int const channels;
cubeb_channel_layout const layout;
} layout_info;
layout_info const layout_infos[CUBEB_LAYOUT_MAX] = {
{ "undefined", 0, CUBEB_LAYOUT_UNDEFINED },
{ "dual mono", 2, CUBEB_LAYOUT_DUAL_MONO },
{ "dual mono lfe", 3, CUBEB_LAYOUT_DUAL_MONO_LFE },
{ "mono", 1, CUBEB_LAYOUT_MONO },
{ "mono lfe", 2, CUBEB_LAYOUT_MONO_LFE },
{ "stereo", 2, CUBEB_LAYOUT_STEREO },
{ "stereo lfe", 3, CUBEB_LAYOUT_STEREO_LFE },
{ "3f", 3, CUBEB_LAYOUT_3F },
{ "3f lfe", 4, CUBEB_LAYOUT_3F_LFE },
{ "2f1", 3, CUBEB_LAYOUT_2F1 },
{ "2f1 lfe", 4, CUBEB_LAYOUT_2F1_LFE },
{ "3f1", 4, CUBEB_LAYOUT_3F1 },
{ "3f1 lfe", 5, CUBEB_LAYOUT_3F1_LFE },
{ "2f2", 4, CUBEB_LAYOUT_2F2 },
{ "2f2 lfe", 5, CUBEB_LAYOUT_2F2_LFE },
{ "3f2", 5, CUBEB_LAYOUT_3F2 },
{ "3f2 lfe", 6, CUBEB_LAYOUT_3F2_LFE },
{ "3f3r lfe", 7, CUBEB_LAYOUT_3F3R_LFE },
{ "3f4 lfe", 8, CUBEB_LAYOUT_3F4_LFE }
};
int has_available_input_device(cubeb * ctx)
{
cubeb_device_collection * devices;

Просмотреть файл

@ -24,7 +24,6 @@
#define M_PI 3.14159265358979323846
#endif
#define NELEMS(x) ((int) (sizeof(x) / sizeof(x[0])))
#define VOLUME 0.2
float get_frequency(int channel_index)
@ -118,7 +117,7 @@ int supports_channel_count(const char* backend_id, int nchannels)
(strcmp(backend_id, "opensl") != 0 && strcmp(backend_id, "audiotrack") != 0);
}
int run_test(int num_channels, int sampling_rate, int is_float)
int run_test(int num_channels, layout_info layout, int sampling_rate, int is_float)
{
int r = CUBEB_OK;
@ -142,12 +141,13 @@ int run_test(int num_channels, int sampling_rate, int is_float)
goto cleanup;
}
fprintf(stderr, "Testing %d channel(s), %d Hz, %s (%s)\n", num_channels, sampling_rate, is_float ? "float" : "short", cubeb_get_backend_id(ctx));
fprintf(stderr, "Testing %d channel(s), layout: %s, %d Hz, %s (%s)\n", num_channels, layout.name, sampling_rate, is_float ? "float" : "short", cubeb_get_backend_id(ctx));
cubeb_stream_params params;
params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE;
params.rate = sampling_rate;
params.channels = num_channels;
params.layout = layout.layout;
synth = synth_create(params.channels, params.rate);
if (synth == NULL) {
@ -200,6 +200,7 @@ int run_panning_volume_test(int is_float)
params.format = is_float ? CUBEB_SAMPLE_FLOAT32NE : CUBEB_SAMPLE_S16NE;
params.rate = 44100;
params.channels = 2;
params.layout = CUBEB_LAYOUT_STEREO;
synth = synth_create(params.channels, params.rate);
if (synth == NULL) {
@ -259,7 +260,7 @@ TEST(cubeb, run_panning_volume_test_float)
TEST(cubeb, run_channel_rate_test)
{
int channel_values[] = {
unsigned int channel_values[] = {
1,
2,
3,
@ -274,13 +275,16 @@ TEST(cubeb, run_channel_rate_test)
48000,
};
for(int j = 0; j < NELEMS(channel_values); ++j) {
for(int i = 0; i < NELEMS(freq_values); ++i) {
for(unsigned int j = 0; j < ARRAY_LENGTH(channel_values); ++j) {
for(unsigned int i = 0; i < ARRAY_LENGTH(freq_values); ++i) {
ASSERT_TRUE(channel_values[j] < MAX_NUM_CHANNELS);
fprintf(stderr, "--------------------------\n");
ASSERT_EQ(run_test(channel_values[j], freq_values[i], 0), CUBEB_OK);
ASSERT_EQ(run_test(channel_values[j], freq_values[i], 1), CUBEB_OK);
for (unsigned int k = 0 ; k < ARRAY_LENGTH(layout_infos); ++k ) {
if (layout_infos[k].channels == channel_values[j]) {
ASSERT_EQ(run_test(channel_values[j], layout_infos[k], freq_values[i], 0), CUBEB_OK);
ASSERT_EQ(run_test(channel_values[j], layout_infos[k], freq_values[i], 1), CUBEB_OK);
}
}
}
}
}

Просмотреть файл

@ -108,9 +108,11 @@ TEST(cubeb, duplex)
input_params.format = STREAM_FORMAT;
input_params.rate = 48000;
input_params.channels = 1;
input_params.layout = CUBEB_LAYOUT_MONO;
output_params.format = STREAM_FORMAT;
output_params.rate = 48000;
output_params.channels = 2;
output_params.layout = CUBEB_LAYOUT_STEREO;
r = cubeb_get_min_latency(ctx, output_params, &latency_frames);

Просмотреть файл

@ -9,6 +9,7 @@ TEST(cubeb, latency)
uint32_t max_channels;
uint32_t preferred_rate;
uint32_t latency_frames;
cubeb_channel_layout layout;
r = cubeb_init(&ctx, "Cubeb audio test");
ASSERT_EQ(r, CUBEB_OK);
@ -25,10 +26,17 @@ TEST(cubeb, latency)
ASSERT_GT(preferred_rate, 0u);
}
r = cubeb_get_preferred_channel_layout(ctx, &layout);
ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
cubeb_stream_params params = {
CUBEB_SAMPLE_FLOAT32NE,
preferred_rate,
max_channels
max_channels,
(r == CUBEB_OK) ? layout : CUBEB_LAYOUT_UNDEFINED
#if defined(__ANDROID__)
, CUBEB_STREAM_TYPE_MUSIC
#endif
};
r = cubeb_get_min_latency(ctx, params, &latency_frames);
ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);

Просмотреть файл

@ -0,0 +1,181 @@
/*
* Copyright © 2016 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#include "gtest/gtest.h"
#include "cubeb/cubeb.h"
#include "cubeb_mixer.h"
#include "common.h"
#include <vector>
using std::vector;
#define STREAM_FREQUENCY 48000
#define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
float const M = 1.0f; // Mono
float const L = 2.0f; // Left
float const R = 3.0f; // Right
float const C = 4.0f; // Center
float const LS = 5.0f; // Left Surround
float const RS = 6.0f; // Right Surround
float const RLS = 7.0f; // Rear Left Surround
float const RC = 8.0f; // Rear Center
float const RRS = 9.0f; // Rear Right Surround
float const LFE = 10.0f; // Low Frequency Effects
float const INV_SQRT_2 = 0.707106f; // 1/sqrt(2)
static float const DOWNMIX_3F2_RESULTS[2][12][5] = {
// 3F2
{
{ INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS) }, // Mono
{ INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS), 0 }, // Mono-LFE
{ L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS) }, // Stereo
{ L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS), 0 }, // Stereo-LFE
{ L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C }, // 3F
{ L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C, 0 }, // 3F-LFE
{ L + C*INV_SQRT_2, R + C*INV_SQRT_2, INV_SQRT_2*(LS+RS) }, // 2F1
{ L + C*INV_SQRT_2, R + C*INV_SQRT_2, 0, INV_SQRT_2*(LS+RS) }, // 2F1-LFE
{ L, R, C, INV_SQRT_2*(LS+RS) }, // 3F1
{ L, R, C, 0, INV_SQRT_2*(LS+RS) }, // 3F1-LFE
{ L + INV_SQRT_2*C, R + INV_SQRT_2*C, LS, RS }, // 2F2
{ L + INV_SQRT_2*C, R + INV_SQRT_2*C, 0, LS, RS } // 2F2-LFE
},
// 3F2-LFE
{
{ INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS) }, // Mono
{ INV_SQRT_2*(L+R) + C + 0.5f*(LS+RS), LFE }, // Mono-LFE
{ L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS) }, // Stereo
{ L + INV_SQRT_2*(C+LS), R + INV_SQRT_2*(C+RS), LFE }, // Stereo-LFE
{ L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C }, // 3F
{ L + INV_SQRT_2*LS, R + INV_SQRT_2*RS, C, LFE }, // 3F-LFE
{ L + C*INV_SQRT_2, R + C*INV_SQRT_2, INV_SQRT_2*(LS+RS) }, // 2F1
{ L + C*INV_SQRT_2, R + C*INV_SQRT_2, LFE, INV_SQRT_2*(LS+RS) }, // 2F1-LFE
{ L, R, C, INV_SQRT_2*(LS+RS) }, // 3F1
{ L, R, C, LFE, INV_SQRT_2*(LS+RS) }, // 3F1-LFE
{ L + INV_SQRT_2*C, R + INV_SQRT_2*C, LS, RS }, // 2F2
{ L + INV_SQRT_2*C, R + INV_SQRT_2*C, LFE, LS, RS } // 2F2-LFE
}
};
typedef struct {
cubeb_channel_layout layout;
float data[10];
} audio_input;
audio_input audio_inputs[CUBEB_LAYOUT_MAX] = {
{ CUBEB_LAYOUT_UNDEFINED, { } },
{ CUBEB_LAYOUT_DUAL_MONO, { L, R } },
{ CUBEB_LAYOUT_DUAL_MONO_LFE, { L, R, LFE } },
{ CUBEB_LAYOUT_MONO, { M } },
{ CUBEB_LAYOUT_MONO_LFE, { M, LFE } },
{ CUBEB_LAYOUT_STEREO, { L, R } },
{ CUBEB_LAYOUT_STEREO_LFE, { L, R, LFE } },
{ CUBEB_LAYOUT_3F, { L, R, C } },
{ CUBEB_LAYOUT_3F_LFE, { L, R, C, LFE } },
{ CUBEB_LAYOUT_2F1, { L, R, RC } },
{ CUBEB_LAYOUT_2F1_LFE, { L, R, LFE, RC } },
{ CUBEB_LAYOUT_3F1, { L, R, C, RC } },
{ CUBEB_LAYOUT_3F1_LFE, { L, R, C, LFE, RC } },
{ CUBEB_LAYOUT_2F2, { L, R, LS, RS } },
{ CUBEB_LAYOUT_2F2_LFE, { L, R, LFE, LS, RS } },
{ CUBEB_LAYOUT_3F2, { L, R, C, LS, RS } },
{ CUBEB_LAYOUT_3F2_LFE, { L, R, C, LFE, LS, RS } },
{ CUBEB_LAYOUT_3F3R_LFE, { L, R, C, LFE, RC, LS, RS } },
{ CUBEB_LAYOUT_3F4_LFE, { L, R, C, LFE, RLS, RRS, LS, RS } }
};
void
downmix_test(float const * data, cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
{
if (in_layout == CUBEB_LAYOUT_UNDEFINED) {
return; // Only possible output layout would be UNDEFINED.
}
cubeb_stream_params in_params = {
STREAM_FORMAT,
STREAM_FREQUENCY,
layout_infos[in_layout].channels,
in_layout
#if defined(__ANDROID__)
, CUBEB_STREAM_TYPE_MUSIC
#endif
};
cubeb_stream_params out_params = {
STREAM_FORMAT,
STREAM_FREQUENCY,
// To downmix audio data with undefined layout, its channel number must be
// smaller than or equal to the input channels.
(out_layout == CUBEB_LAYOUT_UNDEFINED) ?
layout_infos[in_layout].channels : layout_infos[out_layout].channels,
out_layout
#if defined(__ANDROID__)
, CUBEB_STREAM_TYPE_MUSIC
#endif
};
if (!cubeb_should_downmix(&in_params, &out_params)) {
return;
}
fprintf(stderr, "Downmix from %s to %s\n", layout_infos[in_layout].name, layout_infos[out_layout].name);
unsigned int const inframes = 10;
vector<float> in(in_params.channels * inframes);
vector<float> out(out_params.channels * inframes);
for (unsigned int offset = 0 ; offset < inframes * in_params.channels ; offset += in_params.channels) {
for (unsigned int i = 0 ; i < in_params.channels ; ++i) {
in[offset + i] = data[i];
}
}
cubeb_downmix_float(in.data(), inframes, out.data(), in_params.channels, out_params.channels, in_params.layout, out_params.layout);
uint32_t in_layout_mask = 0;
for (unsigned int i = 0 ; i < in_params.channels; ++i) {
in_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[in_layout][i];
}
uint32_t out_layout_mask = 0;
for (unsigned int i = 0 ; out_layout != CUBEB_LAYOUT_UNDEFINED && i < out_params.channels; ++i) {
out_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[out_layout][i];
}
for (unsigned int i = 0 ; i < inframes * out_params.channels ; ++i) {
unsigned int index = i % out_params.channels;
// downmix_3f2
if ((in_layout == CUBEB_LAYOUT_3F2 || in_layout == CUBEB_LAYOUT_3F2_LFE) &&
out_layout >= CUBEB_LAYOUT_MONO && out_layout <= CUBEB_LAYOUT_2F2_LFE) {
auto & downmix_results = DOWNMIX_3F2_RESULTS[in_layout - CUBEB_LAYOUT_3F2][out_layout - CUBEB_LAYOUT_MONO];
fprintf(stderr, "[3f2] Expect: %lf, Get: %lf\n", downmix_results[index], out[index]);
ASSERT_EQ(out[index], downmix_results[index]);
continue;
}
// mix_remap
if (out_layout_mask & in_layout_mask) {
uint32_t mask = 1 << CHANNEL_INDEX_TO_ORDER[out_layout][index];
fprintf(stderr, "[map channels] Expect: %lf, Get: %lf\n", (mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[index]);
ASSERT_EQ(out[index], (mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0);
continue;
}
// downmix_fallback
fprintf(stderr, "[fallback] Expect: %lf, Get: %lf\n", audio_inputs[in_layout].data[index], out[index]);
ASSERT_EQ(out[index], audio_inputs[in_layout].data[index]);
}
}
TEST(cubeb, run_mixing_test)
{
for (unsigned int i = 0 ; i < ARRAY_LENGTH(audio_inputs) ; ++i) {
for (unsigned int j = 0 ; j < ARRAY_LENGTH(layout_infos) ; ++j) {
downmix_test(audio_inputs[i].data, audio_inputs[i].layout, layout_infos[j].layout);
}
}
}

Просмотреть файл

@ -95,6 +95,7 @@ TEST(cubeb, record)
params.format = STREAM_FORMAT;
params.rate = SAMPLE_FREQUENCY;
params.channels = 1;
params.layout = CUBEB_LAYOUT_MONO;
r = cubeb_stream_init(ctx, &stream, "Cubeb record (mono)", NULL, &params, NULL, nullptr,
4096, data_cb_record, state_cb_record, &stream_state);

Просмотреть файл

@ -286,7 +286,6 @@ long data_cb_resampler(cubeb_stream * /*stm*/, void * user_ptr,
const float * in = reinterpret_cast<const float*>(input_buffer);
float * out = reinterpret_cast<float*>(output_buffer);
state->input.push(in, frame_count * state->input_channels);
/* Check how much output frames we need to write */
@ -362,7 +361,6 @@ void test_resampler_duplex(uint32_t input_channels, uint32_t output_channels,
fill_with_sine(expected_resampled_output.data() + latency,
output_rate, output_channels, output_rate * duration_s - latency, 0);
while (state.output_phase_index != state.max_output_phase_index) {
uint32_t leftover_samples = input_buffer.length() * input_channels;
input_buffer.reserve(input_array_frame_count);

Просмотреть файл

@ -18,19 +18,13 @@
#define STREAM_RATE 44100
#define STREAM_LATENCY 100 * STREAM_RATE / 1000
#define STREAM_CHANNELS 1
#define STREAM_LAYOUT CUBEB_LAYOUT_MONO
#if (defined(_WIN32) || defined(__WIN32__))
#define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
#else
#define STREAM_FORMAT CUBEB_SAMPLE_S16LE
#endif
template<typename T, size_t N>
constexpr size_t
ARRAY_LENGTH(T(&)[N])
{
return N;
}
int is_windows_7()
{
#ifdef __MINGW32__
@ -95,7 +89,6 @@ TEST(cubeb, init_destroy_context)
ASSERT_EQ(r, CUBEB_OK);
ASSERT_NE(ctx, nullptr);
backend_id = cubeb_get_backend_id(ctx);
ASSERT_TRUE(backend_id);
@ -138,6 +131,7 @@ TEST(cubeb, context_variables)
params.channels = STREAM_CHANNELS;
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.layout = STREAM_LAYOUT;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -170,6 +164,7 @@ TEST(cubeb, init_destroy_stream)
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.channels = STREAM_CHANNELS;
params.layout = STREAM_LAYOUT;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -198,6 +193,7 @@ TEST(cubeb, init_destroy_multiple_streams)
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.channels = STREAM_CHANNELS;
params.layout = STREAM_LAYOUT;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -230,6 +226,7 @@ TEST(cubeb, configure_stream)
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.channels = 2; // panning
params.layout = CUBEB_LAYOUT_STEREO;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -265,6 +262,7 @@ test_init_start_stop_destroy_multiple_streams(int early, int delay_ms)
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.channels = STREAM_CHANNELS;
params.layout = STREAM_LAYOUT;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -280,7 +278,6 @@ test_init_start_stop_destroy_multiple_streams(int early, int delay_ms)
}
}
if (!early) {
for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
r = cubeb_stream_start(stream[i]);
@ -352,6 +349,7 @@ TEST(cubeb, init_destroy_multiple_contexts_and_streams)
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.channels = STREAM_CHANNELS;
params.layout = STREAM_LAYOUT;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -392,6 +390,7 @@ TEST(cubeb, basic_stream_operations)
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.channels = STREAM_CHANNELS;
params.layout = STREAM_LAYOUT;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -442,6 +441,7 @@ TEST(cubeb, stream_position)
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.channels = STREAM_CHANNELS;
params.layout = STREAM_LAYOUT;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -581,6 +581,7 @@ TEST(cubeb, drain)
params.format = STREAM_FORMAT;
params.rate = STREAM_RATE;
params.channels = STREAM_CHANNELS;
params.layout = STREAM_LAYOUT;
#if defined(__ANDROID__)
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif

Просмотреть файл

@ -110,6 +110,7 @@ TEST(cubeb, tone)
params.format = STREAM_FORMAT;
params.rate = SAMPLE_FREQUENCY;
params.channels = 1;
params.layout = CUBEB_LAYOUT_MONO;
user_data = (struct cb_user_data *) malloc(sizeof(*user_data));
if (user_data == NULL) {

Просмотреть файл

@ -176,12 +176,71 @@ typedef enum {
CUBEB_LOG_VERBOSE = 2, /**< Verbose logging of callbacks, can have performance implications. */
} cubeb_log_level;
/** SMPTE channel layout (also known as wave order)
* DUAL-MONO L R
* DUAL-MONO-LFE L R LFE
* MONO M
* MONO-LFE M LFE
* STEREO L R
* STEREO-LFE L R LFE
* 3F L R C
* 3F-LFE L R C LFE
* 2F1 L R S
* 2F1-LFE L R LFE S
* 3F1 L R C S
* 3F1-LFE L R C LFE S
* 2F2 L R LS RS
* 2F2-LFE L R LFE LS RS
* 3F2 L R C LS RS
* 3F2-LFE L R C LFE LS RS
* 3F3R-LFE L R C LFE RC LS RS
* 3F4-LFE L R C LFE RLS RRS LS RS
*
* The abbreviation of channel name is defined in following table:
* Abbr Channel name
* ---------------------------
* M Mono
* L Left
* R Right
* C Center
* LS Left Surround
* RS Right Surround
* RLS Rear Left Surround
* RC Rear Center
* RRS Rear Right Surround
* LFE Low Frequency Effects
*/
typedef enum {
CUBEB_LAYOUT_UNDEFINED, // Indicate the speaker's layout is undefined.
CUBEB_LAYOUT_DUAL_MONO,
CUBEB_LAYOUT_DUAL_MONO_LFE,
CUBEB_LAYOUT_MONO,
CUBEB_LAYOUT_MONO_LFE,
CUBEB_LAYOUT_STEREO,
CUBEB_LAYOUT_STEREO_LFE,
CUBEB_LAYOUT_3F,
CUBEB_LAYOUT_3F_LFE,
CUBEB_LAYOUT_2F1,
CUBEB_LAYOUT_2F1_LFE,
CUBEB_LAYOUT_3F1,
CUBEB_LAYOUT_3F1_LFE,
CUBEB_LAYOUT_2F2,
CUBEB_LAYOUT_2F2_LFE,
CUBEB_LAYOUT_3F2,
CUBEB_LAYOUT_3F2_LFE,
CUBEB_LAYOUT_3F3R_LFE,
CUBEB_LAYOUT_3F4_LFE,
CUBEB_LAYOUT_MAX
} cubeb_channel_layout;
/** Stream format initialization parameters. */
typedef struct {
cubeb_sample_format format; /**< Requested sample format. One of
#cubeb_sample_format. */
unsigned int rate; /**< Requested sample rate. Valid range is [1000, 192000]. */
unsigned int channels; /**< Requested channel count. Valid range is [1, 8]. */
cubeb_sample_format format; /**< Requested sample format. One of
#cubeb_sample_format. */
unsigned int rate; /**< Requested sample rate. Valid range is [1000, 192000]. */
unsigned int channels; /**< Requested channel count. Valid range is [1, 8]. */
cubeb_channel_layout layout; /**< Requested channel layout. This must be consistent with the provided channels. */
#if defined(__ANDROID__)
cubeb_stream_type stream_type; /**< Used to map Android audio stream types */
#endif
@ -376,7 +435,7 @@ CUBEB_EXPORT int cubeb_get_max_channel_count(cubeb * context, uint32_t * max_cha
/** Get the minimal latency value, in frames, that is guaranteed to work
when creating a stream for the specified sample rate. This is platform,
hardware and backend dependant.
hardware and backend dependent.
@param context A pointer to the cubeb context.
@param params On some backends, the minimum achievable latency depends on
the characteristics of the stream.
@ -390,7 +449,7 @@ CUBEB_EXPORT int cubeb_get_min_latency(cubeb * context,
uint32_t * latency_frames);
/** Get the preferred sample rate for this backend: this is hardware and
platform dependant, and can avoid resampling, and/or trigger fastpaths.
platform dependent, and can avoid resampling, and/or trigger fastpaths.
@param context A pointer to the cubeb context.
@param rate The samplerate (in Hz) the current configuration prefers.
@retval CUBEB_OK
@ -398,6 +457,15 @@ CUBEB_EXPORT int cubeb_get_min_latency(cubeb * context,
@retval CUBEB_ERROR_NOT_SUPPORTED */
CUBEB_EXPORT int cubeb_get_preferred_sample_rate(cubeb * context, uint32_t * rate);
/** Get the preferred layout for this backend: this is hardware and
platform dependent.
@param context A pointer to the cubeb context.
@param layout The layout of the current speaker configuration.
@retval CUBEB_OK
@retval CUBEB_ERROR_INVALID_PARAMETER
@retval CUBEB_ERROR_NOT_SUPPORTED */
CUBEB_EXPORT int cubeb_get_preferred_channel_layout(cubeb * context, cubeb_channel_layout * layout);
/** Destroy an application context. This must be called after all stream have
* been destroyed.
@param context A pointer to the cubeb context.*/

Просмотреть файл

@ -35,6 +35,14 @@ void cubeb_crash() CLANG_ANALYZER_NORETURN;
}
#endif
typedef struct {
char const * name;
unsigned int const channels;
cubeb_channel_layout const layout;
} cubeb_layout_map;
extern cubeb_layout_map const CUBEB_CHANNEL_LAYOUT_MAPS[CUBEB_LAYOUT_MAX];
struct cubeb_ops {
int (* init)(cubeb ** context, char const * context_name);
char const * (* get_backend_id)(cubeb * context);
@ -43,6 +51,7 @@ struct cubeb_ops {
cubeb_stream_params params,
uint32_t * latency_ms);
int (* get_preferred_sample_rate)(cubeb * context, uint32_t * rate);
int (* get_preferred_channel_layout)(cubeb * context, cubeb_channel_layout * layout);
int (* enumerate_devices)(cubeb * context, cubeb_device_type type,
cubeb_device_collection ** collection);
void (* destroy)(cubeb * context);

Просмотреть файл

@ -55,7 +55,6 @@ int audiotrack_init(cubeb ** context, char const * context_name);
int kai_init(cubeb ** context, char const * context_name);
#endif
static int
validate_stream_params(cubeb_stream_params * input_stream_params,
cubeb_stream_params * output_stream_params)
@ -96,8 +95,6 @@ validate_stream_params(cubeb_stream_params * input_stream_params,
return CUBEB_ERROR_INVALID_FORMAT;
}
static int
validate_latency(int latency)
{
@ -218,6 +215,20 @@ cubeb_get_preferred_sample_rate(cubeb * context, uint32_t * rate)
return context->ops->get_preferred_sample_rate(context, rate);
}
int
cubeb_get_preferred_channel_layout(cubeb * context, cubeb_channel_layout * layout)
{
if (!context || !layout) {
return CUBEB_ERROR_INVALID_PARAMETER;
}
if (!context->ops->get_preferred_channel_layout) {
return CUBEB_ERROR_NOT_SUPPORTED;
}
return context->ops->get_preferred_channel_layout(context, layout);
}
void
cubeb_destroy(cubeb * context)
{
@ -565,4 +576,3 @@ cubeb_crash()
abort();
*((volatile int *) NULL) = 0;
}

Просмотреть файл

@ -82,7 +82,7 @@ struct cubeb_stream {
cubeb_data_callback data_callback;
cubeb_state_callback state_callback;
void * user_ptr;
snd_pcm_uframes_t write_position;
snd_pcm_uframes_t stream_position;
snd_pcm_uframes_t last_position;
snd_pcm_uframes_t buffer_size;
cubeb_stream_params params;
@ -107,6 +107,12 @@ struct cubeb_stream {
being logically active and playing. */
struct timeval last_activity;
float volume;
char * buffer;
snd_pcm_uframes_t bufframes;
snd_pcm_stream_t stream_type;
struct cubeb_stream * other_stream;
};
static int
@ -234,6 +240,14 @@ set_timeout(struct timeval * timeout, unsigned int ms)
timeout->tv_usec += (ms % 1000) * 1000;
}
static void
stream_buffer_decrement(cubeb_stream * stm, long count)
{
char * bufremains = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, count);
memmove(stm->buffer, bufremains, snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes - count));
stm->bufframes -= count;
}
static void
alsa_set_stream_state(cubeb_stream * stm, enum stream_state state)
{
@ -249,92 +263,173 @@ alsa_set_stream_state(cubeb_stream * stm, enum stream_state state)
}
static enum stream_state
alsa_refill_stream(cubeb_stream * stm)
alsa_process_stream(cubeb_stream * stm)
{
unsigned short revents;
snd_pcm_sframes_t avail;
long got;
void * p;
int draining;
draining = 0;
pthread_mutex_lock(&stm->mutex);
/* Call _poll_descriptors_revents() even if we don't use it
to let underlying plugins clear null events. Otherwise poll()
may wake up again and again, producing unnecessary CPU usage. */
snd_pcm_poll_descriptors_revents(stm->pcm, stm->fds, stm->nfds, &revents);
avail = snd_pcm_avail_update(stm->pcm);
if (avail < 0) {
snd_pcm_recover(stm->pcm, avail, 1);
avail = snd_pcm_avail_update(stm->pcm);
}
/* Failed to recover from an xrun, this stream must be broken. */
if (avail < 0) {
pthread_mutex_unlock(&stm->mutex);
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
return ERROR;
}
/* This should never happen. */
if ((unsigned int) avail > stm->buffer_size) {
avail = stm->buffer_size;
}
/* poll(2) claims this stream is active, so there should be some space
available to write. If avail is still zero here, the stream must be in
a funky state, bail and wait for another wakeup. */
/* Got null event? Bail and wait for another wakeup. */
if (avail == 0) {
pthread_mutex_unlock(&stm->mutex);
return RUNNING;
}
p = calloc(1, snd_pcm_frames_to_bytes(stm->pcm, avail));
assert(p);
pthread_mutex_unlock(&stm->mutex);
got = stm->data_callback(stm, stm->user_ptr, NULL, p, avail);
pthread_mutex_lock(&stm->mutex);
if (got < 0) {
pthread_mutex_unlock(&stm->mutex);
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
free(p);
return ERROR;
/* This could happen if we were suspended with SIGSTOP/Ctrl+Z for a long time. */
if ((unsigned int) avail > stm->buffer_size) {
avail = stm->buffer_size;
}
if (got > 0) {
/* Capture: Read available frames */
if (stm->stream_type == SND_PCM_STREAM_CAPTURE && avail > 0) {
snd_pcm_sframes_t got;
if (avail + stm->bufframes > stm->buffer_size) {
/* Buffer overflow. Skip and overwrite with new data. */
stm->bufframes = 0;
// TODO: should it be marked as DRAINING?
}
got = snd_pcm_readi(stm->pcm, stm->buffer+stm->bufframes, avail);
if (got < 0) {
avail = got; // the error handler below will recover us
} else {
stm->bufframes += got;
stm->stream_position += got;
gettimeofday(&stm->last_activity, NULL);
}
}
/* Capture: Pass read frames to callback function */
if (stm->stream_type == SND_PCM_STREAM_CAPTURE && stm->bufframes > 0 &&
(!stm->other_stream || stm->other_stream->bufframes < stm->other_stream->buffer_size)) {
long wrote = stm->bufframes;
struct cubeb_stream * mainstm = stm->other_stream ? stm->other_stream : stm;
void * other_buffer = stm->other_stream ? stm->other_stream->buffer + stm->other_stream->bufframes : NULL;
/* Correct write size to the other stream available space */
if (stm->other_stream && wrote > stm->other_stream->buffer_size - stm->other_stream->bufframes) {
wrote = stm->other_stream->buffer_size - stm->other_stream->bufframes;
}
pthread_mutex_unlock(&stm->mutex);
wrote = stm->data_callback(mainstm, stm->user_ptr, stm->buffer, other_buffer, wrote);
pthread_mutex_lock(&stm->mutex);
if (wrote < 0) {
avail = wrote; // the error handler below will recover us
} else {
stream_buffer_decrement(stm, wrote);
if (stm->other_stream) {
stm->other_stream->bufframes += wrote;
}
}
}
/* Playback: Don't have enough data? Let's ask for more. */
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && avail > stm->bufframes &&
(!stm->other_stream || stm->other_stream->bufframes > 0)) {
long got = avail - stm->bufframes;
void * other_buffer = stm->other_stream ? stm->other_stream->buffer : NULL;
char * buftail = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes);
/* Correct read size to the other stream available frames */
if (stm->other_stream && got > stm->other_stream->bufframes) {
got = stm->other_stream->bufframes;
}
pthread_mutex_unlock(&stm->mutex);
got = stm->data_callback(stm, stm->user_ptr, other_buffer, buftail, got);
pthread_mutex_lock(&stm->mutex);
if (got < 0) {
avail = got; // the error handler below will recover us
} else {
stm->bufframes += got;
if (stm->other_stream) {
stream_buffer_decrement(stm->other_stream, got);
}
}
}
/* Playback: Still don't have enough data? Add some silence. */
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && avail > stm->bufframes) {
long drain_frames = avail - stm->bufframes;
double drain_time = (double) drain_frames / stm->params.rate;
char * buftail = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes);
memset(buftail, 0, snd_pcm_frames_to_bytes(stm->pcm, drain_frames));
stm->bufframes = avail;
/* Mark as draining, unless we're waiting for capture */
if (!stm->other_stream || stm->other_stream->bufframes > 0) {
set_timeout(&stm->drain_timeout, drain_time * 1000);
draining = 1;
}
}
/* Playback: Have enough data and no errors. Let's write it out. */
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && avail > 0) {
snd_pcm_sframes_t wrote;
if (stm->params.format == CUBEB_SAMPLE_FLOAT32NE) {
float * b = (float *) p;
for (uint32_t i = 0; i < got * stm->params.channels; i++) {
float * b = (float *) stm->buffer;
for (uint32_t i = 0; i < avail * stm->params.channels; i++) {
b[i] *= stm->volume;
}
} else {
short * b = (short *) p;
for (uint32_t i = 0; i < got * stm->params.channels; i++) {
short * b = (short *) stm->buffer;
for (uint32_t i = 0; i < avail * stm->params.channels; i++) {
b[i] *= stm->volume;
}
}
wrote = snd_pcm_writei(stm->pcm, p, got);
wrote = snd_pcm_writei(stm->pcm, stm->buffer, avail);
if (wrote < 0) {
snd_pcm_recover(stm->pcm, wrote, 1);
wrote = snd_pcm_writei(stm->pcm, p, got);
avail = wrote; // the error handler below will recover us
} else {
stream_buffer_decrement(stm, wrote);
stm->stream_position += wrote;
gettimeofday(&stm->last_activity, NULL);
}
assert(wrote >= 0 && wrote == got);
stm->write_position += wrote;
gettimeofday(&stm->last_activity, NULL);
}
if (got != avail) {
long buffer_fill = stm->buffer_size - (avail - got);
double buffer_time = (double) buffer_fill / stm->params.rate;
/* Fill the remaining buffer with silence to guarantee one full period
has been written. */
snd_pcm_writei(stm->pcm, (char *) p + got, avail - got);
set_timeout(&stm->drain_timeout, buffer_time * 1000);
draining = 1;
}
free(p);
/* Got some error? Let's try to recover the stream. */
if (avail < 0) {
avail = snd_pcm_recover(stm->pcm, avail, 0);
/* Capture pcm must be started after initial setup/recover */
if (avail >= 0 &&
stm->stream_type == SND_PCM_STREAM_CAPTURE &&
snd_pcm_state(stm->pcm) == SND_PCM_STATE_PREPARED) {
avail = snd_pcm_start(stm->pcm);
}
}
/* Failed to recover, this stream must be broken. */
if (avail < 0) {
pthread_mutex_unlock(&stm->mutex);
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
return ERROR;
}
pthread_mutex_unlock(&stm->mutex);
return draining ? DRAINING : RUNNING;
}
@ -390,7 +485,7 @@ alsa_run(cubeb * ctx)
if (stm && stm->state == RUNNING && stm->fds && any_revents(stm->fds, stm->nfds)) {
alsa_set_stream_state(stm, PROCESSING);
pthread_mutex_unlock(&ctx->mutex);
state = alsa_refill_stream(stm);
state = alsa_process_stream(stm);
pthread_mutex_lock(&ctx->mutex);
alsa_set_stream_state(stm, state);
}
@ -576,15 +671,15 @@ init_local_config_with_workaround(char const * pcm_name)
}
static int
alsa_locked_pcm_open(snd_pcm_t ** pcm, snd_pcm_stream_t stream, snd_config_t * local_config)
alsa_locked_pcm_open(snd_pcm_t ** pcm, char const * pcm_name, snd_pcm_stream_t stream, snd_config_t * local_config)
{
int r;
pthread_mutex_lock(&cubeb_alsa_mutex);
if (local_config) {
r = snd_pcm_open_lconf(pcm, CUBEB_ALSA_PCM_NAME, stream, SND_PCM_NONBLOCK, local_config);
r = snd_pcm_open_lconf(pcm, pcm_name, stream, SND_PCM_NONBLOCK, local_config);
} else {
r = snd_pcm_open(pcm, CUBEB_ALSA_PCM_NAME, stream, SND_PCM_NONBLOCK);
r = snd_pcm_open(pcm, pcm_name, stream, SND_PCM_NONBLOCK);
}
pthread_mutex_unlock(&cubeb_alsa_mutex);
@ -707,7 +802,7 @@ alsa_init(cubeb ** context, char const * context_name)
/* Open a dummy PCM to force the configuration space to be evaluated so that
init_local_config_with_workaround can find and modify the default node. */
r = alsa_locked_pcm_open(&dummy, SND_PCM_STREAM_PLAYBACK, NULL);
r = alsa_locked_pcm_open(&dummy, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK, NULL);
if (r >= 0) {
alsa_locked_pcm_close(dummy);
}
@ -717,7 +812,7 @@ alsa_init(cubeb ** context, char const * context_name)
pthread_mutex_unlock(&cubeb_alsa_mutex);
if (ctx->local_config) {
ctx->is_pa = 1;
r = alsa_locked_pcm_open(&dummy, SND_PCM_STREAM_PLAYBACK, ctx->local_config);
r = alsa_locked_pcm_open(&dummy, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK, ctx->local_config);
/* If we got a local_config, we found a PA PCM. If opening a PCM with that
config fails with EINVAL, the PA PCM is too old for this workaround. */
if (r == -EINVAL) {
@ -774,14 +869,14 @@ alsa_destroy(cubeb * ctx)
static void alsa_stream_destroy(cubeb_stream * stm);
static int
alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
cubeb_devid input_device,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency_frames,
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
void * user_ptr)
alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
snd_pcm_stream_t stream_type,
cubeb_devid deviceid,
cubeb_stream_params * stream_params,
unsigned int latency_frames,
cubeb_data_callback data_callback,
cubeb_state_callback state_callback,
void * user_ptr)
{
(void)stream_name;
cubeb_stream * stm;
@ -789,23 +884,13 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
snd_pcm_format_t format;
snd_pcm_uframes_t period_size;
int latency_us = 0;
char const * pcm_name = deviceid ? (char const *) deviceid : CUBEB_ALSA_PCM_NAME;
assert(ctx && stream);
if (input_stream_params) {
/* Capture support not yet implemented. */
return CUBEB_ERROR_NOT_SUPPORTED;
}
if (input_device || output_device) {
/* Device selection not yet implemented. */
return CUBEB_ERROR_DEVICE_UNAVAILABLE;
}
*stream = NULL;
switch (output_stream_params->format) {
switch (stream_params->format) {
case CUBEB_SAMPLE_S16LE:
format = SND_PCM_FORMAT_S16_LE;
break;
@ -837,14 +922,18 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
stm->data_callback = data_callback;
stm->state_callback = state_callback;
stm->user_ptr = user_ptr;
stm->params = *output_stream_params;
stm->params = *stream_params;
stm->state = INACTIVE;
stm->volume = 1.0;
stm->buffer = NULL;
stm->bufframes = 0;
stm->stream_type = stream_type;
stm->other_stream = NULL;
r = pthread_mutex_init(&stm->mutex, NULL);
assert(r == 0);
r = alsa_locked_pcm_open(&stm->pcm, SND_PCM_STREAM_PLAYBACK, ctx->local_config);
r = alsa_locked_pcm_open(&stm->pcm, pcm_name, stm->stream_type, ctx->local_config);
if (r < 0) {
alsa_stream_destroy(stm);
return CUBEB_ERROR;
@ -874,6 +963,11 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
r = snd_pcm_get_params(stm->pcm, &stm->buffer_size, &period_size);
assert(r == 0);
/* Double internal buffer size to have enough space when waiting for the other side of duplex connection */
stm->buffer_size *= 2;
stm->buffer = calloc(1, snd_pcm_frames_to_bytes(stm->pcm, stm->buffer_size));
assert(stm->buffer);
stm->nfds = snd_pcm_poll_descriptors_count(stm->pcm);
assert(stm->nfds > 0);
@ -895,6 +989,45 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
return CUBEB_OK;
}
static int
alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
cubeb_devid input_device,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params,
unsigned int latency_frames,
cubeb_data_callback data_callback, cubeb_state_callback state_callback,
void * user_ptr)
{
int result = CUBEB_OK;
cubeb_stream * instm = NULL, * outstm = NULL;
if (result == CUBEB_OK && input_stream_params) {
result = alsa_stream_init_single(ctx, &instm, stream_name, SND_PCM_STREAM_CAPTURE,
input_device, input_stream_params, latency_frames,
data_callback, state_callback, user_ptr);
}
if (result == CUBEB_OK && output_stream_params) {
result = alsa_stream_init_single(ctx, &outstm, stream_name, SND_PCM_STREAM_PLAYBACK,
output_device, output_stream_params, latency_frames,
data_callback, state_callback, user_ptr);
}
if (result == CUBEB_OK && input_stream_params && output_stream_params) {
instm->other_stream = outstm;
outstm->other_stream = instm;
}
if (result != CUBEB_OK && instm) {
alsa_stream_destroy(instm);
}
*stream = outstm ? outstm : instm;
return result;
}
static void
alsa_stream_destroy(cubeb_stream * stm)
{
@ -907,6 +1040,11 @@ alsa_stream_destroy(cubeb_stream * stm)
ctx = stm->context;
if (stm->other_stream) {
stm->other_stream->other_stream = NULL; // to stop infinite recursion
alsa_stream_destroy(stm->other_stream);
}
pthread_mutex_lock(&stm->mutex);
if (stm->pcm) {
if (stm->state == DRAINING) {
@ -929,6 +1067,8 @@ alsa_stream_destroy(cubeb_stream * stm)
ctx->active_streams -= 1;
pthread_mutex_unlock(&ctx->mutex);
free(stm->buffer);
free(stm);
}
@ -952,6 +1092,8 @@ alsa_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
return CUBEB_ERROR;
}
assert(stm);
r = snd_pcm_hw_params_any(stm->pcm, hw_params);
if (r < 0) {
return CUBEB_ERROR;
@ -1029,7 +1171,18 @@ alsa_stream_start(cubeb_stream * stm)
assert(stm);
ctx = stm->context;
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && stm->other_stream) {
int r = alsa_stream_start(stm->other_stream);
if (r != CUBEB_OK)
return r;
}
pthread_mutex_lock(&stm->mutex);
/* Capture pcm must be started after initial setup/recover */
if (stm->stream_type == SND_PCM_STREAM_CAPTURE &&
snd_pcm_state(stm->pcm) == SND_PCM_STATE_PREPARED) {
snd_pcm_start(stm->pcm);
}
snd_pcm_pause(stm->pcm, 0);
gettimeofday(&stm->last_activity, NULL);
pthread_mutex_unlock(&stm->mutex);
@ -1054,6 +1207,12 @@ alsa_stream_stop(cubeb_stream * stm)
assert(stm);
ctx = stm->context;
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && stm->other_stream) {
int r = alsa_stream_stop(stm->other_stream);
if (r != CUBEB_OK)
return r;
}
pthread_mutex_lock(&ctx->mutex);
while (stm->state == PROCESSING) {
r = pthread_cond_wait(&stm->cond, &ctx->mutex);
@ -1090,8 +1249,8 @@ alsa_stream_get_position(cubeb_stream * stm, uint64_t * position)
assert(delay >= 0);
*position = 0;
if (stm->write_position >= (snd_pcm_uframes_t) delay) {
*position = stm->write_position - delay;
if (stm->stream_position >= (snd_pcm_uframes_t) delay) {
*position = stm->stream_position - delay;
}
stm->last_position = *position;
@ -1126,13 +1285,63 @@ alsa_stream_set_volume(cubeb_stream * stm, float volume)
return CUBEB_OK;
}
static int
alsa_enumerate_devices(cubeb * context, cubeb_device_type type,
cubeb_device_collection ** collection)
{
if (!context)
return CUBEB_ERROR;
uint32_t rate, max_channels;
int r;
r = alsa_get_preferred_sample_rate(context, &rate);
if (r != CUBEB_OK) {
return CUBEB_ERROR;
}
r = alsa_get_max_channel_count(context, &max_channels);
if (r != CUBEB_OK) {
return CUBEB_ERROR;
}
*collection = (cubeb_device_collection *) calloc(1, sizeof(cubeb_device_collection) + 1*sizeof(cubeb_device_info *));
assert(*collection);
char const * a_name = "default";
(*collection)->device[0] = (cubeb_device_info *) calloc(1, sizeof(cubeb_device_info));
assert((*collection)->device[0]);
(*collection)->device[0]->device_id = strdup(a_name);
(*collection)->device[0]->devid = (*collection)->device[0]->device_id;
(*collection)->device[0]->friendly_name = strdup(a_name);
(*collection)->device[0]->group_id = strdup(a_name);
(*collection)->device[0]->vendor_name = strdup(a_name);
(*collection)->device[0]->type = type;
(*collection)->device[0]->state = CUBEB_DEVICE_STATE_ENABLED;
(*collection)->device[0]->preferred = CUBEB_DEVICE_PREF_ALL;
(*collection)->device[0]->format = CUBEB_DEVICE_FMT_S16NE;
(*collection)->device[0]->default_format = CUBEB_DEVICE_FMT_S16NE;
(*collection)->device[0]->max_channels = max_channels;
(*collection)->device[0]->min_rate = rate;
(*collection)->device[0]->max_rate = rate;
(*collection)->device[0]->default_rate = rate;
(*collection)->device[0]->latency_lo = 0;
(*collection)->device[0]->latency_hi = 0;
(*collection)->count = 1;
return CUBEB_OK;
}
static struct cubeb_ops const alsa_ops = {
.init = alsa_init,
.get_backend_id = alsa_get_backend_id,
.get_max_channel_count = alsa_get_max_channel_count,
.get_min_latency = alsa_get_min_latency,
.get_preferred_sample_rate = alsa_get_preferred_sample_rate,
.enumerate_devices = NULL,
.get_preferred_channel_layout = NULL,
.enumerate_devices = alsa_enumerate_devices,
.destroy = alsa_destroy,
.stream_init = alsa_stream_init,
.stream_destroy = alsa_stream_destroy,

Просмотреть файл

@ -421,6 +421,7 @@ static struct cubeb_ops const audiotrack_ops = {
.get_max_channel_count = audiotrack_get_max_channel_count,
.get_min_latency = audiotrack_get_min_latency,
.get_preferred_sample_rate = audiotrack_get_preferred_sample_rate,
.get_preferred_channel_layout = NULL,
.enumerate_devices = NULL,
.destroy = audiotrack_destroy,
.stream_init = audiotrack_stream_init,

Просмотреть файл

@ -40,9 +40,11 @@ typedef UInt32 AudioFormatFlags;
#define AU_OUT_BUS 0
#define AU_IN_BUS 1
#define PRINT_ERROR_CODE(str, r) do { \
LOG("System call failed: %s (rv: %d)", str, r); \
} while(0)
#define PRINT_ERROR_CODE(str, r) do { \
LOG("System call failed: %s (rv: %d)", str, (int) r); \
} while(0)
const char * DISPATCH_QUEUE_LABEL = "org.mozilla.cubeb";
/* Testing empirically, some headsets report a minimal latency that is very
* low, but this does not work in practice. Lie and say the minimum is 256
@ -52,8 +54,8 @@ const uint32_t SAFE_MAX_LATENCY_FRAMES = 512;
void audiounit_stream_stop_internal(cubeb_stream * stm);
void audiounit_stream_start_internal(cubeb_stream * stm);
static void close_audiounit_stream(cubeb_stream * stm);
static int setup_audiounit_stream(cubeb_stream * stm);
static void audiounit_close_stream(cubeb_stream *stm);
static int audiounit_setup_stream(cubeb_stream *stm);
extern cubeb_ops const audiounit_ops;
@ -61,11 +63,14 @@ struct cubeb {
cubeb_ops const * ops = &audiounit_ops;
owned_critical_section mutex;
std::atomic<int> active_streams{ 0 };
uint32_t global_latency_frames = 0;
cubeb_device_collection_changed_callback collection_changed_callback = nullptr;
void * collection_changed_user_ptr = nullptr;
/* Differentiate input from output devices. */
cubeb_device_type collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN;
std::vector<AudioObjectID> devtype_device_array;
// The queue is asynchronously deallocated once all references to it are released
dispatch_queue_t serial_queue = dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL);
};
struct auto_array_wrapper {
@ -133,8 +138,8 @@ struct cubeb_stream {
cubeb_state_callback state_callback = nullptr;
cubeb_device_changed_callback device_changed_callback = nullptr;
/* Stream creation parameters */
cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0 };
cubeb_stream_params output_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0 };
cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED };
cubeb_stream_params output_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED };
bool is_default_input;
AudioDeviceID input_device = 0;
AudioDeviceID output_device = 0;
@ -177,6 +182,7 @@ struct cubeb_stream {
std::atomic<int> output_callback_in_a_row{ 0 };
/* This is true if a device change callback is currently running. */
std::atomic<bool> switching_device{ false };
std::atomic<bool> buffer_size_change_state{ false };
};
bool has_input(cubeb_stream * stm)
@ -227,6 +233,14 @@ audiotimestamp_to_latency(AudioTimeStamp const * tstamp, cubeb_stream * stream)
return ((pres - now) * stream->output_desc.mSampleRate) / 1000000000LL;
}
static void
audiounit_set_global_latency(cubeb_stream * stm, uint32_t latency_frames)
{
stm->mutex.assert_current_thread_owns();
assert(stm->context->active_streams == 1);
stm->context->global_latency_frames = latency_frames;
}
static void
audiounit_make_silent(AudioBuffer * ioData)
{
@ -267,11 +281,12 @@ audiounit_render_input(cubeb_stream * stm,
stm->input_linear_buffer->push(input_buffer_list.mBuffers[0].mData,
input_frames * stm->input_desc.mChannelsPerFrame);
LOGV("(%p) input: buffers %d, size %d, channels %d, frames %d.",
stm, input_buffer_list.mNumberBuffers,
input_buffer_list.mBuffers[0].mDataByteSize,
input_buffer_list.mBuffers[0].mNumberChannels,
input_frames);
LOGV("(%p) input: buffers %u, size %u, channels %u, frames %d.",
stm,
(unsigned int) input_buffer_list.mNumberBuffers,
(unsigned int) input_buffer_list.mBuffers[0].mDataByteSize,
(unsigned int) input_buffer_list.mBuffers[0].mNumberChannels,
(unsigned int) input_frames);
/* Advance input frame counter. */
assert(input_frames > 0);
@ -289,7 +304,6 @@ audiounit_input_callback(void * user_ptr,
AudioBufferList * /* bufs */)
{
cubeb_stream * stm = static_cast<cubeb_stream *>(user_ptr);
long outframes;
assert(stm->input_unit != NULL);
assert(AU_IN_BUS == bus);
@ -323,15 +337,15 @@ audiounit_input_callback(void * user_ptr,
Resampler will deliver input buffer in the correct rate. */
assert(input_frames <= stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame);
long total_input_frames = stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame;
outframes = cubeb_resampler_fill(stm->resampler.get(),
stm->input_linear_buffer->data(),
&total_input_frames,
NULL,
0);
long outframes = cubeb_resampler_fill(stm->resampler.get(),
stm->input_linear_buffer->data(),
&total_input_frames,
NULL,
0);
// Reset input buffer
stm->input_linear_buffer->clear();
if (outframes < 0 || outframes != input_frames) {
if (outframes < 0 || (UInt32) outframes != input_frames) {
stm->shutdown = true;
return noErr;
}
@ -375,12 +389,14 @@ audiounit_output_callback(void * user_ptr,
stm->output_callback_in_a_row++;
LOGV("(%p) output: buffers %d, size %d, channels %d, frames %d.",
stm, outBufferList->mNumberBuffers,
outBufferList->mBuffers[0].mDataByteSize,
outBufferList->mBuffers[0].mNumberChannels, output_frames);
LOGV("(%p) output: buffers %u, size %u, channels %u, frames %u.",
stm,
(unsigned int) outBufferList->mNumberBuffers,
(unsigned int) outBufferList->mBuffers[0].mDataByteSize,
(unsigned int) outBufferList->mBuffers[0].mNumberChannels,
(unsigned int) output_frames);
long outframes = 0, input_frames = 0;
long input_frames = 0;
void * output_buffer = NULL, * input_buffer = NULL;
if (stm->shutdown) {
@ -419,11 +435,11 @@ audiounit_output_callback(void * user_ptr,
}
/* Call user callback through resampler. */
outframes = cubeb_resampler_fill(stm->resampler.get(),
input_buffer,
input_buffer ? &input_frames : NULL,
output_buffer,
output_frames);
long outframes = cubeb_resampler_fill(stm->resampler.get(),
input_buffer,
input_buffer ? &input_frames : NULL,
output_buffer,
output_frames);
if (input_buffer) {
stm->input_linear_buffer->pop(input_frames * stm->input_desc.mChannelsPerFrame);
@ -435,7 +451,7 @@ audiounit_output_callback(void * user_ptr,
}
size_t outbpf = stm->output_desc.mBytesPerFrame;
stm->draining = outframes < output_frames;
stm->draining = (UInt32) outframes < output_frames;
stm->frames_played = stm->frames_queued;
stm->frames_queued += outframes;
@ -533,37 +549,62 @@ audiounit_get_input_device_id(AudioDeviceID * device_id)
return CUBEB_OK;
}
static int
audiounit_reinit_stream(cubeb_stream * stm, bool is_started)
{
if (is_started) {
audiounit_stream_stop_internal(stm);
}
{
auto_lock lock(stm->mutex);
audiounit_close_stream(stm);
if (audiounit_setup_stream(stm) != CUBEB_OK) {
LOG("(%p) Stream reinit failed.", stm);
return CUBEB_ERROR;
}
// Reset input frames to force new stream pre-buffer
// silence if needed, check `is_extra_input_needed()`
stm->frames_read = 0;
// If the stream was running, start it again.
if (is_started) {
audiounit_stream_start_internal(stm);
}
}
return CUBEB_OK;
}
static OSStatus
audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_count,
const AudioObjectPropertyAddress * addresses,
void * user)
{
cubeb_stream * stm = (cubeb_stream*) user;
int rv;
bool was_running = false;
stm->switching_device = true;
// Note if the stream was running or not
was_running = !stm->shutdown;
bool was_running = !stm->shutdown;
LOG("(%p) Audio device changed, %d events.", stm, address_count);
LOG("(%p) Audio device changed, %u events.", stm, (unsigned int) address_count);
for (UInt32 i = 0; i < address_count; i++) {
switch(addresses[i].mSelector) {
case kAudioHardwarePropertyDefaultOutputDevice: {
LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", i);
LOG("Event[%u] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", (unsigned int) i);
// Allow restart to choose the new default
stm->output_device = 0;
}
break;
case kAudioHardwarePropertyDefaultInputDevice: {
LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultInputDevice", i);
LOG("Event[%u] - mSelector == kAudioHardwarePropertyDefaultInputDevice", (unsigned int) i);
// Allow restart to choose the new default
stm->input_device = 0;
}
break;
case kAudioDevicePropertyDeviceIsAlive: {
LOG("Event[%d] - mSelector == kAudioDevicePropertyDeviceIsAlive", i);
LOG("Event[%u] - mSelector == kAudioDevicePropertyDeviceIsAlive", (unsigned int) i);
// If this is the default input device ignore the event,
// kAudioHardwarePropertyDefaultInputDevice will take care of the switch
if (stm->is_default_input) {
@ -575,7 +616,7 @@ audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_coun
}
break;
case kAudioDevicePropertyDataSource:
LOG("Event[%d] - mSelector == kAudioHardwarePropertyDataSource", i);
LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource", (unsigned int) i);
break;
}
}
@ -596,28 +637,15 @@ audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_coun
}
}
// This means the callback won't be called again.
audiounit_stream_stop_internal(stm);
{
auto_lock lock(stm->mutex);
close_audiounit_stream(stm);
rv = setup_audiounit_stream(stm);
if (rv != CUBEB_OK) {
LOG("(%p) Could not reopen a stream after switching.", stm);
// Use a new thread, through the queue, to avoid deadlock when calling
// Get/SetProperties method from inside notify callback
dispatch_async(stm->context->serial_queue, ^() {
if (audiounit_reinit_stream(stm, was_running) != CUBEB_OK) {
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
return noErr;
LOG("(%p) Could not reopen the stream after switching.", stm);
}
stm->frames_read = 0;
// If the stream was running, start it again.
if (was_running) {
audiounit_stream_start_internal(stm);
}
}
stm->switching_device = false;
stm->switching_device = false;
});
return noErr;
}
@ -1099,8 +1127,7 @@ audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity)
}
static uint32_t
audiounit_clamp_latency(cubeb_stream * stm,
uint32_t latency_frames)
audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames)
{
// For the 1st stream set anything within safe min-max
assert(stm->context->active_streams > 0);
@ -1163,16 +1190,364 @@ audiounit_clamp_latency(cubeb_stream * stm,
SAFE_MIN_LATENCY_FRAMES);
}
static int
setup_audiounit_stream(cubeb_stream * stm)
/*
* Change buffer size is prone to deadlock thus we change it
* following the steps:
* - register a listener for the buffer size property
* - change the property
* - wait until the listener is executed
* - property has changed, remove the listener
* */
static void
buffer_size_changed_callback(void * inClientData,
AudioUnit inUnit,
AudioUnitPropertyID inPropertyID,
AudioUnitScope inScope,
AudioUnitElement inElement)
{
stm->mutex.assert_current_thread_owns();
cubeb_stream * stm = (cubeb_stream *)inClientData;
int r;
AudioUnit au = inUnit;
AudioUnitScope au_scope = kAudioUnitScope_Input;
AudioUnitElement au_element = inElement;
const char * au_type = "output";
if (au == stm->input_unit) {
au_scope = kAudioUnitScope_Output;
au_type = "input";
}
switch (inPropertyID) {
case kAudioDevicePropertyBufferFrameSize: {
if (inScope != au_scope) {
break;
}
UInt32 new_buffer_size;
UInt32 outSize = sizeof(UInt32);
OSStatus r = AudioUnitGetProperty(au,
kAudioDevicePropertyBufferFrameSize,
au_scope,
au_element,
&new_buffer_size,
&outSize);
if (r != noErr) {
LOG("(%p) Event: kAudioDevicePropertyBufferFrameSize: Cannot get current buffer size", stm);
} else {
LOG("(%p) Event: kAudioDevicePropertyBufferFrameSize: New %s buffer size = %d for scope %d", stm,
au_type, new_buffer_size, inScope);
}
stm->buffer_size_change_state = true;
break;
}
}
}
enum set_buffer_size_side {
INPUT,
OUTPUT,
};
static int
audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buffer_size_side set_side)
{
AudioUnit au = stm->output_unit;
AudioUnitScope au_scope = kAudioUnitScope_Input;
AudioUnitElement au_element = AU_OUT_BUS;
const char * au_type = "output";
if (set_side == INPUT) {
au = stm->input_unit;
au_scope = kAudioUnitScope_Output;
au_element = AU_IN_BUS;
au_type = "input";
}
uint32_t buffer_frames = 0;
UInt32 size = sizeof(buffer_frames);
int r = AudioUnitGetProperty(au,
kAudioDevicePropertyBufferFrameSize,
au_scope,
au_element,
&buffer_frames,
&size);
if (r != noErr) {
if (set_side == INPUT) {
PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
}
return CUBEB_ERROR;
}
if (new_size_frames == buffer_frames) {
LOG("(%p) No need to update %s buffer size already %u frames", stm, au_type, buffer_frames);
return CUBEB_OK;
}
r = AudioUnitAddPropertyListener(au,
kAudioDevicePropertyBufferFrameSize,
buffer_size_changed_callback,
stm);
if (r != noErr) {
if (set_side == INPUT) {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
}
return CUBEB_ERROR;
}
stm->buffer_size_change_state = false;
r = AudioUnitSetProperty(au,
kAudioDevicePropertyBufferFrameSize,
au_scope,
au_element,
&new_size_frames,
sizeof(new_size_frames));
if (r != noErr) {
if (set_side == INPUT) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
}
r = AudioUnitRemovePropertyListenerWithUserData(au,
kAudioDevicePropertyBufferFrameSize,
buffer_size_changed_callback,
stm);
if (r != noErr) {
if (set_side == INPUT) {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
}
}
return CUBEB_ERROR;
}
int count = 0;
while (!stm->buffer_size_change_state && count++ < 30) {
struct timespec req, rem;
req.tv_sec = 0;
req.tv_nsec = 100000000L; // 0.1 sec
if (nanosleep(&req , &rem) < 0 ) {
LOG("(%p) Warning: nanosleep call failed or interrupted. Remaining time %ld nano secs \n", stm, rem.tv_nsec);
}
LOG("(%p) audiounit_set_buffer_size : wait count = %d", stm, count);
}
r = AudioUnitRemovePropertyListenerWithUserData(au,
kAudioDevicePropertyBufferFrameSize,
buffer_size_changed_callback,
stm);
if (r != noErr) {
if (set_side == INPUT) {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
} else {
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
}
return CUBEB_ERROR;
}
if (!stm->buffer_size_change_state && count >= 30) {
LOG("(%p) Error, did not get buffer size change callback ...", stm);
return CUBEB_ERROR;
}
LOG("(%p) %s buffer size changed to %u frames.", stm, au_type, new_size_frames);
return CUBEB_OK;
}
static int
audiounit_configure_input(cubeb_stream * stm)
{
int r = 0;
UInt32 size;
AURenderCallbackStruct aurcbs_in;
LOG("(%p) Opening input side: rate %u, channels %u, format %d, latency in frames %u.",
stm, stm->input_stream_params.rate, stm->input_stream_params.channels,
stm->input_stream_params.format, stm->latency_frames);
/* Get input device sample rate. */
AudioStreamBasicDescription input_hw_desc;
size = sizeof(AudioStreamBasicDescription);
r = AudioUnitGetProperty(stm->input_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
AU_IN_BUS,
&input_hw_desc,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat", r);
return CUBEB_ERROR;
}
stm->input_hw_rate = input_hw_desc.mSampleRate;
LOG("(%p) Input device sampling rate: %.2f", stm, stm->input_hw_rate);
/* Set format description according to the input params. */
r = audio_stream_desc_init(&stm->input_desc, &stm->input_stream_params);
if (r != CUBEB_OK) {
LOG("(%p) Setting format description for input failed.", stm);
return r;
}
// Use latency to set buffer size
stm->input_buffer_frames = stm->latency_frames;
r = audiounit_set_buffer_size(stm, stm->input_buffer_frames, INPUT);
if (r != CUBEB_OK) {
LOG("(%p) Error in change input buffer size.", stm);
return CUBEB_ERROR;
}
AudioStreamBasicDescription src_desc = stm->input_desc;
/* Input AudioUnit must be configured with device's sample rate.
we will resample inside input callback. */
src_desc.mSampleRate = stm->input_hw_rate;
r = AudioUnitSetProperty(stm->input_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
AU_IN_BUS,
&src_desc,
sizeof(AudioStreamBasicDescription));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat", r);
return CUBEB_ERROR;
}
/* Frames per buffer in the input callback. */
r = AudioUnitSetProperty(stm->input_unit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global,
AU_IN_BUS,
&stm->input_buffer_frames,
sizeof(UInt32));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice", r);
return CUBEB_ERROR;
}
// Input only capacity
unsigned int array_capacity = 1;
if (has_output(stm)) {
// Full-duplex increase capacity
array_capacity = 8;
}
if (audiounit_init_input_linear_buffer(stm, array_capacity) != CUBEB_OK) {
return CUBEB_ERROR;
}
assert(stm->input_unit != NULL);
aurcbs_in.inputProc = audiounit_input_callback;
aurcbs_in.inputProcRefCon = stm;
r = AudioUnitSetProperty(stm->input_unit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
AU_OUT_BUS,
&aurcbs_in,
sizeof(aurcbs_in));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback", r);
return CUBEB_ERROR;
}
LOG("(%p) Input audiounit init successfully.", stm);
return CUBEB_OK;
}
static int
audiounit_configure_output(cubeb_stream * stm)
{
int r;
AURenderCallbackStruct aurcbs_out;
UInt32 size;
LOG("(%p) Opening output side: rate %u, channels %u, format %d, latency in frames %u.",
stm, stm->output_stream_params.rate, stm->output_stream_params.channels,
stm->output_stream_params.format, stm->latency_frames);
r = audio_stream_desc_init(&stm->output_desc, &stm->output_stream_params);
if (r != CUBEB_OK) {
LOG("(%p) Could not initialize the audio stream description.", stm);
return r;
}
/* Get output device sample rate. */
AudioStreamBasicDescription output_hw_desc;
size = sizeof(AudioStreamBasicDescription);
memset(&output_hw_desc, 0, size);
r = AudioUnitGetProperty(stm->output_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
AU_OUT_BUS,
&output_hw_desc,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/output/tkAudioUnitProperty_StreamFormat", r);
return CUBEB_ERROR;
}
stm->output_hw_rate = output_hw_desc.mSampleRate;
LOG("(%p) Output device sampling rate: %.2f", stm, output_hw_desc.mSampleRate);
r = AudioUnitSetProperty(stm->output_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
AU_OUT_BUS,
&stm->output_desc,
sizeof(AudioStreamBasicDescription));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat", r);
return CUBEB_ERROR;
}
r = audiounit_set_buffer_size(stm, stm->latency_frames, OUTPUT);
if (r != CUBEB_OK) {
LOG("(%p) Error in change output buffer size.", stm);
return CUBEB_ERROR;
}
/* Frames per buffer in the input callback. */
r = AudioUnitSetProperty(stm->output_unit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Global,
AU_OUT_BUS,
&stm->latency_frames,
sizeof(UInt32));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_MaximumFramesPerSlice", r);
return CUBEB_ERROR;
}
assert(stm->output_unit != NULL);
aurcbs_out.inputProc = audiounit_output_callback;
aurcbs_out.inputProcRefCon = stm;
r = AudioUnitSetProperty(stm->output_unit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
AU_OUT_BUS,
&aurcbs_out,
sizeof(aurcbs_out));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback", r);
return CUBEB_ERROR;
}
LOG("(%p) Output audiounit init successfully.", stm);
return CUBEB_OK;
}
static int
audiounit_setup_stream(cubeb_stream * stm)
{
stm->mutex.assert_current_thread_owns();
int r = 0;
if (has_input(stm)) {
r = audiounit_create_unit(&stm->input_unit, true,
&stm->input_stream_params,
@ -1193,170 +1568,36 @@ setup_audiounit_stream(cubeb_stream * stm)
}
}
/* Latency cannot change if another stream is operating in parallel. In this case
* latecy is set to the other stream value. */
if (stm->context->active_streams > 1) {
LOG("(%p) More than one active stream, use global latency.", stm);
stm->latency_frames = stm->context->global_latency_frames;
} else {
/* Silently clamp the latency down to the platform default, because we
* synthetize the clock from the callbacks, and we want the clock to update
* often. */
stm->latency_frames = audiounit_clamp_latency(stm, stm->latency_frames);
assert(stm->latency_frames); // Ungly error check
audiounit_set_global_latency(stm, stm->latency_frames);
}
/* Setup Input Stream! */
if (has_input(stm)) {
LOG("(%p) Opening input side: rate %u, channels %u, format %d, latency in frames %u.",
stm, stm->input_stream_params.rate, stm->input_stream_params.channels,
stm->input_stream_params.format, stm->latency_frames);
/* Get input device sample rate. */
AudioStreamBasicDescription input_hw_desc;
size = sizeof(AudioStreamBasicDescription);
r = AudioUnitGetProperty(stm->input_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
AU_IN_BUS,
&input_hw_desc,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat", r);
return CUBEB_ERROR;
}
stm->input_hw_rate = input_hw_desc.mSampleRate;
LOG("(%p) Input device sampling rate: %.2f", stm, stm->input_hw_rate);
/* Set format description according to the input params. */
r = audio_stream_desc_init(&stm->input_desc, &stm->input_stream_params);
r = audiounit_configure_input(stm);
if (r != CUBEB_OK) {
LOG("(%p) Setting format description for input failed.", stm);
LOG("(%p) Configure audiounit input failed.", stm);
return r;
}
// Use latency to set buffer size
stm->input_buffer_frames = stm->latency_frames;
LOG("(%p) Input buffer frame count %u.", stm, unsigned(stm->input_buffer_frames));
r = AudioUnitSetProperty(stm->input_unit,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Output,
AU_IN_BUS,
&stm->input_buffer_frames,
sizeof(UInt32));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
return CUBEB_ERROR;
}
AudioStreamBasicDescription src_desc = stm->input_desc;
/* Input AudioUnit must be configured with device's sample rate.
we will resample inside input callback. */
src_desc.mSampleRate = stm->input_hw_rate;
r = AudioUnitSetProperty(stm->input_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
AU_IN_BUS,
&src_desc,
sizeof(AudioStreamBasicDescription));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat", r);
return CUBEB_ERROR;
}
/* Frames per buffer in the input callback. */
r = AudioUnitSetProperty(stm->input_unit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Output,
AU_IN_BUS,
&stm->input_buffer_frames,
sizeof(UInt32));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice", r);
return CUBEB_ERROR;
}
// Input only capacity
unsigned int array_capacity = 1;
if (has_output(stm)) {
// Full-duplex increase capacity
array_capacity = 8;
}
if (audiounit_init_input_linear_buffer(stm, array_capacity) != CUBEB_OK) {
return CUBEB_ERROR;
}
assert(stm->input_unit != NULL);
aurcbs_in.inputProc = audiounit_input_callback;
aurcbs_in.inputProcRefCon = stm;
r = AudioUnitSetProperty(stm->input_unit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
AU_OUT_BUS,
&aurcbs_in,
sizeof(aurcbs_in));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback", r);
return CUBEB_ERROR;
}
LOG("(%p) Input audiounit init successfully.", stm);
}
/* Setup Output Stream! */
if (has_output(stm)) {
LOG("(%p) Opening output side: rate %u, channels %u, format %d, latency in frames %u.",
stm, stm->output_stream_params.rate, stm->output_stream_params.channels,
stm->output_stream_params.format, stm->latency_frames);
r = audio_stream_desc_init(&stm->output_desc, &stm->output_stream_params);
r = audiounit_configure_output(stm);
if (r != CUBEB_OK) {
LOG("(%p) Could not initialize the audio stream description.", stm);
LOG("(%p) Configure audiounit output failed.", stm);
return r;
}
/* Get output device sample rate. */
AudioStreamBasicDescription output_hw_desc;
size = sizeof(AudioStreamBasicDescription);
memset(&output_hw_desc, 0, size);
r = AudioUnitGetProperty(stm->output_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
AU_OUT_BUS,
&output_hw_desc,
&size);
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitGetProperty/output/tkAudioUnitProperty_StreamFormat", r);
return CUBEB_ERROR;
}
stm->output_hw_rate = output_hw_desc.mSampleRate;
LOG("(%p) Output device sampling rate: %.2f", stm, output_hw_desc.mSampleRate);
r = AudioUnitSetProperty(stm->output_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
AU_OUT_BUS,
&stm->output_desc,
sizeof(AudioStreamBasicDescription));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat", r);
return CUBEB_ERROR;
}
// Use latency to calculate buffer size
uint32_t output_buffer_frames = stm->latency_frames;
LOG("(%p) Output buffer frame count %u.", stm, output_buffer_frames);
r = AudioUnitSetProperty(stm->output_unit,
kAudioDevicePropertyBufferFrameSize,
kAudioUnitScope_Input,
AU_OUT_BUS,
&output_buffer_frames,
sizeof(output_buffer_frames));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
return CUBEB_ERROR;
}
assert(stm->output_unit != NULL);
aurcbs_out.inputProc = audiounit_output_callback;
aurcbs_out.inputProcRefCon = stm;
r = AudioUnitSetProperty(stm->output_unit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
AU_OUT_BUS,
&aurcbs_out,
sizeof(aurcbs_out));
if (r != noErr) {
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback", r);
return CUBEB_ERROR;
}
LOG("(%p) Output audiounit init successfully.", stm);
}
// Setting the latency doesn't work well for USB headsets (eg. plantronics).
@ -1486,14 +1727,12 @@ audiounit_stream_init(cubeb * context,
assert(context);
*stream = NULL;
assert(latency_frames > 0);
if ((input_device && !input_stream_params) ||
(output_device && !output_stream_params)) {
return CUBEB_ERROR_INVALID_PARAMETER;
}
context->active_streams += 1;
stm.reset(new cubeb_stream(context));
/* These could be different in the future if we have both
@ -1501,6 +1740,7 @@ audiounit_stream_init(cubeb * context,
stm->data_callback = data_callback;
stm->state_callback = state_callback;
stm->user_ptr = user_ptr;
stm->latency_frames = latency_frames;
if (input_stream_params) {
stm->input_stream_params = *input_stream_params;
stm->input_device = reinterpret_cast<uintptr_t>(input_device);
@ -1512,18 +1752,14 @@ audiounit_stream_init(cubeb * context,
stm->output_device = reinterpret_cast<uintptr_t>(output_device);
}
/* Silently clamp the latency down to the platform default, because we
* synthetize the clock from the callbacks, and we want the clock to update
* often. */
stm->latency_frames = audiounit_clamp_latency(stm.get(), latency_frames);
assert(latency_frames > 0);
auto_lock context_lock(context->mutex);
{
// It's not critical to lock here, because no other thread has been started
// yet, but it allows to assert that the lock has been taken in
// `setup_audiounit_stream`.
// `audiounit_setup_stream`.
context->active_streams += 1;
auto_lock lock(stm->mutex);
r = setup_audiounit_stream(stm.get());
r = audiounit_setup_stream(stm.get());
}
if (r != CUBEB_OK) {
@ -1543,7 +1779,7 @@ audiounit_stream_init(cubeb * context,
}
static void
close_audiounit_stream(cubeb_stream * stm)
audiounit_close_stream(cubeb_stream *stm)
{
stm->mutex.assert_current_thread_owns();
if (stm->input_unit) {
@ -1566,11 +1802,12 @@ audiounit_stream_destroy(cubeb_stream * stm)
{
stm->shutdown = true;
auto_lock context_locl(stm->context->mutex);
audiounit_stream_stop_internal(stm);
{
auto_lock lock(stm->mutex);
close_audiounit_stream(stm);
audiounit_close_stream(stm);
}
#if !TARGET_OS_IPHONE
@ -1583,6 +1820,7 @@ audiounit_stream_destroy(cubeb_stream * stm)
assert(stm->context->active_streams >= 1);
stm->context->active_streams -= 1;
LOG("Cubeb stream (%p) destroyed successful.", stm);
delete stm;
}
@ -1606,6 +1844,7 @@ audiounit_stream_start(cubeb_stream * stm)
stm->shutdown = false;
stm->draining = false;
auto_lock context_locl(stm->context->mutex);
audiounit_stream_start_internal(stm);
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
@ -1633,6 +1872,7 @@ audiounit_stream_stop(cubeb_stream * stm)
{
stm->shutdown = true;
auto_lock context_locl(stm->context->mutex);
audiounit_stream_stop_internal(stm);
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
@ -2294,6 +2534,7 @@ cubeb_ops const audiounit_ops = {
/*.get_max_channel_count =*/ audiounit_get_max_channel_count,
/*.get_min_latency =*/ audiounit_get_min_latency,
/*.get_preferred_sample_rate =*/ audiounit_get_preferred_sample_rate,
/*.get_preferred_channel_layout =*/ nullptr,
/*.enumerate_devices =*/ audiounit_enumerate_devices,
/*.destroy =*/ audiounit_destroy,
/*.stream_init =*/ audiounit_stream_init,

Просмотреть файл

@ -114,6 +114,7 @@ static struct cubeb_ops const cbjack_ops = {
.get_max_channel_count = cbjack_get_max_channel_count,
.get_min_latency = cbjack_get_min_latency,
.get_preferred_sample_rate = cbjack_get_preferred_sample_rate,
.get_preferred_channel_layout = NULL,
.enumerate_devices = cbjack_enumerate_devices,
.destroy = cbjack_destroy,
.stream_init = cbjack_stream_init,
@ -420,7 +421,6 @@ cbjack_process(jack_nframes_t nframes, void * arg)
return 0;
}
static void
cbjack_deinterleave_playback_refill_float(cubeb_stream * stream, float ** in, float ** bufs_out, jack_nframes_t nframes)
{
@ -433,7 +433,6 @@ cbjack_deinterleave_playback_refill_float(cubeb_stream * stream, float ** in, fl
long done_frames = 0;
long input_frames_count = (in != NULL) ? nframes : 0;
done_frames = cubeb_resampler_fill(stream->resampler,
inptr,
&input_frames_count,
@ -934,7 +933,6 @@ cbjack_stream_set_volume(cubeb_stream * stm, float volume)
return CUBEB_OK;
}
static int
cbjack_stream_get_current_device(cubeb_stream * stm, cubeb_device ** const device)
{

Просмотреть файл

@ -0,0 +1,348 @@
/*
* Copyright © 2016 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#include <cassert>
#include "cubeb-internal.h"
#include "cubeb_mixer.h"
cubeb_layout_map const CUBEB_CHANNEL_LAYOUT_MAPS[CUBEB_LAYOUT_MAX] = {
{ "undefined", 0, CUBEB_LAYOUT_UNDEFINED },
{ "dual mono", 2, CUBEB_LAYOUT_DUAL_MONO },
{ "dual mono lfe", 3, CUBEB_LAYOUT_DUAL_MONO_LFE },
{ "mono", 1, CUBEB_LAYOUT_MONO },
{ "mono lfe", 2, CUBEB_LAYOUT_MONO_LFE },
{ "stereo", 2, CUBEB_LAYOUT_STEREO },
{ "stereo lfe", 3, CUBEB_LAYOUT_STEREO_LFE },
{ "3f", 3, CUBEB_LAYOUT_3F },
{ "3f lfe", 4, CUBEB_LAYOUT_3F_LFE },
{ "2f1", 3, CUBEB_LAYOUT_2F1 },
{ "2f1 lfe", 4, CUBEB_LAYOUT_2F1_LFE },
{ "3f1", 4, CUBEB_LAYOUT_3F1 },
{ "3f1 lfe", 5, CUBEB_LAYOUT_3F1_LFE },
{ "2f2", 4, CUBEB_LAYOUT_2F2 },
{ "2f2 lfe", 5, CUBEB_LAYOUT_2F2_LFE },
{ "3f2", 5, CUBEB_LAYOUT_3F2 },
{ "3f2 lfe", 6, CUBEB_LAYOUT_3F2_LFE },
{ "3f3r lfe", 7, CUBEB_LAYOUT_3F3R_LFE },
{ "3f4 lfe", 8, CUBEB_LAYOUT_3F4_LFE }
};
static int const CHANNEL_ORDER_TO_INDEX[CUBEB_LAYOUT_MAX][CHANNEL_MAX] = {
// M | L | R | C | LS | RS | RLS | RC | RRS | LFE
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // UNDEFINED
{ -1, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, // DUAL_MONO
{ -1, 0, 1, -1, -1, -1, -1, -1, -1, 2 }, // DUAL_MONO_LFE
{ 0, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // MONO
{ 0, -1, -1, -1, -1, -1, -1, -1, -1, 1 }, // MONO_LFE
{ -1, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, // STEREO
{ -1, 0, 1, -1, -1, -1, -1, -1, -1, 2 }, // STEREO_LFE
{ -1, 0, 1, 2, -1, -1, -1, -1, -1, -1 }, // 3F
{ -1, 0, 1, 2, -1, -1, -1, -1, -1, 3 }, // 3F_LFE
{ -1, 0, 1, -1, -1, -1, -1, 2, -1, -1 }, // 2F1
{ -1, 0, 1, -1, -1, -1, -1, 3, -1, 2 }, // 2F1_LFE
{ -1, 0, 1, 2, -1, -1, -1, 3, -1, -1 }, // 3F1
{ -1, 0, 1, 2, -1, -1, -1, 4, -1, 3 }, // 3F1_LFE
{ -1, 0, 1, -1, 2, 3, -1, -1, -1, -1 }, // 2F2
{ -1, 0, 1, -1, 3, 4, -1, -1, -1, 2 }, // 2F2_LFE
{ -1, 0, 1, 2, 3, 4, -1, -1, -1, -1 }, // 3F2
{ -1, 0, 1, 2, 4, 5, -1, -1, -1, 3 }, // 3F2_LFE
{ -1, 0, 1, 2, 5, 6, -1, 4, -1, 3 }, // 3F3R_LFE
{ -1, 0, 1, 2, 6, 7, 4, -1, 5, 3 }, // 3F4_LFE
};
// The downmix matrix from TABLE 2 in the ITU-R BS.775-3[1] defines a way to
// convert 3F2 input data to 1F, 2F, 3F, 2F1, 3F1, 2F2 output data. We extend it
// to convert 3F2-LFE input data to 1F, 2F, 3F, 2F1, 3F1, 2F2 and their LFEs
// output data.
// [1] https://www.itu.int/dms_pubrec/itu-r/rec/bs/R-REC-BS.775-3-201208-I!!PDF-E.pdf
// Number of converted layouts: 1F, 2F, 3F, 2F1, 3F1, 2F2 and their LFEs.
unsigned int const SUPPORTED_LAYOUT_NUM = 12;
// Number of input channel for downmix conversion.
unsigned int const INPUT_CHANNEL_NUM = 6; // 3F2-LFE
// Max number of possible output channels.
unsigned int const MAX_OUTPUT_CHANNEL_NUM = 5; // 2F2-LFE or 3F1-LFE
float const INV_SQRT_2 = 0.707106f; // 1/sqrt(2)
// Each array contains coefficients that will be multiplied with
// { L, R, C, LFE, LS, RS } channels respectively.
static float const DOWNMIX_MATRIX_3F2_LFE[SUPPORTED_LAYOUT_NUM][MAX_OUTPUT_CHANNEL_NUM][INPUT_CHANNEL_NUM] =
{
// 1F Mono
{
{ INV_SQRT_2, INV_SQRT_2, 1, 0, 0.5, 0.5 }, // M
},
// 1F Mono-LFE
{
{ INV_SQRT_2, INV_SQRT_2, 1, 0, 0.5, 0.5 }, // M
{ 0, 0, 0, 1, 0, 0 } // LFE
},
// 2F Stereo
{
{ 1, 0, INV_SQRT_2, 0, INV_SQRT_2, 0 }, // L
{ 0, 1, INV_SQRT_2, 0, 0, INV_SQRT_2 } // R
},
// 2F Stereo-LFE
{
{ 1, 0, INV_SQRT_2, 0, INV_SQRT_2, 0 }, // L
{ 0, 1, INV_SQRT_2, 0, 0, INV_SQRT_2 }, // R
{ 0, 0, 0, 1, 0, 0 } // LFE
},
// 3F
{
{ 1, 0, 0, 0, INV_SQRT_2, 0 }, // L
{ 0, 1, 0, 0, 0, INV_SQRT_2 }, // R
{ 0, 0, 1, 0, 0, 0 } // C
},
// 3F-LFE
{
{ 1, 0, 0, 0, INV_SQRT_2, 0 }, // L
{ 0, 1, 0, 0, 0, INV_SQRT_2 }, // R
{ 0, 0, 1, 0, 0, 0 }, // C
{ 0, 0, 0, 1, 0, 0 } // LFE
},
// 2F1
{
{ 1, 0, INV_SQRT_2, 0, 0, 0 }, // L
{ 0, 1, INV_SQRT_2, 0, 0, 0 }, // R
{ 0, 0, 0, 0, INV_SQRT_2, INV_SQRT_2 } // S
},
// 2F1-LFE
{
{ 1, 0, INV_SQRT_2, 0, 0, 0 }, // L
{ 0, 1, INV_SQRT_2, 0, 0, 0 }, // R
{ 0, 0, 0, 1, 0, 0 }, // LFE
{ 0, 0, 0, 0, INV_SQRT_2, INV_SQRT_2 } // S
},
// 3F1
{
{ 1, 0, 0, 0, 0, 0 }, // L
{ 0, 1, 0, 0, 0, 0 }, // R
{ 0, 0, 1, 0, 0, 0 }, // C
{ 0, 0, 0, 0, INV_SQRT_2, INV_SQRT_2 } // S
},
// 3F1-LFE
{
{ 1, 0, 0, 0, 0, 0 }, // L
{ 0, 1, 0, 0, 0, 0 }, // R
{ 0, 0, 1, 0, 0, 0 }, // C
{ 0, 0, 0, 1, 0, 0 }, // LFE
{ 0, 0, 0, 0, INV_SQRT_2, INV_SQRT_2 } // S
},
// 2F2
{
{ 1, 0, INV_SQRT_2, 0, 0, 0 }, // L
{ 0, 1, INV_SQRT_2, 0, 0, 0 }, // R
{ 0, 0, 0, 0, 1, 0 }, // LS
{ 0, 0, 0, 0, 0, 1 } // RS
},
// 2F2-LFE
{
{ 1, 0, INV_SQRT_2, 0, 0, 0 }, // L
{ 0, 1, INV_SQRT_2, 0, 0, 0 }, // R
{ 0, 0, 0, 1, 0, 0 }, // LFE
{ 0, 0, 0, 0, 1, 0 }, // LS
{ 0, 0, 0, 0, 0, 1 } // RS
}
};
/* Convert audio data from 3F2(-LFE) to 1F, 2F, 3F, 2F1, 3F1, 2F2 and their LFEs. */
template<typename T>
bool
downmix_3f2(T const * const in, unsigned long inframes, T * out, cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
{
if ((in_layout != CUBEB_LAYOUT_3F2 && in_layout != CUBEB_LAYOUT_3F2_LFE) ||
out_layout < CUBEB_LAYOUT_MONO || out_layout > CUBEB_LAYOUT_2F2_LFE) {
return false;
}
unsigned int in_channels = CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels;
unsigned int out_channels = CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels;
// Conversion from 3F2 to 2F2-LFE or 3F1-LFE is allowed, so we use '<=' instead of '<'.
assert(out_channels <= in_channels);
long out_index = 0;
auto & downmix_matrix = DOWNMIX_MATRIX_3F2_LFE[out_layout - CUBEB_LAYOUT_MONO]; // The matrix is started from mono.
for (unsigned long i = 0; i < inframes * in_channels; i += in_channels) {
for (unsigned int j = 0; j < out_channels; ++j) {
out[out_index + j] = 0; // Clear its value.
for (unsigned int k = 0 ; k < INPUT_CHANNEL_NUM ; ++k) {
// 3F2-LFE has 6 channels: L, R, C, LFE, LS, RS, while 3F2 has only 5
// channels: L, R, C, LS, RS. Thus, we need to append 0 to LFE(index 3)
// to simulate a 3F2-LFE data when input layout is 3F2.
T data = (in_layout == CUBEB_LAYOUT_3F2_LFE) ? in[i + k] : (k == 3) ? 0 : in[i + ((k < 3) ? k : k - 1)];
out[out_index + j] += downmix_matrix[j][k] * data;
}
}
out_index += out_channels;
}
return true;
}
/* Map the audio data by channel name. */
template<class T>
bool
mix_remap(T const * const in, unsigned long inframes, T * out, cubeb_channel_layout in_layout, cubeb_channel_layout out_layout) {
assert(in_layout != out_layout);
unsigned int in_channels = CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels;
unsigned int out_channels = CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels;
uint32_t in_layout_mask = 0;
for (unsigned int i = 0 ; i < in_channels ; ++i) {
in_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[in_layout][i];
}
uint32_t out_layout_mask = 0;
for (unsigned int i = 0 ; i < out_channels ; ++i) {
out_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[out_layout][i];
}
// If there is no matched channel, then do nothing.
if (!(out_layout_mask & in_layout_mask)) {
return false;
}
long out_index = 0;
for (unsigned long i = 0; i < inframes * in_channels; i += in_channels) {
for (unsigned int j = 0; j < out_channels; ++j) {
cubeb_channel channel = CHANNEL_INDEX_TO_ORDER[out_layout][j];
uint32_t channel_mask = 1 << channel;
int channel_index = CHANNEL_ORDER_TO_INDEX[in_layout][channel];
if (in_layout_mask & channel_mask) {
assert(channel_index != -1);
out[out_index + j] = in[i + channel_index];
} else {
assert(channel_index == -1);
out[out_index + j] = 0;
}
}
out_index += out_channels;
}
return true;
}
/* Drop the extra channels beyond the provided output channels. */
template<typename T>
void
downmix_fallback(T const * const in, unsigned long inframes, T * out, unsigned int in_channels, unsigned int out_channels)
{
assert(in_channels >= out_channels);
long out_index = 0;
for (unsigned long i = 0; i < inframes * in_channels; i += in_channels) {
for (unsigned int j = 0; j < out_channels; ++j) {
out[out_index + j] = in[i + j];
}
out_index += out_channels;
}
}
template<typename T>
void
cubeb_downmix(T const * const in, long inframes, T * out,
unsigned int in_channels, unsigned int out_channels,
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
{
assert(in_channels >= out_channels && in_layout != CUBEB_LAYOUT_UNDEFINED);
// If the channel number is different from the layout's setting or it's not a
// valid audio 5.1 downmix, then we use fallback downmix mechanism.
if (out_channels == CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels &&
in_channels == CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels) {
if (downmix_3f2(in, inframes, out, in_layout, out_layout)) {
return;
}
if (mix_remap(in, inframes, out, in_layout, out_layout)) {
return;
}
}
downmix_fallback(in, inframes, out, in_channels, out_channels);
}
/* Upmix function, copies a mono channel into L and R. */
template<typename T>
void
mono_to_stereo(T const * in, long insamples, T * out, unsigned int out_channels)
{
for (long i = 0, j = 0; i < insamples; ++i, j += out_channels) {
out[j] = out[j + 1] = in[i];
}
}
template<typename T>
void
cubeb_upmix(T const * in, long inframes, T * out,
unsigned int in_channels, unsigned int out_channels)
{
assert(out_channels >= in_channels && in_channels > 0);
/* Either way, if we have 2 or more channels, the first two are L and R. */
/* If we are playing a mono stream over stereo speakers, copy the data over. */
if (in_channels == 1 && out_channels >= 2) {
mono_to_stereo(in, inframes, out, out_channels);
} else {
/* Copy through. */
for (unsigned int i = 0, o = 0; i < inframes * in_channels;
i += in_channels, o += out_channels) {
for (unsigned int j = 0; j < in_channels; ++j) {
out[o + j] = in[i + j];
}
}
}
/* Check if more channels. */
if (out_channels <= 2) {
return;
}
/* Put silence in remaining channels. */
for (long i = 0, o = 0; i < inframes; ++i, o += out_channels) {
for (unsigned int j = 2; j < out_channels; ++j) {
out[o + j] = 0.0;
}
}
}
bool
cubeb_should_upmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
{
return mixer->channels > stream->channels;
}
bool
cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
{
if (mixer->channels > stream->channels || mixer->layout == stream->layout) {
return false;
}
return mixer->channels < stream->channels ||
// When mixer.channels == stream.channels
mixer->layout == CUBEB_LAYOUT_UNDEFINED || // fallback downmix
(stream->layout == CUBEB_LAYOUT_3F2 && // 3f2 downmix
(mixer->layout == CUBEB_LAYOUT_2F2_LFE ||
mixer->layout == CUBEB_LAYOUT_3F1_LFE));
}
void
cubeb_downmix_float(float * const in, long inframes, float * out,
unsigned int in_channels, unsigned int out_channels,
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
{
cubeb_downmix(in, inframes, out, in_channels, out_channels, in_layout, out_layout);
}
void
cubeb_upmix_float(float * const in, long inframes, float * out,
unsigned int in_channels, unsigned int out_channels)
{
cubeb_upmix(in, inframes, out, in_channels, out_channels);
}

Просмотреть файл

@ -0,0 +1,70 @@
/*
* Copyright © 2016 Mozilla Foundation
*
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
#ifndef CUBEB_MIXER
#define CUBEB_MIXER
#include "cubeb/cubeb.h" // for cubeb_channel_layout ,CUBEB_CHANNEL_LAYOUT_MAPS and cubeb_stream_params.
#include <stdbool.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef enum {
CHANNEL_INVALID = -1,
CHANNEL_MONO = 0,
CHANNEL_LEFT,
CHANNEL_RIGHT,
CHANNEL_CENTER,
CHANNEL_LS,
CHANNEL_RS,
CHANNEL_RLS,
CHANNEL_RCENTER,
CHANNEL_RRS,
CHANNEL_LFE,
CHANNEL_MAX // Max number of supported channels.
} cubeb_channel;
static cubeb_channel const CHANNEL_INDEX_TO_ORDER[CUBEB_LAYOUT_MAX][CHANNEL_MAX] = {
{ CHANNEL_INVALID }, // UNDEFINED
{ CHANNEL_LEFT, CHANNEL_RIGHT }, // DUAL_MONO
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE }, // DUAL_MONO_LFE
{ CHANNEL_MONO }, // MONO
{ CHANNEL_MONO, CHANNEL_LFE }, // MONO_LFE
{ CHANNEL_LEFT, CHANNEL_RIGHT }, // STEREO
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE }, // STEREO_LFE
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER }, // 3F
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE }, // 3F_LFE
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_RCENTER }, // 2F1
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE, CHANNEL_RCENTER }, // 2F1_LFE
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_RCENTER }, // 3F1
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RCENTER }, // 3F1_LFE
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LS, CHANNEL_RS }, // 2F2
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE, CHANNEL_LS, CHANNEL_RS }, // 2F2_LFE
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LS, CHANNEL_RS }, // 3F2
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_LS, CHANNEL_RS }, // 3F2_LFE
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RCENTER, CHANNEL_LS, CHANNEL_RS }, // 3F3R_LFE
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RLS, CHANNEL_RRS, CHANNEL_LS, CHANNEL_RS } // 3F4_LFE
};
bool cubeb_should_upmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
bool cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
void cubeb_downmix_float(float * const in, long inframes, float * out,
unsigned int in_channels, unsigned int out_channels,
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout);
void cubeb_upmix_float(float * const in, long inframes, float * out,
unsigned int in_channels, unsigned int out_channels);
#if defined(__cplusplus)
}
#endif
#endif // CUBEB_MIXER

Просмотреть файл

@ -1740,6 +1740,7 @@ static struct cubeb_ops const opensl_ops = {
.get_max_channel_count = opensl_get_max_channel_count,
.get_min_latency = opensl_get_min_latency,
.get_preferred_sample_rate = opensl_get_preferred_sample_rate,
.get_preferred_channel_layout = NULL,
.enumerate_devices = NULL,
.destroy = opensl_destroy,
.stream_init = opensl_stream_init,

Просмотреть файл

@ -12,6 +12,7 @@
#include <string.h>
#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
#include "cubeb_mixer.h"
#include <stdio.h>
#ifdef DISABLE_LIBPULSE_DLOPEN
@ -20,7 +21,7 @@
#define WRAP(x) cubeb_##x
#define LIBPULSE_API_VISIT(X) \
X(pa_channel_map_can_balance) \
X(pa_channel_map_init_auto) \
X(pa_channel_map_init) \
X(pa_context_connect) \
X(pa_context_disconnect) \
X(pa_context_drain) \
@ -468,6 +469,113 @@ stream_update_timing_info(cubeb_stream * stm)
return r;
}
static pa_channel_position_t
cubeb_channel_to_pa_channel(cubeb_channel channel)
{
assert(channel != CHANNEL_INVALID);
// This variable may be used for multiple times, so we should avoid to
// allocate it in stack, or it will be created and removed repeatedly.
// Use static to allocate this local variable in data space instead of stack.
static pa_channel_position_t map[CHANNEL_MAX] = {
// PA_CHANNEL_POSITION_INVALID, // CHANNEL_INVALID
PA_CHANNEL_POSITION_MONO, // CHANNEL_MONO
PA_CHANNEL_POSITION_FRONT_LEFT, // CHANNEL_LEFT
PA_CHANNEL_POSITION_FRONT_RIGHT, // CHANNEL_RIGHT
PA_CHANNEL_POSITION_FRONT_CENTER, // CHANNEL_CENTER
PA_CHANNEL_POSITION_SIDE_LEFT, // CHANNEL_LS
PA_CHANNEL_POSITION_SIDE_RIGHT, // CHANNEL_RS
PA_CHANNEL_POSITION_REAR_LEFT, // CHANNEL_RLS
PA_CHANNEL_POSITION_REAR_CENTER, // CHANNEL_RCENTER
PA_CHANNEL_POSITION_REAR_RIGHT, // CHANNEL_RRS
PA_CHANNEL_POSITION_LFE // CHANNEL_LFE
};
return map[channel];
}
static cubeb_channel
pa_channel_to_cubeb_channel(pa_channel_position_t channel)
{
assert(channel != PA_CHANNEL_POSITION_INVALID);
switch(channel) {
case PA_CHANNEL_POSITION_MONO: return CHANNEL_MONO;
case PA_CHANNEL_POSITION_FRONT_LEFT: return CHANNEL_LEFT;
case PA_CHANNEL_POSITION_FRONT_RIGHT: return CHANNEL_RIGHT;
case PA_CHANNEL_POSITION_FRONT_CENTER: return CHANNEL_CENTER;
case PA_CHANNEL_POSITION_SIDE_LEFT: return CHANNEL_LS;
case PA_CHANNEL_POSITION_SIDE_RIGHT: return CHANNEL_RS;
case PA_CHANNEL_POSITION_REAR_LEFT: return CHANNEL_RLS;
case PA_CHANNEL_POSITION_REAR_CENTER: return CHANNEL_RCENTER;
case PA_CHANNEL_POSITION_REAR_RIGHT: return CHANNEL_RRS;
case PA_CHANNEL_POSITION_LFE: return CHANNEL_LFE;
default: return CHANNEL_INVALID;
}
}
static void
layout_to_channel_map(cubeb_channel_layout layout, pa_channel_map * cm)
{
assert(cm && layout != CUBEB_LAYOUT_UNDEFINED);
WRAP(pa_channel_map_init)(cm);
cm->channels = CUBEB_CHANNEL_LAYOUT_MAPS[layout].channels;
for (uint8_t i = 0 ; i < cm->channels ; ++i) {
cm->map[i] = cubeb_channel_to_pa_channel(CHANNEL_INDEX_TO_ORDER[layout][i]);
}
}
// DUAL_MONO(_LFE) is same as STEREO(_LFE).
#define MASK_MONO (1 << CHANNEL_MONO)
#define MASK_MONO_LFE (MASK_MONO | (1 << CHANNEL_LFE))
#define MASK_STEREO ((1 << CHANNEL_LEFT) | (1 << CHANNEL_RIGHT))
#define MASK_STEREO_LFE (MASK_STEREO | (1 << CHANNEL_LFE))
#define MASK_3F (MASK_STEREO | (1 << CHANNEL_CENTER))
#define MASK_3F_LFE (MASK_3F | (1 << CHANNEL_LFE))
#define MASK_2F1 (MASK_STEREO | (1 << CHANNEL_RCENTER))
#define MASK_2F1_LFE (MASK_2F1 | (1 << CHANNEL_LFE))
#define MASK_3F1 (MASK_3F | (1 << CHANNEL_RCENTER))
#define MASK_3F1_LFE (MASK_3F1 | (1 << CHANNEL_LFE))
#define MASK_2F2 (MASK_STEREO | (1 << CHANNEL_LS) | (1 << CHANNEL_RS))
#define MASK_2F2_LFE (MASK_2F2 | (1 << CHANNEL_LFE))
#define MASK_3F2 (MASK_2F2 | (1 << CHANNEL_CENTER))
#define MASK_3F2_LFE (MASK_3F2 | (1 << CHANNEL_LFE))
#define MASK_3F3R_LFE (MASK_3F2_LFE | (1 << CHANNEL_RCENTER))
#define MASK_3F4_LFE (MASK_3F2_LFE | (1 << CHANNEL_RLS) | (1 << CHANNEL_RRS))
static cubeb_channel_layout
channel_map_to_layout(pa_channel_map * cm)
{
uint32_t channel_mask = 0;
for (uint8_t i = 0 ; i < cm->channels ; ++i) {
cubeb_channel channel = pa_channel_to_cubeb_channel(cm->map[i]);
if (channel == CHANNEL_INVALID) {
return CUBEB_LAYOUT_UNDEFINED;
}
channel_mask |= 1 << channel;
}
switch(channel_mask) {
case MASK_MONO: return CUBEB_LAYOUT_MONO;
case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
case MASK_STEREO: return CUBEB_LAYOUT_STEREO;
case MASK_STEREO_LFE: return CUBEB_LAYOUT_STEREO_LFE;
case MASK_3F: return CUBEB_LAYOUT_3F;
case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
case MASK_2F1: return CUBEB_LAYOUT_2F1;
case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
case MASK_3F1: return CUBEB_LAYOUT_3F1;
case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
case MASK_2F2: return CUBEB_LAYOUT_2F2;
case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
case MASK_3F2: return CUBEB_LAYOUT_3F2;
case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
default: return CUBEB_LAYOUT_UNDEFINED;
}
}
static void pulse_context_destroy(cubeb * ctx);
static void pulse_destroy(cubeb * ctx);
@ -596,6 +704,23 @@ pulse_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
return CUBEB_OK;
}
static int
pulse_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layout)
{
assert(ctx && layout);
(void)ctx;
WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
while (!ctx->default_sink_info) {
WRAP(pa_threaded_mainloop_wait)(ctx->mainloop);
}
WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
*layout = channel_map_to_layout(&ctx->default_sink_info->channel_map);
return CUBEB_OK;
}
static int
pulse_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
{
@ -672,7 +797,8 @@ create_pa_stream(cubeb_stream * stm,
cubeb_stream_params * stream_params,
char const * stream_name)
{
assert(stm && stream_params);
assert(stm && stream_params && stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels == stream_params->channels);
*pa_stm = NULL;
pa_sample_spec ss;
ss.format = to_pulse_format(stream_params->format);
@ -681,7 +807,10 @@ create_pa_stream(cubeb_stream * stm,
ss.rate = stream_params->rate;
ss.channels = stream_params->channels;
*pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, NULL);
pa_channel_map cm;
layout_to_channel_map(stream_params->layout, &cm);
*pa_stm = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, &cm);
return (*pa_stm == NULL) ? CUBEB_ERROR : CUBEB_OK;
}
@ -1410,6 +1539,7 @@ static struct cubeb_ops const pulse_ops = {
.get_max_channel_count = pulse_get_max_channel_count,
.get_min_latency = pulse_get_min_latency,
.get_preferred_sample_rate = pulse_get_preferred_sample_rate,
.get_preferred_channel_layout = pulse_get_preferred_channel_layout,
.enumerate_devices = pulse_enumerate_devices,
.destroy = pulse_destroy,
.stream_init = pulse_stream_init,

Просмотреть файл

@ -124,7 +124,6 @@ cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
T * out_unprocessed = nullptr;
long output_frames_before_processing = 0;
/* fill directly the input buffer of the output processor to save a copy */
output_frames_before_processing =
output_processor->input_needed_for_output(output_frames_needed);
@ -174,7 +173,6 @@ cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
return (*input_frames_count) * (got / resampled_frame_count);
}
template<typename T, typename InputProcessor, typename OutputProcessor>
long
cubeb_resampler_speex<T, InputProcessor, OutputProcessor>

Просмотреть файл

@ -366,6 +366,7 @@ static struct cubeb_ops const sndio_ops = {
.get_max_channel_count = sndio_get_max_channel_count,
.get_min_latency = sndio_get_min_latency,
.get_preferred_sample_rate = sndio_get_preferred_sample_rate,
.get_preferred_channel_layout = NULL,
.enumerate_devices = NULL,
.destroy = sndio_destroy,
.stream_init = sndio_stream_init,

Просмотреть файл

@ -46,6 +46,63 @@ void PodZero(T * destination, size_t count)
memset(destination, 0, count * sizeof(T));
}
namespace {
template<typename T, typename Trait>
void Copy(T * destination, const T * source, size_t count, Trait)
{
for (size_t i = 0; i < count; i++) {
destination[i] = source[i];
}
}
template<typename T>
void Copy(T * destination, const T * source, size_t count, std::true_type)
{
PodCopy(destination, source, count);
}
}
/**
* This allows copying a number of elements from a `source` pointer to a
* `destination` pointer, using `memcpy` if it is safe to do so, or a loop that
* calls the constructors and destructors otherwise.
*/
template<typename T>
void Copy(T * destination, const T * source, size_t count)
{
assert(destination && source);
Copy(destination, source, count, typename std::is_trivial<T>::type());
}
namespace {
template<typename T, typename Trait>
void ConstructDefault(T * destination, size_t count, Trait)
{
for (size_t i = 0; i < count; i++) {
destination[i] = T();
}
}
template<typename T>
void ConstructDefault(T * destination,
size_t count, std::true_type)
{
PodZero(destination, count);
}
}
/**
* This allows zeroing (using memset) or default-constructing a number of
* elements calling the constructors and destructors if necessary.
*/
template<typename T>
void ConstructDefault(T * destination, size_t count)
{
assert(destination);
ConstructDefault(destination, count,
typename std::is_arithmetic<T>::type());
}
template<typename T>
class auto_array
{

Просмотреть файл

@ -4,6 +4,11 @@
* This program is made available under an ISC-style license. See the
* accompanying file LICENSE for details.
*/
// Explicitly define NTDDI_VERSION rather than letting the value be derived
// from _WIN32_WINNT because we depend on values defined for XP SP2 and WS03
// SP1.
#define _WIN32_WINNT 0x0502
#define NTDDI_VERSION 0x05020100
#define NOMINMAX
#include <initguid.h>
@ -27,6 +32,7 @@
#include "cubeb/cubeb.h"
#include "cubeb-internal.h"
#include "cubeb_mixer.h"
#include "cubeb_resampler.h"
#include "cubeb_utils.h"
@ -198,12 +204,12 @@ struct cubeb_stream {
/* Mixer pameters. We need to convert the input stream to this
samplerate/channel layout, as WASAPI does not resample nor upmix
itself. */
cubeb_stream_params input_mix_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0 };
cubeb_stream_params output_mix_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0 };
cubeb_stream_params input_mix_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED };
cubeb_stream_params output_mix_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED };
/* Stream parameters. This is what the client requested,
* and what will be presented in the callback. */
cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0 };
cubeb_stream_params output_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0 };
cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED };
cubeb_stream_params output_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED };
/* The input and output device, or NULL for default. */
std::unique_ptr<const wchar_t[]> input_device;
std::unique_ptr<const wchar_t[]> output_device;
@ -392,21 +398,89 @@ bool has_output(cubeb_stream * stm)
return stm->output_stream_params.rate != 0;
}
bool should_upmix(cubeb_stream_params & stream, cubeb_stream_params & mixer)
{
return mixer.channels > stream.channels;
}
bool should_downmix(cubeb_stream_params & stream, cubeb_stream_params & mixer)
{
return mixer.channels < stream.channels;
}
double stream_to_mix_samplerate_ratio(cubeb_stream_params & stream, cubeb_stream_params & mixer)
{
return double(stream.rate) / mixer.rate;
}
/* Convert the channel layout into the corresponding KSAUDIO_CHANNEL_CONFIG.
See more: https://msdn.microsoft.com/en-us/library/windows/hardware/ff537083(v=vs.85).aspx */
#define MASK_DUAL_MONO (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
#define MASK_DUAL_MONO_LFE (MASK_DUAL_MONO | SPEAKER_LOW_FREQUENCY)
#define MASK_MONO (KSAUDIO_SPEAKER_MONO)
#define MASK_MONO_LFE (MASK_MONO | SPEAKER_LOW_FREQUENCY)
#define MASK_STEREO (KSAUDIO_SPEAKER_STEREO)
#define MASK_STEREO_LFE (MASK_STEREO | SPEAKER_LOW_FREQUENCY)
#define MASK_3F (MASK_STEREO | SPEAKER_FRONT_CENTER)
#define MASK_3F_LFE (MASK_3F | SPEAKER_LOW_FREQUENCY)
#define MASK_2F1 (MASK_STEREO | SPEAKER_BACK_CENTER)
#define MASK_2F1_LFE (MASK_2F1 | SPEAKER_LOW_FREQUENCY)
#define MASK_3F1 (KSAUDIO_SPEAKER_SURROUND)
#define MASK_3F1_LFE (MASK_3F1 | SPEAKER_LOW_FREQUENCY)
#define MASK_2F2 (MASK_STEREO | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
#define MASK_2F2_LFE (MASK_2F2 | SPEAKER_LOW_FREQUENCY)
#define MASK_3F2 (MASK_3F | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
#define MASK_3F2_LFE (KSAUDIO_SPEAKER_5POINT1_SURROUND)
#define MASK_3F3R_LFE (MASK_3F2_LFE | SPEAKER_BACK_CENTER)
#define MASK_3F4_LFE (KSAUDIO_SPEAKER_7POINT1_SURROUND)
static DWORD
channel_layout_to_mask(cubeb_channel_layout layout)
{
XASSERT(layout > CUBEB_LAYOUT_UNDEFINED && layout < CUBEB_LAYOUT_MAX &&
"This mask conversion is not allowed.");
// This variable may be used for multiple times, so we should avoid to
// allocate it in stack, or it will be created and removed repeatedly.
// Use static to allocate this local variable in data space instead of stack.
static DWORD map[CUBEB_LAYOUT_MAX] = {
0, // CUBEB_LAYOUT_UNDEFINED (this won't be used.)
MASK_DUAL_MONO, // CUBEB_LAYOUT_DUAL_MONO
MASK_DUAL_MONO_LFE, // CUBEB_LAYOUT_DUAL_MONO_LFE
MASK_MONO, // CUBEB_LAYOUT_MONO
MASK_MONO_LFE, // CUBEB_LAYOUT_MONO_LFE
MASK_STEREO, // CUBEB_LAYOUT_STEREO
MASK_STEREO_LFE, // CUBEB_LAYOUT_STEREO_LFE
MASK_3F, // CUBEB_LAYOUT_3F
MASK_3F_LFE, // CUBEB_LAYOUT_3F_LFE
MASK_2F1, // CUBEB_LAYOUT_2F1
MASK_2F1_LFE, // CUBEB_LAYOUT_2F1_LFE
MASK_3F1, // CUBEB_LAYOUT_3F1
MASK_3F1_LFE, // CUBEB_LAYOUT_3F1_LFE
MASK_2F2, // CUBEB_LAYOUT_2F2
MASK_2F2_LFE, // CUBEB_LAYOUT_2F2_LFE
MASK_3F2, // CUBEB_LAYOUT_3F2
MASK_3F2_LFE, // CUBEB_LAYOUT_3F2_LFE
MASK_3F3R_LFE, // CUBEB_LAYOUT_3F3R_LFE
MASK_3F4_LFE, // CUBEB_LAYOUT_3F4_LFE
};
return map[layout];
}
cubeb_channel_layout
mask_to_channel_layout(DWORD mask)
{
switch (mask) {
// MASK_DUAL_MONO(_LFE) is same as STEREO(_LFE), so we skip it.
case MASK_MONO: return CUBEB_LAYOUT_MONO;
case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
case MASK_STEREO: return CUBEB_LAYOUT_STEREO;
case MASK_STEREO_LFE: return CUBEB_LAYOUT_STEREO_LFE;
case MASK_3F: return CUBEB_LAYOUT_3F;
case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
case MASK_2F1: return CUBEB_LAYOUT_2F1;
case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
case MASK_3F1: return CUBEB_LAYOUT_3F1;
case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
case MASK_2F2: return CUBEB_LAYOUT_2F2;
case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
case MASK_3F2: return CUBEB_LAYOUT_3F2;
case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
default: return CUBEB_LAYOUT_UNDEFINED;
}
}
uint32_t
get_rate(cubeb_stream * stm)
@ -439,71 +513,13 @@ frames_to_hns(cubeb_stream * stm, uint32_t frames)
return frames * 1000 / get_rate(stm);
}
/* Upmix function, copies a mono channel into L and R */
template<typename T>
void
mono_to_stereo(T * in, long insamples, T * out, int32_t out_channels)
{
for (int i = 0, j = 0; i < insamples; ++i, j += out_channels) {
out[j] = out[j + 1] = in[i];
}
}
template<typename T>
void
upmix(T * in, long inframes, T * out, int32_t in_channels, int32_t out_channels)
{
XASSERT(out_channels >= in_channels && in_channels > 0);
/* Either way, if we have 2 or more channels, the first two are L and R. */
/* If we are playing a mono stream over stereo speakers, copy the data over. */
if (in_channels == 1 && out_channels >= 2) {
mono_to_stereo(in, inframes, out, out_channels);
} else {
/* Copy through. */
for (int i = 0, o = 0; i < inframes * in_channels;
i += in_channels, o += out_channels) {
for (int j = 0; j < in_channels; ++j) {
out[o + j] = in[i + j];
}
}
}
/* Check if more channels. */
if (out_channels <= 2) {
return;
}
/* Put silence in remaining channels. */
for (long i = 0, o = 0; i < inframes; ++i, o += out_channels) {
for (int j = 2; j < out_channels; ++j) {
out[o + j] = 0.0;
}
}
}
template<typename T>
void
downmix(T * in, long inframes, T * out, int32_t in_channels, int32_t out_channels)
{
XASSERT(in_channels >= out_channels);
/* We could use a downmix matrix here, applying mixing weight based on the
channel, but directsound and winmm simply drop the channels that cannot be
rendered by the hardware, so we do the same for consistency. */
long out_index = 0;
for (long i = 0; i < inframes * in_channels; i += in_channels) {
for (int j = 0; j < out_channels; ++j) {
out[out_index + j] = in[i + j];
}
out_index += out_channels;
}
}
/* This returns the size of a frame in the stream, before the eventual upmix
occurs. */
static size_t
frames_to_bytes_before_mix(cubeb_stream * stm, size_t frames)
{
// This is called only when we has a output client.
XASSERT(has_output(stm));
size_t stream_frame_size = stm->output_stream_params.channels * sizeof(float);
return stream_frame_size * frames;
}
@ -519,8 +535,8 @@ refill(cubeb_stream * stm, float * input_buffer, long input_frames_count,
avoid a copy. */
float * dest = nullptr;
if (has_output(stm)) {
if (should_upmix(stm->output_stream_params, stm->output_mix_params) ||
should_downmix(stm->output_stream_params, stm->output_mix_params)) {
if (cubeb_should_upmix(&stm->output_stream_params, &stm->output_mix_params) ||
cubeb_should_downmix(&stm->output_stream_params, &stm->output_mix_params)) {
dest = stm->mix_buffer.data();
} else {
dest = output_buffer;
@ -551,12 +567,13 @@ refill(cubeb_stream * stm, float * input_buffer, long input_frames_count,
XASSERT(out_frames == output_frames_needed || stm->draining || !has_output(stm));
if (has_output(stm)) {
if (should_upmix(stm->output_stream_params, stm->output_mix_params)) {
upmix(dest, out_frames, output_buffer,
stm->output_stream_params.channels, stm->output_mix_params.channels);
} else if (should_downmix(stm->output_stream_params, stm->output_mix_params)) {
downmix(dest, out_frames, output_buffer,
stm->output_stream_params.channels, stm->output_mix_params.channels);
if (cubeb_should_upmix(&stm->output_stream_params, &stm->output_mix_params)) {
cubeb_upmix_float(dest, out_frames, output_buffer,
stm->output_stream_params.channels, stm->output_mix_params.channels);
} else if (cubeb_should_downmix(&stm->output_stream_params, &stm->output_mix_params)) {
cubeb_downmix_float(dest, out_frames, output_buffer,
stm->output_stream_params.channels, stm->output_mix_params.channels,
stm->output_stream_params.layout, stm->output_mix_params.layout);
}
}
@ -615,23 +632,25 @@ bool get_input_buffer(cubeb_stream * stm)
LOG("insert silence: ps=%u", packet_size);
stm->linear_input_buffer.push_silence(packet_size * stm->input_stream_params.channels);
} else {
if (should_upmix(stm->input_mix_params, stm->input_stream_params)) {
if (cubeb_should_upmix(&stm->input_mix_params, &stm->input_stream_params)) {
bool ok = stm->linear_input_buffer.reserve(stm->linear_input_buffer.length() +
packet_size * stm->input_stream_params.channels);
XASSERT(ok);
upmix(reinterpret_cast<float*>(input_packet), packet_size,
stm->linear_input_buffer.data() + stm->linear_input_buffer.length(),
stm->input_mix_params.channels,
stm->input_stream_params.channels);
cubeb_upmix_float(reinterpret_cast<float*>(input_packet), packet_size,
stm->linear_input_buffer.data() + stm->linear_input_buffer.length(),
stm->input_mix_params.channels,
stm->input_stream_params.channels);
stm->linear_input_buffer.set_length(stm->linear_input_buffer.length() + packet_size * stm->input_stream_params.channels);
} else if (should_downmix(stm->input_mix_params, stm->input_stream_params)) {
} else if (cubeb_should_downmix(&stm->input_mix_params, &stm->input_stream_params)) {
bool ok = stm->linear_input_buffer.reserve(stm->linear_input_buffer.length() +
packet_size * stm->input_stream_params.channels);
XASSERT(ok);
downmix(reinterpret_cast<float*>(input_packet), packet_size,
stm->linear_input_buffer.data() + stm->linear_input_buffer.length(),
stm->input_mix_params.channels,
stm->input_stream_params.channels);
cubeb_downmix_float(reinterpret_cast<float*>(input_packet), packet_size,
stm->linear_input_buffer.data() + stm->linear_input_buffer.length(),
stm->input_mix_params.channels,
stm->input_stream_params.channels,
stm->input_mix_params.layout,
stm->input_stream_params.layout);
stm->linear_input_buffer.set_length(stm->linear_input_buffer.length() + packet_size * stm->input_stream_params.channels);
} else {
stm->linear_input_buffer.push(reinterpret_cast<float*>(input_packet),
@ -781,7 +800,8 @@ refill_callback_input(cubeb_stream * stm)
nullptr,
0);
consumed_all_buffer = read == stm->linear_input_buffer.length();
XASSERT(read >= 0);
consumed_all_buffer = (unsigned long) read == stm->linear_input_buffer.length();
stm->linear_input_buffer.clear();
@ -817,7 +837,7 @@ refill_callback_output(cubeb_stream * stm)
output_frames, got);
XASSERT(got >= 0);
XASSERT(got == output_frames || stm->draining);
XASSERT((unsigned long) got == output_frames || stm->draining);
hr = stm->render_client->ReleaseBuffer(got, 0);
if (FAILED(hr)) {
@ -825,7 +845,7 @@ refill_callback_output(cubeb_stream * stm)
return false;
}
return got == output_frames || stm->draining;
return (unsigned long) got == output_frames || stm->draining;
}
static unsigned int __stdcall
@ -860,7 +880,6 @@ wasapi_stream_render_loop(LPVOID stream)
LOG("Unable to use mmcss to bump the render thread priority: %lx", GetLastError());
}
/* WaitForMultipleObjects timeout can trigger in cases where we don't want to
treat it as a timeout, such as across a system sleep/wake cycle. Trigger
the timeout error handling only when the timeout_limit is reached, which is
@ -1211,13 +1230,18 @@ bool stop_and_join_render_thread(cubeb_stream * stm)
rv = false;
}
LOG("Closing thread.");
CloseHandle(stm->thread);
stm->thread = NULL;
// Only attempts to close and null out the thread and event if the
// WaitForSingleObject above succeeded, so that calling this function again
// attemps to clean up the thread and event each time.
if (rv) {
LOG("Closing thread.");
CloseHandle(stm->thread);
stm->thread = NULL;
CloseHandle(stm->shutdown_event);
stm->shutdown_event = 0;
CloseHandle(stm->shutdown_event);
stm->shutdown_event = 0;
}
return rv;
}
@ -1359,6 +1383,44 @@ wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
return CUBEB_OK;
}
int
wasapi_get_preferred_channel_layout(cubeb * context, cubeb_channel_layout * layout)
{
HRESULT hr;
auto_com com;
if (!com.ok()) {
return CUBEB_ERROR;
}
com_ptr<IMMDevice> device;
hr = get_default_endpoint(device, eRender);
if (FAILED(hr)) {
return CUBEB_ERROR;
}
com_ptr<IAudioClient> client;
hr = device->Activate(__uuidof(IAudioClient),
CLSCTX_INPROC_SERVER,
NULL, client.receive_vpp());
if (FAILED(hr)) {
return CUBEB_ERROR;
}
WAVEFORMATEX * tmp = nullptr;
hr = client->GetMixFormat(&tmp);
if (FAILED(hr)) {
return CUBEB_ERROR;
}
com_heap_ptr<WAVEFORMATEX> mix_format(tmp);
WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.get());
*layout = mask_to_channel_layout(format_pcm->dwChannelMask);
LOG("Preferred channel layout: %s", CUBEB_CHANNEL_LAYOUT_MAPS[*layout].name);
return CUBEB_OK;
}
void wasapi_stream_destroy(cubeb_stream * stm);
/* Based on the mix format and the stream format, try to find a way to play
@ -1366,12 +1428,7 @@ void wasapi_stream_destroy(cubeb_stream * stm);
static void
handle_channel_layout(cubeb_stream * stm, com_heap_ptr<WAVEFORMATEX> & mix_format, const cubeb_stream_params * stream_params)
{
/* Common case: the hardware is stereo. Up-mixing and down-mixing will be
handled in the callback. */
if (mix_format->nChannels <= 2) {
return;
}
XASSERT(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
/* The docs say that GetMixFormat is always of type WAVEFORMATEXTENSIBLE [1],
so the reinterpret_cast below should be safe. In practice, this is not
true, and we just want to bail out and let the rest of the code find a good
@ -1386,19 +1443,10 @@ handle_channel_layout(cubeb_stream * stm, com_heap_ptr<WAVEFORMATEX> & mix_form
/* Stash a copy of the original mix format in case we need to restore it later. */
WAVEFORMATEXTENSIBLE hw_mix_format = *format_pcm;
/* The hardware is in surround mode, we want to only use front left and front
right. Try that, and check if it works. */
switch (stream_params->channels) {
case 1: /* Mono */
format_pcm->dwChannelMask = KSAUDIO_SPEAKER_MONO;
break;
case 2: /* Stereo */
format_pcm->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
break;
default:
XASSERT(false && "Channel layout not supported.");
break;
}
/* Get the channel mask by the channel layout.
If the layout is not supported, we will get a closest settings below. */
format_pcm->dwChannelMask = channel_layout_to_mask(stream_params->layout);
mix_format->nChannels = stream_params->channels;
mix_format->nBlockAlign = mix_format->wBitsPerSample * mix_format->nChannels / 8;
mix_format->nAvgBytesPerSec = mix_format->nSamplesPerSec * mix_format->nBlockAlign;
@ -1499,16 +1547,39 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
}
com_heap_ptr<WAVEFORMATEX> mix_format(tmp);
handle_channel_layout(stm, mix_format, stream_params);
/* Set channel layout only when there're more than two channels. Otherwise,
* use the default setting retrieved from the stream format of the audio
* engine's internal processing by GetMixFormat. */
if (mix_format->nChannels > 2) {
/* Currently, we only support mono and stereo for capture stream. */
if (direction == eCapture) {
XASSERT(false && "Multichannel recording is not supported.");
}
handle_channel_layout(stm, mix_format, stream_params);
}
/* Shared mode WASAPI always supports float32 sample format, so this
* is safe. */
mix_params->format = CUBEB_SAMPLE_FLOAT32NE;
mix_params->rate = mix_format->nSamplesPerSec;
mix_params->channels = mix_format->nChannels;
LOG("Setup requested=[f=%d r=%u c=%u] mix=[f=%d r=%u c=%u]",
WAVEFORMATEXTENSIBLE * format_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(mix_format.get());
mix_params->layout = mask_to_channel_layout(format_pcm->dwChannelMask);
if (mix_params->layout == CUBEB_LAYOUT_UNDEFINED) {
LOG("Output using undefined layout!\n");
} else if (mix_format->nChannels != CUBEB_CHANNEL_LAYOUT_MAPS[mix_params->layout].channels) {
// The CUBEB_CHANNEL_LAYOUT_MAPS[mix_params->layout].channels may be
// different from the mix_params->channels. 6 channel ouput with stereo
// layout is acceptable in Windows. If this happens, it should not downmix
// audio according to layout.
LOG("Channel count is different from the layout standard!\n");
}
LOG("Setup requested=[f=%d r=%u c=%u l=%s] mix=[f=%d r=%u c=%u l=%s]",
stream_params->format, stream_params->rate, stream_params->channels,
mix_params->format, mix_params->rate, mix_params->channels);
CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].name,
mix_params->format, mix_params->rate, mix_params->channels,
CUBEB_CHANNEL_LAYOUT_MAPS[mix_params->layout].name);
hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
@ -1530,8 +1601,8 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
}
// Input is up/down mixed when depacketized in get_input_buffer.
if (has_output(stm) &&
(should_upmix(*stream_params, *mix_params) ||
should_downmix(*stream_params, *mix_params))) {
(cubeb_should_upmix(stream_params, mix_params) ||
cubeb_should_downmix(stream_params, mix_params))) {
stm->mix_buffer.resize(frames_to_bytes_before_mix(stm, *buffer_frame_count));
}
@ -1712,10 +1783,14 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
if (input_stream_params) {
stm->input_stream_params = *input_stream_params;
stm->input_device = utf8_to_wstr(reinterpret_cast<char const *>(input_device));
// Make sure the layout matches the channel count.
XASSERT(stm->input_stream_params.channels == CUBEB_CHANNEL_LAYOUT_MAPS[stm->input_stream_params.layout].channels);
}
if (output_stream_params) {
stm->output_stream_params = *output_stream_params;
stm->output_device = utf8_to_wstr(reinterpret_cast<char const *>(output_device));
// Make sure the layout matches the channel count.
XASSERT(stm->output_stream_params.channels == CUBEB_CHANNEL_LAYOUT_MAPS[stm->output_stream_params.layout].channels);
}
stm->latency = latency_frames;
@ -1921,7 +1996,6 @@ int wasapi_stream_stop(cubeb_stream * stm)
}
}
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
}
@ -2252,6 +2326,7 @@ cubeb_ops const wasapi_ops = {
/*.get_max_channel_count =*/ wasapi_get_max_channel_count,
/*.get_min_latency =*/ wasapi_get_min_latency,
/*.get_preferred_sample_rate =*/ wasapi_get_preferred_sample_rate,
/*.get_preferred_channel_layout =*/ wasapi_get_preferred_channel_layout,
/*.enumerate_devices =*/ wasapi_enumerate_devices,
/*.destroy =*/ wasapi_destroy,
/*.stream_init =*/ wasapi_stream_init,

Просмотреть файл

@ -512,7 +512,6 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n
return CUBEB_ERROR;
}
for (i = 0; i < NBUFS; ++i) {
WAVEHDR * hdr = &stm->buffers[i];
@ -769,7 +768,6 @@ winmm_calculate_device_rate(cubeb_device_info * info, DWORD formats)
}
}
#define MM_S16_MASK (WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4M16 | \
WAVE_FORMAT_4S16 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16)
static int
@ -1050,6 +1048,7 @@ static struct cubeb_ops const winmm_ops = {
/*.get_max_channel_count=*/ winmm_get_max_channel_count,
/*.get_min_latency=*/ winmm_get_min_latency,
/*.get_preferred_sample_rate =*/ winmm_get_preferred_sample_rate,
/*.get_preferred_channel_layout =*/ NULL,
/*.enumerate_devices =*/ winmm_enumerate_devices,
/*.destroy =*/ winmm_destroy,
/*.stream_init =*/ winmm_stream_init,

Просмотреть файл

@ -10,6 +10,7 @@ Library('cubeb')
SOURCES += [
'cubeb.c',
'cubeb_mixer.cpp',
'cubeb_panner.cpp'
]

Просмотреть файл

@ -31,6 +31,8 @@ cp $1/src/cubeb_utils_unix.h src
cp $1/src/cubeb_utils_win.h src
cp $1/src/cubeb_wasapi.cpp src
cp $1/src/cubeb_winmm.c src
cp $1/src/cubeb_mixer.h src
cp $1/src/cubeb_mixer.cpp src
cp $1/test/common.h gtest
cp $1/test/test_audio.cpp gtest
cp $1/test/test_devices.cpp gtest
@ -42,6 +44,7 @@ cp $1/test/test_ring_array.cpp gtest
cp $1/test/test_sanity.cpp gtest
cp $1/test/test_tone.cpp gtest
cp $1/test/test_utils.cpp gtest
cp $1/test/test_mixer.cpp gtest
if [ -d $1/.git ]; then
rev=$(cd $1 && git rev-parse --verify HEAD)

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIICxTCCAa+gAwIBAgIUQy+m6w0ZtMTfbmtELQQz8zwqCAowCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICxTCCAa+gAwIBAgIUL5zykZEc2ro5d6th43aWGfm735cwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMA0xCzAJBgNVBAMMAmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
@ -8,10 +8,10 @@ Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1Ud
DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAJQcekrdR+S6U0I3owUQxVOoUJMzHdTj
u562Ra7cOiJQwe1OQZbvo6rQkQWPrpuDOGpwwr1+HBMGb8mjUqeFo5wIinU003TC
UYYEpDCbPwXOKDkDUukKd1aO4wpJc/v8YIiCz7aCRj9HQ3L5YO5JsgMNSCXKKoUm
ILcz2V+IQZ6lePzFfd2aO3zLMDPwEOyujYYtQnBVZIT4F/x/6nU8E6bkbDSGPjQW
CSVhwa0YQ9lCRSM6e//wGry4i8X8718t1V+Nqh7y6u7UlOrXbNEA4pR6mvJsqPhF
Mj82We4OGNBxXbyuGJObQgLBfmRuwKQT9SNtKWEifiaTw8apT/fBagc=
DwQEAwIBBjALBgkqhkiG9w0BAQsDggEBAHPYBjNnv//Ssc8Elepb8SWIXRdahKbL
/dcPoMR+7yhJVaelUaxdwUytJWJAGdkkuv+P+G4b82RVYEXT+9k1S/aAfByFyR9q
vS7POfdy/ZPfGTXltlnmYX/84a6QeYQa4Nl4JpIOXBCesLxmErBhczka6D26iqsz
GeseKRSjVPgF3mXc2CRGZnTDRhUmd7wOABLmj7GtuFvOm96363M3IUByMohvoj1G
dic3s5D0seXwTKnEc5B27lJt7Q0oIXEldL+UW8Mo1hfGWQeXzqTZbpOVLnVWvHBH
H8yYs5hyH01qFJZbztJ1JJ3F2NpYLlr4P5I6fW2e9w5MG/VMQRU3wzQ=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIICxDCCAa6gAwIBAgIUdey1Pi3nj8syGBLqTY30bbsak7swCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICxDCCAa6gAwIBAgIUSbYQoLY1s6wWqgbKhxQZ3XME7ukwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBIxEDAOBgNVBAMMB2NvZGUtZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
@ -8,10 +8,10 @@ TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjFzAVMBMGA1UdJQQMMAoGCCsG
AQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAubYFMnDLOK8/99OLWeejdD6HQ8Qg2W4u
7I9hZySo+g0w2U6jvtgSTvUfN/Zk33fSu90yOnWg1v+6tvd/jdwxfooVfz7zNWa9
i6/oSY/0THBhX9bf9b0wHmZLnuhS7AwG6BCbqulQ3xJxCSWUieFTyoMl4UnW64md
QBI+ZkLkS7O71pARnw0SdE4nxO1J8fLPi/7nYHiGfebqcoBC/AUwMM/Zni9KFkgy
/uQRXUylNAgAByIdG6vS4ULgTKh34FS08Ff7/cWZppe9eUogLLQ+J2cyPupN8LYd
hWC1mCbgCX3QqHiHg6ACX05Zc3YFW80ddlczDVNpM09g1GSGYpllng==
AQUFBwMDMAsGCSqGSIb3DQEBCwOCAQEAV69uBbyc/d1eBdZlT7eAw4onQzkdndd8
kEXdmP3hd+jJm1+/F733IflLLqE5mmUL9l7q7EJ+TgdZa19T6JHEaVjdJcIuwJO/
kKSJXXqADQXoxHOZADDWjAFStiR3xd78BzYfuUANgozG6hq7QuVh0cYBx/8Q9gx/
pGtuCJiN0d2Mknu0SoQzIZlXTuqmnFj7G/88O5Yh5MaFZxbvIJJSIWQoS396GrI6
yXAdqHNoVM9mwwaMcnG5QeeKSIPuvEkZncQsxFc0zqIjeOVx/zEx2Bocx71dLuVB
fqrIrAXLpwparoSxLzNqq8UgtXF8NQOuAcUu7ok0r1VbdMbSZHZ3Gg==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICvjCCAaigAwIBAgIUMUZEIRRo2v0demTGW3vuRccAgCMwCwYJKoZIhvcNAQEL
MBUxEzARBgNVBAMMCmV4cGlyZWQtY2EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3
MDIwNDAwMDAwMFowHTEbMBkGA1UEAwwSZWUtZnJvbS1leHBpcmVkLWNhMIIBIjAN
MIICvjCCAaigAwIBAgIUGzSP8KEmmRm3sIPiyQW35sazlHEwCwYJKoZIhvcNAQEL
MBUxEzARBgNVBAMMCmV4cGlyZWQtY2EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4
MDIwNTAwMDAwMFowHTEbMBkGA1UEAwwSZWUtZnJvbS1leHBpcmVkLWNhMIIBIjAN
BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq
5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SSc
An7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39
ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYk
zBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3u
JtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQAB
MAsGCSqGSIb3DQEBCwOCAQEABbpfCUwzbTCDWWwBqaY8+3q3PjeQK/QdyI4HSX5C
+dp7LJF+x/24xArqKf8HTuhndprUvlJOFkojK1CLaece7yC1fh/viFZ6NLoTPNXU
cmdEHsrzO4LTOY/eeR9ml7Rx26B50Wva01SyXkW9TZbPGPQysCgD31XkxmzTAG9t
M5kp+XplMd/UEjkNQaXD0lzm3lJ+3n2U6xMmDc+8us0l6X8yBmjjywBWTSX+U83a
eZXMpU40Y4ZHyNqfALGZUG22trd+68YVvK7jmnbk9fu/FZkjh0qiPlAUJXg0OybW
YHerQxXuf+5+ftPTDkzyPY9txQGFoqY8k3zVQNw33wFzGQ==
MAsGCSqGSIb3DQEBCwOCAQEAZ6Nrb/1fit8cALMhcbmuZ5kd3J34d0o9p3g3E7m7
8RsTbYLA4xp9UmSzpO/10x9q4TUZ8jxW1dotoCVf7OqYYxQewrU2x3qoxKvP/Fvf
8ssWSIang91w+app+fv7QYDySymT6DJMLWyCmxyhaFjYnmr67GKldcgK9hbyjfDB
Rj382czI/HMSvw/vCB6rRKchzr5hsDGl+YN0MMI4M7/3b5wvMUmxlXqKu1VlslDZ
8Ez6ONuMdPJD3aQZMxmEph05pEMvhjFhLh+0n7kfLR+9n0D7IR9paVc6LgHLLxsP
ENoZLGOwJYNdAwwkd6fIa9E6KCpaRgyvWslm+iFCg3XxoA==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICwjCCAaygAwIBAgIUTUHM6wHTfIkC0P4Z9VRrPJV6O6IwCwYJKoZIhvcNAQEL
MBcxFTATBgNVBAMMDHVudHJ1c3RlZC1jYTAiGA8yMDE0MTEyNzAwMDAwMFoYDzIw
MTcwMjA0MDAwMDAwWjAfMR0wGwYDVQQDDBRlZS1mcm9tLXVudHJ1c3RlZC1jYTCC
MIICwjCCAaygAwIBAgIUI/4Y+KSEZo8YGQK6Ptrdmev5FO0wCwYJKoZIhvcNAQEL
MBcxFTATBgNVBAMMDHVudHJ1c3RlZC1jYTAiGA8yMDE1MTEyODAwMDAwMFoYDzIw
MTgwMjA1MDAwMDAwWjAfMR0wGwYDVQQDDBRlZS1mcm9tLXVudHJ1c3RlZC1jYTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
AwEAATALBgkqhkiG9w0BAQsDggEBAJlRi+i7+kPXxfx6If69aQMsAIYwBXhbeHJr
TfaljltazfCirKB1hDb/pTYmSFMWDO+C9GIRBBKWR4+rR6D8n1qiJOJqe+QHtQam
BPi8xMTHEkNVTEax+Ux2im21BPUU8xFzCta/STMCt2E+6g832JX1XxLxRlp631Vn
pF9MFZU9HQqW4z8YBPPKE4ny9eBOGH/PzYHETL5AgJn1K5iRFZjA94iwqsHvJ/6v
AY1b5hw1slwem9ZWYcoUUl3YAV7sF3pIbakrRSjU3HEfGcDUDOePrBZekJhICwK4
xs2cqEX0FLZqsNiS7rpfRZXt4Ufl6V3G8MEO010lICk9ZuHr9vc=
AwEAATALBgkqhkiG9w0BAQsDggEBAJqsDDoJqxrmV4Mlt815HmJwhr/SuYhPwhoQ
RyU56Ci5kY/8fYa3F1uxSrpzuiYBX4bq6g8keXmltPZGN9gexPP2QJDAecNt0NKW
+04ZKSiz6Tbu+MEyBaXCINDKaAHVPRnbMWR1eCyHzYpZRKZW2Sb2NinWGebzq0mI
wt5l7veMkL5ZbeYF8u8bNFsdvhl1PM7/AfAZLJL4+fncaqQeDRyVffxrl4mCooS9
DYajnw7AhFvN0XtXb5vK3HYiz9mv/OnXeoeWxYcWI6aY6LR0OwHHQQptKQSIOP87
2mo64IbAwzuBrhxNrdrQKCnf1mtyDZig+2r6R4TP3EM3sCNAoiU=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIICxTCCAa+gAwIBAgIUI2oh2cgrnM8p3D/8Ijd06wwY/UQwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICxTCCAa+gAwIBAgIUJctkeS6qP+WqsgOLbjATJuPlN40wCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBMxETAPBgNVBAMMCGVtYWlsLWVlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4Ngf
vbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTb
@ -8,10 +8,10 @@ uUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3S
O8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR
3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv
5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxcwFTATBgNVHSUEDDAKBggr
BgEFBQcDBDALBgkqhkiG9w0BAQsDggEBAIpPVolSwoZTwhouPemDUJTP8cZ/IPTg
0GvzU07GH7y0Q9svPEBELRdgdHTWk3s5FaLgVGYStzs9OOpNj4fiP+CUJIwKlm6L
Kt4mPganE67SRvHHYMzH+jjaL+xNl0Wa0O9ms+k+DQ+zB57hX8qE1oMszq00jZxH
VIRl767e66Jgh89ac5BGoj1KXJxtUIocTKC+fMgUHbQ4oZ2v1IU2CeE6k2cvWvcU
gclagK4EgWzIL8O2HLTLkLN163yWBYiOWQTOI+hCqsLz1OeU+J8pZ/eEYemeUV7g
opZ5aLRzvXAkNz/eaeygEAu+6wkqVj3Btcabvx7dxmLkwDV8PjJsscs=
BgEFBQcDBDALBgkqhkiG9w0BAQsDggEBAIFmRk4ZfcxWjetAoyYp0bIFLr5AjGqv
ecmc0khsRkW7NR23ywJsRsCU1u82JIGrE0bpDu/KQPAMJsi6QMc9hZEOzO1t1QmG
OJFLhCNTe+wf+5X+UKHKo01lEp7vDcO7DjuZIgEZSyOp9qbV88AtEiqESIzRBWYp
dL15cS1PDH8fa5k7MHCAh0C/HeDRD5EP8derIWWrFIesEdJAhwzMRzJrCWIqzLPP
Lv2gsXhehXCN7U14zkoGU97sSE09k5BopHd4fgqZesSApJrd2OenQAzdRIs3+UQy
iCs7oLH16lOl/yeRxVjcHRWaSRM47eGpn5+YOnGkoE/lqfux+jjB3rc=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIIC0DCCAbqgAwIBAgIUBdYRNGqgoPy8QL2qxNIAIbGiUsowCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIIC0DCCAbqgAwIBAgIUfQIwxuYCoWiJuu/qTiEf7fbljnswCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMDcxDDAKBgNVBAMMA0ZvbzEMMAoGA1UECwwDQmFyMQwwCgYDVQQKDANCYXox
CzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR
qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv
@ -8,11 +8,11 @@ WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+
rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv
JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5
Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6
clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAB1QaKkpRAhxoeSa6
vfhiJS9a3kC+ChE/0zRqu/wVaNkxlmnq6rR5e0iZ7K2Xo7FDPxfC14UolaTFs7KH
bEA4XzCvctDD7J1MTtcGZKDjH8ua4unpm8Ux6cnXqy3SpHzirshxU/cxOm8JtjmI
89Xq1BQ34fck+wNkK894d3+uniMyy4WrAiVeQHWQ6cUnzqt+8THgWXoRQSvMgEcM
ItSIylwll9pILylS5p7wI1upXkZD0V72WR+Pp/XSP07MOR13MPkAjZxXP/8hGQRR
URtLhwGrVf5Ovc9JnFhv3CqkKR/sEcGooA3VcCafVnxyucj1bmXmbkgWCE+b/zMQ
cVSPvw==
clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAJ2fIigbkc2Lh5Z/s
Y7s4o0D9UnzttXjjEqKYhttk6PJnmVYG3zn3MBmyWPhDcXYW9fJwx7IOcC0woVdJ
yjkVZUIlJY6xAqIC6kVNtbI3PJ+mji8qQk/ecXCwhTGk0H2lZXrUtc6WMmD3GUIP
yNQGN/qAniRLnXzzVY3MJPLKKSlWSJEJCY4F4uDwBtwudPc+1yRIR6XblEL3dazS
H2kuIzGwIu6/i3AN2WIFWFhcuRTfLZINlNeH9gYEaUrwI3MS0aMPqGXtOHz+imZl
RwNng0xaiDxZXcEPjrRw5HEZcIEGBc6X8WtSzbWufiWBqMue1ltEpc1AkvUamuB3
KJxYPA==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,16 +1,16 @@
-----BEGIN CERTIFICATE-----
MIIChjCCAXCgAwIBAgIBCjALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP
MjAxNDExMjcwMDAwMDBaGA8yMDE3MDIwNDAwMDAwMFowADCCASIwDQYJKoZIhvcN
MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowADCCASIwDQYJKoZIhvcN
AQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhX
bCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQ
OCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9
uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFb
t+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhO
NsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG
9w0BAQsDggEBAKAFuEA9TJ+o8myZ0AciYyCjsIcQhfPvL16vfhVmbr8IXudjeIQm
orBPLWOZWT/IVeLOYU+GecS86IFWdBjKLOMoPkZC3o6nQ95txGQrODN1uMQOQBc3
0AMQFnKbGCgoN8VtAsn7zppipvc6FcG83fh8YnrtGa8r9LBd5r2lX3npvG8qmhWD
J+2heHQp8D3NfCzad+jQy4hUhHalbH5aTky3T/1UGfgr/cXsDAcZb09Wd5tzDVpS
CP6iZyumHdH24ta5yYTHEEKDtR+/YU987crD79DcBK+7K2k4feFEzLfPDzmbtM3G
ZadO9SSf9GWHUovurJJNJaIBMYpNGeq4nT4=
9w0BAQsDggEBAF/OD4h9UNl2afVbw/Hv2dCV5uMyDV3T8iEUI9eiCvYDMAOElkAN
NZbDfGfQdg8rNLKG6r7Vz8VBu0T/Vn2lswtKYPll63ANv9qZVtKGsDTGzN8JSC0k
xgMbtVsj+OsJs81hmNnW6xw7wehpPw3l1UakAEb6dbYuYCanR/p/u/hvTz7phe9D
AsJyRAo4a+QDyeqgAPKrzTatawshNnz9O4QhNzUqj53fMkpUq2ebOyIGMOvbh/N5
nT6AVT2wn95mWawnS5v2VTRPALyMkgbl+0bb/VzXHN6CjDHO+n239lL2uQlAZFHe
8pKr4lmb82dLU9qUFbY7exLyV1aUyYSXSNU=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICpjCCAZCgAwIBAgIUS5/RALAav3GqFmr/hG5FumIUs/gwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICpjCCAZCgAwIBAgIUCwPRyN8HCSE5XEIq7e2eEEe1OdIwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMA0xCzAJBgNVBAYTAlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptu
Gobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO
7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgf
qDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/yt
HSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcx
uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEArANWYwZp
g5Z9sRrvPIaEjgJO4fnTf5/3nECTFljJH7YjGzFhnEGk52aRGubowhTOxAtqK1lc
cA5QRMuQ/Qrr7xZOdGfoxoMnQXONcEQNobcWbxa0Z8VZrpanAhXevlk5Z/8it96g
uLtCmgz32L6J2FpsftHI38+IAGjbgZjyOnyr4jGwgltZUKV1YRGClnMQnI6N/8TH
UrESziJ6JmVWnIwvKWvtwy68gRLvSaJ+lD1KTrqOVris0yPcR+dWlXaHovegxwDB
gkhtFOYJePK8p7op+WAyKlM922UYBC4X2h/4QeySrC2LYauGFz3ZARO2ylCJ1CsJ
ypuqIXstbO0h3g==
uLP+SSP6clHEMdUDrNoYCjXtjQIDAQABMAsGCSqGSIb3DQEBCwOCAQEAt2CF0E7d
QYnfn/kc8hb6GF6sYpCFA6egEzr6OsYMYE7jt5mKlMJdbIxw57L8jg8IZ1fjH5AQ
KA5cchGcgjCkHoJ7jOYfMZCubCBdrsNKx2YYWcna8WIAZjwOIfNC0Ajs3IDiRDWm
vlBrFP9Z6bGuzNrvLFAB0lU2dM2b99DqzaYNZeQP5DcP6ZjaPkSvqOWr3Lf6ZAvO
tU70OcTelx74Hj9bI75bxVYd71Vorv5qB77zrl7GHb36f2pkludDOKeZ6XhRgy9e
vN6DLctM0v6fJprG50xrILDhqsTydTdjhETLaIWhF9aUHzFybpFArp8TLoWbXiX1
eAVaASutFVprhA==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIICtDCCAZ6gAwIBAgIUG62RAQRi0nQBf5QEVbVQ6tS4QOwwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICtDCCAZ6gAwIBAgIUeXeYs5jw41bNt0btBeEFNbUQonAwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBsxDDAKBgNVBAoMA0JhejELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk
e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg
@ -8,10 +8,10 @@ KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI
YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi
lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL
HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcN
AQELA4IBAQBKExQp1zdXXkl60yJsRcUNBPbprmHDlYLFtAcAY7s8+IKn+6kWUgNG
1wrKsaoSJUxK8MO6ULSbK8Xb9djjZ5Xcy622cOe3wk3/AIwc8nhAE6d5mtCDzOGR
MWEn+wGsCtW+eWDTlefx/+D3zBNAsb7hyW54JKDjfRADN6VtFO4ca4Ybw92G6CRf
g452KvRl90oZ2cxXyxOP3qdMOpB5a9DkUVS39n7iWgv//f3qlo3eUlHHoeygJQOM
qca5cnQbYKhat2edgK5OY4eHCFOWXpxRy83/zNywLki4zozwXnTWSmuBpe2jZEev
nOCxqVD3xceDzZ3NNkFj+c7Q2IX0ykmf
AQELA4IBAQAs60sU1VqjaVQbGBHvBNyiQn9oTugmuEx9ogwVKhnmgRK+hYw+wgBn
H4yYZF1gF4xG7Rt+ut+EruSd4ht8vY9ZMvKrbgMrZ6HbNIZg9oIX+u0i9Bba2lh7
p87mCePS5L7U1gPbg/fZ8jd0FvW8EusC/TX5tOeeUnawXWE4ciqPZfIVriU0iCP1
nKzvFtawYzWwgN+QZ1ruzBi7qqrHNDAhgLu9+3g+9QyBd40XV7/EhDQ18kViaTSj
WmaUX7jJD1FUkGBkxjqHfgGkaYnt7UXGMDTeQ8vFeja11PJJIdRT8hSu0oTMdE6M
WCEw02+Fc+qsYH5I6vp3MOV8wyBqIqYc
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIICwjCCAaygAwIBAgIUI7neyiHwgLifhsVz4PP5NKkCWqIwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICwjCCAaygAwIBAgIUU/td7MxWYwvdFLfgNUraIpy3GP8wCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMCkxDDAKBgNVBAsMA0JhcjEMMAoGA1UECgwDQmF6MQswCQYDVQQGEwJVUzCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
@ -8,10 +8,10 @@ HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3Dg
Dw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7
EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
AwEAATALBgkqhkiG9w0BAQsDggEBAGKpDaMHux0AWDSH/3scV6W+6ZFtsAH/kTw2
zPfPad1z7xECUDzNaLjJYdTiXplBFoB9lFNmM2pb/Z98FZPLCK7wD36jLtSrBjLm
KlDKieE3aoHHe2RANz3fEod7jV/YVuZXLNQaMEMXAdXV1qfrMOuyiYgo+Crr/EMO
ApAQvOPxOR34Z7mBPnxVwn3w85zxrpcRzbg+UFJcr1yk0yKrlawSCB1CV/itIkCJ
sdpqub2wRy6w3nCwaCmp92bmDAOS9K4UG4tCvwKFihYLBx1MiVmUZC90nrXSynh8
b1hdzFnKZxzoZgM7yNuqw06Xzx0eg8yqi4wLjj+uA3UdZHP7MAk=
AwEAATALBgkqhkiG9w0BAQsDggEBAGbVHQ19S6R62HovLt9Ltir1z9KJ4QXWNAEu
FKicntKaId+jJY42y1+iAqQHy3FpjfLfx5eVKPW8vHbyTQSL/y0jJ9bPKepYsSay
5McWggOxMxVFazUCOntZN282WYIg3H/OFaeRarjeHlraZjwmNxrfHKzyBJ6bBqBJ
2vtmDez/+h+f0reutgnY1v4bJ02x/5YuG39+i08uRI0Vc+lrDiqDPYMxlmzwVvJM
xqo9TZu9gU4XFbK8c8EUsPjMMO1gKyroiBhthtEZ8a9Q4jdeD92cOZRcPrHtYyvR
qw9VhFLJRgLJ0DVOWqCHqYXUFfYngFezem1eeNxrz2eAbaURdCs=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIICvDCCAaagAwIBAgIUI3mu28hwWjSE4ii2aLFNdXKo79MwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICvDCCAaagAwIBAgIUcy9NBl2j6kWrXfJ6Na36AnwN2Q8wCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBIxEDAOBgNVBAMMB2ludmFsaWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
@ -8,10 +8,10 @@ TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjDzANMAsGA1UdDwQEAwIBBjAL
BgkqhkiG9w0BAQsDggEBACKFOLNLmPB5hFhmP3cruJydC3/5/1sKPmig+c5MMBKN
hgKaPhU6JalCdrHK+httffvjwXkPRdqWHWM9ILcDcAuYzJqIMofiFlW6gthTvvdP
sqkqXdxC2S00Dc55z47mKbLPkZm7/HMSOAya6oghywLuL3US6cmKrYZZbFqrecWc
GIja9MtthFcoS84u+GmV3pRiU+sDvwo67u7R3recmAPDU75r9Yhh68H/urKoRhre
+10QOfQ0GGM80RP2fXg6P9MXI7/MEd8QTlUOK8xWrU6Q30R5BzF6lgwUqF5VoVxb
WMPdPIS5gFktfqNituRNdMKlIFQ6f7YjaILDcu3upe0=
BgkqhkiG9w0BAQsDggEBAHw1PeRKbGVaiNBPlshPnuEjJ5XN+ls3Lv8CVplvuFgM
uvOAfuXNcLcQmqU4QZm9PvIboCAe2FTFMJ+szDbCIFaBzzJ4RnuJ0FnBZDf1fKJm
/Nj4XikPePo5DnsqSs53aNKM7Nf5dcdCCA8kfpMm50Nw6ufWrr8HAEqQbDixecv1
6as6xc458UU8AXKZb30VfLFAm0uPz2Y/ZjROnSqrNSB5ZRx9m4MqS3/4H7fSnlFU
yMcetH5ovGk3xJg65qWhaRlaoeExco9E5x1nUr+eK4OmP3MXlGbxxMQx1R43Ea11
zSyaqlhGUs06uDOl4rk4b2FmkPgGV+A26gtjMYD005k=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICqjCCAZSgAwIBAgIUT89onfON5U+5LLJ7imzzschILDgwCwYJKoZIhvcNAQEE
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICqjCCAZSgAwIBAgIURZ4xXpmcV9oh3RekbTwkCGv62NowCwYJKoZIhvcNAQEE
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBExDzANBgNVBAMMBm1kNS1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQQDggEBAB4q
QfSzrkQOHwIeVw/W1bpAzJ5Al92wDUNQEcw7JmZZ6Oz3bH+spBhq6xTnXqhMjCYM
srINOlc+u/W6TqE1uPWPZvX1M9VFCWR5okXoFbc+8l6er5tun6tP7oWs7TxXzy7O
e0GimlZ3W+LqA2ICynSYaULipFAJUvmmyFxlC3yPIawncpBWwPofPpGziF0FImSW
PMslU5PExu982go8a6hfNAYEYH8bKetlfFPJ0DHe7/crmjE3NulnHt7HVh11OkuR
FkjVTnuOoHGG4Z4tekPP0g1P+9m3EdTuP9Nk8hTZBThmRdAWIeBaefJJmZ91gJqA
txFeIhOo4f1whxqNDk4=
j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAATALBgkqhkiG9w0BAQQDggEBAKs7
7/g5m901xqDth2t0tDTFWlfh/h94KLk8d8JAAa8AMdVwpMUMc2IKPk+H+f7JkBeE
hhJ/r4ZEbQkjZuoLSkAR6aKRprE97Ddw1LJLVish39DitEXxpyDemCIl8V6E8FpW
CWqbOZtvUScOQOlJ2uJfPwHkh93RJbzP9EY8Hd2arFYKuExi5z8Z465feZ53mdOe
17WG9IKKIQirr4OAxD+ab1EdMuPuXKQ9qfg4fSW/LDsb97x0/ElRfHwFDxsbEiVi
zR/gGMW9AQhc+eW2qchjYkO0v/ps7dzjDQFDJzLAd/mlb90cK1cpUz6XVn/HagvZ
0MRczu3MnE6KRPVpW8Y=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICqzCCAZWgAwIBAgIUIYb+7rSz8q+7zTVh7KE/MZTclrAwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICqzCCAZWgAwIBAgIUD1t15yWPBLIhosAm9w9++t/F/fkwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBIxEDAOBgNVBAMMB3Jldm9rZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IBAQBF
h+yu2y2s3gulEXR80Hmm45+B/egT1K2fjoz8X5BcbqT5BcbPB4utokvUQq3W6uyr
AHVmo55vpgbWp1Thz0RoHGZ5kkYlcrYy1S7sfuoowoMXv8iWu9DSyXqhqSUhYp9F
9sov5d5lyeHLAekss1Aaybq0vh1O1tHtKHoanlfn5HEBDjbNpQozPh/kGQTuSZVY
e9Ikh1lFNsUCzCElC+wdkATQbo5PpGEsJqk5bmz7W9l90j7+JFdH5onIFD4gSOK8
2hsPCFDhmnma8/CvAY08hwEYmb26gnGQbVusIPr+Ui7LjUqW9b6XAdon2teXXEoa
vCp11ICfcHvIHhoLDjkC
8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IBAQCy
eobd3+MhGhQvhKQax5XNBqAEmogtsv6G1ZCoAx0kKU83r3Oj9ha4VfGN0syP8NQV
nmkecZ630QXQcyCD3RRiiLqU07N3nC5djm8v+vM5RhuDADkIwddH3WNWB+8KUJEd
3Sym1EN6xAYdQEAwWdPno73sUsFebuoL/c4gpTjD7PF+/vPzN0c3KVanlrMhayKe
3PLq8jST2OSdLvooa8qMYsFFG2S4A+gmp9Cx30moMG2+w1GBKZdtY2tlFx5DppIU
AoQzUl9pvT6AFDcY2RO6UvsWF9Pzr4dTjjgk8SO05jKcmj2GnBm480ZezDx5N5zm
+XVGgonJZRAucaVuJY79
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIICzTCCAbegAwIBAgIUZ71J5xveWHK5SkrwbRXbsbUtrlgwCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICzTCCAbegAwIBAgIUYfe94xSwDUoffRodCo1TPdV/PaswCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBExDzANBgNVBAMMBnNzbC1lZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
@ -8,11 +8,11 @@ wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMhMB8wHQYDVR0lBBYwFAYIKwYB
BQUHAwEGCCsGAQUFBwMCMAsGCSqGSIb3DQEBCwOCAQEAkDks1086hp7MS0anvQw8
XnkD8ItCFkcVk3aPdLlwODBGqDvrjIR9kCX2aJzdChiCnKPtN5pDiyfb/e+lJ4zN
qXoSP2ksYbFtFr7Vp/eDEI9iwvFTEubYgq9Y8etInetFxEqRQPDtAYtZF7P6i1su
FZUHlHYHsVmCCXXlhTy6BhmJCj0ANaquHHuACty55uNw2IbNYUKN7xp1qOJO2TUc
ip4fybk+Rdm5fJOj48W7uUBpvzfnLI/ifABuVRy2koZvIewjAwwPZ8ggWyi6PHT3
iLrLmorNMDWTWN898zO09skrcobFKrWJCuSafAeZYCYHDC7x1uVlLDM+v6N+fN14
RA==
BQUHAwEGCCsGAQUFBwMCMAsGCSqGSIb3DQEBCwOCAQEAprVI8tGWBHIN2SV66ZnC
vOfWcQguUQg8QO3Al+O4X5U18hzgsmCjqt99b+oJCJD0qWBnPPBgqY52pckCgmTY
w73TZ5w3Rnr3v+BlQ5xPTyAQoUeutm1LMxY/Ju7m1XV44tyDnq6GZbOZLVWtRLXe
W4UEqVex4qbCw3GOvFyHmubSNUk81v4Iexe1SmIJN8glZsVmWJdaC2Xo7qhz+vvq
HljfO+/ejiBtZOJSf9qG6HcGW/Rf15Io0e+IA6jbZWrlAzIjBcYKumZF8LjRONHZ
vwiCwWit/IP6KvmsHAb7wj5c0U/p1TuyGdvu/ccp6nCdx8Ya7/QKfAEQTZXnloBG
4w==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICtzCCAaGgAwIBAgIUc97erK6I1KzZpBDPfRQkFj/yzHQwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB3Vua25vd24wIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowGTEXMBUGA1UEAwwOdW5rbm93bi1pc3N1ZXIwggEiMA0GCSqGSIb3
MIICtzCCAaGgAwIBAgIUEfR3vHTQuzModYBSMepORIL++2gwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB3Vua25vd24wIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowGTEXMBUGA1UEAwwOdW5rbm93bi1pc3N1ZXIwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVo
V2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p
0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKk
fbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZh
W7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EI
TjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZI
hvcNAQELA4IBAQAzi/BVt5ZYRAbAI1sue6Qduqlk6OwVuROZS92xoo1G+bqJuMvv
K1jiJWeZn1xGGrZcCeyTnf+Qst4Hd34PLApNHfDPdNW9C7QiTUva4GELCZsCS0+b
hkX1W62OCS2gY64KVriAzbdKgx8nWhxlEa8zKBJEhWsX0t6PmjCxTEp1uyyJDlgg
vG4OEvUxywbk/MDnsjs7pJ3jUZ3DVQb9t6+z5w29AL7qpzo0CZ77YEuZsV6IuAtg
mNG1jfg7EkWBuxhHoI9UCqMquS4S9IHhuaDQ/qK8hBvjXTRsXyCKuwvIcxEns2aq
1fIW02nd0nX6+UxASTfY+grYNE8US2XFluE3
hvcNAQELA4IBAQB4pRQvglUpzNZ2fH0oj5bcqfcTjE3dwEzGg7WaMD2t50zKgCRp
2sDObvEB1Nv5SHSkebxDeS9xQ6Dghf+TvuCnkapi/6q9etP51lkIOhl6okAGUwdZ
vO3duIvXCVUWbut3ATQghKovDYuJXKMx1OYapxyLKKCsdvTQ8LNQpPcwbpVtqWKC
jLYpa1i/vtn4Pv8xs/ceOf10z5AdydpFBgZ8JpY0CbRI73WHR5fr1yYI7tfzaAA8
d+OBZ7nqlg81khD/Oepl/h6/IJ3L2eB+lUZx6+yWML9jRD0HX1xRje19u2vxCuQ+
tNo6lQr9fTRG76Md1d4fdg9+F9LGqDd+yBBv
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIICzzCCAbmgAwIBAgIUC/H/PjmG29sIm7mYo9C4emq7th8wCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICzzCCAbmgAwIBAgIUT/T//UMr8YnbQBWj+61OMGPKRC4wCwYJKoZIhvcNAQEL
MA0xCzAJBgNVBAMMAmNhMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBcxFTATBgNVBAMMDHVudHJ1c3RlZC1jYTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
@ -8,11 +8,11 @@ w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUw
AwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQB0kH+mBoFNCKtakbPa
WoptSlYB3v0Hivr64+6RGgbE1Ns0ZcEUpid/0PYCPo+2LE7Db6LRMmygQZ67G5Wq
SQN9Wb2WR/RqwikX+UbsbRuTElM+QMQ2AmOKBjmF7krzixq3zP9/c+CtSN4+E6Qo
XvH6GO3HWJ/7QdS/oGgbP63O9BszCOmZRAjNcBstwiVSxKSvJHpelbHsN7Ml4k0c
CXRkxIebfNUcHSSAgDme7f0bGgG8XJSGONebLAJgQcq59EHYD5sE2xR0rF2lmFEq
LO5IlW7TfTEGSQyinYO09nXcwuIbyFdYKaEBtE+ol6GIQyZGcb2AqSVXiseEWVId
B0CN
AwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQCiDFgskGRygaarkruu
gTwsX59ULb7yhXyYKZLTdsUitHi8Zk4KUmsbkBHGaek30Ud9A1GyLzuP3hb1/M7M
FdARYO8qrl414tW3hiON36R47qtw5cO6a2YZfvxU79esuoa6uxChhHLUugqNotJb
bbGwSMszKzkGtOQ5ZTFNc8+t1kWeQfFoPMznjg5WC2oq9Pl45Rt9lFrU3SD8MkVA
8fLAGR5TEOY2ZvjDDMKg+ceJNIaA3SPXDTVSXWNIakJU2vsdUXThTyfnoCw0sMQG
ZwkmKbCXioYXDB/nrjoVBgJh85JSc4KX137y5m2FK+wHzkKMgf4yn6Ql2eg/yTen
CaeK
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIC5DCCAc6gAwIBAgIUZ0oJPtx/+Z/XhMrbXNEoRnqL+VYwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowJjEkMCIGA1UEAwwbRUUgd2l0aCBiYWQgc3ViamVjdEFsdE5hbWVz
MIIC5DCCAc6gAwIBAgIUaauScBIwFX7ueYmCXknl2gMYElAwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowJjEkMCIGA1UEAwwbRUUgd2l0aCBiYWQgc3ViamVjdEFsdE5hbWVz
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2
ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdF
h/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6n
@ -9,10 +9,10 @@ cOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAv
OnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2nj
tIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXt
jQIDAQABox4wHDAaBgNVHREEEzARgg8qLiouZXhhbXBsZS5jb20wCwYJKoZIhvcN
AQELA4IBAQCTfW3PqL/kgGyKiEDJMNdg+7oiwqaU6o5PP4zjE95Rl/etZgdrvcRI
kgQTdA4OJrW9qGQcia0lk3jP4OYxyVfkMYvLTen/cT60yBl9h7r03itzgDwPBa3d
ISdjZm1a8tPkskwjARYh+k+aqInSN5CcrjIp73ZI7AW9DuxhgTbXrFi+LDxwgk/J
Z4CdMcglnCMRwQ/wjaXpvuJjyOb5yP38KCb9V6SGr6rAWFj4dpkdpHL6859jDaeQ
TEae93OtgGGFVNwoqbfSTraRPu4ei4qNDG5D1Pg8WCnu5aMsnsrhdv58zgzszV2Q
fr/jDAA3BhKkjyFN1lc8GLZaI2hIw/OJ
AQELA4IBAQBQsZKhZe/1VkfifLqD4bni/7VY8xfXQO4DDu9HSkFmeJOhaIzfdQls
q4LN+HVuJcJQZD1ni24UbJib+Jh8cbuzRA8l6w+PUBB6XPeF8BfYDkSbDoIYxj6h
OclX4HInco4O4Ul+1K0u7qF9xtMYK+xaAZqiEzU638nW2n5EWV8v7y5dJsmx7rz3
s7boQNkjgZo7R0Lw5Z8zzKYE0jVp+dRztP/f0X9uG6YW3thFIfHbewXBKP1kiIv6
jymQMdcdnc+LhtM5/+KJcCstGA1YUaZ7pNkU7/KyB0Ch1m+b40EOSnZKelUFkmvp
yaMC1hUND9LZjKwnGKNwuF5HR4OX/w0g
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDVjCCAkCgAwIBAgIUVVr+LToc+550ED/EYrG46cALo4gwCwYJKoZIhvcNAQEL
MIIDVjCCAkCgAwIBAgIUHY/2g5fyvV2MONrnjGi3fWc83j0wCwYJKoZIhvcNAQEL
MC4xLDAqBgNVBAMMI0JlZm9yZSBVTklYIEVwb2NoIFRlc3QgSW50ZXJtZWRpYXRl
MCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAwMDBaMDgxNjA0BgNVBAMM
MCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMDgxNjA0BgNVBAMM
LVRlc3QgRW5kLWVudGl0eSB3aXRoIEJlZm9yZSBVTklYIEVwb2NoIGlzc3VlcjCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
@ -11,10 +11,10 @@ EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SK
lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
AwEAAaNiMGAwKgYDVR0RBCMwIYIfYmVmb3JlLWVwb2NoLWlzc3Vlci5leGFtcGxl
LmNvbTAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9sb2NhbGhv
c3Q6ODg4OC8wCwYJKoZIhvcNAQELA4IBAQCc749RSjx6UyTbEmLD3U5UjWE0vkoe
QhvPPxZsTdywmvhTPolLwJrxTURyHZsbqj1ABY8895IRLzBZs90BOpzLHAhjz0yE
hJMmBwMXUJciT6Ws3hm5f7TpbbL6iHuL8b1t5E9Y94eMYnziu1xhTfRSgmFsjHI+
LRE42COnHq5/OdBYiv4p8xh+0D/r4IdMKMVdAnd7qVyAXuMo5ejji+UGtk1TPNWL
zjo9n9UZZmJcCPXUCHlnBAUchXsVeIXDhx2O8NxrshrG2qvpTZFEe2lg1URS6C5c
X7X4/QMajKsfkTSjLsXUVsbXLSSM6FxWMACFpiXdpiLSSgke9XHidkKF
c3Q6ODg4OC8wCwYJKoZIhvcNAQELA4IBAQAAYmpIy15lrWSrorG+HfjZNckhAsCG
1BOVYRr+s1Zks4wj1aMXFSzblgNgdRuZA20TkRfJKw40cyuNLfm5DhKZUbo+0LAN
jthu2cHFBaQn+XV6xMb2tEKTU8rBqzAYIAnmEIlLukYQBVICL9tirC1JJhqe1/S8
U139izFYNnSqNmss2cJOuI4VM7B951v1h4mQYfcX1Sv27qWaKBK7k9fKBWWE0DCX
YR1nB4RlI+92ncTOwbjtXR92gqR/z1wGDOPj/0VNNUn4SKo5Xif9TqXh4LhnY9fD
HgoZSMDxftXou1MjN0cWnIP6QMyLfg2kSN0vnQpVle6KgsxpfrgLiMoU
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDQTCCAiugAwIBAgIUQfb09PMAT1SEtF4xJshkxtV9Hr0wCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowLzEtMCsGA1UEAwwkVGVzdCBJbnRlcm1lZGlhdGUgdXNlZCBhcyBF
MIIDQTCCAiugAwIBAgIUBUmy5jtGrDso26TeIelwmtF+KFAwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowLzEtMCsGA1UEAwwkVGVzdCBJbnRlcm1lZGlhdGUgdXNlZCBhcyBF
bmQtRW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
@ -11,10 +11,10 @@ aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
MdUDrNoYCjXtjQIDAQABo3IwcDAMBgNVHRMEBTADAQH/MDIGCCsGAQUFBwEBBCYw
JDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzAsBgNVHREEJTAj
giFjYS11c2VkLWFzLWVuZC1lbnRpdHkuZXhhbXBsZS5jb20wCwYJKoZIhvcNAQEL
A4IBAQCESfPz4M7Cm9wd3OekRNB+U+FRT0Mc3Hu6NJIlW1NSCCxhHjdw/uXUd4ZT
/vQVFgnicOoBkWNuDmq0EEy4bezcgSCEdYbQ6DBc4ce3+q1gELBQCUqP5ocUqS6a
nA9rRYn2ycZki5OYfW3y6XfZQHKQRDjTCKxGrsytWMJdwNhXaa8dB0pPc3vgob/m
URxozNWu3nLMfvKiZl2wBz34vbTrV1cm4J2p7Il2nq4F0FveHfDenmp8FoaFkUCy
n5yPuOCjbRAYMYFJryO+6aRreHjrQC3B9OQT9CDr7W4smE47IHE08IfIVhsNiCEN
aYahky99OFB4yK9kCBJ5fhEY6qCw
A4IBAQApr3pPS4uWz6oPEhrTO73K+JTP2VRTKgtbooPhOZ6tCRz75P729RzVOEZF
Vf87VSFTTXUdG5Q6+SDNuCdDuyyPR4q38s+8jgv3OVfsEbhPuSx73pLAzYg727Ip
U2ROGoVysc3JrUfwPZSvQ/i4iqdb2sVwtqR5LM1nApy5+p6Ef8cwjfm9qsdrHlnx
3VdiioEOp+8SKH5rzfZe+1jepRODlqvFEO9gFbaqjHLzL005xAcfpsZPH5JzDhqD
g4QiIFlm+wwQ9pTBpk1ZmbgDyk4frrxughFsbR4zDDTfJCREa5RlwH34xOkx/cTu
ee/qZzerx61VI88GvLK87eX2ZiH1
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDhTCCAm+gAwIBAgIUGydiTcNwvz22Zpgz2Dx02e4sVsEwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowGjEYMBYGA1UEAwwPVGVzdCBFbmQtZW50aXR5MIIBIjANBgkqhkiG
MIIDhTCCAm+gAwIBAgIUNRvpOhsDHEYbRf6bsiAPbvKe2VAwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowGjEYMBYGA1UEAwwPVGVzdCBFbmQtZW50aXR5MIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1
aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/we
adA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSS
@ -12,10 +12,10 @@ MIGQBgNVHREEgYgwgYWCCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbYIVKi5waW5u
aW5nLmV4YW1wbGUuY29tgigqLmluY2x1ZGUtc3ViZG9tYWlucy5waW5uaW5nLmV4
YW1wbGUuY29tgigqLmV4Y2x1ZGUtc3ViZG9tYWlucy5waW5uaW5nLmV4YW1wbGUu
Y29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9z
dDo4ODg4LzALBgkqhkiG9w0BAQsDggEBAKz1r0K+VORxth3U50e0l2zywRlGjIP5
hNGkLG0aNWifnGPpw3aMVWCvIUHa6R+7xuKg3EeqnknT0D/g+vKrzTnOVsu7tt3o
+llvXOuRAUCoa19W4kM8/750r+c2i5N6HUDYaeMg8J/o6c4J6vnusFC9SBO8MR73
ijnpeSOc/huVucUx8Njko578rfaRcYdD1yOHVGm/d0UF2T042WgBmmyj0W0aO5Fg
tRgMW45lx7QY1RpLqwAOV1f3LYVgtoCkhP14skkKaqNsUIZqxSV9Z7KwXm1oZt5d
ZD0X+b3+0JefO52/8oO/fWJt182xCb2Hsz5TtbIWpQ4s9LHR+1bPTtk=
dDo4ODg4LzALBgkqhkiG9w0BAQsDggEBAH6+Qe/y1TTCx2w6f31VWp5lcizPkS8s
ODfbgT9pKYqqvYDeiDu3q8SLGHTTsHWWewBCu5Jd0mXPXfZ4FEHcwbVJZUZBvQVr
1aNBCriuzhNUyfjkvfCgM4OuxgNwjbihGDE8VzfxTiz8mDN0AgACCZaUTQnybQc0
SW+ldxspBgQJom0tkZ+TGi80L3/5P5J2+7AchxhAZzQmebDnxNYDZXCJH8w15was
OzM5BrQzz3vuxupO7lsRzZIzAU+uQD4bjcMpz3oMdj3/0lb0HZGMdU22Ub36PvLC
6mYbTtf0IS5TVyLnbCNeliE6zoPnQPBzAUfoOeD1Tn6HQUQUT8oTf2E=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDITCCAgugAwIBAgIUf1H5JdnGe1twEedkLyafrWOU2iEwCwYJKoZIhvcNAQEL
MBoxGDAWBgNVBAMMD1Rlc3QgRW5kLWVudGl0eTAiGA8yMDE0MTEyNzAwMDAwMFoY
DzIwMTcwMjA0MDAwMDAwWjAeMRwwGgYDVQQDDBNFRSBJc3N1ZWQgYnkgbm9uLUNB
MIIDITCCAgugAwIBAgIURex/TuOH9TNqma6czhjn0gJqzqwwCwYJKoZIhvcNAQEL
MBoxGDAWBgNVBAMMD1Rlc3QgRW5kLWVudGl0eTAiGA8yMDE1MTEyODAwMDAwMFoY
DzIwMTgwMjA1MDAwMDAwWjAeMRwwGgYDVQQDDBNFRSBJc3N1ZWQgYnkgbm9uLUNB
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2
ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdF
h/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6n
@ -10,10 +10,10 @@ OnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2nj
tIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXt
jQIDAQABo1swWTAjBgNVHREEHDAagglsb2NhbGhvc3SCDSouZXhhbXBsZS5jb20w
MgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4
ODgvMAsGCSqGSIb3DQEBCwOCAQEAa1/9eVx+H48q63fB6yTK5Lk4loAxWEO59a7h
PVRJKW54ihRH0HmQaaZtmprihQBLnzQRRJhsnIQ0og6WAWqPCLKJU7TbDAyRqoz1
LKKs+JBFOu5NNZza2u3/7hkTVqBfwFMGm/zsnJZgEcebZr6Wbmtncu7OP0agMHol
H3+xuP45tlmo0v/st4JUUL163u4QSUGJ2OFkKZju28in7Dpugha+FB0glagAyc2t
Pd22Nfeieket3XMB7DSlhDWgcMT62ufg/WRLot4zh7ShfJUGAnsc/u0tDwqM5zWP
QkpxKhULe/B0GwB7+ObAT34/Lr3bAQ79cxOfBP/WT1m6R8BF9g==
ODgvMAsGCSqGSIb3DQEBCwOCAQEAnLI+egtdtaCj/pGgINrEi98m6gvK+wANDhDS
RhX2IztG/xuLCXIEcecjl2ifppklo6BnGqMebuLxndygkEGXiuvTvAbtd8Ac3s7O
Cln/JW3OOBs6a3UJJeo1rpADn5F7tSXJshnVFNshZlXACnb25JIvKKIZwEhNKCmz
whfX5xVW7RumZ5I4BYrE16YkQKQ9Fc7orioPbcTfH/zmoBBseMFi9UHCsI/u6P2/
2DpdD2hlld/Cy0cEzb8IJFnx1CYIpfKCP2OZR+YEn8i1P6WwEyYy47YlFmZGkVmQ
t1zEXNWT6xdW9+jREoyvl2pb/4BzQDzUhUg6P1jbFqHKtBgFqg==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIC5jCCAdCgAwIBAgIUcfT2W+hqx+xtzoUeW/Rk4GxQsvkwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1YxIENlcnQwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowHzEdMBsGA1UEAwwURUUgSXNzdWVkIGJ5IFYxIENlcnQwggEiMA0G
MIIC5jCCAdCgAwIBAgIUWdJEDrMcdJcIJoGstXeNPWoUzCcwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1YxIENlcnQwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowHzEdMBsGA1UEAwwURUUgSXNzdWVkIGJ5IFYxIENlcnQwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erk
NUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwC
fs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1m
@ -9,10 +9,10 @@ CyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTM
HGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m
1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGj
JzAlMCMGA1UdEQQcMBqCCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbTALBgkqhkiG
9w0BAQsDggEBAI+/pu+8iiO0FI/jjGM+Kc6z7ehGt8bCfEtQXjQcNpHRm7u0A9CN
ngDTrEmZfUsU0ATXwLO9bj+ecXRmjlZSZXifqL2GFg2EPlMSbCWvQI/326Axx0jQ
lzydPGCwhgva2/U69gq8ldSZu9uF+kD9ciM4jxprO3LVqVv+J4okoSJWbGtsyapf
bjMRjE5V+EfMKx/eqGth7H4q9nFo4CE9gtVLuywJBDMZ0GVtkEtzQtONW4ImHX26
CAwezURS9HICZwbaAurRcrG9+EK2yvURsJ+YAbnFOs43/hFKghGcQ8j/ZcB3yzPk
BjTiNsIx2fkoqwaBvQLldKg9omq/HNvTq4E=
9w0BAQsDggEBAFlYTwajTjFg0lvULVveYmWQWzPlRjdDi+TM/guuC13D9sDXN9vi
y5ofPdtqlGo2owjEe8XII/3enZHJqJAk/zDcjVg7ErXoui54K5q6eZGN+6hdhiGB
iT4TxrHAQXPfkXgLr6AQx0JkIO5G8l/PZDETLkxNMoFssQwb1x2D28LxYhqcGQJY
A7h8M8kMNZiltGqLUBXdYdmM1IljJb/BlqULV7QbCh8jXsvdP3leIQCRK+vUONcK
MjnLEzAYhNhRYWkjCBF/Q+qsPlL/aSbkupr6z4lXuCUIPF8TWs8q0V0uwGeOT0MZ
aWkw8tsi1UYRR9Z5WdTe8l0dYF0G/kpD44Q=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIIC5TCCAc+gAwIBAgIUOfhaGfji7wWORLPtvvh3qwLG2EYwCwYJKoZIhvcNAQEL
MAAwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIwNDAwMDAwMFowLTErMCkGA1UE
MIIC5TCCAc+gAwIBAgIUWcXPQzwjDQvgxBhAb1cUwuJNgfswCwYJKoZIhvcNAQEL
MAAwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowLTErMCkGA1UE
AwwiRW5kIGVudGl0eSBzaWduZWQgYnkgZW1wdHkgbmFtZSBDQTCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs
9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8
@ -9,10 +9,10 @@ kqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJet
lmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2r
kQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMqMCgw
JgYDVR0RBB8wHYIbZW1wdHlpc3N1ZXJuYW1lLmV4YW1wbGUuY29tMAsGCSqGSIb3
DQEBCwOCAQEASD6B6KgSrGdbF/gu9B7K3l9wbqj6LpnTxdgDuySAHZNkv8yjR3uR
Y17lj+AwHtmphWhdwbnRzRSFRbVIZWfGhsUqBYGcL9Avur1oGbEPsKlQ5lAcFZwY
XknWccmfhI/BDd99CIq5oJtMvZ7b1v/9ySBSNCyiztU8mTuXEN4fIEXQ7NnIFgKb
RNl/mZH5FBOQygqYN/JvyGCjOY5+hmOiDDt50th66s+kt8SBBP/oO4+lIBL5kDW4
WwnRVLDGQBT5F7x0Xt4StI+Wh3gsCELRq30yeiXSOV1ywjDkivGzW4WoumOzj90l
9ScI6+32LtTdUGkBnLPocSTRZo8CGLDU3A==
DQEBCwOCAQEAqbRuhfV+zSaD8FqWMaaX3Q0V08aazNE+xt/4z0E79Ap0LWUs8h2j
IVC61EsJKrgYMseNd6DqyzhucQYgH1yuyZjb9VC+BuEA/GvcbzxMKr9jf9hMFXvf
PtyrAPDKbkscfjF1Xpq0nfTld0zxDaa01lZEyY175Ga8OM0oUaOr9tsa/m6d4/qT
2J1qOus/doyoD8CJB5vOAFjK1C0u4EMmZoayjiOQori61wsmcn6I077Pdwbhi49d
iuZGc3UU9VBPyQ6CWN5tP2e2OSfT3p1ep/7gb7RJXQXEHksokq53Rg8HM97wQxLi
134jJOJFJmeq+8pZ9NSTwrA6mo1nLfiPwA==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICvTCCAaegAwIBAgIUPaQULYcIRJvvQrmqScjw4oE73zkwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahE
MIICvTCCAaegAwIBAgIUQYl3Nyjq38ZPBpJZBi8APD7LGXcwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahE
jhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1
a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1p
GrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW
2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcO
p2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJR
xDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYw
CwYJKoZIhvcNAQELA4IBAQC4DOrJRuOJv58C8WhWUDeArR9JcOBk0Lzarzk0xE1M
JpkmGi0EOlxTCBscbjA7rOqLn5/Rfkqyt90AukdAwUuz6q+59D8erZAwulkMT90M
GGQPbVl6Jqk9zAYhB2hl7Go6b6Y2YAOJdIBMbEjUJce4dY5UoaEAvDbXQLBouJZo
Jarc5sFM4Aq0OjXVFiF22JHIAs/ljTqRFDVL7smr4XfWet2AcPMhnaTFKMpzbfa2
C1L0SebD8DR0tnVQiGF+OqvbXrOoxFy6zuBydYPZWR4GOc/zvAGBS0XwieOKq3op
J0G3TTIc/6NtNlHbf6NT9ien6FMdk/XvqV66YVHLFsF/
CwYJKoZIhvcNAQELA4IBAQAbXSUfUwpYXLieOce+6P1Sqtcg0nuDf46vmR+1vykN
sRZNnvsO32PNCh+WgsvJ/Yy6SPS3LKG/NwBK2yH0fiq/b+JPK15cvV/hRkb23ght
4D1+CZ6hMgirvMDFMk9wb24zUMn1MshHSfed5RM01GCnSTsBUldM93bFaMNlghyH
AIFz3aj2VTMZvL8XeoytDChfE/RYoI4eFD8O2MPyRCkJ1grN8PmpoU5xdiDIpKIp
4UK5/SnRnyci6oBpjJTECnboTv0qyfpODr/QBU5iO+8Yg02Uco27fiy5MmcejRg1
7+pRFfrvBU7DP3uJhGOTKZzsrgsrYK6qSo7zbPyhD8oJ
-----END CERTIFICATE-----

Просмотреть файл

@ -1,6 +1,6 @@
-----BEGIN CERTIFICATE-----
MIIDNzCCAiGgAwIBAgIUdakyQxHEOz8eq2oddSdoUYT0DP0wCwYJKoZIhvcNAQEL
MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE0MTEyNzAwMDAwMFoYDzIwMTcwMjA0
MIIDNzCCAiGgAwIBAgIUeWc23T2mQmvsb7b3an7jH8J3eAwwCwYJKoZIhvcNAQEL
MBExDzANBgNVBAMMBmV2cm9vdDAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1
MDAwMDAwWjAfMR0wGwYDVQQDDBRldi10ZXN0LWludGVybWVkaWF0ZTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
@ -10,11 +10,11 @@ bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaN5
MHcwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwRwYIKwYBBQUHAQEEOzA5MDcG
CCsGAQUFBzABhitodHRwOi8vbG9jYWxob3N0Ojg4ODgvZXYtdGVzdC1pbnRlcm1l
ZGlhdGUvMBEGA1UdIAQKMAgwBgYEVR0gADALBgkqhkiG9w0BAQsDggEBAEnoeMK3
VQ18/OA9LzFSlkr8YFLnz/0iL8l2LnftDtcoTckr3Zhyo6HdQDYvWf7Ox1sN3BLB
PFgQ0bEWSLRUSCTuUjLM+gKR8Dzo5LWY3ZyHh851NRP4o/mwXujr4qlMiCpKMlJi
itjIIPEID2/oFdf8uujH+q6/Mk038v+Bq0FcfLmpcfmsptCHza1Ryw2lxc3WVvOv
J+5t6qA1H6xJIVcb0dQwF5doTMV27YDmuLyg2VTKnoF4Fux/glH1v/YXdfxi6WKC
8L7jeeVMurd3huWLRIoBimOn26e/wMQJAJMOXfwnYU1RULgbwdFCVZUeSNYW4pDY
4ga6LzbJdLBvb6k=
ZGlhdGUvMBEGA1UdIAQKMAgwBgYEVR0gADALBgkqhkiG9w0BAQsDggEBAHZl5S4d
aiBNutInbA5t4qjcyhimG10JI70r14ijN5RXNf0TjCJjE1GDCEz3/VGAH+TFMO+c
6jAKGro2hojGPwnth49D359dMMgppcpRGq+G4paB8PuXcmTlF3slFfDa8KIay4bB
+g2db724ctqtXEHE5/FcmpTNkZftO1lHCEw+O1Sle1Firulo75WivLWyNsOh2znO
+pBQ98oYqb3q+LmKnlFw61cFLcpJ6qOs9d0X0IvGHbh7KL9Hc97orLZ5qH3UsV7k
Ews3BJjSqjZj75nciNzQUfEAYCK+t/I/tDSgebn/Ka5bVAv0iuglYHQksc4oXVgB
WIn/SxQDsNphGGQ=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDPjCCAiigAwIBAgIUD91RYDYNkAEZj914Ztj5ISzYywEwCwYJKoZIhvcNAQEL
MB8xHTAbBgNVBAMMFGV2LXRlc3QtaW50ZXJtZWRpYXRlMCIYDzIwMTQxMTI3MDAw
MDAwWhgPMjAxNzAyMDQwMDAwMDBaMBIxEDAOBgNVBAMMB2V2LXRlc3QwggEiMA0G
MIIDPjCCAiigAwIBAgIUJ/RiEbbZUXgHnSnds1C7ViloXtQwCwYJKoZIhvcNAQEL
MB8xHTAbBgNVBAMMFGV2LXRlc3QtaW50ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAw
MDAwWhgPMjAxODAyMDUwMDAwMDBaMBIxEDAOBgNVBAMMB2V2LXRlc3QwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erk
NUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwC
fs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1m
@ -11,10 +11,10 @@ HGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m
fzB9MDoGCCsGAQUFBwEBBC4wLDAqBggrBgEFBQcwAYYeaHR0cDovL2xvY2FsaG9z
dDo4ODg4L2V2LXRlc3QvMB8GA1UdIAQYMBYwFAYSKwYBBAHrSYUahRqFGgGDdAkB
MB4GA1UdEQQXMBWCE2V2LXRlc3QuZXhhbXBsZS5jb20wCwYJKoZIhvcNAQELA4IB
AQCGr7tHhNrdziIH9DlTc6KOtwgHAC/9oq2t5r+nTw2PAzGnXlVDhechXaXHYJJ0
6PAEh+VkN+QGluG2qUfQsKDoMMNTOdJekZWlnhPuAwQPfjzLa06yLbmzMwUSHJZU
XdeAbf1o79xyMHfJMcmA5pduAv0RAsAZl6SyiR5Fm6nORHVHWu0Zw9WqPDBCb+BW
Mx2Lgl3M95jAbUeR2HfDOHTh3Crpf0V8FL2n9jFgpQ+niO3JFZOBg3dVQ+BMIov/
pldY1jGnSAaf1xGh3vL5ildKQVH2an69KjIliwofEW0qq6q4OTZgZXYBuARzGvPl
Pbf+6Wnb09vLKtJ4QXy9cBHO
AQBvoPaWE/YaF3sD+tYoAGdjNDbmQcP8QRhVG8wlIWSAfk9RRbvUbs8RNjdXntYV
8J4ikq9/ajwHN85rJsRq3054qbqjit2Cn73tVhTzhe/h8xnXjLA357w/jXXXx1lD
VZKxUvWqTvC9tHPjF3w17A2a1/3OltdLHPfzWF0Zf6Zo4uaaI8x+ayMMF6MCS3ZC
FM2fNvIW/euVhjtLC3b+++5lMq/ZZCuJGB1kANDsX5LpXSZ23AXNhPrPxvgkmfoB
TPoBoy2kD814qljp8G8RguNYpaz5wSYXZNROnVBCqafEbE8VlIAwAxWp5H5qN6Et
F3OoQMb5dBIffK3lNw6UjFaZ
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDPDCCAiagAwIBAgIURyUvvAxBjllsvSknUWv3jipp9/cwCwYJKoZIhvcNAQEL
MCQxIjAgBgNVBAMMGUV4cGlyZWQgVGVzdCBJbnRlcm1lZGlhdGUwIhgPMjAxNDEx
MjcwMDAwMDBaGA8yMDE3MDIwNDAwMDAwMFowLjEsMCoGA1UEAwwjVGVzdCBFbmQt
MIIDPDCCAiagAwIBAgIUS9fUW0vPRYOaV8nstqC62Y6Qk08wCwYJKoZIhvcNAQEL
MCQxIjAgBgNVBAMMGUV4cGlyZWQgVGVzdCBJbnRlcm1lZGlhdGUwIhgPMjAxNTEx
MjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowLjEsMCoGA1UEAwwjVGVzdCBFbmQt
ZW50aXR5IHdpdGggZXhwaXJlZCBpc3N1ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg
2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ
@ -11,10 +11,10 @@ DJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8W
iy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjXDBaMCQGA1UdEQQdMBuC
GWV4cGlyZWRpc3N1ZXIuZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsG
AQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEA
Qv41tO8/5rlJl6VWYHkC27tK5XCf/0mvn5j6na7d4bo80yf8wIctL57smoIO5vIv
qPt6BfnV2wfSqdWq5yy8/INuvwi6lgOQg7QLnXXSq+qLo1PcKjpm8ibHlfY3N2Iv
x/+SXoznLVGitklawK9Wp56y0iyCYNUyH/eLvWh8Y/1E6UQw/Co7DA//3wdv3he5
X3hr3EnKetvA1KWCIvHAz52LLBI3ypR3ffPtP4pFDH1gPn2jNDEi9ov+u+lWIb7T
xl2xqokM6+IA6zLRHVl0o4CyZUXIhXcrUeyYbPj8fA1XLsF3kIhfmiNTAR2hDT5O
bNF1z1x1SK41crHd1Swphw==
alq65e2NhGZhr/ph19pR7V6Tijqwd5ZubfMOQX/kVex5EerZGYWvc31+wBk6nf5r
0z6MscHAtu/M6kN/obrFoYYro7cWFCBd6GeaSG6aDBqrjT2nnBuZ2TGICRc4h8jM
274y1x9qzC3/kzXKS0XqeFQmbwJ9eEaqn3m9Kb8jQPbyC+hZyUFatGhcKYbFPaAo
fdgZL2FQpJ9uG1QsblYQ1ERBvbabN4Y0jg5XFza5nQftFkY6xevmYt7asc+npNkv
qh2aNL3pmG9E0hXZD5N3LMbndP8rzG6vnBq/6SO2eGtos2AjEVXGypJzFhBGNOfs
mwNzXXuiatkIHp2r5pyQuw==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIC+TCCAeOgAwIBAgIUW38GKpYKu6VNBPy5o4Sfa4L8WgkwCwYJKoZIhvcNAQEL
MBkxFzAVBgNVBAMMDlVua25vd24gSXNzdWVyMCIYDzIwMTQxMTI3MDAwMDAwWhgP
MjAxNzAyMDQwMDAwMDBaMBoxGDAWBgNVBAMMD0lETiBDZXJ0aWZpY2F0ZTCCASIw
MIIC+TCCAeOgAwIBAgIUPxkDf9AiLxVWjs21J/3by0oWUJcwCwYJKoZIhvcNAQEL
MBkxFzAVBgNVBAMMDlVua25vd24gSXNzdWVyMCIYDzIwMTUxMTI4MDAwMDAwWhgP
MjAxODAyMDUwMDAwMDBaMBoxGDAWBgNVBAMMD0lETiBDZXJ0aWZpY2F0ZTCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ
6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUk
nAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N
@ -9,10 +9,10 @@ nAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N
JMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd
7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEA
AaM4MDYwNAYDVR0RBC0wK4IpYnVnNDEzOTA5LnhuLS1oeGFqYmhlZzJhejNhbC54
bi0tanhhbHBkbHAwCwYJKoZIhvcNAQELA4IBAQC3QdFZLlqhdyBz78Y+89dkdSpb
Xn2V+FLXNbPiAn91HVCU8+9rVINyjlYPhcKqCF/YLOg4+aabnbkJzaYk24BO+WR2
x4TUaJ1R+WB3zrG1IwyleTkvkCFml7nXZkulRIgxFZG1O3hbovo+BWsQHUNOvsbi
wdk2IMAaCSSX5l7bFjBY0mMP8dMm21pcnCjEx5NnVqKrjmAI0xRZu4uYc8TKwthY
ozcLjk/LtAalLu4xUpPhoEJtrdcu3TDOuItK0X0GhAAgJ3F+uD9ePxdRcyjgePWI
J2mcGIeYW3ktZXqEjOwcyoFQfu8Yvnk3itroMRi5e5rgZzojtM+SJ4AqXZ63
bi0tanhhbHBkbHAwCwYJKoZIhvcNAQELA4IBAQBOBtdU6gEu6bu2pVN4QobNL1eS
TFEGDazNKDq2s/90ddUz7DL029rhnzaIJib7dc4/dxgl5TgcL/8PwPUHRZXteRTX
3hAA+XCunBacQYfZDiG8Bpp1ClslU0FVOngivFHw/mseM7hxOCAJg++1oa1uCqBz
bcVvau/ISa/fApWBICmfRjaD7ztrdVyE5b2M90T7ywedBJHShk8gpJKp3s2/neQB
CcBp3LNoIb0JDMZCk4pVCNTRB9DOpa5zMTu/Emd3EpV9wISEGvDmNUGmuunrgr2h
xZ01TDSLknEJyZR7IbMjkhS4SFpIc6bK19h9yblzDUcCJj+ZH1Po23Fk6muT
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICszCCAZ2gAwIBAgIUe8UEyCNIXKLw+0D5a/t/+y4IClYwCwYJKoZIhvcNAQEL
MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRlMCIYDzIwMTQxMTI3MDAwMDAw
WhgPMjAxNzAyMDQwMDAwMDBaMCkxJzAlBgNVBAMMHkluYWRlcXVhdGUgS2V5IFNp
MIICszCCAZ2gAwIBAgIULXNWBRUzJ/V70VPd4+9U6rf/lYswCwYJKoZIhvcNAQEL
MBwxGjAYBgNVBAMMEVRlc3QgSW50ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAwMDAw
WhgPMjAxODAyMDUwMDAwMDBaMCkxJzAlBgNVBAMMHkluYWRlcXVhdGUgS2V5IFNp
emUgRW5kLUVudGl0eTCBnjANBgkqhkiG9w0BAQEFAAOBjAAwgYgCgYAA0puxL7hP
3c0ps6UZy2bEO42Pi+VFunk4TOZj7QPfdZkWAOuSB5DSUwzs5UTbmacfBYlqPtIH
FlU0qpkFfkfEfjvIGtpvoeEuNyaLUEalUmj52tfMtIXYGi4Z1Q1PC2hUrK9te+ad
mggxNuFa+o9TwcjIT8YHcnndDlXXNppb3QIDAQABo2UwYzAtBgNVHREEJjAkgiJp
bmFkZXF1YXRlLWtleS1zaXplLWVlLmV4YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYw
JDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0B
AQsDggEBAJsdUB8a2j+CxH9RV6uC8AtnXemuAcq0VTo+VucF2A77GNnwO7QetwGk
tAqpSvepDG8rOjBHtrXntZ9zLzuEOnm6DDpyG0DVI5hkHYXfsEtSTRRis9Sp0uFO
9eE1JNdZjX+JdviKHmM35C2KVmLSwntyx9jMesmWJ3OaA5mxDXD7kpUPJumqMRFb
ZyIsvirrEkJz5VHOeJxZ4Q4ZGQicYzuvoHzewcOqLK2l33/YenfSVfJIdtuWTq68
F/5n8dFfqpdhk+uRtSOWRUTCZe552YHzeTkINw/AGx6Is9Gt00LTZ5/F1U0SvTPS
m8bzob8vj7GKrm5Gxl4dF0gy9aMUqK8=
AQsDggEBALhNoeoHzQoeaGR/5bxF8VGE2XrCPoDatHwanND8rp1esVsmkkOSLof1
DXgjZpg9ZJWw1PnprkYkV3XU1PIZWfUh/B/ir7QnsjRrORfJ+BP3Az+Sf1vX8fTB
rfInVWtmRzTkzX/taouPBwJj+CN14hncbaT1FxX74XXmkZXHf2MfRjHjzuB1dNPP
dAu+YVJSxZMv7QD/6qYZoy81dfqcN31IjxoFO0039ZmKrLpUjOZzOnmqzy0+wJpc
Gz7lBvoHNv8SjVeUslb9IpP0uAqkpVYNZhWpPFpJ7xOdVKSWAUG1jDeMAD1tXC7R
N0iiOloMHZ70o84Z6b7IB10IpoymVt4=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDPTCCAiegAwIBAgIUW1cxWpuNaqkzF0ijJHiUQVtUUm8wCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowLzEtMCsGA1UEAwwkSW5hZGVxdWF0ZSBLZXkgVXNhZ2UgVGVzdCBF
MIIDPTCCAiegAwIBAgIUOTTgOhTYLxvzfXf1OSZs5pCrnTUwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowLzEtMCsGA1UEAwwkSW5hZGVxdWF0ZSBLZXkgVXNhZ2UgVGVzdCBF
bmQtZW50aXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
@ -11,10 +11,10 @@ aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
MdUDrNoYCjXtjQIDAQABo24wbDALBgNVHQ8EBAMCAQIwKQYDVR0RBCIwIIIeaW5h
ZGVxdWF0ZWtleXVzYWdlLmV4YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYwJDAiBggr
BgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0BAQsDggEB
AI81ax7NxutctzY+Bc7MIHyhNJmxhnsezibHqba0QRAJNLa+ICXundkgp8u2EadR
LhqnJ3hd2f1eiriupbB+v/K5pnLE9GIp8Tfu/FxczptyRRQfesIabrHp0QpfRUHn
lbDwKjik59d1YI8eSubzkdRk2W6qwnpdFNAAeXz1W+a61rfR6YaATlqpJVVcWktj
U/wvA33UMsPKUdM5gmvfG4o0aNZj7L0MrDP/3gLKBX+YleGNHjLSNC5hpIomWuoR
oEN87eTCmhdW5oCnIiJlycvepcwb8AjGbMO1IU/hOagKw9qXldun3/y28895ryBH
gjObopyDLQt88mmsCNZ3ClE=
ABOkyemfFGxIC9qMI5B7cYQJ7Mrc8qG1wlnc5aKFZ65wnBURgQUw2TtVwBOweLGz
82qR+MnDho8inUTyilydw7WwyLAi2A2jlqcgCaBcyRh8g7/BBJ9dEP2u1BNp2r9R
8VvTlUKj/4Ta8/GG2mEKqyhd8bpevZaaTyjQUGcFYr76/XZ0D6TxtOM0SBLrybNg
A/hbKste6MIXE0rJwUzN2+xWBvfeFqMwzRYZ3F/393qT3vWMgHZt4ZBo/RqQzEM4
I8k6n3s7zssdPOXHy0lezYwkCtnya2OPdGEAyABviARZjIl9Hn+0nsymZmFUkV9A
vUw83907j7buWerBFwnAxuo=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICzDCCAbagAwIBAgIUEYlr2gmxn6hNgEBJC92l945pReAwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowFDESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEF
MIICzDCCAbagAwIBAgIUaWHoyJhhB4GixK3MP8mpJLbOZYMwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowFDESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvB
xyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmT
qyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5
kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYS
wHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwk
BCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQIDAQABoxgwFjAUBgNVHREE
DTALggkxMjcuMC4wLjEwCwYJKoZIhvcNAQELA4IBAQBRIJ5kDC83ZLwN4GMErwn5
J/qySBFkKFQUHZQeDMcs0o/L1JYOFWxGoEjXCSoltaNp9h/g4kOKsKvjIy4o4QPO
Gri9UnylAuH0fyd1oV6c73067QuNWdn0NHsNP4mJcwdyB5kjYcXG3yKHZrp8PdYV
yFRrE/otq53kli6TYMvLzTptFiqsAN2juA/5e8uZeeo95+YCIGmHYnM2+KgxyY9u
i0hjfO4rbAA/fbZSSziU7ZgEjeK3gdaMVRyFiMEVr4gGsar3IFTC6ZBeE93fMWna
/H7WFWxmvUQbT9CDjexFnpO/zpJT8hSJWgcbRD/g6g/vp5EgDTt4//+ylEHqgVZd
DTALggkxMjcuMC4wLjEwCwYJKoZIhvcNAQELA4IBAQCFFyBe938Z1/1WFILrNZ//
3YlpJW0ww46JXCD+RheG2IdI2zdnbNOr7hUnLt4KprntLwmzWFYJInj+sq886c6x
yKImpnVvjB0yDxJki85lNX6ARRHQrTNNf3wczSHdUmGlpzFUUuDkjYZS5Y6P//ms
wPBxppkYguZVvU1s6nvHnuG2wDPKogeD5wmBSfJf8oVo03M6TqNYRK5socyeQ740
LxXjlLYqQaUI+FEQLrCfv4LLrWpoH6mKg3hyKWoG6bEcCyvMBBJ+vDxCCpGE7b2L
tMLn8BML+23CQ5SO53FR7dnWOuxSjnR+GRoFxw5E0qOZEGt+Fb9An5+R4xxRENfB
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDKDCCAhKgAwIBAgIUMUp2S90k4LK/8cGaRqhtJl8b7wMwCwYJKoZIhvcNAQEE
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowLTErMCkGA1UEAwwiVGVzdCBFbmQtZW50aXR5IHdpdGggTUQ1IHNp
MIIDKDCCAhKgAwIBAgIUCcBjO7AcpbQJxZbg9Jic6+Wjd88wCwYJKoZIhvcNAQEE
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowLTErMCkGA1UEAwwiVGVzdCBFbmQtZW50aXR5IHdpdGggTUQ1IHNp
Z25hdHVyZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbW
Qf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pk
cQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHT
@ -10,10 +10,10 @@ ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jh
s3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHV
A6zaGAo17Y0CAwEAAaNbMFkwIwYDVR0RBBwwGoIYbWQ1c2lnbmF0dXJlLmV4YW1w
bGUuY29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2Fs
aG9zdDo4ODg4LzALBgkqhkiG9w0BAQQDggEBALgpQuPyoS9htbABALX3PhEdmwjO
1+UobPxfm2344BdkRJqMVGKHb7ipoqEcbZr5VzQUK8UhPGn3HrnTeKMVDer0tOXm
MWpManIwvr+3GPtouZn0Qd9NVSJqXIfPc6/z+qd+X4vzP4WwQP5RaaTEwc1IegqB
9BwahkgL9fmq9+b2GSvF4tm9kEULS+RMIeUFvtUmmF+ktIHcJfadLQHTx1GHwOu9
lMxSrQmxG1x22Hq+BPE1512brLQg/QCRSuX5n83iuFpYPij3pMS5XaowwZrEUPYV
+r7VUtkSiIJwYuEISoud5O6U4ZyzeasJD0AqWZEw7K0tvr7aUwR3lCC57JA=
aG9zdDo4ODg4LzALBgkqhkiG9w0BAQQDggEBAGEUSKisSADWzD5jGCfvXOoUsYdh
AuGaJqbQFQ+D3hJlmuPXcqOFV8oZNAaaMt0tcyH6Ak4KjpLcitRLQE2W6ChF2nQK
qxz0OWYuFhtDg6c7JBXIT0c0/nM1NCoyDxZLK7oTpjAR5Ji6LIwuvj6uW0CLFZz2
CqwlS+7RirFyzHr279ylFJxoGmApJjIG4Fds0BJoAdU8V4ZbDNE8LwcrYfI+h817
y0IGGkrfpZ2eT94Ih+UfuYhKWyJ5pkxNtoG85It63MN+8i2flxSazuEk9sqRJznF
OTYfaktXXlgBTlvr9m7P8kg+JQbwf915GMN3cgHuN00NiRqsvOQxJQl1BHs=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDLTCCAhegAwIBAgIUR8E5+ceWtBTvOha5AetRGpcomJIwCwYJKoZIhvcNAQEL
MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8y
MDE3MDIwNDAwMDAwMFowLTErMCkGA1UEAwwiTWlzbWF0Y2gtVW50cnVzdGVkIFRl
MIIDLTCCAhegAwIBAgIUBUkHM4qYlHhlajaquYXsh/XJw+swCwYJKoZIhvcNAQEL
MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8y
MDE4MDIwNTAwMDAwMFowLTErMCkGA1UEAwwiTWlzbWF0Y2gtVW50cnVzdGVkIFRl
c3QgRW5kLWVudGl0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqI
UahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvi
r1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/x
@ -10,11 +10,11 @@ fq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD
uRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj
+nJRxDHVA6zaGAo17Y0CAwEAAaNaMFgwIgYDVR0RBBswGYIXZG9lc250bWF0Y2gu
ZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8v
bG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEAD8yy7Gd39NUsrRKcCytX
MTcqCEEmQNtK571afsJP1odGP6Y4CGG4p+KaECLDWask+bciiBslcE/egIJKIIde
DtbXb4+nekmIs2Ocyf+DvucUCigpepHrRwIqxXCpk8YsoK6F5KQFj+X0wJ1bRq7P
rzAKKxAwEgxMS4s6UpRrif0bPIaK8l3nmOjWJDplCYwDttb3Stbo4WIu+bB/BV0m
aTc5liyZ8JzXsriYJpqY2qyfmPaT6PFPiaFahSTzUdwzxzIFdQMF4sKEPnsn/wfD
hwVYSMqSLyBbZjHsRZkgEgOJ2EE3viian13/HfPE/PW8uB4iD1mJ5ciOGQjyxQh1
5g==
bG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEAstqHR4upkLa4tJcDD4vH
cUAJrMT+FzazHXIe4ukUiWG1HtyCjUiFI+NhS7YhCY2+rigO58UKgNkaG6BkrlJM
I81gnyfljMUmukNDmOmsOtXHhP8MXdEa6ye266M/CflTI1oAnLir/6ZJm8AwcLVW
vh4rhEjARMMPpmUC7vpf2aK4qTAcxuymei9Q7uy2tjJT4PExwa4aMBc195yXAyat
oMnVQWZqcQE1Gq/AUzQpHsZAvZOPzEQVLk1gAnZrDLZCQucEbd0P2cJ929cK5Zz0
8t13hDTRa4NpHeaqCTz1l8tVf70FyeQn/tpRQT3uw6aUTbVpELONOFsgt/n/7RBb
Tg==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDPDCCAiagAwIBAgIUeRngcvJif4TaGc8e1QW61ahzoV4wCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowIzEhMB8GA1UEAwwYTWlzbWF0Y2ggVGVzdCBFbmQtZW50aXR5MIIB
MIIDPDCCAiagAwIBAgIUexDM8FvRSX/MKvVCro1JmGq023EwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowIzEhMB8GA1UEAwwYTWlzbWF0Y2ggVGVzdCBFbmQtZW50aXR5MIIB
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62iAY2ED08
E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHqlWqdFh/cc
1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosqQe6ncOAP
@ -11,10 +11,10 @@ YR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoYCjXtjQID
AQABo3kwdzBBBgNVHREEOjA4ghdkb2VzbnRtYXRjaC5leGFtcGxlLmNvbYIdKi5h
bHNvZG9lc250bWF0Y2guZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsG
AQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEA
hgdZQpsh0aFrFgxiPll/JdJO31zf1M7a6oD9S6Q4XYJqOL6NjL3MLmsVyYQR2kcb
mH2+mhLEDF4t8ZOG6jvztf7I/BZHzb2YUHyc/VmG7Wfu5/nnkg+xxIhS7kuFqo2N
aRWI3cTns9umI4mPX44lG2HGwPDiQa8hlSC6PAIL62YEZDQeT147gw1m5gtCX+G7
J6ouQySGT+xbm/5EXWUeTUWuT5K6hYGXM1KF+hud+SdYsUSy3zrsp/dCm738gV8I
fUFlQRjPpdJdZUT50iYLGmkdKzOuiffIt3wckpbD8cvfAji0ydzMumFrXst1YWhj
R8C+YTNJrYm+xjtlFdlhjQ==
CGnfn+l13zgSEIzCmZL2JLUHCKH7OilQ0tE7QjGTXo12KXUML8uNhoxXgH/z7ZnG
0N2ya+Y1pGOyAFsj37nAipH5xsM2mP1aAlPEjgrmoskyhiMszKxr8OD8TFHOfvkS
BlRjnGVjWpwkc2sAbHneN/aitkWDoQ2nacipdQl0OuW4jEjNXa1GE60kCmlfI72b
aP0yN0NPnIcx8Q4M++tfQ7imJbnonxIdQGJdjHHjIRE2CNFyt2Qeb66IyK/pnEDm
oVjx5VZPLUr0g1Ubg6W65LbIuNzalpzPBP30CAEqLXNNZ6wqKTgEHB5UB8sQnFTS
2AZeBlTZ42e5UpU/+h8Mog==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICwDCCAaqgAwIBAgIUA82UAymwFPTOmryByanzY+FQDtgwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowIjEgMB4GA1UEAwwXZG9lc250bWF0Y2guZXhhbXBsZS5jb20wggEi
MIICwDCCAaqgAwIBAgIUJzlO5E47g+NUJjL7EcrQMDmXq04wCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowIjEgMB4GA1UEAwwXZG9lc250bWF0Y2guZXhhbXBsZS5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
AAEwCwYJKoZIhvcNAQELA4IBAQCUS4rF/oNhpL/qSCurIe+0EfDeJ2Q2uNUt1c44
byMsoafu0qgtCRSlkVSYQIrslOd/w1eRTMDWGZI2U1qwDlJR6/UZ0FHBYXJMhL1D
aWuFNYX3AxxkCsyG+TocWz8bSxufHpLkFPpq3RfxdfEqB/X6QLyT3n3IsimOOVNq
TN0Y2RVJJ0N9C6VyfQKsjJSy2/IVT/vge1qdwdBfnJj8NFrpZpWNWZtbEsmoVr7q
5naatxt8xTfOqQQ5hcd6K59mynKJiA/UJ/K7eCdO7kikZDfwHYm67mS2sAk6I0KV
XRNQ3L+WyawXG1HpM50WnCXVWW78wAEKJKJ4M4K5efE+cZ2+
AAEwCwYJKoZIhvcNAQELA4IBAQBy/KCwjrh0emnzBnuw+yEZElSD23wKKhAjUISO
27ndrI6Gmv/wKHdgUP2yBPZbTcUT7RrzamdkOrsVASL2vAFAI1r/wHp/PXEnuNY5
mUWVZLH3kCzJjvZXvGbdQUJhNraNbvDgV+GI/AAo+67QnSmYM0bqhaMsgbGHILGl
qZNOE6GZdWDFBSdNIdKz3AXeKiTXduR7rb03CiuGkG+RmByPEARiUdt2xdZMxx+Q
nhOTnBEu3KsyvJ0Y79Z6T8s3qo2dUsjHF9Kn77CKNYQFTbyoDMsBnulZZuL3uL0A
Fn7CB+VWzVooOhq+BvbeynWGDj3rHsMQUPyP8DMKuwJZwSxa
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIC/zCCAemgAwIBAgIUNaZZRRs6yrYRpiFJJCili/6JGIEwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowKTEnMCUGA1UEAwweRW5kLWVudGl0eSB3aXRoIG5vIHZhbGlkIG5h
MIIC/zCCAemgAwIBAgIUD8+FcBmecy2K1vllEQ2SgGucJCQwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowKTEnMCUGA1UEAwweRW5kLWVudGl0eSB3aXRoIG5vIHZhbGlkIG5h
bWVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESOFtZB/W62
iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVramRxCHql
WqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWkasdMCOosq
@ -9,11 +9,11 @@ Qe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPvJxbYVbdmWqp+
ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6naOGzey8i
b2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHEMdUDrNoY
CjXtjQIDAQABozYwNDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6
Ly9sb2NhbGhvc3Q6ODg4OC8wCwYJKoZIhvcNAQELA4IBAQB9abq4vsm5Nwt4xUuA
Og9gRQKjUOGNLg7DuGh1B1rgP/qXt6+Er6CRPSI7N2+jrldDnZ4HCvaCjFa+Gpu9
dyC0IF27tWpczl+uGwdoo80VM2eJxFx40C8pzDBZsAHU9F9mx1vBvXuwO+tX9zGc
Ngf14neY+3gZcQWsDkzbxWrM2ZyGjjvIL5Zaqd9KbBhxKvTXB1MpAsP49cq+Gdbx
uXMP2NFRUhUN+M3JZO+/8iYkHJ5b+A523NZIZTa696QkLfDkIMZvUO4Ly80K+aOS
liT5CPMf1MNeBMAC0WlK0DX2RGqOh0gePwxLhc1ce2EtydBR8oGsgh3pNf3/SXcM
G7Wb
Ly9sb2NhbGhvc3Q6ODg4OC8wCwYJKoZIhvcNAQELA4IBAQBiwTfHRmir5VnSNxOs
S806Ao1xXqaz7ff/qi32Nnio855qHulmKjsRfmEv09N7/PNFkAa6yILe0/8YdroC
aOd1iOdawsNMoeud7mD0FjuOYcjSnCx0WTeW5LZ/yXkgKwA8+shZzhr9TYiXQtnt
TIgQma15CyjpFp9ztHj6MtInVFhjDxe9DzJsgLv8EAxbLacPN6ZFB6DevvI+NL6M
wsy27OMdFvW7M4AWlWIyCFJg1moxaw8Ht8vUooe3EWbRknuM5IasgwZDt5YUeXkO
0nQF4IKtLoASla3UOL7exkMLJA7kE4zTlOKADXi56lNZd/2ck/+wd9hrwo8aXLsO
T34M
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDTDCCAjagAwIBAgIUO5jc5+Ptwn4v3jUNYRL7xdZ90fgwCwYJKoZIhvcNAQEL
MIIDTDCCAjagAwIBAgIUd2Xdl3VR8l0IU2OPSgy6zPCjvaQwCwYJKoZIhvcNAQEL
MCoxKDAmBgNVBAMMH05vdCBZZXQgVmFsaWQgVGVzdCBJbnRlcm1lZGlhdGUwIhgP
MjAxNDExMjcwMDAwMDBaGA8yMDE3MDIwNDAwMDAwMFowNDEyMDAGA1UEAwwpVGVz
MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowNDEyMDAGA1UEAwwpVGVz
dCBFbmQtZW50aXR5IHdpdGggbm90IHlldCB2YWxpZCBpc3N1ZXIwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq0
7PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D
@ -11,10 +11,10 @@ rZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWd
q5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjYDBe
MCgGA1UdEQQhMB+CHW5vdHlldHZhbGlkaXNzdWVyLmV4YW1wbGUuY29tMDIGCCsG
AQUFBwEBBCYwJDAiBggrBgEFBQcwAYYWaHR0cDovL2xvY2FsaG9zdDo4ODg4LzAL
BgkqhkiG9w0BAQsDggEBADVrWCQKRidNa6fzpdcpQOry5zvOSLWIcRUZKYzwzKe7
hkF3CsaWUurlesR6Qg7cM2q2mXOQv7BvaG7luYN1jCGJwPliOUKn8sJqH56qkMls
rzYYKMJhK1LUKpgg973Gxy12Zwg9zaGhev/OTnLemQSu2xQw10kUI3smkBL1YxlA
blRDy5z6aWwM2ZXzzdQzjeYV0LZHMF/z3xpfoKNxZuApF9OldFnEBk+27m8NHb7S
ZEArrdqMfJDi9MqCihCuBRGjphKS9iQX3KIYgqrDMzIf19EQNRQSLgWLHn+JSRNg
TzrZS+kIWJQypSv45ejSCp8rYx9OVnj/U9RJ908R/RM=
BgkqhkiG9w0BAQsDggEBAEI5yQNpc3afAa4iN9uVBBDv9gT3X2FbhrWKCNYbLsRD
dtntFIuZMHJvH0IuKqgUoDnFMJciOkhY8GrJUi6bZIOd15YL/jsodJHxYO9g0vT0
0E33/Ka+0DEy4g/skJTy7xQsF0OTw042Aoe23RFxwbAmzqQn0BDRzJ6Qhx4WLQ2f
QVhmDrvwF+VRshrp6bJKjcTZRmgIX3nVYAR0THuJu+zcB8de7G3lOH7YCl0rpboI
fFkQxnTSt/MtU3FEJaajmz3PvzLkCI4FHFv8SouQ3ZIp/XRHk6luW0QWO3z6cy5l
3V9BkhP0jkPpr9wfCZcmqu8EkCWZCfiu0Rf+k2uR2wo=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIC+zCCAeWgAwIBAgIUPzR9NCfflP36Y/7nVoUjCbOTReswCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowHjEcMBoGA1UEAwwTbnNDZXJ0VHlwZSBDcml0aWNhbDCCASIwDQYJ
MIIC+zCCAeWgAwIBAgIUQaNz+iusE21wkn6JJ/qLaB6Q8gEwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowHjEcMBoGA1UEAwwTbnNDZXJ0VHlwZSBDcml0aWNhbDCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1
SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+
zUP8HmnQOCApk6sgw0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYL
@ -9,10 +9,10 @@ K7AkkqR9uYhheZCxV5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwc
bJetlmFbt+KWEsB1MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibW
JZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaM9
MDswIwYDVR0RBBwwGoIJbG9jYWxob3N0gg0qLmV4YW1wbGUuY29tMBQGCWCGSAGG
+EIBAQEB/wQEAwIGQDALBgkqhkiG9w0BAQsDggEBAF0xKcPiDSPv5pPJYOtWPpoh
7NaYXQjhx/J6c0W6gFvlEC5mkhaWxonLr5CRLzujLEKM0zzw8+J6mKnsdJbK7GxY
4G0K1ymt49rsbxVEBtl9cbG6Cp155RYFThdKAj/f9EVEQgRqH2kzdtsvlljVgQtT
EvDm0uhpBwzR13N+ZqStrVi8/SLUdXZnQxUNaFJzlggg/+AgfRi1dN5Da7P2t+0b
pIG3MPzX7nxXBfqqb1MlA+Qn6kppdKWyzO60g++l4zfa/Z7PxIDsXJfhKgAbzWQ3
hZi2k7P956QfLw0M6UfTl4pCFOMtENZdkqLQmEoa6KbcRvLPtb6ldqGPKoxa/Mc=
+EIBAQEB/wQEAwIGQDALBgkqhkiG9w0BAQsDggEBAKWjJlobJfQhQxSNmvhokt1f
rSWbHFyePtawqHSBKIOG9RrNB9E+nbDsI/gVvgVwi1GVu7cmg5SJDAuK19dpWXTh
Pf4FPTm+FrLXwfPUOay5S3aGSwg29/PjnVayuBrJbMeYvtMJd7NGtadyv5wg3K3P
SSFqYjUKOeWewt2NrX07LII68uctBja3BVpAPVvcoYsnR30ozuuiZTy6rBu0n4g0
KU2stuuOnVLf7A7C2clj/ls0uX0hbSAaFH2RNQPsu+TL2ziSEEV9DYUm4pPMnpuO
dhSDgTDkCTMqzS84FFTemzbkOUxBechMogtPkEhr157kbBXYzjytYgGLL7FGGRc=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDLzCCAhmgAwIBAgIUR/TVVDn0AzJEVj3V3p48mYE86n4wCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowLzEtMCsGA1UEAwwkbnNDZXJ0VHlwZSBDcml0aWNhbCBXaXRoIGV4
MIIDLzCCAhmgAwIBAgIUL0RNPgFGtsQZxanRCa2IGPqVWZIwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowLzEtMCsGA1UEAwwkbnNDZXJ0VHlwZSBDcml0aWNhbCBXaXRoIGV4
dEtleVVzYWdlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohRqESO
FtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+KvWnVr
amRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+rWka
@ -10,11 +10,11 @@ VbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5Fw6n
aOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6clHE
MdUDrNoYCjXtjQIDAQABo2AwXjAjBgNVHREEHDAagglsb2NhbGhvc3SCDSouZXhh
bXBsZS5jb20wFAYJYIZIAYb4QgEBAQH/BAQDAgZAMAwGA1UdEwQFMAMBAQAwEwYD
VR0lBAwwCgYIKwYBBQUHAwEwCwYJKoZIhvcNAQELA4IBAQAksxqbHtU7c2bXxhQF
MASnpavCgexr/spzwzf1Slr4bj/Jz6ss8199B9CNuPcyZ2ufP23iqnrgJU1arxjk
f3cxXr4PV4IgDsYbccBaNBWOc9+XnCTfvuE0yPOdZctbcfA6bey/phZNrVCWpFpa
9D4aJesbmlm2MzSEKehjb3nL55UDO6iVNWYAB1MFFYzQGPUL2dmp5PgK6gYzMbjK
VGQK4lyZZAgDR7bXAcKQPhT/ekKcYw7dbtbfm01/ELqqzIL7l/W6VlRO7xC8Htyn
mlz3GNqNo73pIR41xHSHYAhjqwHtiIe8rZJyr4HqcSgaYZ0D6Js0PPT/k1saQq+r
PHme
VR0lBAwwCgYIKwYBBQUHAwEwCwYJKoZIhvcNAQELA4IBAQAO+rOEK3vhTmoLNg5w
upxSODlCFghBLZ1qui7RWJME62JG/1sxZw4rHa0Pl2NP1U/Wy0ErAT/QQLyIahBL
mjggdD3Vh9wfx4Qf4FwHGzJEopfsx6YQlHcXR1v5qb7lLeuywhA6m7agn9DWBGlg
lLFNqtHmofQFaileQOA50Uu9qOAdbea5+rjZn9rBBvUUVeSc9hNWjDRCMk/5PSm4
6ONpFjal4npPA8V/U7LleJR+VNbiCWNHaQD/9H+xBoay81m8GL0CdM9udBjbyf9W
NlYtu87XanZn2//LghGGUW4HQn1YXWD6UeZngo91UdQeIOs+dCiTI8CldgpGafld
8UdC
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIC/DCCAeagAwIBAgIUKxdSO/ZfeYGpAf501TLycMrJEgQwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowIjEgMB4GA1UEAwwXbnNDZXJ0VHlwZSBOb3QgQ3JpdGljYWwwggEi
MIIC/DCCAeagAwIBAgIUSeaDecTuqo807NV7Z4OGuTUEoKowCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowIjEgMB4GA1UEAwwXbnNDZXJ0VHlwZSBOb3QgQ3JpdGljYWwwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT
2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzV
JJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8N
@ -9,10 +9,10 @@ jf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCA
BiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVh
He4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMB
AAGjOjA4MCMGA1UdEQQcMBqCCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbTARBglg
hkgBhvhCAQEEBAMCBkAwCwYJKoZIhvcNAQELA4IBAQBy7Hoo6D8JypxDVuTviT60
hWKPY1prVr6uuyIokXqwGwWgw8ZQ0zAwo9zd5blM49ooKlZ0C/2DEY2fBXA+cpf8
eZV0E1DiyNjOYSLpJQSj/lpn/isUGmQPFIyr9dnltSiAFPaT5LktrG+MPNs1Qitx
wuXU7RKpGO52eiwxuFrwrFb0G0nAnItZncL+tgFRGb+pYK4BNxPIOmwHU+MxUF5O
MsF1FHFYsy3cdihnA3+dGmmIAOLUtACZu3yxIT82AkXbLG9Ds9NIRXnC9+QO45B0
eq4UzDdAxJSJIgIRsvuGqaN7oaxXBKv9J7PYCCn6RkiAYT1YDNJVmVdufMzQhZId
hkgBhvhCAQEEBAMCBkAwCwYJKoZIhvcNAQELA4IBAQBUkcVO1xXJv8/BR5tUyQDt
Y6gQMH9hfg2MZwR7mKj/ZdTEUMUqpOo4zfxRj8j3WNAF01g88D/oQw3IcDay9kpE
EZDSLLQpVYW6l9xEWuCl+p9jNbFDmNxyPe2KOD+Pmp0ggkyeKyfC2l1cZS9kuQjW
rIYgGdDVcXvBH/cfi8Dxl4IjWa/Fmkpw/W4uvcKcpLdtwZkGAa2CH1ymmeE3gtE8
+uYJuWWP9RE1cwXtwoGTPoU2fxBP8V2gRgPrlHQlhlJzyWthJ30Cv+RBNU6IkzNT
ZO10f39iPQScLbrcaDULX44vhUGhXlaXsOBWZnyX7exBWdUxNNpIjReO1nrZxufi
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDezCCAmWgAwIBAgIUHxXorgvSekn8KPmeXlYZnxM89m4wCwYJKoZIhvcNAQEL
MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8y
MDE3MDIwNDAwMDAwMFowJzElMCMGA1UEAwwcV3JvbmcgQ0EgUGluIFRlc3QgRW5k
MIIDezCCAmWgAwIBAgIUNVbKGlj3T9hCc0QZzD1Zs4cFzeUwCwYJKoZIhvcNAQEL
MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8y
MDE4MDIwNTAwMDAwMFowJzElMCMGA1UEAwwcV3JvbmcgQ0EgUGluIFRlc3QgRW5k
LUVudGl0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF1xlJmCZ93
CCpnkfG4dsN/XOU4sGxKzSKxy9RvplraKt1ByMJJisSjs8H2FIf0G2mJQb2ApRw8
EgJExYSkxEgzBeUTjAEGzwi+moYnYLrmoujzbyPF2YMTud+vN4NF2s5R1Nbc0qbL
@ -12,10 +12,10 @@ HhkdcSFo07sCAwEAAaOBrTCBqjB0BgNVHREEbTBrgigqLmluY2x1ZGUtc3ViZG9t
YWlucy5waW5uaW5nLmV4YW1wbGUuY29tgigqLmV4Y2x1ZGUtc3ViZG9tYWlucy5w
aW5uaW5nLmV4YW1wbGUuY29tghUqLnBpbm5pbmcuZXhhbXBsZS5jb20wMgYIKwYB
BQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsG
CSqGSIb3DQEBCwOCAQEAkQQFE0UqtrplaZqzvosJiLveVGfDGqRAjGCT3mimXUYt
VuBXxYL66jQ2yq0pKKckQD/sZcgmToTGRwXCbErjIwM+IBgey7OBlCRNbkxUswCS
DDk/80sIe1s0nCBs4BG0nG1PZMMayA277ExhdWlouTBvU2Xt5IieVN8yVNCi2bsX
IGnLtQgt3naBPcMCGrjeKc+t3+mSnCzPIZTsx+faPJmTk5M2jwc75t5g/RUZOpf5
ymNNq4OBIiHd9/bsmwEYrKetO99IEGNuWTcakM4bZ42WLXe7CJu/D8CLQhb9vCLG
d4rTA2YmxNcsvV0d3TRoCALkBgc4Ho5dvaj/SXRplw==
CSqGSIb3DQEBCwOCAQEArJqM6iooFNCAk11WMdPCxa4iGkG4V5zYuFjdd2K3LTLM
ai5SZS875tXNol+YZgUh6cdTbVARdsB4saYGH1v5pAmK+VJniYQHWYsSLofgBfFw
yAk1Ymj5pz8y6+ExYzWPBV5ihevtyCRPGG8xgZqRbERTdB2uBZGmQ441LLnZZZFX
BByEFQ4M7qYmOTZaIxncSGZbwVncBYkLbYmOIPdcahVtnK1mIm1q7ET0KeUEPTLB
5UEdNa7bd5ULWeCIVZxRWdawzktWdF7CfBVO2KeWiEE6wkL1Y3N29mUOynWKRs7w
wo5ETwxEw/6UqOaGCmbCTN5Xa+N+ZE5/4g0gEEcFUg==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDdTCCAl+gAwIBAgIUa2BV5DHcAA84YP7Zdf4TnA4LUIcwCwYJKoZIhvcNAQEL
MIIDdTCCAl+gAwIBAgIUOZxBsWqmNkNX1bk4vwjN7oalyxcwCwYJKoZIhvcNAQEL
MDMxMTAvBgNVBAMMKFRlc3QgU2VsZi1zaWduZWQgRW5kLWVudGl0eSB3aXRoIENB
IHRydWUwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIwNDAwMDAwMFowMzExMC8G
IHRydWUwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowMzExMC8G
A1UEAwwoVGVzdCBTZWxmLXNpZ25lZCBFbmQtZW50aXR5IHdpdGggQ0EgdHJ1ZTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9
PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3
@ -12,10 +12,10 @@ lWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0C
AwEAAaOBgDB+MAwGA1UdEwQFMAMBAf8wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUF
BzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMDoGA1UdEQQzMDGCL3NlbGYtc2ln
bmVkLWVuZC1lbnRpdHktd2l0aC1jQS10cnVlLmV4YW1wbGUuY29tMAsGCSqGSIb3
DQEBCwOCAQEAB2PEVMfffGy2JQjo1kaiVt6U1eI0tSTTntk7GqhgUo/JRIikqy3v
E2m/oM6Xb/uP7kgd+DjCfJR75WmB8pldR8s/PFJWPzjhKdVPj+q++yw7mR+Z58sp
YMmanGzGAZ+S3/MEP+tOX2COf5kt1CyrWOn3hGsedXkYlROzLrMfoFQ2ZAW82Qs2
NoN5DYxcv2x9lEY+mez4mwPXMXFfYZgOqqvv1c8f/yykStvHMPMgFgjhA5+PV8Xz
EvhGHXAZ+/EIBw+ypZaWrg+DhWrFrjnqT/DUSUsddGnoe/Ehkwj8WI3gD7yohT0h
lijn0+4KSM6a+jHQqhQ+P/dy+t9vPDdvSw==
DQEBCwOCAQEAOOiI4FYCOj5N75+ix87qQQjtyG//CTUi8SMRAIG9sQId7fRtXAcl
qEtWKxdcNy4RYVoEQTNPrY6gr9amiPEpZ9IobtX1WW8gJiVj3EFLfXBKTE3B6Kxp
Qim7bJvrqoumLgXtH7eljHdfN86I6Xnyk7L4tl30UhlOSd24jiQ8T5FxF7lcmEnT
w+AthUUhOyKyDRXvV3jUpM3SKv6mz0rzm19A/qBOYM6Q+bAS5n47d/TPbmCff8T/
zKU/Su7WYXsw7gU208DhWrqLjpUzPuGSRRTZgHCG35KpOlNcN81iZsvEYIyL+b68
G2rlSZK2C3LaGi/0t7s3O8gUep20KSF7WA==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDgzCCAm2gAwIBAgIUReMvQBqE9q6NmzO14X6J+pL1vGwwCwYJKoZIhvcNAQEL
MIIDgzCCAm2gAwIBAgIUV9yIaHMDuAdDCVBEzuEE5tSGIncwCwYJKoZIhvcNAQEL
MDUxMzAxBgNVBAMMKlNlbGYtc2lnbmVkIEluYWRlcXVhdGUgRUtVIFRlc3QgRW5k
LWVudGl0eTAiGA8yMDE0MTEyNzAwMDAwMFoYDzIwMTcwMjA0MDAwMDAwWjA1MTMw
LWVudGl0eTAiGA8yMDE1MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjA1MTMw
MQYDVQQDDCpTZWxmLXNpZ25lZCBJbmFkZXF1YXRlIEVLVSBUZXN0IEVuZC1lbnRp
dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braI
BjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVa
@ -12,10 +12,10 @@ aeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgK
Ne2NAgMBAAGjgYowgYcwCwYDVR0PBAQDAgQwMBMGA1UdJQQMMAoGCCsGAQUFBwMB
MC8GA1UdEQQoMCaCJHNlbGZzaWduZWQtaW5hZGVxdWF0ZUVLVS5leGFtcGxlLmNv
bTAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9sb2NhbGhvc3Q6
ODg4OC8wCwYJKoZIhvcNAQELA4IBAQBULgN+U1uYk+FAGSUtSubSdAbSEzUAKUTn
IEtowgow4y8oK0SmWOmlUCMuV3c6w9NYOX+JsYoyv9mw/Krz4hb4jAU9EdiS83xX
qWc3l0CVbC704jaBBxsf6ZTrYCV+QgCCERlyThEBHUBAq2ROZ62FviWyAI8RDI07
gOpKYf/+OfJ0BmWRX89Kmc9jgniWzEGBninxsN4fNsXldxw+Ppd78JBXneDOqgRd
5v1iGABilqYUjAHHT+i5W70ItTMlHkQS9Jj6gOgad7tncoDzPGN+LIyLtIuQeWEU
V4Q19gANGu/TqfSFgFPxu1k0G54mnBe5ShIC9QrdBySsecY3VSjH
ODg4OC8wCwYJKoZIhvcNAQELA4IBAQAhtt1BOrCjch5fzJ+OIvqSF2qERDB7CJDA
avhypMbCVCEabM1JBD8vtA5U7izjWpAJVlOwFBUPtGpeCtXkCZEyy6/JPOdc5hhJ
1h0+c9CeKkmjwyydqqz3v4quXAI0WX7ChuO5WfsVY1swFcp6TYtGYBsjMVpVQaTw
CGNFZ73EEksRWP0NH/SKABo+6dlvOghivAa3Wx1HEOVTFUo8u6odwZ596Xl/IhY4
I0G/GuGCwMhBE/5GGpSI8qH8DxRXT7nrvdHZmuiRB2SJYeuF4Cs08KHO+ymiST/d
OLnAKR1WWgslQbxZu3zdBDqKuKf2vOKS9xo6sQXP3TsLsSPxY1v2
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDMzCCAh2gAwIBAgIUdQJiAD83CKuJB6rEOWBo8c/zQ/owCwYJKoZIhvcNAQEL
MCYxJDAiBgNVBAMMG1NlbGYtc2lnbmVkIFRlc3QgRW5kLWVudGl0eTAiGA8yMDE0
MTEyNzAwMDAwMFoYDzIwMTcwMjA0MDAwMDAwWjAmMSQwIgYDVQQDDBtTZWxmLXNp
MIIDMzCCAh2gAwIBAgIUFdYBQ3rk5hXCs0Bz6ERmayqrMTYwCwYJKoZIhvcNAQEL
MCYxJDAiBgNVBAMMG1NlbGYtc2lnbmVkIFRlc3QgRW5kLWVudGl0eTAiGA8yMDE1
MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAmMSQwIgYDVQQDDBtTZWxmLXNp
Z25lZCBUZXN0IEVuZC1lbnRpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwG
m24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJr
@ -10,11 +10,11 @@ SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3
/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+Z
FzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjWTBXMCEGA1UdEQQaMBiCFnNlbGZz
aWduZWQuZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZo
dHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEAFdjt0c2Y0HDs
Go+YRBmSPqOoqj6F0G/UukXLBc8AgiRKeygMZ7EcKcNEwPRnurWDxKqrQ4URJva9
1sNS8RSVy4XBBZpxYNXqnmoKqFZbnhZ2GAvlbPfRHGya+NmaPr2PFPbdCGaZBVAB
tirKJ3uHRH0OzohWgSqnBnGaZNYiyiaFap/sJavvhWhjJMPZxlo41a73yq+7p6Uy
l8N5Oyq1/kuSMqDZpTnSjW6j9/Qs0BGbbixnTWPbvF5Gkz0LZCkpYpGFtmDgBbmL
5owmw32ypwwHns8BSTmjDRbC/lb99KmxP2/Tgmvocn/yZdsUyx0s89ddNbLtj7Qw
915Hd8Wmnw==
dHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3DQEBCwOCAQEAiPY8Ka4thJkS
6HzgnIpJyd09rmAls/LwAPRwhk8s652FEEGpZzkreDjOJ9LGYx01JWGQPDxOgddt
ynYtbZVzwnSuJnISglU/mAsmgG47hSeBamOm9zg2KAC1+64nVgpkmYMEDGQC4h79
cADh5g5ay0E47x/9u7F02z4ovXyJCDC/bOTFKv4WCkHEaIKhnbrv4EGT+lkfCFol
obLR6h4mwclIDycIR9D2hg4ZSrnace1JzF0OALMVshwtclmJMS4yH+yACSeovT6t
fN1CTvLAY8nYtyuxWc3D/gv0T5MWVvkSSfbrvt+nCUvrEsLFnDgKqMzh7S/iph3M
UyeHQjtRIQ==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,18 +1,18 @@
-----BEGIN CERTIFICATE-----
MIICzzCCAbmgAwIBAgIUf80CD8/4YEbWhwYeA2isocegVpwwCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8yMDE3MDIw
NDAwMDAwMFowEjEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
MIICzzCCAbmgAwIBAgIUH9DaznYx1NE1Cu9I8cBqxV9VgF4wCwYJKoZIhvcNAQEL
MBIxEDAOBgNVBAMMB1Rlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8yMDE4MDIw
NTAwMDAwMFowEjEQMA4GA1UEAwwHVGVzdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
w0nk27lMwmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCx
V5A90jvF4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1
MaMMkd20yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQs
vxaLL+Xxj5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaMdMBswDAYDVR0TBAUw
AwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQAhh2tjd37eSIBrm2fA
Zd2thIyIID5tjQOnqx5dG/Spn2exJNMYaFMP88wu7CZA5UbKIjpkLTZH/t+96DZq
0jVSybCl4MmBVsoxguoGVzSrByPtcVQTjX/W35ysQMB/sbQjqb9C/ecL2rBtqWxa
H6mIuU9qyUZgBKyTXylPEdGmNWm7CJ3RCVMFtzS6+JLgAhpemPFwj/sF57rMfiiK
X3v8yjqthq09qzv7XUP1PreScv72xkYlX+HsdlPfZ8xLokJoOLs0/qm3LKS4cIou
v+WeqFWkct60qi42/3dBrnoD0LUP6CNmbJYmSNT8OfNSqx8bUSF3MsAdcVC/jIQf
NYS/
AwEB/zALBgNVHQ8EBAMCAQYwCwYJKoZIhvcNAQELA4IBAQA1o3GayNFRlVTrsoj2
Ag06YatbGe94M/FT0MXngjlmrMkGZqHaDlrii7Jz+JP16CBjaIZ0ZP7I56Nn/l8y
/kfe++zvr1uwRaKjtRGBiFpCjx10rI508wzSnOox3+bOtv9qjYaY7UjkBV3F40IS
P8qKMtNspsR4tjS/D1jbculhngkPqhskefZFQQvcgG54L5j921GFKNeeX6i9QAzV
jjM6i/iQYpAWCuh5+CetwUnfFuZCM80npp/qHMESkT3PyPpwqT9A5K+xQdVfpXq5
SmVy5+QGWALuSV1sfIRXRwOh+2jCWwWPbyi9TlHrvlO5mL38qikdYBDPat3ve4cq
5viq
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDpTCCAo+gAwIBAgIUfcZIUGx9/FiLBGq+1T5dtIJIicgwCwYJKoZIhvcNAQEL
MCYxJDAiBgNVBAMMG1Rlc3QgSW50ZXJtZWRpYXRlIHRvIGRlbGV0ZTAiGA8yMDE0
MTEyNzAwMDAwMFoYDzIwMTcwMjA0MDAwMDAwWjAuMSwwKgYDVQQDDCNUZXN0IEVu
MIIDpTCCAo+gAwIBAgIUHccbzbbSEhGlmiWbLlfHcRQFD7MwCwYJKoZIhvcNAQEL
MCYxJDAiBgNVBAMMG1Rlc3QgSW50ZXJtZWRpYXRlIHRvIGRlbGV0ZTAiGA8yMDE1
MTEyODAwMDAwMFoYDzIwMTgwMjA1MDAwMDAwWjAuMSwwKgYDVQQDDCNUZXN0IEVu
ZC1lbnRpdHkgZnJvbSB1bmtub3duIGlzc3VlcjCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wccl
qODYH72xnAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sg
@ -13,10 +13,10 @@ BIGAMH6CGXVua25vd25pc3N1ZXIuZXhhbXBsZS5jb22CNHVua25vd25pc3N1ZXIu
aW5jbHVkZS1zdWJkb21haW5zLnBpbm5pbmcuZXhhbXBsZS5jb22CK3Vua25vd25p
c3N1ZXIudGVzdC1tb2RlLnBpbm5pbmcuZXhhbXBsZS5jb20wMgYIKwYBBQUHAQEE
JjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxob3N0Ojg4ODgvMAsGCSqGSIb3
DQEBCwOCAQEAuk4lvtvQf2IkgzGdnJUHfbpSE+B3aWwMY5yi2a5A6mx4lcMS4tsH
3CI905S2GeLrs7iLd8qAZWsV4dlGr2/aNfTZMo824cSyj80StyMx37jMdC7+zXhY
YhSiLZ1oLm1OMF95w3E+Nie/lf/VsIzlpmi8rAfnSLao/nWPKn8VEbotBOFyn/+Q
qIQ026reZ3zURoNN1LMyJqSSApQoUSZZQh4OIuiSDkwh1TfxZHSdBVCM9OTju7q0
rEqLX1ibnJv5pr7jMSwVGqP4ye1giz+cInIkCs+/l57hsx2cr97Q3vb/n4VoHZlA
/2J3ikUU80aIEV5Cgj4yxZTDQ7fR+m8uZQ==
DQEBCwOCAQEAjvk1a9yDZSYDNilWlvRcUk6stPfmjG7p0Owu0a+Lh8JIxOZXflZ1
/hpVp0L5ds6mc74Q5VBJgqpkrpYBIVDPa3LJzW4HX8y7FtDo71Ca/ob+Xyc4hFdg
3G2DqLePZXqkV+h6bsg/Rqv2FUt/GbUmv4sIkTwL5KgMEjLJGxwRTyrQZJlTMC5N
uSxtWiCv+wLnP9NbkMgBHE1NnBQjF5nR/mJC7HUGykGYe+oJHuozq+/VCn3bXFUm
kq9YXS0R84LcQH7gHtOlp5xwxiYXPH3C2cxobaJNdo5qsyOZYc5Diq/ukCN5rg0N
5IOg9SPThtEzlCjTFRVHKE7ncgo7JxJ3gw==
-----END CERTIFICATE-----

Просмотреть файл

@ -1,7 +1,7 @@
-----BEGIN CERTIFICATE-----
MIIDNDCCAh6gAwIBAgIUN8wiHkr2t4HgCMoCqp+Gw/vrOrkwCwYJKoZIhvcNAQEL
MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNDExMjcwMDAwMDBaGA8y
MDE3MDIwNDAwMDAwMFowMDEuMCwGA1UEAwwlVGVzdCBFbmQtZW50aXR5IHdpdGgg
MIIDNDCCAh6gAwIBAgIUC7+ekJBbfCa4+95t1Lc9QFnFM00wCwYJKoZIhvcNAQEL
MBgxFjAUBgNVBAMMDU90aGVyIHRlc3QgQ0EwIhgPMjAxNTExMjgwMDAwMDBaGA8y
MDE4MDIwNTAwMDAwMFowMDEuMCwGA1UEAwwlVGVzdCBFbmQtZW50aXR5IHdpdGgg
dW50cnVzdGVkIGlzc3VlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72xnAabbhqG
8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lMwmtsDu0V
@ -10,11 +10,11 @@ gg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF4LhIH6g3
0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xxj5kXMbiz
/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaNeMFwwJgYDVR0RBB8wHYIbdW50cnVzdGVk
aXNzdWVyLmV4YW1wbGUuY29tMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcwAYYW
aHR0cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0BAQsDggEBAAvrVXj3ZPVc
xxcuz9zDwU4NSaNTwtf+p4dVLN9LN/zewgvrKUtT7+v7CtAky8hlD8QRFTgtiLsl
XwPUWQtFqJikLe/ukQTkFtYAnZPunTt+s6Tyi2xqRFm8RwdvZv/9KRky2z7in2+Q
z12srCdiNBZhPP4lR7Q+PZoIR487cnbmiDknK1aHnjimMW0XfOagdF3mR4MHU2ST
0UHZaQ6Hwg453ZUuEvo9/+yQSCcmt3DUdAge0uV3M9v5OajzRTVNlWfcNfmQBxUi
Aoafr/f8Esq9pefqfB+gfW31IhP+CQtxrVw5dv3MGrK8cnVck37umOwHqYDh26s9
Xnp8KC7ijy8=
aHR0cDovL2xvY2FsaG9zdDo4ODg4LzALBgkqhkiG9w0BAQsDggEBADoMA0m+eXNs
tdp2WpRyK3F9+FXIYbZGdlQFi+G9Dku/8J/cysb3jnN7zdSiCwkSJ38XR/8z4M0O
x4i3/alFWP1HTvQmVOwP7U31u1h56QlS8ltFasZtd+lOELWvaj9WzG2glcFGTynT
iIIl3LCm47O6u501xZsp5XPRaeY9956vuP7TwVIx8v2JR5H3hFhk9fR/mhR8QCOB
HVu/iW9ux7g/9Up1Fi5mYAq6cmArpJ2LzEr57gdV1lfgKObTE++ZWtRa5N+zMZGX
TU6WARBPH+vVHC1VKxY2SYENxswFtkgCSVoRFzn7sj/8jQ6iaJ86sf9poK0NrHdg
P0ybC9Y8juA=
-----END CERTIFICATE-----

Просмотреть файл

@ -1,17 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICqzCCAZUCFDX+15ASjo+0HtUTwYoepyZiQ6bbMAsGCSqGSIb3DQEBCzASMRAw
DgYDVQQDDAdUZXN0IENBMCIYDzIwMTQxMTI3MDAwMDAwWhgPMjAxNzAyMDQwMDAw
MIICqzCCAZUCFDt6FYWPwMbZVlZa329PtAVVBtsnMAsGCSqGSIb3DQEBCzASMRAw
DgYDVQQDDAdUZXN0IENBMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAw
MDBaMBIxEDAOBgNVBAMMB1YxIENlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wke8HHJajg2B+9
sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5
TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7
xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7filhLAdTGjDJHd
tMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l
8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IBAQCh
jm9EQwLVxTNm5pQc78MVuaHXgKUmgukbdlfMJf5Hf1wUwwA26YVzOrvSTg3XSnO9
1OZBJgZkwI0xZZe3r7ZgHNOkCz/OcIJENPBROHTms2RkL2Vc8Q/9JjBjh6Eh7QIN
fSROi93QjSAqfiV95ymWqzxb2FD9CHUzKq/94uYsdr89rvjthw1/vaSx6ZaD21uM
zTyL7rj7dQ63NiJZ82REqBmgZh/1Ha+RoLxWeEOA6RNE1I4nMapT5qDcXlq5Iiw/
MPkpsbMfElWYIWklSfZU93HVTf+zLHlol7I/NauMxyoGO5tYjlIE2sfmtAv5vva6
iw9NV8XL6V8C9d9L15gI
8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJKoZIhvcNAQELA4IBAQCW
fJUaT3AtmftAlBtS3e1hs6V1XoQNaeSiff8PR6ootvISg5MpU1b2whEvNalJCUMD
zBXkM7y3ERSgAvROu+CbBFOrOTPPStg88iZFm4WDrgotADxepbYd+x3IOL0vGq7F
vcqdiQCRuhVRoopipqmowWF4KZtm0SnXoce7GnDhIjLtGxwz+zq3ls/2MrdaxdpL
ggRkBUNfbTmDMvsjc3GxFHsXuX5cJUKVM2V8x5gNvtDBINiavy8HyQjhwSyTprRM
KBConOKsh/WntsiakcsefVpc9kAR6DJjVvhFmLqHBUMrpBtDf5pb2JVgp/qn0oCw
YqD30umtSUWyZaW1I1Nh
-----END CERTIFICATE-----

Просмотреть файл

@ -21,6 +21,7 @@ TEST_DIRS += [
'test_cert_trust',
'test_cert_version',
'test_certDB_import',
'test_content_signing',
'test_ev_certs',
'test_getchain',
'test_intermediate_basic_usage_constraints',

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше