<pre style='margin:0'>
Herby Gillot (herbygillot) pushed a commit to branch master
in repository macports-ports.
</pre>
<p><a href="https://github.com/macports/macports-ports/commit/f19d419984c33bff4d3695ccbec4b620d31f82f5">https://github.com/macports/macports-ports/commit/f19d419984c33bff4d3695ccbec4b620d31f82f5</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit f19d419984c33bff4d3695ccbec4b620d31f82f5
</span>Author: Sergey Fedorov <barracuda@macos-powerpc.org>
AuthorDate: Fri Nov 29 21:07:23 2024 +0800
<span style='display:block; white-space:pre;color:#404040;'> QMPlay2: legacy version: fix YouTube search, backport bit-perfect audio
</span>---
multimedia/QMPlay2/Portfile | 24 +-
multimedia/QMPlay2/files/0007-Fix-YT-search.patch | 414 +++++++
.../QMPlay2/files/0008-Switch-to-yt-dlp.patch | 85 ++
...llow-bit-perfect-audio-output-for-macOS-1.patch | 1207 ++++++++++++++++++++
...e-fetching-yt-dlp-it-does-not-work-use-Ma.patch | 61 +
.../files/0011-YouTubeDL-move-to-QJson.patch | 88 ++
...-Fix-Qt-paths.patch => 0012-Fix-Qt-paths.patch} | 0
7 files changed, 1876 insertions(+), 3 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/multimedia/QMPlay2/Portfile b/multimedia/QMPlay2/Portfile
</span><span style='display:block; white-space:pre;color:#808080;'>index adca8308f22..3e2aee1897b 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/multimedia/QMPlay2/Portfile
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/multimedia/QMPlay2/Portfile
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -18,6 +18,12 @@ if {${os.platform} eq "darwin" && ${os.major} < 15} {
</span> size 1228156
github.tarball_from archive
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ # These are added to support YouTube:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_lib-append \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:qjson4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_run-append \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:yt-dlp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> patchfiles-append \
0001-macOS-unbreak-build-with-Qt4.patch \
0002-MainWidget-fix-for-missing-qt_mac_set_dock_menu.patch \
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -25,14 +31,19 @@ if {${os.platform} eq "darwin" && ${os.major} < 15} {
</span> 0004-PlayClass-do-not-use-QRawFont.patch \
0005-Revert-some-broken-code.patch \
0006-FFMpeg-fix-compatibility-with-modern-FFMpeg.patch \
<span style='display:block; white-space:pre;background:#ffe0e0;'>- 0007-Fix-Qt-paths.patch
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 0007-Fix-YT-search.patch \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 0008-Switch-to-yt-dlp.patch \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 0009-PortAudio-Allow-bit-perfect-audio-output-for-macOS-1.patch \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 0010-Do-not-force-fetching-yt-dlp-it-does-not-work-use-Ma.patch \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 0011-YouTubeDL-move-to-QJson.patch \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 0012-Fix-Qt-paths.patch
</span>
configure.args-append \
-DDEFAULT_QT5=OFF \
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ -DUSE_FFMPEG_VTB=OFF \
</span> -DUSE_JEMALLOC=OFF \
-DUSE_OPENGL2=OFF \
<span style='display:block; white-space:pre;background:#ffe0e0;'>- -DUSE_TEKSTOWO=ON \
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- -DUSE_FFMPEG_VTB=OFF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ -DUSE_TEKSTOWO=ON
</span>
compiler.cxx_standard 2011
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -51,6 +62,13 @@ if {${os.platform} eq "darwin" && ${os.major} < 15} {
</span> }
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ notes "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ${name} expects to have yt-dlp in ~/.qmplay2/ and use it for YouTube playback.\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ After installation you could make a symlink to MacPorts-provided yt-dlp:\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ln -s ${prefix}/bin/yt-dlp ~/.qmplay/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> variant jemalloc description "Use Jemalloc" {
depends_lib-append \
port:jemalloc
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/multimedia/QMPlay2/files/0007-Fix-YT-search.patch b/multimedia/QMPlay2/files/0007-Fix-YT-search.patch
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 00000000000..eb9c52917d8
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/multimedia/QMPlay2/files/0007-Fix-YT-search.patch
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,414 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From 176915efac285fe23935db666771af3b93f3bbfc Mon Sep 17 00:00:00 2001
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From: Sergey Fedorov <vital.had@gmail.com>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Date: Tue, 19 Nov 2024 15:09:39 +0800
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Subject: [PATCH 07/11] Fix YT search
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/Extensions/CMakeLists.txt | 3 +-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/Extensions/YouTube.cpp | 261 ++++++++++++--------------
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/Extensions/YouTube.hpp | 7 +-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/qmplay2/Functions.cpp | 31 +++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/qmplay2/headers/Functions.hpp | 2 +
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 5 files changed, 157 insertions(+), 147 deletions(-)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/Extensions/CMakeLists.txt src/modules/Extensions/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index a56ceea4..6f69bb81 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/Extensions/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/Extensions/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -117,7 +117,8 @@ add_library(${PROJECT_NAME} ${QMPLAY2_MODULE}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if(USE_QT5)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ qt5_use_modules(${PROJECT_NAME} Gui Widgets ${DBUS})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- target_link_libraries(${PROJECT_NAME} Qt4::QtCore Qt4::QtGui ${DBUS})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ add_definitions(-I/opt/local/include/QJson4)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ target_link_libraries(${PROJECT_NAME} Qt4::QtCore Qt4::QtGui QJson4 ${DBUS})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ endif()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ add_dependencies(${PROJECT_NAME} libqmplay2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/Extensions/YouTube.cpp src/modules/Extensions/YouTube.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 4e71605b..73924de2 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/Extensions/YouTube.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/Extensions/YouTube.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -26,6 +26,9 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QStringListModel>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QDesktopServices>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QTextDocument>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonParseError.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonObject.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonArray.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QProgressBar>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QApplication>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QHeaderView>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -819,133 +822,94 @@ void YouTube::setAutocomplete(const QByteArray &data)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ completer->complete();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-void YouTube::setSearchResults(QString data)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void YouTube::setSearchResults(const QByteArray &data)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- /* Usuwanie komentarzy HTML */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- for (int commentIdx = 0 ;;)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto json = getYtInitialData(data);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto contents = json.object()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["contents"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["twoColumnSearchResultsRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["primaryContents"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["sectionListRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["contents"].toArray().at(0).toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["itemSectionRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["contents"].toArray()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (auto &&obj : contents)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if ((commentIdx = data.indexOf("<!--", commentIdx)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int commentEndIdx = data.indexOf("-->", commentIdx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (commentEndIdx >= 0) //Jeżeli jest koniec komentarza
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- data.remove(commentIdx, commentEndIdx - commentIdx + 3); //Wyrzuć zakomentowany fragment
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- data.remove(commentIdx, data.length() - commentIdx); //Wyrzuć cały tekst do końca
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto videoRenderer = obj.toObject()["videoRenderer"].toObject();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto playlistRenderer = obj.toObject()["playlistRenderer"].toObject();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const QStringList splitted = data.split("yt-lockup ");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- for (i = 1; i < splitted.count(); ++i)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QString title, videoInfoLink, duration, image, user;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const QString &entry = splitted[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const bool isVideo = !videoRenderer.isEmpty() && playlistRenderer.isEmpty();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (entry.contains("yt-lockup-channel")) //Ignore channels
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QString title, contentId, length, user, publishedTime, viewCount, thumbnail, url;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const bool isPlaylist = entry.contains("yt-lockup-playlist");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if ((idx = entry.indexOf("yt-lockup-title")) > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (isVideo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int urlIdx = entry.indexOf("href=\"", idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int titleIdx = entry.indexOf("title=\"", idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (titleIdx > -1 && urlIdx > -1 && titleIdx > urlIdx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const int endUrlIdx = entry.indexOf("\"", urlIdx += 6);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const int endTitleIdx = entry.indexOf("\"", titleIdx += 7);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (endTitleIdx > -1 && endUrlIdx > -1 && endTitleIdx > endUrlIdx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- videoInfoLink = entry.mid(urlIdx, endUrlIdx - urlIdx).replace("&", "&");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (!videoInfoLink.isEmpty() && videoInfoLink.startsWith('/'))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- videoInfoLink.prepend(YOUTUBE_URL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- title = entry.mid(titleIdx, endTitleIdx - titleIdx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ title = videoRenderer["title"].toObject()["runs"].toArray().at(0).toObject()["text"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ contentId = videoRenderer["videoId"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (title.isEmpty() || contentId.isEmpty())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ length = videoRenderer["lengthText"].toObject()["simpleText"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ user = videoRenderer["ownerText"].toObject()["runs"].toArray().at(0).toObject()["text"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ publishedTime = videoRenderer["publishedTimeText"].toObject()["simpleText"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ viewCount = videoRenderer["shortViewCountText"].toObject()["simpleText"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ thumbnail = videoRenderer["thumbnail"].toObject()["thumbnails"].toArray().at(0).toObject()["url"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ url = YOUTUBE_URL "/watch?v=" + contentId;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if ((idx = entry.indexOf("video-thumb")) > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int skip = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int imgIdx = entry.indexOf("data-thumb=\"", idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (imgIdx > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- skip = 12;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- imgIdx = entry.indexOf("src=\"", idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- skip = 5;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (imgIdx > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int imgEndIdx = entry.indexOf("\"", imgIdx += skip);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (imgEndIdx > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- image = entry.mid(imgIdx, imgEndIdx - imgIdx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (image.endsWith(".gif")) //GIF nie jest miniaturką - jest to pojedynczy piksel :D (very old code, is it still relevant?)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- image.clear();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- else if (image.startsWith("//"))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- image.prepend("https:");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if ((idx = image.indexOf("?")) > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- image.truncate(idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (!isPlaylist && (idx = entry.indexOf("video-time")) > -1 && (idx = entry.indexOf(">", idx)) > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int endIdx = entry.indexOf("<", idx += 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (endIdx > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- duration = entry.mid(idx, endIdx - idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (!duration.startsWith("0") && duration.indexOf(":") == 1 && duration.count(":") == 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- duration.prepend("0");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if ((idx = entry.indexOf("yt-lockup-byline")) > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int endIdx = entry.indexOf("</a>", idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (endIdx > -1 && (idx = entry.lastIndexOf(">", endIdx)) > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- ++idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- user = entry.mid(idx, endIdx - idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ title = playlistRenderer["title"].toObject()["simpleText"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ contentId = playlistRenderer["playlistId"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (title.isEmpty() || contentId.isEmpty())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ user = playlistRenderer["longBylineText"].toObject()["runs"].toArray().at(0).toObject()["text"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ thumbnail = playlistRenderer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["thumbnailRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["playlistVideoThumbnailRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["thumbnail"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["thumbnails"].toArray().at(0).toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["url"].toString()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ url = YOUTUBE_URL "/playlist?list=" + contentId;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (!title.isEmpty() && !videoInfoLink.isEmpty())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QTreeWidgetItem *tWI = new QTreeWidgetItem(resultsW);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setDisabled(true);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ auto tWI = new QTreeWidgetItem(resultsW);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QTextDocument txtDoc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- txtDoc.setHtml(title);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setText(0, title);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setText(1, isVideo ? length : tr("Playlist"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setText(2, user);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setText(0, txtDoc.toPlainText());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setText(1, !isPlaylist ? duration : tr("Playlist"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setText(2, user);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QString tooltip;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tooltip += QString("%1: %2\n").arg(resultsW->headerItem()->text(0), tWI->text(0));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tooltip += QString("%1: %2\n").arg(isVideo ? resultsW->headerItem()->text(1) : tr("Playlist"), isVideo ? tWI->text(1) : tr("yes"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tooltip += QString("%1: %2\n").arg(resultsW->headerItem()->text(2), tWI->text(2));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tooltip += QString("%1: %2\n").arg(tr("Published time"), publishedTime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tooltip += QString("%1: %2").arg(tr("View count"), viewCount);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setToolTip(0, tooltip);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setToolTip(0, QString("%1: %2\n%3: %4\n%5: %6")
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- .arg(resultsW->headerItem()->text(0), tWI->text(0),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- !isPlaylist ? resultsW->headerItem()->text(1) : tr("Playlist"),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- !isPlaylist ? tWI->text(1) : tr("yes"),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- resultsW->headerItem()->text(2), tWI->text(2))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setData(0, Qt::UserRole, url);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setData(1, Qt::UserRole, !isVideo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setData(0, Qt::UserRole, videoInfoLink);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setData(1, Qt::UserRole, isPlaylist);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!isVideo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setDisabled(true);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- NetworkReply *linkReply = net.start(videoInfoLink);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- NetworkReply *imageReply = net.start(image);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- linkReply->setProperty("tWI", qVariantFromValue((void *)tWI));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- imageReply->setProperty("tWI", qVariantFromValue((void *)tWI));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ auto linkReply = net.start(url);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ linkReply->setProperty("tWI", QVariant::fromValue((void *)tWI));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ linkReplies += linkReply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!thumbnail.isEmpty())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ auto imageReply = net.start(thumbnail);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ imageReply->setProperty("tWI", QVariant::fromValue((void *)tWI));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ imageReplies += imageReply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (i == 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- resultsW->clear();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (resultsW->topLevelItemCount() > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pageSwitcher->currPageB->setValue(currPage);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pageSwitcher->show();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1249,44 +1213,53 @@ QStringList YouTube::getUrlByItagPriority(const QList<int> &itags, QStringList r
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-void YouTube::preparePlaylist(const QString &data, QTreeWidgetItem *tWI)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void YouTube::preparePlaylist(const QByteArray &data, QTreeWidgetItem *tWI)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- int idx = data.indexOf("playlist-videos-container");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (idx > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QStringList playlist;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto json = getYtInitialData(data);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto contents = json.object()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["contents"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["twoColumnBrowseResultsRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["tabs"].toArray().at(0).toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["tabRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["content"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["sectionListRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["contents"].toArray().at(0).toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["itemSectionRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["contents"].toArray().at(0).toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["playlistVideoListRenderer"].toObject()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ["contents"].toArray()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (auto &&obj : contents)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const QString tags[2] = {"video-id", "video-title"};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QStringList playlist, entries = data.mid(idx).split("yt-uix-scroller-scroll-unit", QString::SkipEmptyParts);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- entries.removeFirst();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- for (const QString &entry : entries)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QStringList plistEntry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- for (int i = 0; i < 2; ++i)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- idx = entry.indexOf(tags[i]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (idx > -1 && (idx = entry.indexOf('"', idx += tags[i].length())) > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const int endIdx = entry.indexOf('"', idx += 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (endIdx > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const QString str = entry.mid(idx, endIdx - idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (!i)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- plistEntry += str;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QTextDocument txtDoc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- txtDoc.setHtml(str);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- plistEntry += txtDoc.toPlainText();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (plistEntry.count() == 2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- playlist += plistEntry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (!playlist.isEmpty())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setData(0, Qt::UserRole + 1, playlist);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- tWI->setDisabled(false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto playlistRenderer = obj.toObject()["playlistVideoRenderer"].toObject();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto title = playlistRenderer["title"].toObject()["simpleText"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto videoId = playlistRenderer["videoId"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (title.isEmpty() || videoId.isEmpty())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ playlist += {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ videoId,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ title,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!playlist.isEmpty())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setData(0, Qt::UserRole + 1, playlist);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ tWI->setDisabled(false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++QJsonDocument YouTube::getYtInitialData(const QByteArray &data)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ int idx = data.indexOf("ytInitialData");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (idx < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return QJsonDocument();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ idx = data.indexOf("{", idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (idx < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return QJsonDocument();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ int idx2 = Functions::findJsonEnd(data, idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (idx2 < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return QJsonDocument();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const auto jsonData = data.mid(idx, idx2 - idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return QJsonDocument::fromJson(jsonData);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/Extensions/YouTube.hpp src/modules/Extensions/YouTube.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 97e7be21..9070b408 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/Extensions/YouTube.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/Extensions/YouTube.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -25,6 +25,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QTreeWidget>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QPointer>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QMap>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonDocument.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ class QProgressBar;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ class QToolButton;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -132,13 +133,15 @@ private:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ void deleteReplies();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ void setAutocomplete(const QByteArray &data);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- void setSearchResults(QString data);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ void setSearchResults(const QByteArray &data);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QStringList getYouTubeVideo(const QString &data, const QString &PARAM = QString(), QTreeWidgetItem *tWI = nullptr, const QString &url = QString(), IOController<YouTubeDL> *youtube_dl = nullptr); //jeżeli (tWI == nullptr) to zwraca {URL, file_extension, TITLE}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QStringList getUrlByItagPriority(const QList<int> &itags, QStringList ret);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- void preparePlaylist(const QString &data, QTreeWidgetItem *tWI);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ void preparePlaylist(const QByteArray &data, QTreeWidgetItem *tWI);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QJsonDocument getYtInitialData(const QByteArray &data);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++private:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DockWidget *dw;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QIcon youtubeIcon, videoIcon;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/qmplay2/Functions.cpp src/qmplay2/Functions.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 35e59931..03ec70ee 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/qmplay2/Functions.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/qmplay2/Functions.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -912,3 +912,34 @@ QByteArray Functions::decryptAes256Cbc(const QByteArray &password, const QByteAr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deciphered.resize(decryptedLen + finalizeLen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return deciphered;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++int Functions::findJsonEnd(const QByteArray &data, int idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const int dataLen = data.length();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dataLen < 1 || idx < 0 || idx >= dataLen || data.at(idx) != '{')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ int brackets = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ bool inString = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ char prevChr = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (int i = idx + 1; i < dataLen; ++i)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const char chr = data.at(i);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (chr == '"')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!inString)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ inString = true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ else if (prevChr != '\\')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ inString = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ prevChr = chr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (inString)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (chr == '{')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ++brackets;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ else if (chr == '}')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ --brackets;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (brackets == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return i + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/qmplay2/headers/Functions.hpp src/qmplay2/headers/Functions.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index e74c48f1..ef4dd090 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/qmplay2/headers/Functions.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/qmplay2/headers/Functions.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -158,4 +158,6 @@ namespace Functions
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ void setHeaderSectionResizeMode(QHeaderView *header, int index, int resizeMode);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QByteArray decryptAes256Cbc(const QByteArray &password, const QByteArray &salt, const QByteArray &ciphered);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ int findJsonEnd(const QByteArray &data, int idx = 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/multimedia/QMPlay2/files/0008-Switch-to-yt-dlp.patch b/multimedia/QMPlay2/files/0008-Switch-to-yt-dlp.patch
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 00000000000..fc70aafd8c1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/multimedia/QMPlay2/files/0008-Switch-to-yt-dlp.patch
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,85 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From bf4f953cf6f083d6bc876543f7ac8e77a123abbf Mon Sep 17 00:00:00 2001
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From: Sergey Fedorov <vital.had@gmail.com>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Date: Tue, 19 Nov 2024 17:04:56 +0800
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Subject: [PATCH 08/11] Switch to yt-dlp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/qmplay2/YouTubeDL.cpp | 40 ++++++++++-----------------------------
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 1 file changed, 10 insertions(+), 30 deletions(-)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/qmplay2/YouTubeDL.cpp src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index de7b96be..98071fea 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -22,10 +22,9 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QMPlay2Core.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <Version.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <Json11.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#ifdef Q_OS_WIN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- #include <Functions.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <Functions.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QRegExp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QReadWriteLock>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QFile>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -50,9 +49,9 @@ static void exportCookiesFromJSON(const QString &jsonData, const QString &url)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QString YouTubeDL::getFilePath()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- return QMPlay2Core.getSettingsDir() + "youtube-dl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return QMPlay2Core.getSettingsDir() + "yt-dlp"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #ifdef Q_OS_WIN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- ".exe"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ "_x86.exe"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -286,30 +285,11 @@ QStringList YouTubeDL::exec(const QString &url, const QStringList &args, QString
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updateOutput += m_process.readAllStandardOutput() + m_process.readAllStandardError();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (updateOutput.contains("ERROR:") || updateOutput.contains("package manager"))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ error += "\n" + updateOutput;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- else if (m_process.exitCode() == 0 && !updateOutput.contains("up-to-date"))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ else if (m_process.exitCode() == 0 && !updateOutput.contains(QRegExp(R"(up\Wto\Wdate)")))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#ifdef Q_OS_WIN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const QString updatedFile = ytDlPath + ".new";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QFile::remove(Functions::filePath(ytDlPath) + "youtube-dl-updater.bat");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (QFile::exists(updatedFile))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- Functions::s_wait(0.2); //Wait 200 ms to be sure that file is closed
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QFile::remove(ytDlPath);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (QFile::rename(updatedFile, ytDlPath))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QMPlay2Core.setWorking(false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- emit QMPlay2Core.sendMessage(tr("\"youtube-dl\" has been successfully updated!"), g_name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- g_lock.unlock(); // Unlock for write
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- return exec(url, args, silentErr, false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#ifdef Q_OS_WIN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- error += "\nUpdated youtube-dl file: \"" + updatedFile + "\" not found!";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QMPlay2Core.setWorking(false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ emit QMPlay2Core.sendMessage(tr("\"youtube-dl\" has been successfully updated!"), g_name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return {};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else if (updating && m_aborted)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -339,9 +319,9 @@ QStringList YouTubeDL::exec(const QString &url, const QStringList &args, QString
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else if (canUpdate && !m_aborted && m_process.error() == QProcess::FailedToStart)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const QString downloadUrl = "https://yt-dl.org/downloads/latest/youtube-dl"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const QString downloadUrl = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #ifdef Q_OS_WIN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- ".exe"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ "_x86.exe"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/multimedia/QMPlay2/files/0009-PortAudio-Allow-bit-perfect-audio-output-for-macOS-1.patch b/multimedia/QMPlay2/files/0009-PortAudio-Allow-bit-perfect-audio-output-for-macOS-1.patch
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 00000000000..6ec8eb1db4d
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/multimedia/QMPlay2/files/0009-PortAudio-Allow-bit-perfect-audio-output-for-macOS-1.patch
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,1207 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From 4ce1e7e12d4801d03c25ae6b9ef12ef366c0b083 Mon Sep 17 00:00:00 2001
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From: =?UTF-8?q?Ren=C3=A9=20Bertin?= <rjvbertin@gmail.com>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Date: Mon, 12 Feb 2018 18:20:07 +0100
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Subject: [PATCH] PortAudio: Allow bit-perfect audio output for macOS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (#108)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+When QMPlay2 isn't configured to resample all audio content to a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+user-specific sample rate it sends the demuxed and decoded audio stream
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+"as is" to the selected audio device. When using the PortAudio module a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+stream is opened that is set to the content sample rate, but no attempt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+is made to configure the device appropriately.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+This patch introduces an initial implementation of a bit-perfect audio
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+option in the PortAudio module for macOS. After opening the PA stream,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+platform-native APIs are called to switch the selected audio device to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+the content's sample rate or to the most appropriate (closest) supported
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+sample rate. The initial device settings are cached and restored when
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+playback is stopped.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+barracuda156: Some fixes added for Qt4 compat.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .../3rdparty/CoreAudio/AudioDevice.h | 136 ++++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .../3rdparty/CoreAudio/AudioDevice.mm | 645 ++++++++++++++++++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .../3rdparty/CoreAudio/AudioDeviceList.cpp | 98 +++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ .../3rdparty/CoreAudio/AudioDeviceList.h | 82 +++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/PortAudio/CMakeLists.txt | 10 +
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/PortAudio/PortAudio.cpp | 12 +
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/PortAudio/PortAudio.hpp | 3 +
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/PortAudio/PortAudioWriter.cpp | 53 +-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/PortAudio/PortAudioWriter.hpp | 7 +
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 9 files changed, 1045 insertions(+), 1 deletion(-)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ create mode 100644 src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ create mode 100644 src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.mm
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ create mode 100644 src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ create mode 100644 src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.h src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+new file mode 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 00000000..9d5788e4
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -0,0 +1,136 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ File: AudioDevice.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Adapted from the CAPlayThough example
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Version: 1.2.2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Inc. ("Apple") in consideration of your agreement to the following
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ terms, and your use, installation, modification or redistribution of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ this Apple software constitutes acceptance of these terms. If you do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ not agree with these terms, please do not use, install, modify or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ redistribute this Apple software.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ In consideration of your agreement to abide by the following terms, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ subject to these terms, Apple grants you a personal, non-exclusive
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ license, under Apple's copyrights in this original Apple software (the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ "Apple Software"), to use, reproduce, modify and redistribute the Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Software, with or without modifications, in source and/or binary forms;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ provided that if you redistribute the Apple Software in its entirety and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ without modifications, you must retain this notice and the following
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ text and disclaimers in all such redistributions of the Apple Software.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Neither the name, trademarks, service marks or logos of Apple Inc. may
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ be used to endorse or promote products derived from the Apple Software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ without specific prior written permission from Apple. Except as
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ expressly stated in this notice, no other rights or licenses, express or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ implied, are granted by Apple herein, including but not limited to any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ patent rights that may be infringed by your derivative works or by other
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ works in which the Apple Software may be incorporated.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ The Apple Software is provided by Apple on an "AS IS" basis. APPLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ POSSIBILITY OF SUCH DAMAGE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Copyright (C) 2013 Apple Inc. All Rights Reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Copyright (C) 2017,18 René J.V. Bertin All Rights Reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifndef __AudioDevice_h__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define __AudioDevice_h__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <CoreServices/CoreServices.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <CoreAudio/CoreAudio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <AvailabilityMacros.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <qglobal.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifndef DEPRECATED_LISTENER_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# define DEPRECATED_LISTENER_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# warning "Using the deprecated PropertyListener API; at least it works"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef DEPRECATED_LISTENER_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++using AudioPropertyListenerProc = AudioDevicePropertyListenerProc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++using AudioPropertyListenerProc = AudioObjectPropertyListenerProc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++class AudioDeviceList;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++class AudioDevice {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++public:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevice();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevice(AudioDeviceID devid, bool isInput=false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevice(AudioDeviceID devid, AudioPropertyListenerProc lProc, bool isInput=false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ~AudioDevice();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ void Init(AudioPropertyListenerProc lProc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ bool Valid() { return mID != kAudioDeviceUnknown; }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ void SetBufferSize(UInt32 size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus NominalSampleRate(Float64 &sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ inline Float64 ClosestNominalSampleRate(Float64 sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus SetNominalSampleRate(Float64 sampleRate, Boolean force=false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus ResetNominalSampleRate(Boolean force=false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus SetStreamBasicDescription(AudioStreamBasicDescription *desc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ int CountChannels();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ char *GetName(char *buf=NULL, UInt32 maxlen=0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ void SetInitialNominalSampleRate(Float64 sampleRate)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mInitialFormat.mSampleRate = sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 CurrentNominalSampleRate()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return currentNominalSR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceID ID()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return mID;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ static AudioDevice *GetDefaultDevice(Boolean forInput, OSStatus &err, AudioDevice *dev=NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ static AudioDevice *GetDevice(AudioDeviceID devId, Boolean forInput, AudioDevice *dev=NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++protected:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevice(AudioDeviceID devid, bool quick, bool isInput);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioStreamBasicDescription mInitialFormat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioPropertyListenerProc listenerProc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus GetPropertyDataSize( AudioObjectPropertySelector property, UInt32 *size, AudioObjectPropertyAddress *propertyAddress=NULL );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 currentNominalSR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 minNominalSR, maxNominalSR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 nominalSampleRates;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 *nominalSampleRateList = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ bool discreteSampleRateList;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const AudioDeviceID mID;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const bool mForInput;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 mSafetyOffset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 mBufferSizeFrames;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioStreamBasicDescription mFormat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ char mDevName[256] = "";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ bool mInitialised = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++friend class AudioDeviceList;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++public:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 listenerSilentFor;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif // __AudioDevice_h__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.mm src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.mm
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+new file mode 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 00000000..f631b4e7
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.mm
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -0,0 +1,645 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ File: AudioDevice.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Adapted from the CAPlayThough example
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Version: 1.2.2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Inc. ("Apple") in consideration of your agreement to the following
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ terms, and your use, installation, modification or redistribution of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ this Apple software constitutes acceptance of these terms. If you do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ not agree with these terms, please do not use, install, modify or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ redistribute this Apple software.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ In consideration of your agreement to abide by the following terms, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ subject to these terms, Apple grants you a personal, non-exclusive
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ license, under Apple's copyrights in this original Apple software (the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ "Apple Software"), to use, reproduce, modify and redistribute the Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Software, with or without modifications, in source and/or binary forms;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ provided that if you redistribute the Apple Software in its entirety and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ without modifications, you must retain this notice and the following
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ text and disclaimers in all such redistributions of the Apple Software.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Neither the name, trademarks, service marks or logos of Apple Inc. may
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ be used to endorse or promote products derived from the Apple Software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ without specific prior written permission from Apple. Except as
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ expressly stated in this notice, no other rights or licenses, express or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ implied, are granted by Apple herein, including but not limited to any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ patent rights that may be infringed by your derivative works or by other
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ works in which the Apple Software may be incorporated.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ The Apple Software is provided by Apple on an "AS IS" basis. APPLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ POSSIBILITY OF SUCH DAMAGE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Copyright (C) 2013 Apple Inc. All Rights Reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Copyright (C) 2017,18 René J.V. Bertin All Rights Reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "AudioDevice.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#import <Cocoa/Cocoa.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#if MAC_OS_X_VERSION_MIN_REQUIRED > 1080
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ #define verify_noerr __Verify_noErr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++char *OSTStr(OSType type)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ static union OSTStr {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ uint32_t four;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ char str[5];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } ltype;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ltype.four = EndianU32_BtoN(type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ltype.str[4] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return ltype.str;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++// the sample rates that can be found in the selections proposed by Audio Midi Setup. Are these representative
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++// for the devices I have at my disposal, or are they determined by discrete supported values hardcoded into
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++// CoreAudio or the HAL? Is there any advantage in using one of these rates, as opposed to using a different rate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++// on devices that support any rate in an interval?
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static Float64 supportedSRateList[] = {6400, 8000, 11025, 12000, 16000, 22050,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ 24000, 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static UInt32 supportedSRates = sizeof(supportedSRateList) / sizeof(Float64);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef DEPRECATED_LISTENER_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++OSStatus DefaultListener(AudioDeviceID inDevice, UInt32 inChannel, Boolean forInput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevicePropertyID inPropertyID,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ void *inClientData)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevice *dev = (AudioDevice *) inClientData;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSString *msg = [NSString stringWithFormat:@"Property %s of device %u changed; data=%p",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSTStr((OSType)inPropertyID), (unsigned int)inDevice, inClientData ];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { inPropertyID,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ forInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ switch (inPropertyID) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ case kAudioDevicePropertyNominalSampleRate:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ size = sizeof(sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (AudioObjectGetPropertyData(inPropertyID, &theAddress, 0, NULL, &size, &sampleRate) == noErr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ && (dev && !dev->listenerSilentFor)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"%@\n\tkAudioDevicePropertyNominalSampleRate=%g\n", msg, sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ case kAudioDevicePropertyActualSampleRate:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ size = sizeof(sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (AudioObjectGetPropertyData(inPropertyID, &theAddress, 0, NULL, &size, &sampleRate) == noErr && dev) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // update the rate we should reset to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ dev->SetInitialNominalSampleRate(sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!dev->listenerSilentFor) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"%@\n\tkAudioDevicePropertyActualSampleRate=%g\n", msg, sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if ((dev && !dev->listenerSilentFor)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"%@", msg);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dev && dev->listenerSilentFor) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ dev->listenerSilentFor -= 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (pool) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ [pool drain];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return noErr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else // !DEPRECATED_LISTENER_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static OSStatus DefaultListener(AudioObjectID inObjectID, UInt32 inNumberProperties,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const AudioObjectPropertyAddress propTable[],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ void *inClientData)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevice *dev = static_cast<AudioDevice *>(inClientData);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (int i = 0 ; i < inNumberProperties ; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSString *msg = [NSString stringWithFormat:@"#%d Property %s of device %u changed; data=%p", i,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSTStr((OSType)propTable[i].mElement), (unsigned int)inObjectID, inClientData ];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ switch (propTable[i].mElement) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ case kAudioDevicePropertyNominalSampleRate:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ size = sizeof(sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (AudioObjectGetPropertyData(inObjectID, &propTable[i], 0, NULL, &size, &sampleRate) == noErr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ && (dev && !dev->listenerSilentFor)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"%@\n\tkAudioDevicePropertyNominalSampleRate=%g\n", msg, sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ case kAudioDevicePropertyActualSampleRate:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ size = sizeof(sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (AudioObjectGetPropertyData(inObjectID, &propTable[i], 0, NULL, &size, &sampleRate) == noErr && dev) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // update the rate we should reset to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ dev->SetInitialNominalSampleRate(sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!dev->listenerSilentFor) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"%@\n\tkAudioDevicePropertyActualSampleRate=%g\n", msg, sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if ((dev && !dev->listenerSilentFor)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"%@", msg);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dev && dev->listenerSilentFor) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ dev->listenerSilentFor -= 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (pool) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ [pool drain];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return noErr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void AudioDevice::Init(AudioPropertyListenerProc lProc = DefaultListener)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (mID == kAudioDeviceUnknown) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus err = noErr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // getting the device name can be surprisingly slow, so we get and cache it here
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ GetName();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 propsize = sizeof(Float32);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { kAudioDevicePropertySafetyOffset,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mForInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }; // channel
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &propsize, &mSafetyOffset));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propsize = sizeof(UInt32);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ theAddress.mSelector = kAudioDevicePropertyBufferFrameSize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &propsize, &mBufferSizeFrames));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerProc = lProc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerSilentFor = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (lProc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef DEPRECATED_LISTENER_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceAddPropertyListener(mID, 0, false, kAudioDevicePropertyActualSampleRate, lProc, this);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceAddPropertyListener(mID, 0, false, kAudioDevicePropertyNominalSampleRate, lProc, this);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceAddPropertyListener(mID, 0, false, kAudioHardwarePropertyDefaultOutputDevice, lProc, this);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress prop = { kAudioDevicePropertyActualSampleRate,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyScopeGlobal,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if ((err = AudioObjectAddPropertyListener(mID, &prop, lProc, this)) != noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"Couldn't register property listener for actual sample rate: %d (%s)", err, OSTStr(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ prop.mElement = kAudioDevicePropertyNominalSampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if ((err = AudioObjectAddPropertyListener(mID, &prop, lProc, this)) != noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"Couldn't register property listener for nominal sample rate: %d (%s)", err, OSTStr(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ prop.mElement = kAudioHardwarePropertyDefaultOutputDevice;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if ((err = AudioObjectAddPropertyListener(mID, &prop, lProc, this)) != noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"Couldn't register property listener for selected default device: %d (%s)", err, OSTStr(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"Warning: no CoreAudio event listener has been defined");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propsize = sizeof(Float64);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ theAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &propsize, ¤tNominalSR));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propsize = sizeof(AudioStreamBasicDescription);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ theAddress.mSelector = kAudioDevicePropertyStreamFormat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &propsize, &mInitialFormat));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mFormat = mInitialFormat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propsize = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ theAddress.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // attempt to build a list of the supported sample rates
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if ((err = AudioObjectGetPropertyDataSize(mID, &theAddress, 0, NULL, &propsize)) == noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioValueRange *list;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // use a fall-back value of 100 supported rates:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (propsize == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propsize = 100 * sizeof(AudioValueRange);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if ((list = (AudioValueRange *) calloc(1, propsize))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ theAddress.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &propsize, list);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (err == noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ nominalSampleRates = propsize / sizeof(AudioValueRange);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSMutableArray *a = [NSMutableArray arrayWithCapacity:nominalSampleRates];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ minNominalSR = list[0].mMinimum;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ maxNominalSR = list[0].mMaximum;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // store the returned sample rates in [a] and record the extreme values
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (i = 0 ; i < nominalSampleRates ; i++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (minNominalSR > list[i].mMinimum) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ minNominalSR = list[i].mMinimum;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (maxNominalSR < list[i].mMaximum) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ maxNominalSR = list[i].mMaximum;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (a) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (list[i].mMinimum != list[i].mMaximum) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 j;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ discreteSampleRateList = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // the 'guessing' case: the device specifies one or more ranges, without
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // indicating which rates in that range(s) are supported. We assume the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // rates that Audio Midi Setup shows.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (j = 0 ; j < supportedSRates ; j++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (supportedSRateList[j] >= list[i].mMinimum
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ && supportedSRateList[j] <= list[i].mMaximum
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ [a addObject:[NSNumber numberWithDouble:supportedSRateList[j]]];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // there's at least one part of the sample rate list that contains discrete
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // supported values. I don't know if there are devices that "do this" or if they all
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // either give discrete rates or a single continuous range. So we take the easy
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // opt-out solution: this only costs a few cycles attempting to match a requested
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // non-listed rate (with the potential "risk" of matching to a listed integer multiple,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // which should not cause any aliasing).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ discreteSampleRateList = true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // the easy case: the device specifies one or more discrete rates
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (![a containsObject:[NSNumber numberWithDouble:list[i].mMinimum]]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ [a addObject:[NSNumber numberWithDouble:list[i].mMinimum]];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (a) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // sort the array (should be the case but one never knows)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ [a sortUsingSelector:@selector(compare:)];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // retrieve the number of unique rates:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ nominalSampleRates = [a count];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // now copy the rates into a simple C array for faster access
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if ((nominalSampleRateList = new Float64[nominalSampleRates])) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (i = 0 ; i < nominalSampleRates ; i++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ nominalSampleRateList[i] = [[a objectAtIndex:i] doubleValue];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"Using audio device %u \"%s\", %u sample rates in %lu range(s); [%g,%g] %@; current sample rate %gHz",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mID, GetName(), nominalSampleRates, propsize / sizeof(AudioValueRange),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ minNominalSR, maxNominalSR, (discreteSampleRateList) ? [a description] : @"continuous", currentNominalSR);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"Using audio device %u \"%s\", %u sample rates in %lu range(s); [%g,%g] %s; current sample rate %gHz",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mID, GetName(), nominalSampleRates, propsize / sizeof(AudioValueRange),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ minNominalSR, maxNominalSR, (discreteSampleRateList) ? "" : "continuous", currentNominalSR);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // [a] will be flushed down the drain:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ [pool drain];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ free(list);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mInitialised = true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDevice::AudioDevice()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ : mID(kAudioDeviceUnknown)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ , mForInput(false)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerProc = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDevice::AudioDevice(AudioDeviceID devid, bool forInput)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ : mID(devid)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ , mForInput(forInput)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Init(DefaultListener);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDevice::AudioDevice(AudioDeviceID devid, bool quick, bool forInput)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ : mID(devid)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ , mForInput(forInput)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!quick) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Init(DefaultListener);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDevice::AudioDevice(AudioDeviceID devid, AudioPropertyListenerProc lProc, bool forInput)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ : mID(devid)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ , mForInput(forInput)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Init(lProc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDevice::~AudioDevice()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (mID != kAudioDeviceUnknown && mInitialised) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceID devId = mID;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // RJVB 20120902: setting the StreamFormat to the initially read values will set the channel bitdepth to 16??
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // so we reset just the nominal sample rate.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = SetNominalSampleRate(mInitialFormat.mSampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (err != noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ fprintf(stderr, "Cannot reset initial settings for device %u (%s): err %s, %ld\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ (unsigned int) mID, GetName(), OSTStr(err), (long) err);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (listenerProc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef DEPRECATED_LISTENER_API
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceRemovePropertyListener(mID, 0, false, kAudioDevicePropertyActualSampleRate, listenerProc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceRemovePropertyListener(mID, 0, false, kAudioDevicePropertyNominalSampleRate, listenerProc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceRemovePropertyListener(mID, 0, false, kAudioHardwarePropertyDefaultOutputDevice, listenerProc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress prop = { kAudioDevicePropertyActualSampleRate,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyScopeGlobal,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectRemovePropertyListener(mID, &prop, listenerProc, this));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ prop.mElement = kAudioDevicePropertyNominalSampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectRemovePropertyListener(mID, &prop, listenerProc, this));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ prop.mElement = kAudioHardwarePropertyDefaultOutputDevice;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectRemovePropertyListener(mID, &prop, listenerProc, this));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (nominalSampleRateList) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ delete nominalSampleRateList;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"AudioDevice %s (%u) released", mDevName, devId);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void AudioDevice::SetBufferSize(UInt32 size)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 propsize = sizeof(UInt32);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyBufferFrameSize,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mForInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }; // channel
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectSetPropertyData(mID, &theAddress, 0, NULL, propsize, &size));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &propsize, &mBufferSizeFrames));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++OSStatus AudioDevice::NominalSampleRate(Float64 &sampleRate)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 size = sizeof(Float64);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyNominalSampleRate,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mForInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &size, &sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (err == noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ currentNominalSR = sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++inline Float64 AudioDevice::ClosestNominalSampleRate(Float64 sampleRate)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (sampleRate > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifndef FORCE_STANDARD_SAMPLERATES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!discreteSampleRateList && sampleRate >= minNominalSR && sampleRate <= maxNominalSR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // the device suggests it supports this exact sample rate; use it.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerSilentFor = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (nominalSampleRateList && sampleRate >= minNominalSR && sampleRate <= maxNominalSR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 minRemainder = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 closest = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (UInt32 i = 0 ; i < nominalSampleRates ; i++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // check if we have a hit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (sampleRate == nominalSampleRateList[i]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ double dec, ent;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ dec = modf(nominalSampleRateList[i] / sampleRate, &ent);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // if the rate at i is an integer multiple of the requested sample rate.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dec == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerSilentFor = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return nominalSampleRateList[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else if ((1 - dec) < minRemainder) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // find the match that is closest to either 1*sampleRate or 2*sampleRate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // IOW, the fractional part of nominalSampleRate/sampleRate is closest
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // either to 0 or to 1 .
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ minRemainder = dec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ closest = nominalSampleRateList[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (closest > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerSilentFor = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return closest;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ static bool pass2 = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!pass2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 sr = sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ int fact = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // if we're here it's either because there's no list of known supported rates,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // or we didn't find an integer multiple of the requested rate in the list.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // scale up as required in steps of 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ while (sampleRate * fact < minNominalSR && sampleRate * (fact + 1) <= maxNominalSR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ fact += 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ sampleRate *= fact;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ fact = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // scale down as required in steps of 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ while (sampleRate / fact > maxNominalSR && sampleRate / (fact + 1) >= minNominalSR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ fact += 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ sampleRate /= fact;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (sr != sampleRate) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ pass2 = true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // we're now in range, do another pass to find a matching supported rate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ sampleRate = ClosestNominalSampleRate(sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ pass2 = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerSilentFor = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (sampleRate > maxNominalSR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ sampleRate = maxNominalSR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ sampleRate = minNominalSR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // note that we really ought to resample the content if we're sending it to a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ // device running at a lower sample rate!
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++OSStatus AudioDevice::SetNominalSampleRate(Float64 sampleRate, Boolean force)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 size = sizeof(Float64);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (sampleRate <= 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return paramErr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerSilentFor = 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 sampleRate2 = ClosestNominalSampleRate(sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"SetNominalSampleRate(%g) setting rate to %gHz", sampleRate, sampleRate2);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (sampleRate2 != currentNominalSR || force) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyNominalSampleRate,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mForInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = AudioObjectSetPropertyData(mID, &theAddress, 0, NULL, size, &sampleRate2);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (err == noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ currentNominalSR = sampleRate2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ NSLog(@"Failure setting device \"%s\" to %gHz: %d (%s)", GetName(), sampleRate2, err, OSTStr(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = noErr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*!
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Reset the nominal sample rate to the value found when opening the device
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++OSStatus AudioDevice::ResetNominalSampleRate(Boolean force)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 size = sizeof(Float64);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Float64 sampleRate = mInitialFormat.mSampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus err = noErr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (sampleRate != currentNominalSR || force) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerSilentFor = 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyNominalSampleRate,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mForInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = AudioObjectSetPropertyData(mID, &theAddress, 0, NULL, size, &sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (err == noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ currentNominalSR = sampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++OSStatus AudioDevice::SetStreamBasicDescription(AudioStreamBasicDescription *desc)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 size = sizeof(AudioStreamBasicDescription);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ listenerSilentFor = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyStreamFormat,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mForInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = AudioObjectSetPropertyData(mID, &theAddress, 0, NULL, size, desc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (err == noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ currentNominalSR = desc->mSampleRate;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++// AudioDeviceGetPropertyInfo() is deprecated, so we wrap AudioObjectGetPropertyDataSize().
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++OSStatus AudioDevice::GetPropertyDataSize(AudioObjectPropertySelector property, UInt32 *size, AudioObjectPropertyAddress *propertyAddress)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress l_propertyAddress;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!propertyAddress) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propertyAddress = &l_propertyAddress;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propertyAddress->mSelector = property;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propertyAddress->mScope = (mForInput) ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propertyAddress->mElement = kAudioObjectPropertyElementMaster;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return AudioObjectGetPropertyDataSize(mID, propertyAddress, 0, NULL, size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++int AudioDevice::CountChannels()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OSStatus err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 propSize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ int result = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = GetPropertyDataSize(kAudioDevicePropertyStreamConfiguration, &propSize, &theAddress);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (err) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioBufferList *buflist = (AudioBufferList *)malloc(propSize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &propSize, buflist);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!err) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (UInt32 i = 0; i < buflist->mNumberBuffers; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ result += buflist->mBuffers[i].mNumberChannels;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ free(buflist);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return result;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++char *AudioDevice::GetName(char *buf, UInt32 maxlen)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!buf) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ buf = mDevName;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ maxlen = sizeof(mDevName) / sizeof(char);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (*buf) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return buf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { kAudioDevicePropertyDeviceName,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mForInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }; // channel
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectGetPropertyData(mID, &theAddress, 0, NULL, &maxlen, buf));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return buf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDevice *AudioDevice::GetDefaultDevice(Boolean forInput, OSStatus &err, AudioDevice *dev)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 propsize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceID defaultDeviceID;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ propsize = sizeof(AudioDeviceID);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ forInput ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyScopeGlobal,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, &propsize, &defaultDeviceID);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (err == noErr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dev) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dev->ID() != defaultDeviceID) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ delete dev;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ goto bail;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ dev = new AudioDevice(defaultDeviceID, forInput);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++bail:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return dev;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDevice *AudioDevice::GetDevice(AudioDeviceID devId, Boolean forInput, AudioDevice *dev)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dev) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dev->ID() != devId) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ delete dev;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ goto bail;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ dev = new AudioDevice(devId, forInput);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++bail:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return dev;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++// kate: indent-mode cstyle; indent-width 4; replace-tabs on;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.cpp src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+new file mode 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 00000000..ba3e00f1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -0,0 +1,98 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ File: AudioDeviceList.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Adapted from the CAPlayThough example
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Version: 1.2.2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Inc. ("Apple") in consideration of your agreement to the following
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ terms, and your use, installation, modification or redistribution of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ this Apple software constitutes acceptance of these terms. If you do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ not agree with these terms, please do not use, install, modify or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ redistribute this Apple software.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ In consideration of your agreement to abide by the following terms, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ subject to these terms, Apple grants you a personal, non-exclusive
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ license, under Apple's copyrights in this original Apple software (the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ "Apple Software"), to use, reproduce, modify and redistribute the Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Software, with or without modifications, in source and/or binary forms;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ provided that if you redistribute the Apple Software in its entirety and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ without modifications, you must retain this notice and the following
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ text and disclaimers in all such redistributions of the Apple Software.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Neither the name, trademarks, service marks or logos of Apple Inc. may
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ be used to endorse or promote products derived from the Apple Software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ without specific prior written permission from Apple. Except as
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ expressly stated in this notice, no other rights or licenses, express or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ implied, are granted by Apple herein, including but not limited to any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ patent rights that may be infringed by your derivative works or by other
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ works in which the Apple Software may be incorporated.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ The Apple Software is provided by Apple on an "AS IS" basis. APPLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ POSSIBILITY OF SUCH DAMAGE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Copyright (C) 2013 Apple Inc. All Rights Reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Copyright (C) 2017,18 René J.V. Bertin All Rights Reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "AudioDeviceList.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <AvailabilityMacros.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#if MAC_OS_X_VERSION_MIN_REQUIRED > 1080
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ #define verify_noerr __Verify_noErr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDeviceList::AudioDeviceList(bool forInput)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ : mForInput(forInput)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ BuildList();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++AudioDeviceList::~AudioDeviceList()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void AudioDeviceList::BuildList()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mDeviceList.clear();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mDeviceDict.clear();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ UInt32 propsize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyDevices,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyScopeGlobal,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ kAudioObjectPropertyElementMaster
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &theAddress, 0, NULL, &propsize));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ int nDevices = propsize / sizeof(AudioDeviceID);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceID *devids = new AudioDeviceID[nDevices];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ verify_noerr(AudioObjectGetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, &propsize, devids));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (int i = 0; i < nDevices; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevice dev(devids[i], true, mForInput);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (dev.CountChannels() > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Device d;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ d.mID = devids[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ dev.GetName(d.mName, sizeof(d.mName));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mDeviceList.push_back(d);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QString name = QString::fromUtf8(d.mName);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (!mDeviceDict.contains(name)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ mDeviceDict[name] = d.mID;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ delete[] devids;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.h src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+new file mode 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 00000000..89ff3a87
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -0,0 +1,82 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ File: AudioDeviceList.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Adapted from the CAPlayThough example
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Version: 1.2.2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Inc. ("Apple") in consideration of your agreement to the following
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ terms, and your use, installation, modification or redistribution of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ this Apple software constitutes acceptance of these terms. If you do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ not agree with these terms, please do not use, install, modify or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ redistribute this Apple software.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ In consideration of your agreement to abide by the following terms, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ subject to these terms, Apple grants you a personal, non-exclusive
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ license, under Apple's copyrights in this original Apple software (the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ "Apple Software"), to use, reproduce, modify and redistribute the Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Software, with or without modifications, in source and/or binary forms;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ provided that if you redistribute the Apple Software in its entirety and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ without modifications, you must retain this notice and the following
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ text and disclaimers in all such redistributions of the Apple Software.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Neither the name, trademarks, service marks or logos of Apple Inc. may
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ be used to endorse or promote products derived from the Apple Software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ without specific prior written permission from Apple. Except as
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ expressly stated in this notice, no other rights or licenses, express or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ implied, are granted by Apple herein, including but not limited to any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ patent rights that may be infringed by your derivative works or by other
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ works in which the Apple Software may be incorporated.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ The Apple Software is provided by Apple on an "AS IS" basis. APPLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ POSSIBILITY OF SUCH DAMAGE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Copyright (C) 2013 Apple Inc. All Rights Reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ Copyright (C) 2017,18 René J.V. Bertin All Rights Reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifndef __AudioDeviceList_h__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define __AudioDeviceList_h__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <CoreServices/CoreServices.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <CoreAudio/CoreAudio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "AudioDevice.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QList>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QHash>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++class AudioDeviceList {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++public:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ struct Device {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ char mName[256];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceID mID;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ typedef QList<Device> DeviceList;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ typedef QHash<QString,AudioDeviceID> DeviceDict;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDeviceList(bool forInput=false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ ~AudioDeviceList();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ DeviceList &GetList() { return mDeviceList; }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ DeviceDict &GetDict() { return mDeviceDict; }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++protected:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ void BuildList();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ bool mForInput;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ DeviceList mDeviceList;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ DeviceDict mDeviceDict;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif // __AudioDeviceList_h__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/CMakeLists.txt src/modules/PortAudio/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index b0310d5c..add7286f 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/PortAudio/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -27,6 +27,13 @@ set(PortAudio_SRC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ PortAudioWriter.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++if(APPLE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ list(APPEND PortAudio_SRC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ 3rdparty/CoreAudio/AudioDevice.mm
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ 3rdparty/CoreAudio/AudioDeviceList.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++endif()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ set(PortAudio_RESOURCES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ icon.qrc
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -69,6 +76,9 @@ if(WIN32 AND CUSTOM_PORTAUDIO_LIBRARIES)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ target_link_libraries(${PROJECT_NAME} ${CUSTOM_PORTAUDIO_LIBRARIES})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ target_link_libraries(${PROJECT_NAME} ${LIBPORTAUDIO_LIBRARIES})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if(APPLE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ target_link_libraries(${PROJECT_NAME} "-framework CoreAudio -framework Foundation")
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ endif()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ endif()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${MODULES_INSTALL_PATH})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/PortAudio.cpp src/modules/PortAudio/PortAudio.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index a130fe25..5ee2845d 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/PortAudio/PortAudio.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/PortAudio.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -88,10 +88,19 @@ ModuleSettingsWidget::ModuleSettingsWidget(Module &module) :
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int idx = devicesB->findText(sets().getString("OutputDevice"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ devicesB->setCurrentIndex(idx < 0 ? 0 : idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ bitPerfect = new QCheckBox(tr("Bit-perfect audio"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ bitPerfect->setChecked(sets().getBool("BitPerfect"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ bitPerfect->setToolTip(tr("This sets the selected output device to the sample rate of the content being played"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QFormLayout *layout = new QFormLayout(this);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ layout->addRow(enabledB);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ layout->addRow(tr("Playback device") + ": ", devicesB);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ layout->addRow(tr("Delay") + ": ", delayB);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ layout->addRow(bitPerfect);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ void ModuleSettingsWidget::saveSettings()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -99,4 +108,7 @@ void ModuleSettingsWidget::saveSettings()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sets().set("WriterEnabled", enabledB->isChecked());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sets().set("OutputDevice", devicesB->currentIndex() == 0 ? QString() : devicesB->currentText());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sets().set("Delay", delayB->value());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ sets().set("BitPerfect", bitPerfect->isChecked());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/PortAudio.hpp src/modules/PortAudio/PortAudio.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 5d3d57d7..98a72471 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/PortAudio/PortAudio.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/PortAudio.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -53,4 +53,7 @@ private:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QCheckBox *enabledB;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QComboBox *devicesB;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QDoubleSpinBox *delayB;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QCheckBox *bitPerfect;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/PortAudioWriter.cpp src/modules/PortAudio/PortAudioWriter.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 38dc27d9..a4a6619b 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/PortAudio/PortAudioWriter.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/PortAudioWriter.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -24,11 +24,17 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ #include "3rdparty/CoreAudio/AudioDeviceList.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ #include "3rdparty/CoreAudio/AudioDevice.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #define DEFAULT_HIGH_AUDIO_DELAY 0.2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #define DEFAULT_HIGH_AUDIO_DELAY 0.1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ #define QStringLiteral QString::fromUtf8
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ PortAudioWriter::PortAudioWriter(Module &module) :
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ stream(NULL),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sample_rate(0),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -47,6 +53,13 @@ PortAudioWriter::PortAudioWriter(Module &module) :
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ PortAudioWriter::~PortAudioWriter()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (coreAudioDevice)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ coreAudioDevice->ResetNominalSampleRate();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ delete coreAudioDevice;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ close();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -191,7 +204,30 @@ void PortAudioWriter::pause()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QString PortAudioWriter::name() const
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- return PortAudioWriterName;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QString name = PortAudioWriterName;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (stream)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (const PaDeviceInfo *dInfo = Pa_GetDeviceInfo(outputParameters.device))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ name += QStringLiteral(" (%1").arg(dInfo->name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (const PaHostApiInfo *hInfo = Pa_GetHostApiInfo(dInfo->hostApi))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ name += QStringLiteral("; %1").arg(hInfo->name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ name += ")";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (const PaStreamInfo *strInfo = Pa_GetStreamInfo(stream))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ name += QStringLiteral(", %1Hz").arg(strInfo->sampleRate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (coreAudioDevice)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ name += QStringLiteral(" -> %1Hz").arg(coreAudioDevice->CurrentNominalSampleRate());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ return name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ bool PortAudioWriter::open()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -209,6 +245,21 @@ bool PortAudioWriter::openStream()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ stream = newStream;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ outputLatency = Pa_GetStreamInfo(stream)->outputLatency;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ modParam("delay", outputLatency);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (sets().getBool("BitPerfect"))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const QString devName(Pa_GetDeviceInfo(outputParameters.device)->name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const AudioDeviceList::DeviceDict devDict = AudioDeviceList().GetDict();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (devDict.contains(devName))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ coreAudioDevice = AudioDevice::GetDevice(devDict[devName], false, coreAudioDevice);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (coreAudioDevice)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ coreAudioDevice->SetNominalSampleRate(sample_rate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/PortAudio/PortAudioWriter.hpp src/modules/PortAudio/PortAudioWriter.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 9d4f617f..009dc013 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/PortAudio/PortAudioWriter.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/PortAudio/PortAudioWriter.hpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -25,6 +25,10 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QCoreApplication>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++class AudioDevice;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ class PortAudioWriter : public Writer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Q_DECLARE_TR_FUNCTIONS(PortAudioWriter)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -66,6 +70,9 @@ private:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ double outputLatency;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ bool err, fullBufferReached;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int underflows;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef Q_OS_MAC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ AudioDevice *coreAudioDevice = nullptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #define PortAudioWriterName "PortAudio"
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/multimedia/QMPlay2/files/0010-Do-not-force-fetching-yt-dlp-it-does-not-work-use-Ma.patch b/multimedia/QMPlay2/files/0010-Do-not-force-fetching-yt-dlp-it-does-not-work-use-Ma.patch
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 00000000000..2bcb4340a81
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/multimedia/QMPlay2/files/0010-Do-not-force-fetching-yt-dlp-it-does-not-work-use-Ma.patch
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,61 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From 2a99e595ce53c0ef1ecef0fad67319dff0001fec Mon Sep 17 00:00:00 2001
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From: Sergey Fedorov <vital.had@gmail.com>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Date: Sat, 30 Nov 2024 03:04:33 +0800
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Subject: [PATCH] =?UTF-8?q?Do=20not=20force=20fetching=20yt-dlp,=20i?=
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ =?UTF-8?q?t=20does=20not=20work;=20use=20MacPorts=E2=80=99=20one?=
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+MIME-Version: 1.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Content-Type: text/plain; charset=UTF-8
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Content-Transfer-Encoding: 8bit
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/qmplay2/YouTubeDL.cpp | 9 +++++++++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 1 file changed, 9 insertions(+)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/qmplay2/YouTubeDL.cpp src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 98071fea..b87f64af 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -28,6 +28,11 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QReadWriteLock>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QFile>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* Avoid downloading yt-dlp, it fails to work correctly. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifndef BUNDLED_YTDLP
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define BUNDLED_YTDLP 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ constexpr char g_name[] = "YouTubeDL";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static QReadWriteLock g_lock;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -263,6 +268,7 @@ QStringList YouTubeDL::exec(const QString &url, const QStringList &args, QString
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (error.indexOf("ERROR: ") == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ error.remove(0, 7);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ #if BUNDLED_YTDLP
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (canUpdate && !error.contains("said:")) // Probably update can fix the error, so do it!
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!doLock(Lock::Write, true)) // Unlock for read and lock for write
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -300,6 +306,7 @@ QStringList YouTubeDL::exec(const QString &url, const QStringList &args, QString
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!doLock(Lock::Read, true)) // Unlock for write and lock for read
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return {};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ finishWithError(error);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return {};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -317,6 +324,7 @@ QStringList YouTubeDL::exec(const QString &url, const QStringList &args, QString
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ g_lock.unlock(); // Unlock for read
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return result;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#if BUNDLED_YTDLP
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else if (canUpdate && !m_aborted && m_process.error() == QProcess::FailedToStart)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const QString downloadUrl = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -361,6 +369,7 @@ QStringList YouTubeDL::exec(const QString &url, const QStringList &args, QString
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ QMPlay2Core.setWorking(false);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ g_lock.unlock(); // Unlock for read or for write (if download has failed)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #else
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/multimedia/QMPlay2/files/0011-YouTubeDL-move-to-QJson.patch b/multimedia/QMPlay2/files/0011-YouTubeDL-move-to-QJson.patch
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 00000000000..a0fe30dead1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/multimedia/QMPlay2/files/0011-YouTubeDL-move-to-QJson.patch
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,88 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From a22054bb93586bdaeb1e29f90ef2367d90fe2d34 Mon Sep 17 00:00:00 2001
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From: Sergey Fedorov <vital.had@gmail.com>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Date: Fri, 29 Nov 2024 10:41:22 +0800
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Subject: [PATCH] YouTubeDL: move to QJson
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/modules/Extensions/MediaBrowser/ProstoPleer.cpp | 7 ++++---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/qmplay2/CMakeLists.txt | 3 ++-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ src/qmplay2/YouTubeDL.cpp | 13 +++++++------
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 3 files changed, 13 insertions(+), 10 deletions(-)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/modules/Extensions/MediaBrowser/ProstoPleer.cpp src/modules/Extensions/MediaBrowser/ProstoPleer.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index cb3c287d..c35bd5d2 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/modules/Extensions/MediaBrowser/ProstoPleer.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/modules/Extensions/MediaBrowser/ProstoPleer.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -21,9 +21,10 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QMPlay2Extensions.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <NetworkAccess.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <Functions.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#include <Json11.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonDocument.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QTextDocument>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonObject.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QHeaderView>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QTreeWidget>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QAction>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -187,8 +188,8 @@ bool ProstoPleer::convertAddress(const QString &prefix, const QString &url, cons
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ IOController<NetworkReply> &netReply = ioCtrl->toRef<NetworkReply>();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (net.startAndWait(netReply, QString("%1/site_api/files/get_url?id=%2").arg(g_url, fileId.mid(idx + 1))))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const Json json = Json::parse(netReply->readAll());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const QString tmpStreamUrl = json["track_link"].string_value();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const QJsonDocument json = QJsonDocument::fromJson(netReply->readAll());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const QString tmpStreamUrl = json.object()["track_link"].toString();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!tmpStreamUrl.isEmpty())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *streamUrl = tmpStreamUrl;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ netReply.clear();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/qmplay2/CMakeLists.txt src/qmplay2/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 01932ce6..270ad9cf 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/qmplay2/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/qmplay2/CMakeLists.txt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -212,7 +212,8 @@ if(USE_QT5)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ target_link_libraries(${PROJECT_NAME} ${APPKIT_LIBRARY})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ endif()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- target_link_libraries(${PROJECT_NAME} Qt4::QtCore Qt4::QtGui ${DBUS})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ add_definitions(-I/opt/local/include/QJson4)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ target_link_libraries(${PROJECT_NAME} Qt4::QtCore Qt4::QtGui QJson4 ${DBUS})
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ endif()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if(WIN32)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git src/qmplay2/YouTubeDL.cpp src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index b87f64af..fb7e72fc 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ src/qmplay2/YouTubeDL.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -21,11 +21,13 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <NetworkAccess.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QMPlay2Core.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <Version.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#include <Json11.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <Functions.hpp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QRegExp>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QReadWriteLock>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonDocument.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonObject.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <QJsonArray.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include <QFile>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Avoid downloading yt-dlp, it fails to work correctly. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -41,12 +43,11 @@ static QReadWriteLock g_lock;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void exportCookiesFromJSON(const QString &jsonData, const QString &url)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const Json json = Json::parse(jsonData.toUtf8());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- const QByteArray urlData = url.toUtf8();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- for (const Json &formats : json["formats"].array_items())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ const QJsonDocument json = QJsonDocument::fromJson(jsonData.toUtf8());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ for (const QJsonValue &formats : json.object()["formats"].toArray())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- if (urlData == formats["url"].string_value())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+- QMPlay2Core.addCookies(url, formats["http_headers"]["Cookie"].string_value());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ if (url == formats.toObject()["url"].toString())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ QMPlay2Core.addCookies(url, formats.toObject()["http_headers"].toObject()["Cookie"].toString().toUtf8());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/multimedia/QMPlay2/files/0007-Fix-Qt-paths.patch b/multimedia/QMPlay2/files/0012-Fix-Qt-paths.patch
</span>similarity index 100%
rename from multimedia/QMPlay2/files/0007-Fix-Qt-paths.patch
rename to multimedia/QMPlay2/files/0012-Fix-Qt-paths.patch
</pre><pre style='margin:0'>
</pre>