Migrate audio pipeline to float from 16-bit integer - #2873

Merged
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio
Jul 26, 2024
Merged

Migrate audio pipeline to float from 16-bit integer#2873
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio

Conversation

@ns6089

@ns6089ns6089 commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

Description

Float is the native format of opus codec and most if not all capture backends.

Implementation progress:

  • Windows
  • MacOS
  • Linux

Screenshot

Issues Fixed or Closed

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

cgutman
cgutman previously approved these changes Jul 18, 2024

@cgutmancgutman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested locally on macOS and Linux

@ns6089
ns6089 marked this pull request as ready for review July 18, 2024 23:47
@cgutman
cgutman enabled auto-merge (squash) July 19, 2024 04:10
@codecov

codecovBot commented Jul 19, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 34.64912% with 149 lines in your changes missing coverage. Please review.

Project coverage is 9.57%. Comparing base (aa2cf8e) to head (6dbb08f).
Report is 137 commits behind head on master.

Files with missing linesPatch %Lines
src/platform/windows/audio.cpp38.53%120 Missing and 6 partials ⚠️
src/logging.cpp0.00%8 Missing ⚠️
src/platform/linux/audio.cpp0.00%6 Missing ⚠️
src/platform/macos/microphone.mm0.00%5 Missing ⚠️
src/audio.cpp0.00%2 Missing ⚠️
src/platform/macos/av_audio.m0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2873 +/- ##
=========================================
+ Coverage 9.19% 9.57% +0.37% 
=========================================
Files 97 97 Lines 17523 17586 +63 Branches 8331 8336 +5 =========================================
+ Hits 1611 1683 +72 - Misses 13086 15099 +2013 + Partials 2826 804 -2022 
FlagCoverage Δ
Linux6.95% <0.00%> (-0.01%)⬇️
Windows5.08% <36.74%> (+0.56%)⬆️
macOS-1210.29% <0.00%> (-0.01%)⬇️
macOS-1310.21% <0.00%> (+<0.01%)⬆️
macOS-1410.52% <0.00%> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing linesCoverage Δ
src/logging.h32.35% <ø> (ø)
src/platform/common.h34.44% <ø> (ø)
src/audio.cpp28.57% <0.00%> (ø)
src/platform/macos/av_audio.m18.03% <0.00%> (ø)
src/platform/macos/microphone.mm37.77% <0.00%> (ø)
src/platform/linux/audio.cpp9.64% <0.00%> (-0.05%)⬇️
src/logging.cpp77.98% <0.00%> (-6.18%)⬇️
src/platform/windows/audio.cpp26.38% <38.53%> (+12.31%)⬆️

... and 28 files with indirect coverage changes

Comment threadsrc/platform/linux/audio.cpp Fixed

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
@psyke83

psyke83 commented Jul 19, 2024

Copy link
Copy Markdown
Contributor

This seems to break audio on my system by default.

Log is here; relevant lines:

[2024:07:19:19:51:47]: Error: Couldn't set Wave Format [0x88890008]
[2024:07:19:19:51:47]: Error: Unable to initialize audio capture. The stream will not have audio.

I can make audio work with your PR by disabling (or rather, disallowing audio playback via the Sound settings) the Steam Streaming Speaker and Microphone devices and reconnecting the session; simply setting a real (non-Steam) endpoint to the default doesn't fix the issue, as the Steam virtual devices are always set to default when a new session is started.

@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

@ns6089
ns6089 disabled auto-merge July 20, 2024 07:35
@ns6089
ns6089 marked this pull request as draft July 20, 2024 07:35
@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

@ns6089
ns6089 marked this pull request as ready for review July 20, 2024 08:24
@ns6089

Copy link
Copy Markdown
ContributorAuthor

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically.
No new changes to Linux or MacOS code, the review is still valid.

@ReenigneArcher

ReenigneArcher commented Jul 20, 2024

Copy link
Copy Markdown
Member

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically. No new changes to Linux or MacOS code, the review is still valid.

Reviews get dismissed when the code changes. That is a branch protection rule I have enabled.

@psyke83

Copy link
Copy Markdown
Contributor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

Confirmed working via Steam endpoints with latest changes on your PR branch - thanks.

Comment threadsrc/platform/windows/audio.cpp Outdated
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned we might need some additional logic for this. I don't know if it's guaranteed that all devices will support 24-bit PCM for all channel configurations. I think it would be best if we tried them in order: 32-bit -> 24-bit -> 16-bit

That would ensure we don't possibly regress any audio devices that are 16-bit only, and also provide the highest quality on devices with 32-bit support.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

/** * If the requested sink is a virtual sink, meaning no speakers attached to * the host, then we can seamlessly set the format to stereo and surround sound. * * Any virtual sink detected will be prefixed by: * virtual-(format name) * If it doesn't contain that prefix, then the format will not be changed*/
std::optional<std::wstring>
set_format(const std::string &sink) {
auto sink_info = get_sink_info(sink);
// If the sink isn't a device name, we'll assume it's a device IDauto wstring_device_id = find_device_id_by_name(sink).value_or(from_utf8(sink_info.second.data()));
if (sink_info.first == format_t::none) {
// wstring_device_id does not contain virtual-(format name)// It's a simple deviceId, just pass it backreturnstd::make_optional(std::move(wstring_device_id));
}
wave_format_t wave_format;
auto status = policy->GetMixFormat(wstring_device_id.c_str(), &wave_format);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
set_wave_format(wave_format, formats[(int) sink_info.first - 1]);
WAVEFORMATEXTENSIBLE p {};
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
// Surround 5.1 might contain side-{left, right} instead of speaker in the back// Try again with different speaker mask.if (status == 0x88890008 && sink_info.first == format_t::surr51) {
set_wave_format(wave_format, surround_51_side_speakers);
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
}
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't set Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
returnstd::make_optional(std::move(wstring_device_id));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

Other virtual speakers can be used, such as virtual audio cable https://vb-audio.com/Cable/

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so sunshine can have default or custom audio sink, and default or custom virtual audio sink.
Will check how it can be handled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could just be as simple as a loop that tries SetDeviceFormat() until it succeeds.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be a simple loop too, but then ended up with a nasty memory corruption. The rest of the code had accumulated quite a bit of technical dept. Either way it should be ready soon.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed and tested what I could.

Comment threadsrc/platform/windows/audio.cpp Outdated
auto adapter_name = no_null((LPWSTR) adapter_friendly_name.prop.pszVal);
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit a fix for these and merge

Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;
auto device_description = (LPWSTR) device_desc.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
cgutman
cgutman previously approved these changes Jul 25, 2024
@cgutman
cgutman enabled auto-merge (squash) July 25, 2024 02:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ns6089@psyke83@ReenigneArcher@cgutman@github-advanced-security
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Migrate audio pipeline to float from 16-bit integer - #2873

Merged
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio
Jul 26, 2024
Merged

Migrate audio pipeline to float from 16-bit integer#2873
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio

Conversation

@ns6089

@ns6089ns6089 commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

Description

Float is the native format of opus codec and most if not all capture backends.

Implementation progress:

  • Windows
  • MacOS
  • Linux

Screenshot

Issues Fixed or Closed

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

cgutman
cgutman previously approved these changes Jul 18, 2024

@cgutmancgutman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested locally on macOS and Linux

@ns6089
ns6089 marked this pull request as ready for review July 18, 2024 23:47
@cgutman
cgutman enabled auto-merge (squash) July 19, 2024 04:10
@codecov

codecovBot commented Jul 19, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 34.64912% with 149 lines in your changes missing coverage. Please review.

Project coverage is 9.57%. Comparing base (aa2cf8e) to head (6dbb08f).
Report is 137 commits behind head on master.

Files with missing linesPatch %Lines
src/platform/windows/audio.cpp38.53%120 Missing and 6 partials ⚠️
src/logging.cpp0.00%8 Missing ⚠️
src/platform/linux/audio.cpp0.00%6 Missing ⚠️
src/platform/macos/microphone.mm0.00%5 Missing ⚠️
src/audio.cpp0.00%2 Missing ⚠️
src/platform/macos/av_audio.m0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2873 +/- ##
=========================================
+ Coverage 9.19% 9.57% +0.37% 
=========================================
Files 97 97 Lines 17523 17586 +63 Branches 8331 8336 +5 =========================================
+ Hits 1611 1683 +72 - Misses 13086 15099 +2013 + Partials 2826 804 -2022 
FlagCoverage Δ
Linux6.95% <0.00%> (-0.01%)⬇️
Windows5.08% <36.74%> (+0.56%)⬆️
macOS-1210.29% <0.00%> (-0.01%)⬇️
macOS-1310.21% <0.00%> (+<0.01%)⬆️
macOS-1410.52% <0.00%> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing linesCoverage Δ
src/logging.h32.35% <ø> (ø)
src/platform/common.h34.44% <ø> (ø)
src/audio.cpp28.57% <0.00%> (ø)
src/platform/macos/av_audio.m18.03% <0.00%> (ø)
src/platform/macos/microphone.mm37.77% <0.00%> (ø)
src/platform/linux/audio.cpp9.64% <0.00%> (-0.05%)⬇️
src/logging.cpp77.98% <0.00%> (-6.18%)⬇️
src/platform/windows/audio.cpp26.38% <38.53%> (+12.31%)⬆️

... and 28 files with indirect coverage changes

Comment threadsrc/platform/linux/audio.cpp Fixed

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
@psyke83

psyke83 commented Jul 19, 2024

Copy link
Copy Markdown
Contributor

This seems to break audio on my system by default.

Log is here; relevant lines:

[2024:07:19:19:51:47]: Error: Couldn't set Wave Format [0x88890008]
[2024:07:19:19:51:47]: Error: Unable to initialize audio capture. The stream will not have audio.

I can make audio work with your PR by disabling (or rather, disallowing audio playback via the Sound settings) the Steam Streaming Speaker and Microphone devices and reconnecting the session; simply setting a real (non-Steam) endpoint to the default doesn't fix the issue, as the Steam virtual devices are always set to default when a new session is started.

@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

@ns6089
ns6089 disabled auto-merge July 20, 2024 07:35
@ns6089
ns6089 marked this pull request as draft July 20, 2024 07:35
@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

@ns6089
ns6089 marked this pull request as ready for review July 20, 2024 08:24
@ns6089

Copy link
Copy Markdown
ContributorAuthor

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically.
No new changes to Linux or MacOS code, the review is still valid.

@ReenigneArcher

ReenigneArcher commented Jul 20, 2024

Copy link
Copy Markdown
Member

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically. No new changes to Linux or MacOS code, the review is still valid.

Reviews get dismissed when the code changes. That is a branch protection rule I have enabled.

@psyke83

Copy link
Copy Markdown
Contributor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

Confirmed working via Steam endpoints with latest changes on your PR branch - thanks.

Comment threadsrc/platform/windows/audio.cpp Outdated
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned we might need some additional logic for this. I don't know if it's guaranteed that all devices will support 24-bit PCM for all channel configurations. I think it would be best if we tried them in order: 32-bit -> 24-bit -> 16-bit

That would ensure we don't possibly regress any audio devices that are 16-bit only, and also provide the highest quality on devices with 32-bit support.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

/** * If the requested sink is a virtual sink, meaning no speakers attached to * the host, then we can seamlessly set the format to stereo and surround sound. * * Any virtual sink detected will be prefixed by: * virtual-(format name) * If it doesn't contain that prefix, then the format will not be changed*/
std::optional<std::wstring>
set_format(const std::string &sink) {
auto sink_info = get_sink_info(sink);
// If the sink isn't a device name, we'll assume it's a device IDauto wstring_device_id = find_device_id_by_name(sink).value_or(from_utf8(sink_info.second.data()));
if (sink_info.first == format_t::none) {
// wstring_device_id does not contain virtual-(format name)// It's a simple deviceId, just pass it backreturnstd::make_optional(std::move(wstring_device_id));
}
wave_format_t wave_format;
auto status = policy->GetMixFormat(wstring_device_id.c_str(), &wave_format);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
set_wave_format(wave_format, formats[(int) sink_info.first - 1]);
WAVEFORMATEXTENSIBLE p {};
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
// Surround 5.1 might contain side-{left, right} instead of speaker in the back// Try again with different speaker mask.if (status == 0x88890008 && sink_info.first == format_t::surr51) {
set_wave_format(wave_format, surround_51_side_speakers);
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
}
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't set Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
returnstd::make_optional(std::move(wstring_device_id));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

Other virtual speakers can be used, such as virtual audio cable https://vb-audio.com/Cable/

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so sunshine can have default or custom audio sink, and default or custom virtual audio sink.
Will check how it can be handled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could just be as simple as a loop that tries SetDeviceFormat() until it succeeds.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be a simple loop too, but then ended up with a nasty memory corruption. The rest of the code had accumulated quite a bit of technical dept. Either way it should be ready soon.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed and tested what I could.

Comment threadsrc/platform/windows/audio.cpp Outdated
auto adapter_name = no_null((LPWSTR) adapter_friendly_name.prop.pszVal);
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit a fix for these and merge

Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;
auto device_description = (LPWSTR) device_desc.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
cgutman
cgutman previously approved these changes Jul 25, 2024
@cgutman
cgutman enabled auto-merge (squash) July 25, 2024 02:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ns6089@psyke83@ReenigneArcher@cgutman@github-advanced-security
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Migrate audio pipeline to float from 16-bit integer - #2873

Merged
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio
Jul 26, 2024
Merged

Migrate audio pipeline to float from 16-bit integer#2873
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio

Conversation

@ns6089

@ns6089ns6089 commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

Description

Float is the native format of opus codec and most if not all capture backends.

Implementation progress:

  • Windows
  • MacOS
  • Linux

Screenshot

Issues Fixed or Closed

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

cgutman
cgutman previously approved these changes Jul 18, 2024

@cgutmancgutman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested locally on macOS and Linux

@ns6089
ns6089 marked this pull request as ready for review July 18, 2024 23:47
@cgutman
cgutman enabled auto-merge (squash) July 19, 2024 04:10
@codecov

codecovBot commented Jul 19, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 34.64912% with 149 lines in your changes missing coverage. Please review.

Project coverage is 9.57%. Comparing base (aa2cf8e) to head (6dbb08f).
Report is 137 commits behind head on master.

Files with missing linesPatch %Lines
src/platform/windows/audio.cpp38.53%120 Missing and 6 partials ⚠️
src/logging.cpp0.00%8 Missing ⚠️
src/platform/linux/audio.cpp0.00%6 Missing ⚠️
src/platform/macos/microphone.mm0.00%5 Missing ⚠️
src/audio.cpp0.00%2 Missing ⚠️
src/platform/macos/av_audio.m0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2873 +/- ##
=========================================
+ Coverage 9.19% 9.57% +0.37% 
=========================================
Files 97 97 Lines 17523 17586 +63 Branches 8331 8336 +5 =========================================
+ Hits 1611 1683 +72 - Misses 13086 15099 +2013 + Partials 2826 804 -2022 
FlagCoverage Δ
Linux6.95% <0.00%> (-0.01%)⬇️
Windows5.08% <36.74%> (+0.56%)⬆️
macOS-1210.29% <0.00%> (-0.01%)⬇️
macOS-1310.21% <0.00%> (+<0.01%)⬆️
macOS-1410.52% <0.00%> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing linesCoverage Δ
src/logging.h32.35% <ø> (ø)
src/platform/common.h34.44% <ø> (ø)
src/audio.cpp28.57% <0.00%> (ø)
src/platform/macos/av_audio.m18.03% <0.00%> (ø)
src/platform/macos/microphone.mm37.77% <0.00%> (ø)
src/platform/linux/audio.cpp9.64% <0.00%> (-0.05%)⬇️
src/logging.cpp77.98% <0.00%> (-6.18%)⬇️
src/platform/windows/audio.cpp26.38% <38.53%> (+12.31%)⬆️

... and 28 files with indirect coverage changes

Comment threadsrc/platform/linux/audio.cpp Fixed

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
@psyke83

psyke83 commented Jul 19, 2024

Copy link
Copy Markdown
Contributor

This seems to break audio on my system by default.

Log is here; relevant lines:

[2024:07:19:19:51:47]: Error: Couldn't set Wave Format [0x88890008]
[2024:07:19:19:51:47]: Error: Unable to initialize audio capture. The stream will not have audio.

I can make audio work with your PR by disabling (or rather, disallowing audio playback via the Sound settings) the Steam Streaming Speaker and Microphone devices and reconnecting the session; simply setting a real (non-Steam) endpoint to the default doesn't fix the issue, as the Steam virtual devices are always set to default when a new session is started.

@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

@ns6089
ns6089 disabled auto-merge July 20, 2024 07:35
@ns6089
ns6089 marked this pull request as draft July 20, 2024 07:35
@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

@ns6089
ns6089 marked this pull request as ready for review July 20, 2024 08:24
@ns6089

Copy link
Copy Markdown
ContributorAuthor

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically.
No new changes to Linux or MacOS code, the review is still valid.

@ReenigneArcher

ReenigneArcher commented Jul 20, 2024

Copy link
Copy Markdown
Member

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically. No new changes to Linux or MacOS code, the review is still valid.

Reviews get dismissed when the code changes. That is a branch protection rule I have enabled.

@psyke83

Copy link
Copy Markdown
Contributor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

Confirmed working via Steam endpoints with latest changes on your PR branch - thanks.

Comment threadsrc/platform/windows/audio.cpp Outdated
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned we might need some additional logic for this. I don't know if it's guaranteed that all devices will support 24-bit PCM for all channel configurations. I think it would be best if we tried them in order: 32-bit -> 24-bit -> 16-bit

That would ensure we don't possibly regress any audio devices that are 16-bit only, and also provide the highest quality on devices with 32-bit support.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

/** * If the requested sink is a virtual sink, meaning no speakers attached to * the host, then we can seamlessly set the format to stereo and surround sound. * * Any virtual sink detected will be prefixed by: * virtual-(format name) * If it doesn't contain that prefix, then the format will not be changed*/
std::optional<std::wstring>
set_format(const std::string &sink) {
auto sink_info = get_sink_info(sink);
// If the sink isn't a device name, we'll assume it's a device IDauto wstring_device_id = find_device_id_by_name(sink).value_or(from_utf8(sink_info.second.data()));
if (sink_info.first == format_t::none) {
// wstring_device_id does not contain virtual-(format name)// It's a simple deviceId, just pass it backreturnstd::make_optional(std::move(wstring_device_id));
}
wave_format_t wave_format;
auto status = policy->GetMixFormat(wstring_device_id.c_str(), &wave_format);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
set_wave_format(wave_format, formats[(int) sink_info.first - 1]);
WAVEFORMATEXTENSIBLE p {};
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
// Surround 5.1 might contain side-{left, right} instead of speaker in the back// Try again with different speaker mask.if (status == 0x88890008 && sink_info.first == format_t::surr51) {
set_wave_format(wave_format, surround_51_side_speakers);
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
}
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't set Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
returnstd::make_optional(std::move(wstring_device_id));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

Other virtual speakers can be used, such as virtual audio cable https://vb-audio.com/Cable/

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so sunshine can have default or custom audio sink, and default or custom virtual audio sink.
Will check how it can be handled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could just be as simple as a loop that tries SetDeviceFormat() until it succeeds.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be a simple loop too, but then ended up with a nasty memory corruption. The rest of the code had accumulated quite a bit of technical dept. Either way it should be ready soon.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed and tested what I could.

Comment threadsrc/platform/windows/audio.cpp Outdated
auto adapter_name = no_null((LPWSTR) adapter_friendly_name.prop.pszVal);
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit a fix for these and merge

Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;
auto device_description = (LPWSTR) device_desc.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
cgutman
cgutman previously approved these changes Jul 25, 2024
@cgutman
cgutman enabled auto-merge (squash) July 25, 2024 02:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ns6089@psyke83@ReenigneArcher@cgutman@github-advanced-security
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Migrate audio pipeline to float from 16-bit integer - #2873

Merged
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio
Jul 26, 2024
Merged

Migrate audio pipeline to float from 16-bit integer#2873
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio

Conversation

@ns6089

@ns6089ns6089 commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

Description

Float is the native format of opus codec and most if not all capture backends.

Implementation progress:

  • Windows
  • MacOS
  • Linux

Screenshot

Issues Fixed or Closed

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

cgutman
cgutman previously approved these changes Jul 18, 2024

@cgutmancgutman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested locally on macOS and Linux

@ns6089
ns6089 marked this pull request as ready for review July 18, 2024 23:47
@cgutman
cgutman enabled auto-merge (squash) July 19, 2024 04:10
@codecov

codecovBot commented Jul 19, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 34.64912% with 149 lines in your changes missing coverage. Please review.

Project coverage is 9.57%. Comparing base (aa2cf8e) to head (6dbb08f).
Report is 137 commits behind head on master.

Files with missing linesPatch %Lines
src/platform/windows/audio.cpp38.53%120 Missing and 6 partials ⚠️
src/logging.cpp0.00%8 Missing ⚠️
src/platform/linux/audio.cpp0.00%6 Missing ⚠️
src/platform/macos/microphone.mm0.00%5 Missing ⚠️
src/audio.cpp0.00%2 Missing ⚠️
src/platform/macos/av_audio.m0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2873 +/- ##
=========================================
+ Coverage 9.19% 9.57% +0.37% 
=========================================
Files 97 97 Lines 17523 17586 +63 Branches 8331 8336 +5 =========================================
+ Hits 1611 1683 +72 - Misses 13086 15099 +2013 + Partials 2826 804 -2022 
FlagCoverage Δ
Linux6.95% <0.00%> (-0.01%)⬇️
Windows5.08% <36.74%> (+0.56%)⬆️
macOS-1210.29% <0.00%> (-0.01%)⬇️
macOS-1310.21% <0.00%> (+<0.01%)⬆️
macOS-1410.52% <0.00%> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing linesCoverage Δ
src/logging.h32.35% <ø> (ø)
src/platform/common.h34.44% <ø> (ø)
src/audio.cpp28.57% <0.00%> (ø)
src/platform/macos/av_audio.m18.03% <0.00%> (ø)
src/platform/macos/microphone.mm37.77% <0.00%> (ø)
src/platform/linux/audio.cpp9.64% <0.00%> (-0.05%)⬇️
src/logging.cpp77.98% <0.00%> (-6.18%)⬇️
src/platform/windows/audio.cpp26.38% <38.53%> (+12.31%)⬆️

... and 28 files with indirect coverage changes

Comment threadsrc/platform/linux/audio.cpp Fixed

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
@psyke83

psyke83 commented Jul 19, 2024

Copy link
Copy Markdown
Contributor

This seems to break audio on my system by default.

Log is here; relevant lines:

[2024:07:19:19:51:47]: Error: Couldn't set Wave Format [0x88890008]
[2024:07:19:19:51:47]: Error: Unable to initialize audio capture. The stream will not have audio.

I can make audio work with your PR by disabling (or rather, disallowing audio playback via the Sound settings) the Steam Streaming Speaker and Microphone devices and reconnecting the session; simply setting a real (non-Steam) endpoint to the default doesn't fix the issue, as the Steam virtual devices are always set to default when a new session is started.

@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

@ns6089
ns6089 disabled auto-merge July 20, 2024 07:35
@ns6089
ns6089 marked this pull request as draft July 20, 2024 07:35
@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

@ns6089
ns6089 marked this pull request as ready for review July 20, 2024 08:24
@ns6089

Copy link
Copy Markdown
ContributorAuthor

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically.
No new changes to Linux or MacOS code, the review is still valid.

@ReenigneArcher

ReenigneArcher commented Jul 20, 2024

Copy link
Copy Markdown
Member

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically. No new changes to Linux or MacOS code, the review is still valid.

Reviews get dismissed when the code changes. That is a branch protection rule I have enabled.

@psyke83

Copy link
Copy Markdown
Contributor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

Confirmed working via Steam endpoints with latest changes on your PR branch - thanks.

Comment threadsrc/platform/windows/audio.cpp Outdated
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned we might need some additional logic for this. I don't know if it's guaranteed that all devices will support 24-bit PCM for all channel configurations. I think it would be best if we tried them in order: 32-bit -> 24-bit -> 16-bit

That would ensure we don't possibly regress any audio devices that are 16-bit only, and also provide the highest quality on devices with 32-bit support.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

/** * If the requested sink is a virtual sink, meaning no speakers attached to * the host, then we can seamlessly set the format to stereo and surround sound. * * Any virtual sink detected will be prefixed by: * virtual-(format name) * If it doesn't contain that prefix, then the format will not be changed*/
std::optional<std::wstring>
set_format(const std::string &sink) {
auto sink_info = get_sink_info(sink);
// If the sink isn't a device name, we'll assume it's a device IDauto wstring_device_id = find_device_id_by_name(sink).value_or(from_utf8(sink_info.second.data()));
if (sink_info.first == format_t::none) {
// wstring_device_id does not contain virtual-(format name)// It's a simple deviceId, just pass it backreturnstd::make_optional(std::move(wstring_device_id));
}
wave_format_t wave_format;
auto status = policy->GetMixFormat(wstring_device_id.c_str(), &wave_format);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
set_wave_format(wave_format, formats[(int) sink_info.first - 1]);
WAVEFORMATEXTENSIBLE p {};
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
// Surround 5.1 might contain side-{left, right} instead of speaker in the back// Try again with different speaker mask.if (status == 0x88890008 && sink_info.first == format_t::surr51) {
set_wave_format(wave_format, surround_51_side_speakers);
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
}
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't set Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
returnstd::make_optional(std::move(wstring_device_id));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

Other virtual speakers can be used, such as virtual audio cable https://vb-audio.com/Cable/

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so sunshine can have default or custom audio sink, and default or custom virtual audio sink.
Will check how it can be handled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could just be as simple as a loop that tries SetDeviceFormat() until it succeeds.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be a simple loop too, but then ended up with a nasty memory corruption. The rest of the code had accumulated quite a bit of technical dept. Either way it should be ready soon.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed and tested what I could.

Comment threadsrc/platform/windows/audio.cpp Outdated
auto adapter_name = no_null((LPWSTR) adapter_friendly_name.prop.pszVal);
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit a fix for these and merge

Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;
auto device_description = (LPWSTR) device_desc.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
cgutman
cgutman previously approved these changes Jul 25, 2024
@cgutman
cgutman enabled auto-merge (squash) July 25, 2024 02:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ns6089@psyke83@ReenigneArcher@cgutman@github-advanced-security
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Migrate audio pipeline to float from 16-bit integer - #2873

Merged
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio
Jul 26, 2024
Merged

Migrate audio pipeline to float from 16-bit integer#2873
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio

Conversation

@ns6089

@ns6089ns6089 commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

Description

Float is the native format of opus codec and most if not all capture backends.

Implementation progress:

  • Windows
  • MacOS
  • Linux

Screenshot

Issues Fixed or Closed

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

cgutman
cgutman previously approved these changes Jul 18, 2024

@cgutmancgutman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested locally on macOS and Linux

@ns6089
ns6089 marked this pull request as ready for review July 18, 2024 23:47
@cgutman
cgutman enabled auto-merge (squash) July 19, 2024 04:10
@codecov

codecovBot commented Jul 19, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 34.64912% with 149 lines in your changes missing coverage. Please review.

Project coverage is 9.57%. Comparing base (aa2cf8e) to head (6dbb08f).
Report is 137 commits behind head on master.

Files with missing linesPatch %Lines
src/platform/windows/audio.cpp38.53%120 Missing and 6 partials ⚠️
src/logging.cpp0.00%8 Missing ⚠️
src/platform/linux/audio.cpp0.00%6 Missing ⚠️
src/platform/macos/microphone.mm0.00%5 Missing ⚠️
src/audio.cpp0.00%2 Missing ⚠️
src/platform/macos/av_audio.m0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2873 +/- ##
=========================================
+ Coverage 9.19% 9.57% +0.37% 
=========================================
Files 97 97 Lines 17523 17586 +63 Branches 8331 8336 +5 =========================================
+ Hits 1611 1683 +72 - Misses 13086 15099 +2013 + Partials 2826 804 -2022 
FlagCoverage Δ
Linux6.95% <0.00%> (-0.01%)⬇️
Windows5.08% <36.74%> (+0.56%)⬆️
macOS-1210.29% <0.00%> (-0.01%)⬇️
macOS-1310.21% <0.00%> (+<0.01%)⬆️
macOS-1410.52% <0.00%> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing linesCoverage Δ
src/logging.h32.35% <ø> (ø)
src/platform/common.h34.44% <ø> (ø)
src/audio.cpp28.57% <0.00%> (ø)
src/platform/macos/av_audio.m18.03% <0.00%> (ø)
src/platform/macos/microphone.mm37.77% <0.00%> (ø)
src/platform/linux/audio.cpp9.64% <0.00%> (-0.05%)⬇️
src/logging.cpp77.98% <0.00%> (-6.18%)⬇️
src/platform/windows/audio.cpp26.38% <38.53%> (+12.31%)⬆️

... and 28 files with indirect coverage changes

Comment threadsrc/platform/linux/audio.cpp Fixed

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
@psyke83

psyke83 commented Jul 19, 2024

Copy link
Copy Markdown
Contributor

This seems to break audio on my system by default.

Log is here; relevant lines:

[2024:07:19:19:51:47]: Error: Couldn't set Wave Format [0x88890008]
[2024:07:19:19:51:47]: Error: Unable to initialize audio capture. The stream will not have audio.

I can make audio work with your PR by disabling (or rather, disallowing audio playback via the Sound settings) the Steam Streaming Speaker and Microphone devices and reconnecting the session; simply setting a real (non-Steam) endpoint to the default doesn't fix the issue, as the Steam virtual devices are always set to default when a new session is started.

@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

@ns6089
ns6089 disabled auto-merge July 20, 2024 07:35
@ns6089
ns6089 marked this pull request as draft July 20, 2024 07:35
@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

@ns6089
ns6089 marked this pull request as ready for review July 20, 2024 08:24
@ns6089

Copy link
Copy Markdown
ContributorAuthor

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically.
No new changes to Linux or MacOS code, the review is still valid.

@ReenigneArcher

ReenigneArcher commented Jul 20, 2024

Copy link
Copy Markdown
Member

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically. No new changes to Linux or MacOS code, the review is still valid.

Reviews get dismissed when the code changes. That is a branch protection rule I have enabled.

@psyke83

Copy link
Copy Markdown
Contributor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

Confirmed working via Steam endpoints with latest changes on your PR branch - thanks.

Comment threadsrc/platform/windows/audio.cpp Outdated
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned we might need some additional logic for this. I don't know if it's guaranteed that all devices will support 24-bit PCM for all channel configurations. I think it would be best if we tried them in order: 32-bit -> 24-bit -> 16-bit

That would ensure we don't possibly regress any audio devices that are 16-bit only, and also provide the highest quality on devices with 32-bit support.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

/** * If the requested sink is a virtual sink, meaning no speakers attached to * the host, then we can seamlessly set the format to stereo and surround sound. * * Any virtual sink detected will be prefixed by: * virtual-(format name) * If it doesn't contain that prefix, then the format will not be changed*/
std::optional<std::wstring>
set_format(const std::string &sink) {
auto sink_info = get_sink_info(sink);
// If the sink isn't a device name, we'll assume it's a device IDauto wstring_device_id = find_device_id_by_name(sink).value_or(from_utf8(sink_info.second.data()));
if (sink_info.first == format_t::none) {
// wstring_device_id does not contain virtual-(format name)// It's a simple deviceId, just pass it backreturnstd::make_optional(std::move(wstring_device_id));
}
wave_format_t wave_format;
auto status = policy->GetMixFormat(wstring_device_id.c_str(), &wave_format);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
set_wave_format(wave_format, formats[(int) sink_info.first - 1]);
WAVEFORMATEXTENSIBLE p {};
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
// Surround 5.1 might contain side-{left, right} instead of speaker in the back// Try again with different speaker mask.if (status == 0x88890008 && sink_info.first == format_t::surr51) {
set_wave_format(wave_format, surround_51_side_speakers);
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
}
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't set Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
returnstd::make_optional(std::move(wstring_device_id));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

Other virtual speakers can be used, such as virtual audio cable https://vb-audio.com/Cable/

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so sunshine can have default or custom audio sink, and default or custom virtual audio sink.
Will check how it can be handled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could just be as simple as a loop that tries SetDeviceFormat() until it succeeds.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be a simple loop too, but then ended up with a nasty memory corruption. The rest of the code had accumulated quite a bit of technical dept. Either way it should be ready soon.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed and tested what I could.

Comment threadsrc/platform/windows/audio.cpp Outdated
auto adapter_name = no_null((LPWSTR) adapter_friendly_name.prop.pszVal);
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit a fix for these and merge

Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;
auto device_description = (LPWSTR) device_desc.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
cgutman
cgutman previously approved these changes Jul 25, 2024
@cgutman
cgutman enabled auto-merge (squash) July 25, 2024 02:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ns6089@psyke83@ReenigneArcher@cgutman@github-advanced-security
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Migrate audio pipeline to float from 16-bit integer - #2873

Merged
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio
Jul 26, 2024
Merged

Migrate audio pipeline to float from 16-bit integer#2873
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio

Conversation

@ns6089

@ns6089ns6089 commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

Description

Float is the native format of opus codec and most if not all capture backends.

Implementation progress:

  • Windows
  • MacOS
  • Linux

Screenshot

Issues Fixed or Closed

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

cgutman
cgutman previously approved these changes Jul 18, 2024

@cgutmancgutman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested locally on macOS and Linux

@ns6089
ns6089 marked this pull request as ready for review July 18, 2024 23:47
@cgutman
cgutman enabled auto-merge (squash) July 19, 2024 04:10
@codecov

codecovBot commented Jul 19, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 34.64912% with 149 lines in your changes missing coverage. Please review.

Project coverage is 9.57%. Comparing base (aa2cf8e) to head (6dbb08f).
Report is 137 commits behind head on master.

Files with missing linesPatch %Lines
src/platform/windows/audio.cpp38.53%120 Missing and 6 partials ⚠️
src/logging.cpp0.00%8 Missing ⚠️
src/platform/linux/audio.cpp0.00%6 Missing ⚠️
src/platform/macos/microphone.mm0.00%5 Missing ⚠️
src/audio.cpp0.00%2 Missing ⚠️
src/platform/macos/av_audio.m0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2873 +/- ##
=========================================
+ Coverage 9.19% 9.57% +0.37% 
=========================================
Files 97 97 Lines 17523 17586 +63 Branches 8331 8336 +5 =========================================
+ Hits 1611 1683 +72 - Misses 13086 15099 +2013 + Partials 2826 804 -2022 
FlagCoverage Δ
Linux6.95% <0.00%> (-0.01%)⬇️
Windows5.08% <36.74%> (+0.56%)⬆️
macOS-1210.29% <0.00%> (-0.01%)⬇️
macOS-1310.21% <0.00%> (+<0.01%)⬆️
macOS-1410.52% <0.00%> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing linesCoverage Δ
src/logging.h32.35% <ø> (ø)
src/platform/common.h34.44% <ø> (ø)
src/audio.cpp28.57% <0.00%> (ø)
src/platform/macos/av_audio.m18.03% <0.00%> (ø)
src/platform/macos/microphone.mm37.77% <0.00%> (ø)
src/platform/linux/audio.cpp9.64% <0.00%> (-0.05%)⬇️
src/logging.cpp77.98% <0.00%> (-6.18%)⬇️
src/platform/windows/audio.cpp26.38% <38.53%> (+12.31%)⬆️

... and 28 files with indirect coverage changes

Comment threadsrc/platform/linux/audio.cpp Fixed

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
@psyke83

psyke83 commented Jul 19, 2024

Copy link
Copy Markdown
Contributor

This seems to break audio on my system by default.

Log is here; relevant lines:

[2024:07:19:19:51:47]: Error: Couldn't set Wave Format [0x88890008]
[2024:07:19:19:51:47]: Error: Unable to initialize audio capture. The stream will not have audio.

I can make audio work with your PR by disabling (or rather, disallowing audio playback via the Sound settings) the Steam Streaming Speaker and Microphone devices and reconnecting the session; simply setting a real (non-Steam) endpoint to the default doesn't fix the issue, as the Steam virtual devices are always set to default when a new session is started.

@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

@ns6089
ns6089 disabled auto-merge July 20, 2024 07:35
@ns6089
ns6089 marked this pull request as draft July 20, 2024 07:35
@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

@ns6089
ns6089 marked this pull request as ready for review July 20, 2024 08:24
@ns6089

Copy link
Copy Markdown
ContributorAuthor

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically.
No new changes to Linux or MacOS code, the review is still valid.

@ReenigneArcher

ReenigneArcher commented Jul 20, 2024

Copy link
Copy Markdown
Member

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically. No new changes to Linux or MacOS code, the review is still valid.

Reviews get dismissed when the code changes. That is a branch protection rule I have enabled.

@psyke83

Copy link
Copy Markdown
Contributor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

Confirmed working via Steam endpoints with latest changes on your PR branch - thanks.

Comment threadsrc/platform/windows/audio.cpp Outdated
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned we might need some additional logic for this. I don't know if it's guaranteed that all devices will support 24-bit PCM for all channel configurations. I think it would be best if we tried them in order: 32-bit -> 24-bit -> 16-bit

That would ensure we don't possibly regress any audio devices that are 16-bit only, and also provide the highest quality on devices with 32-bit support.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

/** * If the requested sink is a virtual sink, meaning no speakers attached to * the host, then we can seamlessly set the format to stereo and surround sound. * * Any virtual sink detected will be prefixed by: * virtual-(format name) * If it doesn't contain that prefix, then the format will not be changed*/
std::optional<std::wstring>
set_format(const std::string &sink) {
auto sink_info = get_sink_info(sink);
// If the sink isn't a device name, we'll assume it's a device IDauto wstring_device_id = find_device_id_by_name(sink).value_or(from_utf8(sink_info.second.data()));
if (sink_info.first == format_t::none) {
// wstring_device_id does not contain virtual-(format name)// It's a simple deviceId, just pass it backreturnstd::make_optional(std::move(wstring_device_id));
}
wave_format_t wave_format;
auto status = policy->GetMixFormat(wstring_device_id.c_str(), &wave_format);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
set_wave_format(wave_format, formats[(int) sink_info.first - 1]);
WAVEFORMATEXTENSIBLE p {};
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
// Surround 5.1 might contain side-{left, right} instead of speaker in the back// Try again with different speaker mask.if (status == 0x88890008 && sink_info.first == format_t::surr51) {
set_wave_format(wave_format, surround_51_side_speakers);
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
}
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't set Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
returnstd::make_optional(std::move(wstring_device_id));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

Other virtual speakers can be used, such as virtual audio cable https://vb-audio.com/Cable/

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so sunshine can have default or custom audio sink, and default or custom virtual audio sink.
Will check how it can be handled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could just be as simple as a loop that tries SetDeviceFormat() until it succeeds.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be a simple loop too, but then ended up with a nasty memory corruption. The rest of the code had accumulated quite a bit of technical dept. Either way it should be ready soon.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed and tested what I could.

Comment threadsrc/platform/windows/audio.cpp Outdated
auto adapter_name = no_null((LPWSTR) adapter_friendly_name.prop.pszVal);
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit a fix for these and merge

Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;
auto device_description = (LPWSTR) device_desc.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
cgutman
cgutman previously approved these changes Jul 25, 2024
@cgutman
cgutman enabled auto-merge (squash) July 25, 2024 02:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ns6089@psyke83@ReenigneArcher@cgutman@github-advanced-security
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Migrate audio pipeline to float from 16-bit integer - #2873

Merged
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio
Jul 26, 2024
Merged

Migrate audio pipeline to float from 16-bit integer#2873
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio

Conversation

@ns6089

@ns6089ns6089 commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

Description

Float is the native format of opus codec and most if not all capture backends.

Implementation progress:

  • Windows
  • MacOS
  • Linux

Screenshot

Issues Fixed or Closed

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

cgutman
cgutman previously approved these changes Jul 18, 2024

@cgutmancgutman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested locally on macOS and Linux

@ns6089
ns6089 marked this pull request as ready for review July 18, 2024 23:47
@cgutman
cgutman enabled auto-merge (squash) July 19, 2024 04:10
@codecov

codecovBot commented Jul 19, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 34.64912% with 149 lines in your changes missing coverage. Please review.

Project coverage is 9.57%. Comparing base (aa2cf8e) to head (6dbb08f).
Report is 137 commits behind head on master.

Files with missing linesPatch %Lines
src/platform/windows/audio.cpp38.53%120 Missing and 6 partials ⚠️
src/logging.cpp0.00%8 Missing ⚠️
src/platform/linux/audio.cpp0.00%6 Missing ⚠️
src/platform/macos/microphone.mm0.00%5 Missing ⚠️
src/audio.cpp0.00%2 Missing ⚠️
src/platform/macos/av_audio.m0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2873 +/- ##
=========================================
+ Coverage 9.19% 9.57% +0.37% 
=========================================
Files 97 97 Lines 17523 17586 +63 Branches 8331 8336 +5 =========================================
+ Hits 1611 1683 +72 - Misses 13086 15099 +2013 + Partials 2826 804 -2022 
FlagCoverage Δ
Linux6.95% <0.00%> (-0.01%)⬇️
Windows5.08% <36.74%> (+0.56%)⬆️
macOS-1210.29% <0.00%> (-0.01%)⬇️
macOS-1310.21% <0.00%> (+<0.01%)⬆️
macOS-1410.52% <0.00%> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing linesCoverage Δ
src/logging.h32.35% <ø> (ø)
src/platform/common.h34.44% <ø> (ø)
src/audio.cpp28.57% <0.00%> (ø)
src/platform/macos/av_audio.m18.03% <0.00%> (ø)
src/platform/macos/microphone.mm37.77% <0.00%> (ø)
src/platform/linux/audio.cpp9.64% <0.00%> (-0.05%)⬇️
src/logging.cpp77.98% <0.00%> (-6.18%)⬇️
src/platform/windows/audio.cpp26.38% <38.53%> (+12.31%)⬆️

... and 28 files with indirect coverage changes

Comment threadsrc/platform/linux/audio.cpp Fixed

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
@psyke83

psyke83 commented Jul 19, 2024

Copy link
Copy Markdown
Contributor

This seems to break audio on my system by default.

Log is here; relevant lines:

[2024:07:19:19:51:47]: Error: Couldn't set Wave Format [0x88890008]
[2024:07:19:19:51:47]: Error: Unable to initialize audio capture. The stream will not have audio.

I can make audio work with your PR by disabling (or rather, disallowing audio playback via the Sound settings) the Steam Streaming Speaker and Microphone devices and reconnecting the session; simply setting a real (non-Steam) endpoint to the default doesn't fix the issue, as the Steam virtual devices are always set to default when a new session is started.

@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

@ns6089
ns6089 disabled auto-merge July 20, 2024 07:35
@ns6089
ns6089 marked this pull request as draft July 20, 2024 07:35
@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

@ns6089
ns6089 marked this pull request as ready for review July 20, 2024 08:24
@ns6089

Copy link
Copy Markdown
ContributorAuthor

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically.
No new changes to Linux or MacOS code, the review is still valid.

@ReenigneArcher

ReenigneArcher commented Jul 20, 2024

Copy link
Copy Markdown
Member

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically. No new changes to Linux or MacOS code, the review is still valid.

Reviews get dismissed when the code changes. That is a branch protection rule I have enabled.

@psyke83

Copy link
Copy Markdown
Contributor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

Confirmed working via Steam endpoints with latest changes on your PR branch - thanks.

Comment threadsrc/platform/windows/audio.cpp Outdated
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned we might need some additional logic for this. I don't know if it's guaranteed that all devices will support 24-bit PCM for all channel configurations. I think it would be best if we tried them in order: 32-bit -> 24-bit -> 16-bit

That would ensure we don't possibly regress any audio devices that are 16-bit only, and also provide the highest quality on devices with 32-bit support.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

/** * If the requested sink is a virtual sink, meaning no speakers attached to * the host, then we can seamlessly set the format to stereo and surround sound. * * Any virtual sink detected will be prefixed by: * virtual-(format name) * If it doesn't contain that prefix, then the format will not be changed*/
std::optional<std::wstring>
set_format(const std::string &sink) {
auto sink_info = get_sink_info(sink);
// If the sink isn't a device name, we'll assume it's a device IDauto wstring_device_id = find_device_id_by_name(sink).value_or(from_utf8(sink_info.second.data()));
if (sink_info.first == format_t::none) {
// wstring_device_id does not contain virtual-(format name)// It's a simple deviceId, just pass it backreturnstd::make_optional(std::move(wstring_device_id));
}
wave_format_t wave_format;
auto status = policy->GetMixFormat(wstring_device_id.c_str(), &wave_format);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
set_wave_format(wave_format, formats[(int) sink_info.first - 1]);
WAVEFORMATEXTENSIBLE p {};
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
// Surround 5.1 might contain side-{left, right} instead of speaker in the back// Try again with different speaker mask.if (status == 0x88890008 && sink_info.first == format_t::surr51) {
set_wave_format(wave_format, surround_51_side_speakers);
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
}
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't set Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
returnstd::make_optional(std::move(wstring_device_id));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

Other virtual speakers can be used, such as virtual audio cable https://vb-audio.com/Cable/

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so sunshine can have default or custom audio sink, and default or custom virtual audio sink.
Will check how it can be handled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could just be as simple as a loop that tries SetDeviceFormat() until it succeeds.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be a simple loop too, but then ended up with a nasty memory corruption. The rest of the code had accumulated quite a bit of technical dept. Either way it should be ready soon.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed and tested what I could.

Comment threadsrc/platform/windows/audio.cpp Outdated
auto adapter_name = no_null((LPWSTR) adapter_friendly_name.prop.pszVal);
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit a fix for these and merge

Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;
auto device_description = (LPWSTR) device_desc.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
cgutman
cgutman previously approved these changes Jul 25, 2024
@cgutman
cgutman enabled auto-merge (squash) July 25, 2024 02:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ns6089@psyke83@ReenigneArcher@cgutman@github-advanced-security
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Migrate audio pipeline to float from 16-bit integer - #2873

Merged
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio
Jul 26, 2024
Merged

Migrate audio pipeline to float from 16-bit integer#2873
ReenigneArcher merged 7 commits into
LizardByte:masterfrom
ns6089:float_audio

Conversation

@ns6089

@ns6089ns6089 commented Jul 16, 2024

Copy link
Copy Markdown
Contributor

Description

Float is the native format of opus codec and most if not all capture backends.

Implementation progress:

  • Windows
  • MacOS
  • Linux

Screenshot

Issues Fixed or Closed

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Dependency update (updates to dependencies)
  • Documentation update (changes to documentation)
  • Repository update (changes to repository files, e.g. .github/...)

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated the in code docstring/documentation-blocks for new or existing methods/components

Branch Updates

LizardByte requires that branches be up-to-date before merging. This means that after any PR is merged, this branch
must be updated before it can be merged. You must also
Allow edits from maintainers.

  • I want maintainers to keep my branch updated

cgutman
cgutman previously approved these changes Jul 18, 2024

@cgutmancgutman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully tested locally on macOS and Linux

@ns6089
ns6089 marked this pull request as ready for review July 18, 2024 23:47
@cgutman
cgutman enabled auto-merge (squash) July 19, 2024 04:10
@codecov

codecovBot commented Jul 19, 2024

Copy link
Copy Markdown

Codecov Report

Attention: Patch coverage is 34.64912% with 149 lines in your changes missing coverage. Please review.

Project coverage is 9.57%. Comparing base (aa2cf8e) to head (6dbb08f).
Report is 137 commits behind head on master.

Files with missing linesPatch %Lines
src/platform/windows/audio.cpp38.53%120 Missing and 6 partials ⚠️
src/logging.cpp0.00%8 Missing ⚠️
src/platform/linux/audio.cpp0.00%6 Missing ⚠️
src/platform/macos/microphone.mm0.00%5 Missing ⚠️
src/audio.cpp0.00%2 Missing ⚠️
src/platform/macos/av_audio.m0.00%2 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2873 +/- ##
=========================================
+ Coverage 9.19% 9.57% +0.37% 
=========================================
Files 97 97 Lines 17523 17586 +63 Branches 8331 8336 +5 =========================================
+ Hits 1611 1683 +72 - Misses 13086 15099 +2013 + Partials 2826 804 -2022 
FlagCoverage Δ
Linux6.95% <0.00%> (-0.01%)⬇️
Windows5.08% <36.74%> (+0.56%)⬆️
macOS-1210.29% <0.00%> (-0.01%)⬇️
macOS-1310.21% <0.00%> (+<0.01%)⬆️
macOS-1410.52% <0.00%> (-0.02%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing linesCoverage Δ
src/logging.h32.35% <ø> (ø)
src/platform/common.h34.44% <ø> (ø)
src/audio.cpp28.57% <0.00%> (ø)
src/platform/macos/av_audio.m18.03% <0.00%> (ø)
src/platform/macos/microphone.mm37.77% <0.00%> (ø)
src/platform/linux/audio.cpp9.64% <0.00%> (-0.05%)⬇️
src/logging.cpp77.98% <0.00%> (-6.18%)⬇️
src/platform/windows/audio.cpp26.38% <38.53%> (+12.31%)⬆️

... and 28 files with indirect coverage changes

Comment threadsrc/platform/linux/audio.cpp Fixed

// *2 --> needs to fit double
sample_buf = util::buffer_t<std::int16_t> { std::max(frames, frame_size) * 2 * channels_out };
sample_buf = util::buffer_t<float> { std::max(frames, frame_size) * 2 * channels_out };

Check failure

Code scanning / CodeQL

Multiplication result converted to larger type

Multiplication result may overflow 'unsigned int' before it is converted to 'size_t'.
@psyke83

psyke83 commented Jul 19, 2024

Copy link
Copy Markdown
Contributor

This seems to break audio on my system by default.

Log is here; relevant lines:

[2024:07:19:19:51:47]: Error: Couldn't set Wave Format [0x88890008]
[2024:07:19:19:51:47]: Error: Unable to initialize audio capture. The stream will not have audio.

I can make audio work with your PR by disabling (or rather, disallowing audio playback via the Sound settings) the Steam Streaming Speaker and Microphone devices and reconnecting the session; simply setting a real (non-Steam) endpoint to the default doesn't fix the issue, as the Steam virtual devices are always set to default when a new session is started.

@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

@ns6089
ns6089 disabled auto-merge July 20, 2024 07:35
@ns6089
ns6089 marked this pull request as draft July 20, 2024 07:35
@ns6089

Copy link
Copy Markdown
ContributorAuthor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

@ns6089
ns6089 marked this pull request as ready for review July 20, 2024 08:24
@ns6089

Copy link
Copy Markdown
ContributorAuthor

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically.
No new changes to Linux or MacOS code, the review is still valid.

@ReenigneArcher

ReenigneArcher commented Jul 20, 2024

Copy link
Copy Markdown
Member

2024-07-20 11_33_08-Window

Wasn't me by the way, github did it automatically. No new changes to Linux or MacOS code, the review is still valid.

Reviews get dismissed when the code changes. That is a branch protection rule I have enabled.

@psyke83

Copy link
Copy Markdown
Contributor

Can reproduce, let's see what did I do wrong...

Messed with the function picks format for steam virtual speakers device.

@psyke83 Should work now, good catch

Confirmed working via Steam endpoints with latest changes on your PR branch - thanks.

Comment threadsrc/platform/windows/audio.cpp Outdated
set_wave_format(audio::wave_format_t &wave_format, const format_t &format) {
wave_format->nSamplesPerSec = SAMPLE_RATE;
wave_format->wBitsPerSample = 16;
wave_format->wBitsPerSample = 24;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned we might need some additional logic for this. I don't know if it's guaranteed that all devices will support 24-bit PCM for all channel configurations. I think it would be best if we tried them in order: 32-bit -> 24-bit -> 16-bit

That would ensure we don't possibly regress any audio devices that are 16-bit only, and also provide the highest quality on devices with 32-bit support.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

/** * If the requested sink is a virtual sink, meaning no speakers attached to * the host, then we can seamlessly set the format to stereo and surround sound. * * Any virtual sink detected will be prefixed by: * virtual-(format name) * If it doesn't contain that prefix, then the format will not be changed*/
std::optional<std::wstring>
set_format(const std::string &sink) {
auto sink_info = get_sink_info(sink);
// If the sink isn't a device name, we'll assume it's a device IDauto wstring_device_id = find_device_id_by_name(sink).value_or(from_utf8(sink_info.second.data()));
if (sink_info.first == format_t::none) {
// wstring_device_id does not contain virtual-(format name)// It's a simple deviceId, just pass it backreturnstd::make_optional(std::move(wstring_device_id));
}
wave_format_t wave_format;
auto status = policy->GetMixFormat(wstring_device_id.c_str(), &wave_format);
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't acquire Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
set_wave_format(wave_format, formats[(int) sink_info.first - 1]);
WAVEFORMATEXTENSIBLE p {};
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
// Surround 5.1 might contain side-{left, right} instead of speaker in the back// Try again with different speaker mask.if (status == 0x88890008 && sink_info.first == format_t::surr51) {
set_wave_format(wave_format, surround_51_side_speakers);
status = policy->SetDeviceFormat(wstring_device_id.c_str(), wave_format.get(), (WAVEFORMATEX *) &p);
}
if (FAILED(status)) {
BOOST_LOG(error) << "Couldn't set Wave Format [0x"sv << util::hex(status).to_string_view() << ']';
return std::nullopt;
}
returnstd::make_optional(std::move(wstring_device_id));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used only for "virtual" sinks, which I thought only consisted of steam virtual speakers. Am I wrong in this assumption?

Other virtual speakers can be used, such as virtual audio cable https://vb-audio.com/Cable/

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, so sunshine can have default or custom audio sink, and default or custom virtual audio sink.
Will check how it can be handled.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could just be as simple as a loop that tries SetDeviceFormat() until it succeeds.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be a simple loop too, but then ended up with a nasty memory corruption. The rest of the code had accumulated quite a bit of technical dept. Either way it should be ready soon.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed and tested what I could.

Comment threadsrc/platform/windows/audio.cpp Outdated
auto adapter_name = no_null((LPWSTR) adapter_friendly_name.prop.pszVal);
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll commit a fix for these and merge

Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_name = no_null((LPWSTR) device_friendly_name.prop.pszVal);
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
Comment threadsrc/platform/windows/audio.cpp Outdated
auto device_description = no_null((LPWSTR) device_desc.prop.pszVal);
auto adapter_name = (LPWSTR) adapter_friendly_name.prop.pszVal;
auto device_name = (LPWSTR) device_friendly_name.prop.pszVal;
auto device_description = (LPWSTR) device_desc.prop.pszVal;

Check failure

Code scanning / CodeQL

Cast from char* to wchar_t*

Conversion from LPSTR to LPWSTR. Use of invalid string can lead to undefined behavior.
cgutman
cgutman previously approved these changes Jul 25, 2024
@cgutman
cgutman enabled auto-merge (squash) July 25, 2024 02:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@ns6089@psyke83@ReenigneArcher@cgutman@github-advanced-security