diff --git a/Samples/ApplicationData/README.md b/Samples/ApplicationData/README.md
index 5b6b5f3069..6cd6b5e36d 100644
--- a/Samples/ApplicationData/README.md
+++ b/Samples/ApplicationData/README.md
@@ -2,7 +2,8 @@
page_type: sample
languages:
- csharp
-- vb
+- cpp
+- cppwinrt
products:
- windows
- windows-uwp
@@ -37,41 +38,41 @@ Shows how to store and retrieve data that is specific to each user and app by us
Application data includes session state, user preferences, and other settings. It is created, read, updated, and deleted when the app is running. The operating system manages these data stores for your app:
- local: Data that exists on the current device and is backed up in the cloud
-- roaming: Data that exists on all devices on which the user has installed the app
- temporary: Data that could be removed by the system any time the app isn't running
- localcache: Persistent data that exists only on the current device
-If you use roaming data in your app, your users can easily keep your app's application data in sync across multiple devices. The operating system replicates roaming data to the cloud when it is updated, and synchronizes the data to any other devices on which the app is installed, reducing the amount of setup work that the user needs to do to install your app on multiple devices.
-
If you use local data in your app, your users can back up application data in the cloud. This application data can then be restored back on any other device while setting up the device with the same account.
+The system also manages a roaming data store,
+but the data no longer roams starting in Windows 11.
+
The sample covers these key tasks:
- Reading and writing settings to an app data store
- Reading and writing files to an app data store
-- Responding to roaming events
-
-## Guidelines
-[Guidelines for roaming application data](http://msdn.microsoft.com/library/windows/apps/hh465094)
+## Related topics
-## Concepts
+### Concepts
[Store and retrieve settings and other app data](https://msdn.microsoft.com/library/windows/apps/mt299098)
-## Reference
+### Related samples
+
+* [ApplicationData sample](/archived/ApplicationData/) for Visual Basic (archived)
+
+### Reference
[Windows.Storage.ApplicationData](http://msdn.microsoft.com/library/windows/apps/br241587)
[Windows.Storage.ApplicationDataCompositeValue](http://msdn.microsoft.com/library/windows/apps/br241588)
[Windows.Storage.ApplicationDataContainer](http://msdn.microsoft.com/library/windows/apps/br241599)
[Windows.Storage.ApplicationDataContainerSettings](http://msdn.microsoft.com/library/windows/apps/br241600)
-[WinJS.Application](http://msdn.microsoft.com/library/windows/apps/br229774)
## System requirements
**Client:** Windows 10
-**Server:** Windows Server 2016 Technical Preview
+**Server:** Windows Server 2016
**Phone:** Windows 10
diff --git a/Samples/ApplicationData/cppwinrt/ApplicationData.sln b/Samples/ApplicationData/cppwinrt/ApplicationData.sln
new file mode 100644
index 0000000000..3bb3abc95e
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/ApplicationData.sln
@@ -0,0 +1,43 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31424.327
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ApplicationData", "ApplicationData.vcxproj", "{83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|ARM.ActiveCfg = Debug|ARM
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|ARM.Build.0 = Debug|ARM
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|ARM.Deploy.0 = Debug|ARM
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|x64.ActiveCfg = Debug|x64
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|x64.Build.0 = Debug|x64
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|x64.Deploy.0 = Debug|x64
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|x86.ActiveCfg = Debug|Win32
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|x86.Build.0 = Debug|Win32
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Debug|x86.Deploy.0 = Debug|Win32
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|ARM.ActiveCfg = Release|ARM
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|ARM.Build.0 = Release|ARM
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|ARM.Deploy.0 = Release|ARM
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|x64.ActiveCfg = Release|x64
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|x64.Build.0 = Release|x64
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|x64.Deploy.0 = Release|x64
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|x86.ActiveCfg = Release|Win32
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|x86.Build.0 = Release|Win32
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {391ED8DE-38FA-49C2-A23C-4D0CE73F0017}
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/ApplicationData/cppwinrt/ApplicationData.vcxproj b/Samples/ApplicationData/cppwinrt/ApplicationData.vcxproj
new file mode 100644
index 0000000000..3d4f729b4d
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/ApplicationData.vcxproj
@@ -0,0 +1,253 @@
+
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), LICENSE))\SharedContent
+
+
+ true
+ {83665FC5-1A28-4FF1-A403-2A7ACBA3E6A5}
+ ApplicationData
+ SDKTemplate
+ en-US
+ 15.0
+ true
+ Windows Store
+ 10.0
+ 10.0.22000.0
+ $(WindowsTargetPlatformVersion)
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ Application
+ v142
+ Unicode
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+ $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);$(SharedContentDir)\cppwinrt
+ true
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+ 4453;28204
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+ WindowsApp.lib;onecoreuap.lib;%(AdditionalDependencies)
+
+
+ WindowsApp.lib;onecoreuap.lib;%(AdditionalDependencies)
+
+
+ WindowsApp.lib;onecoreuap.lib;%(AdditionalDependencies)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ WindowsApp.lib;onecoreuap.lib;%(AdditionalDependencies)
+
+
+ WindowsApp.lib;onecoreuap.lib;%(AdditionalDependencies)
+
+
+ WindowsApp.lib;onecoreuap.lib;%(AdditionalDependencies)
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+ ..\shared\Scenario1_Files.xaml
+
+
+ ..\shared\Scenario2_Settings.xaml
+
+
+ ..\shared\Scenario3_SettingContainer.xaml
+
+
+ ..\shared\Scenario4_CompositeSettings.xaml
+
+
+ ..\shared\Scenario5_Msappdata.xaml
+
+
+ ..\shared\Scenario6_ClearScenario.xaml
+
+
+ ..\shared\Scenario7_SetVersion.xaml
+
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+ Styles\Styles.xaml
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+ SampleConfiguration.h
+
+
+ ..\shared\Scenario1_Files.xaml
+
+
+ ..\shared\Scenario2_Settings.xaml
+
+
+ ..\shared\Scenario3_SettingContainer.xaml
+
+
+ ..\shared\Scenario4_CompositeSettings.xaml
+
+
+ ..\shared\Scenario5_Msappdata.xaml
+
+
+ ..\shared\Scenario6_ClearScenario.xaml
+
+
+ ..\shared\Scenario7_SetVersion.xaml
+
+
+ Create
+ pch.h
+
+
+ Project.idl
+
+
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+
+ Designer
+
+
+
+
+ Assets\microsoft-sdk.png
+
+
+ Assets\smallTile-sdk.png
+
+
+ Assets\splash-sdk.png
+
+
+ Assets\squareTile-sdk.png
+
+
+ Assets\storeLogo-sdk.png
+
+
+ Assets\tile-sdk.png
+
+
+ Assets\windows-sdk.png
+
+
+ Assets\appDataLocal.png
+
+
+ Assets\appDataRoaming.png
+
+
+ Assets\appDataTemp.png
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/ApplicationData/cppwinrt/ApplicationData.vcxproj.filters b/Samples/ApplicationData/cppwinrt/ApplicationData.vcxproj.filters
new file mode 100644
index 0000000000..e79512ca25
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/ApplicationData.vcxproj.filters
@@ -0,0 +1,78 @@
+
+
+
+
+ 4416d50a-7676-4d0a-9b2c-91ff70c6047f
+ bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/ApplicationData/cppwinrt/Package.appxmanifest b/Samples/ApplicationData/cppwinrt/Package.appxmanifest
new file mode 100644
index 0000000000..185d8fef63
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Package.appxmanifest
@@ -0,0 +1,42 @@
+
+
+
+
+
+ ApplicationData C++/WinRT Sample
+ Microsoft Corporation
+ Assets\storelogo-sdk.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/ApplicationData/cppwinrt/Project.idl b/Samples/ApplicationData/cppwinrt/Project.idl
new file mode 100644
index 0000000000..08be53dfbd
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Project.idl
@@ -0,0 +1,45 @@
+namespace SDKTemplate
+{
+
+ [default_interface]
+ runtimeclass Scenario1_Files : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario1_Files();
+ }
+
+ [default_interface]
+ runtimeclass Scenario2_Settings : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario2_Settings();
+ }
+
+ [default_interface]
+ runtimeclass Scenario3_SettingContainer : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario3_SettingContainer();
+ }
+
+ [default_interface]
+ runtimeclass Scenario4_CompositeSettings : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario4_CompositeSettings();
+ }
+
+ [default_interface]
+ runtimeclass Scenario5_Msappdata : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario5_Msappdata();
+ }
+
+ [default_interface]
+ runtimeclass Scenario6_ClearScenario : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario6_ClearScenario();
+ }
+
+ [default_interface]
+ runtimeclass Scenario7_SetVersion : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario7_SetVersion();
+ }
+}
\ No newline at end of file
diff --git a/Samples/ApplicationData/cppwinrt/SampleConfiguration.cpp b/Samples/ApplicationData/cppwinrt/SampleConfiguration.cpp
new file mode 100644
index 0000000000..e1c0c0cedb
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/SampleConfiguration.cpp
@@ -0,0 +1,35 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include "MainPage.h"
+#include "SampleConfiguration.h"
+
+using namespace winrt;
+using namespace Windows::Foundation::Collections;
+using namespace SDKTemplate;
+
+hstring implementation::MainPage::FEATURE_NAME()
+{
+ return L"ApplicationData C++/WinRT Sample";
+}
+
+IVector implementation::MainPage::scenariosInner = winrt::single_threaded_observable_vector(
+{
+ Scenario{ L"Files", xaml_typename() },
+ Scenario{ L"Settings", xaml_typename() },
+ Scenario{ L"Setting Containers", xaml_typename() },
+ Scenario{ L"Composite Settings", xaml_typename() },
+ Scenario{ L"ms-appdata:// Protocol", xaml_typename() },
+ Scenario{ L"Clear", xaml_typename() },
+ Scenario{ L"SetVersion", xaml_typename() },
+});
diff --git a/Samples/ApplicationData/cppwinrt/SampleConfiguration.h b/Samples/ApplicationData/cppwinrt/SampleConfiguration.h
new file mode 100644
index 0000000000..ba0eb7c8c2
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/SampleConfiguration.h
@@ -0,0 +1,17 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "pch.h"
+
+namespace winrt::SDKTemplate
+{
+}
diff --git a/Samples/ApplicationData/cppwinrt/Scenario1_Files.cpp b/Samples/ApplicationData/cppwinrt/Scenario1_Files.cpp
new file mode 100644
index 0000000000..16a7bac90f
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario1_Files.cpp
@@ -0,0 +1,150 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario1_Files.h"
+#include "Scenario1_Files.g.cpp"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::Storage;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario1_Files::Scenario1_Files()
+ {
+ InitializeComponent();
+ }
+
+ // Guidance for Local, LocalCache, and Temporary files.
+ //
+ // Files are ideal for storing large data-sets, databases, or data that is
+ // in a common file-format.
+ //
+ // Files can exist in either the Local, LocalCache, or Temporary folders.
+ // (They can also be put in Roaming folders, but the data no longer roams.)
+ //
+ // Local files are not synchronized, but they are backed up, and can then be restored to a
+ // machine different than where they were originally written. These should be for
+ // important files that allow the feel that the user did not lose anything
+ // when they restored to a new device.
+ //
+ // Temporary files are subject to deletion when not in use. The system
+ // considers factors such as available disk capacity and the age of a file when
+ // determining when or whether to delete a temporary file.
+ //
+ // LocalCache files are for larger files that can be recreated by the app, and for
+ // machine specific or private files that should not be restored to a new device.
+
+ fire_and_forget Scenario1_Files::Increment_Local_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto strong = get_strong();
+
+ localCounter++;
+
+ StorageFile file = co_await localFolder.CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting);
+ co_await FileIO::WriteTextAsync(file, std::to_wstring(localCounter));
+
+ Read_Local_Counter();
+ }
+
+ fire_and_forget Scenario1_Files::Read_Local_Counter()
+ {
+ auto strong = get_strong();
+
+ StorageFile file = (co_await localFolder.TryGetItemAsync(filename)).as();
+ if (file != nullptr)
+ {
+ hstring text = co_await FileIO::ReadTextAsync(file);
+
+ LocalOutputTextBlock().Text(L"Local Counter: " + text);
+
+ localCounter = wcstol(text.c_str(), nullptr, 10);
+ }
+ else
+ {
+ LocalOutputTextBlock().Text(L"Local Counter: ");
+ }
+ }
+
+ fire_and_forget Scenario1_Files::Increment_LocalCache_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto strong = get_strong();
+ localCacheCounter++;
+
+ StorageFile file = co_await localCacheFolder.CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting);
+ co_await FileIO::WriteTextAsync(file, std::to_wstring(localCacheCounter));
+
+ Read_LocalCache_Counter();
+ }
+
+ fire_and_forget Scenario1_Files::Read_LocalCache_Counter()
+ {
+ auto strong = get_strong();
+
+ StorageFile file = (co_await localCacheFolder.TryGetItemAsync(filename)).as();
+ if (file != nullptr)
+ {
+ hstring text = co_await FileIO::ReadTextAsync(file);
+
+ LocalCacheOutputTextBlock().Text(L"LocalCache Counter: " + text);
+
+ localCacheCounter = wcstol(text.c_str(), nullptr, 10);
+ }
+ else
+ {
+ LocalCacheOutputTextBlock().Text(L"LocalCache Counter: ");
+ }
+ }
+
+ fire_and_forget Scenario1_Files::Increment_Temporary_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto strong = get_strong();
+ temporaryCounter++;
+
+ StorageFile file = co_await temporaryFolder.CreateFileAsync(filename, CreationCollisionOption::ReplaceExisting);
+ co_await FileIO::WriteTextAsync(file, std::to_wstring(temporaryCounter));
+
+ Read_Temporary_Counter();
+ }
+
+ fire_and_forget Scenario1_Files::Read_Temporary_Counter()
+ {
+ StorageFile file = (co_await temporaryFolder.TryGetItemAsync(filename)).as();
+ if (file != nullptr)
+ {
+ hstring text = co_await FileIO::ReadTextAsync(file);
+
+ TemporaryOutputTextBlock().Text(L"Temporary Counter: " + text);
+
+ temporaryCounter = wcstol(text.c_str(), nullptr, 10);
+ }
+ else
+ {
+ TemporaryOutputTextBlock().Text(L"Temporary Counter: ");
+ }
+ }
+
+ void Scenario1_Files::DisplayOutput()
+ {
+ Read_Local_Counter();
+ Read_LocalCache_Counter();
+ Read_Temporary_Counter();
+ }
+
+ void Scenario1_Files::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ DisplayOutput();
+ }
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario1_Files.h b/Samples/ApplicationData/cppwinrt/Scenario1_Files.h
new file mode 100644
index 0000000000..f34e96738c
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario1_Files.h
@@ -0,0 +1,53 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario1_Files.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario1_Files : Scenario1_FilesT
+ {
+ Scenario1_Files();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+ fire_and_forget Increment_Local_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget Increment_LocalCache_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget Increment_Temporary_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ void DisplayOutput();
+
+ private:
+
+ fire_and_forget Read_Local_Counter();
+ fire_and_forget Read_LocalCache_Counter();
+ fire_and_forget Read_Temporary_Counter();
+
+ Windows::Storage::StorageFolder localFolder = Windows::Storage::ApplicationData::Current().LocalFolder();
+ int localCounter = 0;
+ Windows::Storage::StorageFolder localCacheFolder = Windows::Storage::ApplicationData::Current().LocalCacheFolder();
+ int localCacheCounter = 0;
+ Windows::Storage::StorageFolder temporaryFolder = Windows::Storage::ApplicationData::Current().TemporaryFolder();
+ int temporaryCounter = 0;
+
+ inline static const auto filename = L"sampleFile.txt";
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario1_Files : Scenario1_FilesT
+ {
+ };
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario2_Settings.cpp b/Samples/ApplicationData/cppwinrt/Scenario2_Settings.cpp
new file mode 100644
index 0000000000..03f7ec477a
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario2_Settings.cpp
@@ -0,0 +1,71 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario2_Settings.h"
+#include "Scenario2_Settings.g.cpp"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::Storage;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario2_Settings::Scenario2_Settings()
+ {
+ InitializeComponent();
+ }
+
+ // Guidance for Settings.
+ //
+ // Settings are a convenient way of storing small pieces of configuration data
+ // for your application.
+ //
+ // There are two storage containers for settings: Local and Roaming. However,
+ // Roaming settings no longer roam, so they are functionally equivalent to Local.
+ //
+ // Care should be taken to guard against an excessive volume of data being
+ // stored in settings. Settings are not intended to be used as a database.
+ // Large data sets will take longer to load from disk during your application's
+ // launch.
+
+ // This sample illustrates reading and writing from a local setting.
+
+ void Scenario2_Settings::WriteSetting_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ hstring toSet = L"Hello World";
+ localSettings.Values().Insert(SettingName, box_value(toSet)); // example value
+
+ DisplayOutput();
+ }
+
+ void Scenario2_Settings::DeleteSetting_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ localSettings.Values().Remove(SettingName);
+
+ DisplayOutput();
+ }
+
+ void Scenario2_Settings::DisplayOutput()
+ {
+ auto stringValue = localSettings.Values().TryLookup(SettingName).try_as();
+
+ OutputTextBlock().Text(L"Setting: " + (stringValue.has_value() ? L"\"" + stringValue.value() + L"\"" : L""));
+ }
+
+ void Scenario2_Settings::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ DisplayOutput();
+ }
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario2_Settings.h b/Samples/ApplicationData/cppwinrt/Scenario2_Settings.h
new file mode 100644
index 0000000000..fa6e2f9f2d
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario2_Settings.h
@@ -0,0 +1,43 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario2_Settings.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario2_Settings : Scenario2_SettingsT
+ {
+ Scenario2_Settings();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+ void WriteSetting_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void DeleteSetting_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ private:
+
+ void DisplayOutput();
+
+ Windows::Storage::ApplicationDataContainer localSettings = Windows::Storage::ApplicationData::Current().LocalSettings();
+
+ inline static const auto SettingName = L"exampleSetting";
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario2_Settings : Scenario2_SettingsT
+ {
+ };
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario3_SettingContainer.cpp b/Samples/ApplicationData/cppwinrt/Scenario3_SettingContainer.cpp
new file mode 100644
index 0000000000..9293832efd
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario3_SettingContainer.cpp
@@ -0,0 +1,78 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include "Scenario3_SettingContainer.h"
+#include "Scenario3_SettingContainer.g.cpp"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::Storage;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario3_SettingContainer::Scenario3_SettingContainer()
+ {
+ InitializeComponent();
+ }
+
+ void Scenario3_SettingContainer::CreateContainer_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ ApplicationDataContainer container = localSettings.CreateContainer(containerName, ApplicationDataCreateDisposition::Always);
+
+ DisplayOutput();
+ }
+
+ void Scenario3_SettingContainer::DeleteContainer_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ localSettings.DeleteContainer(containerName);
+
+ DisplayOutput();
+ }
+
+ void Scenario3_SettingContainer::WriteSetting_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ localSettings.Containers().Lookup(containerName).Values().Insert(settingName, box_value(L"Hello World")); // example value
+
+ DisplayOutput();
+ }
+
+ void Scenario3_SettingContainer::DeleteSetting_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ localSettings.Containers().Lookup(containerName).Values().Remove(settingName);
+
+ DisplayOutput();
+ }
+
+ void Scenario3_SettingContainer::DisplayOutput()
+ {
+ ApplicationDataContainer container = localSettings.Containers().TryLookup(containerName);
+ bool hasSetting = container ? container.Values().HasKey(settingName) : false;
+
+ std::wstringstream formatted;
+ formatted << std::boolalpha << L"Container Exists: " << (container != nullptr) << std::endl;
+ formatted << L"Setting Exists: " << hasSetting << std::endl;
+
+ OutputTextBlock().Text(formatted.str());
+
+ WriteSetting().IsEnabled(container != nullptr);
+ DeleteSetting().IsEnabled(container != nullptr);
+ }
+
+ void Scenario3_SettingContainer::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ DisplayOutput();
+ }
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario3_SettingContainer.h b/Samples/ApplicationData/cppwinrt/Scenario3_SettingContainer.h
new file mode 100644
index 0000000000..5eb770d2cd
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario3_SettingContainer.h
@@ -0,0 +1,46 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario3_SettingContainer.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario3_SettingContainer : Scenario3_SettingContainerT
+ {
+ Scenario3_SettingContainer();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+ void CreateContainer_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ void DeleteContainer_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ void WriteSetting_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ void DeleteSetting_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ private:
+
+ void DisplayOutput();
+
+ Windows::Storage::ApplicationDataContainer localSettings = Windows::Storage::ApplicationData::Current().LocalSettings();
+
+ inline static const auto containerName = L"exampleContainer";
+ inline static const auto settingName = L"exampleSetting";
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario3_SettingContainer : Scenario3_SettingContainerT
+ {
+ };
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario4_CompositeSettings.cpp b/Samples/ApplicationData/cppwinrt/Scenario4_CompositeSettings.cpp
new file mode 100644
index 0000000000..36bc962683
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario4_CompositeSettings.cpp
@@ -0,0 +1,73 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include "Scenario4_CompositeSettings.h"
+#include "Scenario4_CompositeSettings.g.cpp"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::Storage;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario4_CompositeSettings::Scenario4_CompositeSettings()
+ {
+ InitializeComponent();
+ }
+
+ void Scenario4_CompositeSettings::WriteCompositeSetting_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ // Composite settings are used to group multiple settings.
+ // Note that Composite settings may not be nested.
+ ApplicationDataCompositeValue composite;
+ composite.Insert(settingName1, box_value(1)); // example value
+ composite.Insert(settingName2, box_value(L"world")); // example value
+
+ localSettings.Values().Insert(settingName, composite);
+
+ DisplayOutput();
+ }
+
+ void Scenario4_CompositeSettings::DeleteCompositeSetting_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ localSettings.Values().Remove(settingName);
+
+ DisplayOutput();
+ }
+
+ void Scenario4_CompositeSettings::DisplayOutput()
+ {
+ auto composite = localSettings.Values().Lookup(settingName).as();
+
+ std::wstringstream output;
+ if (!composite)
+ {
+ output << L"Composite Setting: ";
+ }
+ else
+ {
+ output << L"Composite setting: {" << settingName1 << L" = " << composite.Lookup(settingName1).as() << L", ";
+ output << settingName2 << L" = \"" << composite.Lookup(settingName2).as().c_str() << "\"}";
+ }
+
+ OutputTextBlock().Text(output.str());
+ }
+
+ void Scenario4_CompositeSettings::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ DisplayOutput();
+ }
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario4_CompositeSettings.h b/Samples/ApplicationData/cppwinrt/Scenario4_CompositeSettings.h
new file mode 100644
index 0000000000..92f3eb6c08
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario4_CompositeSettings.h
@@ -0,0 +1,45 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario4_CompositeSettings.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario4_CompositeSettings : Scenario4_CompositeSettingsT
+ {
+ Scenario4_CompositeSettings();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+ void WriteCompositeSetting_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ void DeleteCompositeSetting_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ private:
+
+ void DisplayOutput();
+
+ Windows::Storage::ApplicationDataContainer localSettings = Windows::Storage::ApplicationData::Current().LocalSettings();
+
+ inline static const auto settingName = L"exampleCompositeSetting";
+ inline static const auto settingName1 = L"one";
+ inline static const auto settingName2 = L"hello";
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario4_CompositeSettings : Scenario4_CompositeSettingsT
+ {
+ };
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario5_Msappdata.cpp b/Samples/ApplicationData/cppwinrt/Scenario5_Msappdata.cpp
new file mode 100644
index 0000000000..bc86b04dd1
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario5_Msappdata.cpp
@@ -0,0 +1,61 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario5_Msappdata.h"
+#include "Scenario5_Msappdata.g.cpp"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::Storage;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Media::Imaging;
+using namespace Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario5_Msappdata::Scenario5_Msappdata()
+ {
+ InitializeComponent();
+ }
+
+ IAsyncAction Scenario5_Msappdata::CopyAssetToFolderIfNecessaryAsync(hstring name, StorageFolder const& folder)
+ {
+ if (co_await folder.TryGetItemAsync(name) == nullptr)
+ {
+ auto sourceFile = co_await StorageFile::GetFileFromApplicationUriAsync(Uri{ L"ms-appx:///assets/" + name });
+ co_await sourceFile.CopyAsync(folder);
+ }
+ }
+
+ fire_and_forget Scenario5_Msappdata::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ auto strong = get_strong();
+ ApplicationData appData = ApplicationData::Current();
+
+ co_await CopyAssetToFolderIfNecessaryAsync(L"appDataLocal.png", appData.LocalFolder());
+ co_await CopyAssetToFolderIfNecessaryAsync(L"appDataRoaming.png", appData.RoamingFolder());
+ co_await CopyAssetToFolderIfNecessaryAsync(L"appDataTemp.png", appData.TemporaryFolder());
+
+ LocalImage().Source(BitmapImage{ Uri{L"ms-appdata:///local/appDataLocal.png"} });
+ RoamingImage().Source(BitmapImage{ Uri{L"ms-appdata:///roaming/appDataRoaming.png"} });
+ TempImage().Source(BitmapImage{ Uri{L"ms-appdata:///temp/appDataTemp.png"} });
+ }
+
+ void Scenario5_Msappdata::OnNavigatingFrom(NavigatingCancelEventArgs const&)
+ {
+ LocalImage().Source(nullptr);
+ RoamingImage().Source(nullptr);
+ TempImage().Source(nullptr);
+ }
+
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario5_Msappdata.h b/Samples/ApplicationData/cppwinrt/Scenario5_Msappdata.h
new file mode 100644
index 0000000000..5df7037880
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario5_Msappdata.h
@@ -0,0 +1,37 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario5_Msappdata.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario5_Msappdata : Scenario5_MsappdataT
+ {
+ Scenario5_Msappdata();
+
+ fire_and_forget OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+ void OnNavigatingFrom(Windows::UI::Xaml::Navigation::NavigatingCancelEventArgs const&);
+
+ private:
+ Windows::Foundation::IAsyncAction CopyAssetToFolderIfNecessaryAsync(hstring name, Windows::Storage::StorageFolder const& folder);
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario5_Msappdata : Scenario5_MsappdataT
+ {
+ };
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario6_ClearScenario.cpp b/Samples/ApplicationData/cppwinrt/Scenario6_ClearScenario.cpp
new file mode 100644
index 0000000000..2d65f295cf
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario6_ClearScenario.cpp
@@ -0,0 +1,41 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario6_ClearScenario.h"
+#include "Scenario6_ClearScenario.g.cpp"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::UI::Xaml;
+using namespace Windows::Storage;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario6_ClearScenario::Scenario6_ClearScenario()
+ {
+ InitializeComponent();
+ }
+
+ fire_and_forget Scenario6_ClearScenario::Clear_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ try
+ {
+ co_await ApplicationData::Current().ClearAsync();
+ OutputTextBlock().Text(L"ApplicationData has been cleared. Visit the other scenarios to see that their data has been cleared.");
+ }
+ catch (...)
+ {
+ OutputTextBlock().Text(L"Unable to clear settings. This can happen when files are in use.");
+ }
+ }
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario6_ClearScenario.h b/Samples/ApplicationData/cppwinrt/Scenario6_ClearScenario.h
new file mode 100644
index 0000000000..93c0299487
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario6_ClearScenario.h
@@ -0,0 +1,33 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario6_ClearScenario.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario6_ClearScenario : Scenario6_ClearScenarioT
+ {
+ Scenario6_ClearScenario();
+
+ fire_and_forget Clear_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario6_ClearScenario : Scenario6_ClearScenarioT
+ {
+ };
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario7_SetVersion.cpp b/Samples/ApplicationData/cppwinrt/Scenario7_SetVersion.cpp
new file mode 100644
index 0000000000..d0b6d4fe0d
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario7_SetVersion.cpp
@@ -0,0 +1,109 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario7_SetVersion.h"
+#include "Scenario7_SetVersion.g.cpp"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace Windows::Storage;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario7_SetVersion::Scenario7_SetVersion()
+ {
+ InitializeComponent();
+
+ DisplayOutput();
+ }
+
+ void Scenario7_SetVersion::SetVersionHandler0(SetVersionRequest const& request)
+ {
+ auto deferral = request.GetDeferral();
+
+ uint32_t version = appData.Version();
+
+ switch (version)
+ {
+ case 0:
+ // Version is already 0. Nothing to do.
+ break;
+
+ case 1:
+ // Need to convert data from v1 to v0.
+
+ // This sample simulates that conversion by writing a version-specific value.
+ appData.LocalSettings().Values().Insert(settingName, box_value(settingValue0));
+
+ break;
+
+ default:
+ throw hresult_invalid_argument(L"Unexpected ApplicationData Version: " + to_hstring(version));
+ }
+
+ deferral.Complete();
+ }
+
+ void Scenario7_SetVersion::SetVersionHandler1(SetVersionRequest const& request)
+ {
+ auto deferral = request.GetDeferral();
+
+ uint32_t version = appData.Version();
+
+ switch (version)
+ {
+ case 0:
+ // Need to convert data from v0 to v1.
+
+ // This sample simulates that conversion by writing a version-specific value.
+ appData.LocalSettings().Values().Insert(settingName, box_value(settingValue1));
+
+ break;
+
+ case 1:
+ // Version is already 1. Nothing to do.
+ break;
+
+ default:
+ throw hresult_invalid_argument(L"Unexpected ApplicationData Version: " + to_hstring(version));
+ }
+
+ deferral.Complete();
+ }
+
+ fire_and_forget Scenario7_SetVersion::SetVersion0_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto strong = get_strong();
+ co_await appData.SetVersionAsync(0, { get_weak(), &Scenario7_SetVersion::SetVersionHandler0 });
+ DisplayOutput();
+ }
+
+ fire_and_forget Scenario7_SetVersion::SetVersion1_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ auto strong = get_strong();
+ co_await appData.SetVersionAsync(1, { get_weak(), &Scenario7_SetVersion::SetVersionHandler1 });
+ DisplayOutput();
+ }
+
+ void Scenario7_SetVersion::DisplayOutput()
+ {
+ OutputTextBlock().Text(L"Version: " + to_hstring(appData.Version()));
+ }
+
+ void Scenario7_SetVersion::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ DisplayOutput();
+ }
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/Scenario7_SetVersion.h b/Samples/ApplicationData/cppwinrt/Scenario7_SetVersion.h
new file mode 100644
index 0000000000..7fc407f356
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/Scenario7_SetVersion.h
@@ -0,0 +1,48 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario7_SetVersion.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario7_SetVersion : Scenario7_SetVersionT
+ {
+ Scenario7_SetVersion();
+
+ void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+ fire_and_forget SetVersion0_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+ fire_and_forget SetVersion1_Click(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);
+
+ void DisplayOutput();
+
+ private:
+
+ void SetVersionHandler0(Windows::Storage::SetVersionRequest const& request);
+ void SetVersionHandler1(Windows::Storage::SetVersionRequest const& request);
+
+ Windows::Storage::ApplicationData appData = Windows::Storage::ApplicationData::Current();
+
+ inline static const auto settingName = L"SetVersionSetting";
+ inline static const auto settingValue0 = L"Data.v0";
+ inline static const auto settingValue1 = L"Data.v1";
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario7_SetVersion : Scenario7_SetVersionT
+ {
+ };
+}
+
diff --git a/Samples/ApplicationData/cppwinrt/packages.config b/Samples/ApplicationData/cppwinrt/packages.config
new file mode 100644
index 0000000000..dc8ede20f0
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Samples/ApplicationData/cppwinrt/pch.cpp b/Samples/ApplicationData/cppwinrt/pch.cpp
new file mode 100644
index 0000000000..01484ff5aa
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/pch.cpp
@@ -0,0 +1,6 @@
+//
+// pch.cpp
+// Include the standard header and generate the precompiled header.
+//
+
+#include "pch.h"
diff --git a/Samples/ApplicationData/cppwinrt/pch.h b/Samples/ApplicationData/cppwinrt/pch.h
new file mode 100644
index 0000000000..b47bbb808d
--- /dev/null
+++ b/Samples/ApplicationData/cppwinrt/pch.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+#include "winrt/Windows.Foundation.h"
+#include "winrt/Windows.Foundation.Collections.h"
+#include "winrt/Windows.ApplicationModel.Activation.h"
+#include "winrt/Windows.System.h"
+#include "winrt/Windows.UI.Core.h"
+#include "winrt/Windows.UI.Xaml.h"
+#include "winrt/Windows.UI.Xaml.Automation.Peers.h"
+#include "winrt/Windows.UI.Xaml.Controls.h"
+#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
+#include "winrt/Windows.UI.Xaml.Documents.h"
+#include "winrt/Windows.UI.Xaml.Interop.h"
+#include "winrt/Windows.UI.Xaml.Markup.h"
+#include "winrt/Windows.UI.Xaml.Media.h"
+#include "winrt/Windows.UI.Xaml.Media.Imaging.h"
+#include "winrt/Windows.UI.Xaml.Navigation.h"
+#include "winrt/Windows.Storage.h"
\ No newline at end of file
diff --git a/Samples/ApplicationData/cs/App.xaml.cs b/Samples/ApplicationData/cs/App.xaml.cs
deleted file mode 100644
index 2e620f964b..0000000000
--- a/Samples/ApplicationData/cs/App.xaml.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-//*********************************************************
-//
-// Copyright (c) Microsoft. All rights reserved.
-// This code is licensed under the Microsoft Public License.
-// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
-// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
-// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
-// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
-//
-//*********************************************************
-
-using System;
-using Windows.ApplicationModel;
-using Windows.ApplicationModel.Activation;
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Navigation;
-
-// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=402347&clcid=0x409
-
-namespace SDKTemplate
-{
- ///
- /// Provides application-specific behavior to supplement the default Application class.
- ///
- sealed partial class App : Application
- {
- ///
- /// Initializes the singleton application object. This is the first line of authored code
- /// executed, and as such is the logical equivalent of main() or WinMain().
- ///
- public App()
- {
- this.InitializeComponent();
- this.Suspending += OnSuspending;
- }
-
- ///
- /// Invoked when the application is launched normally by the end user. Other entry points
- /// will be used such as when the application is launched to open a specific file.
- ///
- /// Details about the launch request and process.
- protected override void OnLaunched(LaunchActivatedEventArgs e)
- {
-
-#if DEBUG
- if (System.Diagnostics.Debugger.IsAttached)
- {
- this.DebugSettings.EnableFrameRateCounter = false;
- }
-#endif
-
- Frame rootFrame = Window.Current.Content as Frame;
-
- // Do not repeat app initialization when the Window already has content,
- // just ensure that the window is active
- if (rootFrame == null)
- {
- // Create a Frame to act as the navigation context and navigate to the first page
- rootFrame = new Frame();
- // Set the default language
- rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
-
- rootFrame.NavigationFailed += OnNavigationFailed;
-
- if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
- {
- //TODO: Load state from previously suspended application
- }
-
- // Place the frame in the current Window
- Window.Current.Content = rootFrame;
- }
-
- if (rootFrame.Content == null)
- {
- // When the navigation stack isn't restored navigate to the first page,
- // configuring the new page by passing required information as a navigation
- // parameter
- rootFrame.Navigate(typeof(MainPage), e.Arguments);
- }
- // Ensure the current window is active
- Window.Current.Activate();
- }
-
- ///
- /// Invoked when Navigation to a certain page fails
- ///
- /// The Frame which failed navigation
- /// Details about the navigation failure
- void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
- {
- throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
- }
-
- ///
- /// Invoked when application execution is being suspended. Application state is saved
- /// without knowing whether the application will be terminated or resumed with the contents
- /// of memory still intact.
- ///
- /// The source of the suspend request.
- /// Details about the suspend request.
- private void OnSuspending(object sender, SuspendingEventArgs e)
- {
- var deferral = e.SuspendingOperation.GetDeferral();
- //TODO: Save application state and stop any background activity
- deferral.Complete();
- }
- }
-}
diff --git a/Samples/ApplicationData/cs/ApplicationData.csproj b/Samples/ApplicationData/cs/ApplicationData.csproj
index bde7cb8425..89f06800c6 100644
--- a/Samples/ApplicationData/cs/ApplicationData.csproj
+++ b/Samples/ApplicationData/cs/ApplicationData.csproj
@@ -6,7 +6,7 @@
Debug
- AnyCPU
+ x64
{E3631F30-6FD8-5AE6-88E0-CA94395F48CA}
AppContainerExe
Properties
@@ -15,31 +15,12 @@
en-US
UAP
10.0.22000.0
- 10.0.22000.0
+ $(TargetPlatformVersion)
14
true
512
{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE;NETFX_CORE;WINDOWS_UAP
- prompt
- 4
-
true
bin\ARM\Debug\
@@ -110,10 +91,12 @@
true
-
+
+ App.xaml.cs
App.xaml
-
+
+ MainPage.xaml.cs
MainPage.xaml
@@ -132,22 +115,13 @@
Scenario4_CompositeSettings.xaml
-
- Scenario5_DataChangedEvent.xaml
-
-
- Scenario6_HighPriority.xaml
+
+
+ Scenario6_ClearScenario.xaml
-
- Scenario7_Msappdata.xaml
+
+ Scenario7_SetVersion.xaml
-
- Scenario8_ClearScenario.xaml
-
-
- Scenario9_SetVersion.xaml
-
-
@@ -155,12 +129,12 @@
-
+
App.xaml
MSBuild:Compile
Designer
-
+
MainPage.xaml
MSBuild:Compile
Designer
@@ -185,28 +159,18 @@
MSBuild:Compile
Designer
-
- Scenario5_DataChangedEvent.xaml
- MSBuild:Compile
- Designer
-
-
- Scenario6_HighPriority.xaml
+
+ Scenario5_Msappdata.xaml
MSBuild:Compile
Designer
-
- Scenario7_Msappdata.xaml
+
+ Scenario6_ClearScenario.xaml
MSBuild:Compile
Designer
-
- Scenario8_ClearScenario.xaml
- MSBuild:Compile
- Designer
-
-
- Scenario9_SetVersion.xaml
+
+ Scenario7_SetVersion.xaml
MSBuild:Compile
Designer
@@ -220,9 +184,15 @@
Properties\Default.rd.xml
-
-
-
+
+ Assets\appDataLocal.png
+
+
+ Assets\appDataRoaming.png
+
+
+ Assets\appDataTemp.png
+
Assets\microsoft-sdk.png
diff --git a/Samples/ApplicationData/cs/MainPage.xaml.cs b/Samples/ApplicationData/cs/MainPage.xaml.cs
deleted file mode 100644
index 1de60df818..0000000000
--- a/Samples/ApplicationData/cs/MainPage.xaml.cs
+++ /dev/null
@@ -1,136 +0,0 @@
-//*********************************************************
-//
-// Copyright (c) Microsoft. All rights reserved.
-// This code is licensed under the Microsoft Public License.
-// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
-// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
-// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
-// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
-//
-//*********************************************************
-
-using System;
-using System.Collections.Generic;
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Data;
-using Windows.UI.Xaml.Media;
-using Windows.UI.Xaml.Navigation;
-
-// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
-
-namespace SDKTemplate
-{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class MainPage : Page
- {
- public static MainPage Current;
-
- public MainPage()
- {
- this.InitializeComponent();
-
- // This is a static public property that allows downstream pages to get a handle to the MainPage instance
- // in order to call methods that are in this class.
- Current = this;
- SampleTitle.Text = FEATURE_NAME;
- }
-
- protected override void OnNavigatedTo(NavigationEventArgs e)
- {
- // Populate the scenario list from the SampleConfiguration.cs file
- ScenarioControl.ItemsSource = scenarios;
- if (Window.Current.Bounds.Width < 640)
- {
- ScenarioControl.SelectedIndex = -1;
- }
- else
- {
- ScenarioControl.SelectedIndex = 0;
- }
- }
-
- ///
- /// Called whenever the user changes selection in the scenarios list. This method will navigate to the respective
- /// sample scenario page.
- ///
- ///
- ///
- private void ScenarioControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
- {
- // Clear the status block when navigating scenarios.
- NotifyUser(String.Empty, NotifyType.StatusMessage);
-
- ListBox scenarioListBox = sender as ListBox;
- Scenario s = scenarioListBox.SelectedItem as Scenario;
- if (s != null)
- {
- ScenarioFrame.Navigate(s.ClassType);
- if (Window.Current.Bounds.Width < 640)
- {
- Splitter.IsPaneOpen = false;
- StatusBorder.Visibility = Visibility.Collapsed;
- }
- }
- }
-
- public List Scenarios
- {
- get { return this.scenarios; }
- }
-
- ///
- /// Used to display messages to the user
- ///
- ///
- ///
- public void NotifyUser(string strMessage, NotifyType type)
- {
- switch (type)
- {
- case NotifyType.StatusMessage:
- StatusBorder.Background = new SolidColorBrush(Windows.UI.Colors.Green);
- break;
- case NotifyType.ErrorMessage:
- StatusBorder.Background = new SolidColorBrush(Windows.UI.Colors.Red);
- break;
- }
- StatusBlock.Text = strMessage;
-
- // Collapse the StatusBlock if it has no text to conserve real estate.
- StatusBorder.Visibility = (StatusBlock.Text != String.Empty) ? Visibility.Visible : Visibility.Collapsed;
- }
-
- async void Footer_Click(object sender, RoutedEventArgs e)
- {
- await Windows.System.Launcher.LaunchUriAsync(new Uri(((HyperlinkButton)sender).Tag.ToString()));
- }
-
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- Splitter.IsPaneOpen = (Splitter.IsPaneOpen == true) ? false : true;
- StatusBorder.Visibility = Visibility.Collapsed;
- }
- }
- public enum NotifyType
- {
- StatusMessage,
- ErrorMessage
- };
-
- public class ScenarioBindingConverter : IValueConverter
- {
- public object Convert(object value, Type targetType, object parameter, string language)
- {
- Scenario s = value as Scenario;
- return (MainPage.Current.Scenarios.IndexOf(s) + 1) + ") " + s.Title;
- }
-
- public object ConvertBack(object value, Type targetType, object parameter, string language)
- {
- return true;
- }
- }
-}
diff --git a/Samples/ApplicationData/cs/SampleConfiguration.cs b/Samples/ApplicationData/cs/SampleConfiguration.cs
index 6d9e27cc2f..31ebd23601 100644
--- a/Samples/ApplicationData/cs/SampleConfiguration.cs
+++ b/Samples/ApplicationData/cs/SampleConfiguration.cs
@@ -19,22 +19,15 @@ public partial class MainPage : Page
{
public const string FEATURE_NAME = "ApplicationData";
- // Change the array below to reflect the name of your scenarios.
- // This will be used to populate the list of scenarios on the main page with
- // which the user will choose the specific scenario that they are interested in.
- // These should be in the form: "Navigating to a web page".
- // The code in MainPage will take care of turning this into: "1) Navigating to a web page"
List scenarios = new List
{
- new Scenario() { Title = "Files", ClassType = typeof(ApplicationDataSample.Files) },
- new Scenario() { Title = "Settings", ClassType = typeof(ApplicationDataSample.Settings) },
- new Scenario() { Title = "Setting Containers", ClassType = typeof(ApplicationDataSample.SettingContainer) },
- new Scenario() { Title = "Composite Settings", ClassType = typeof(ApplicationDataSample.CompositeSettings) },
- new Scenario() { Title = "DataChanged Event", ClassType = typeof(ApplicationDataSample.DataChangedEvent) },
- new Scenario() { Title = "Roaming: HighPriority", ClassType = typeof(ApplicationDataSample.HighPriority) },
- new Scenario() { Title = "ms-appdata:// Protocol", ClassType = typeof(ApplicationDataSample.Msappdata) },
- new Scenario() { Title = "Clear", ClassType = typeof(ApplicationDataSample.ClearScenario) },
- new Scenario() { Title = "SetVersion", ClassType = typeof(ApplicationDataSample.SetVersion) },
+ new Scenario() { Title = "Files", ClassType = typeof(Scenario1_Files) },
+ new Scenario() { Title = "Settings", ClassType = typeof(Scenario2_Settings) },
+ new Scenario() { Title = "Setting Containers", ClassType = typeof(Scenario3_SettingContainer) },
+ new Scenario() { Title = "Composite Settings", ClassType = typeof(Scenario4_CompositeSettings) },
+ new Scenario() { Title = "ms-appdata:// Protocol", ClassType = typeof(Scenario5_Msappdata) },
+ new Scenario() { Title = "Clear", ClassType = typeof(Scenario6_ClearScenario) },
+ new Scenario() { Title = "SetVersion", ClassType = typeof(Scenario7_SetVersion) },
};
}
diff --git a/Samples/ApplicationData/cs/Scenario1_Files.xaml.cs b/Samples/ApplicationData/cs/Scenario1_Files.xaml.cs
index 3fbdf2d0da..bc0f5c61f6 100644
--- a/Samples/ApplicationData/cs/Scenario1_Files.xaml.cs
+++ b/Samples/ApplicationData/cs/Scenario1_Files.xaml.cs
@@ -1,4 +1,4 @@
-//*********************************************************
+//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
@@ -8,64 +8,41 @@
//
//*********************************************************
+using System;
+using Windows.Storage;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
-using SDKTemplate;
-using System;
-using Windows.Storage;
-namespace ApplicationDataSample
+namespace SDKTemplate
{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class Files : Page
+ public sealed partial class Scenario1_Files : Page
{
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
- MainPage rootPage = MainPage.Current;
- StorageFolder localFolder = null;
+ StorageFolder localFolder = ApplicationData.Current.LocalFolder;
int localCounter = 0;
- StorageFolder localCacheFolder = null;
+ StorageFolder localCacheFolder = ApplicationData.Current.LocalCacheFolder;
int localCacheCounter = 0;
- StorageFolder roamingFolder = null;
- int roamingCounter = 0;
- StorageFolder temporaryFolder = null;
+ StorageFolder temporaryFolder = ApplicationData.Current.TemporaryFolder;
int temporaryCounter = 0;
const string filename = "sampleFile.txt";
- public Files()
+ public Scenario1_Files()
{
- this.InitializeComponent();
-
- localFolder = ApplicationData.Current.LocalFolder;
- localCacheFolder = ApplicationData.Current.LocalCacheFolder;
- roamingFolder = ApplicationData.Current.RoamingFolder;
- temporaryFolder = ApplicationData.Current.TemporaryFolder;
-
- DisplayOutput();
+ InitializeComponent();
}
- // Guidance for Local, LocalCache, Roaming, and Temporary files.
+ // Guidance for Local, LocalCache, and Temporary files.
//
// Files are ideal for storing large data-sets, databases, or data that is
// in a common file-format.
//
- // Files can exist in either the Local, LocalCache, Roaming, or Temporary folders.
- //
- // Roaming files will be synchronized across machines on which the user has
- // singed in with a connected account. Roaming of files is not instant; the
- // system weighs several factors when determining when to send the data. Usage
- // of roaming data should be kept below the quota (available via the
- // RoamingStorageQuota property), or else roaming of data will be suspended.
- // Files cannot be roamed while an application is writing to them, so be sure
- // to close your application's file objects when they are no longer needed.
+ // Files can exist in either the Local, LocalCache, or Temporary folders.
+ // (They can also be put in Roaming folders, but the data no longer roams.)
//
- // Local files are not synchronized, but are backed up, and can then be restored to a
+ // Local files are not synchronized, but they are backed up, and can then be restored to a
// machine different than where they were originally written. These should be for
- // important files that allow the feel that the user did not loose anything
+ // important files that allow the feel that the user did not lose anything
// when they restored to a new device.
//
// Temporary files are subject to deletion when not in use. The system
@@ -87,16 +64,16 @@ async void Increment_Local_Click(Object sender, RoutedEventArgs e)
async void Read_Local_Counter()
{
- try
+ StorageFile file = (await localFolder.TryGetItemAsync(filename)) as StorageFile;
+ if (file != null)
{
- StorageFile file = await localFolder.GetFileAsync(filename);
string text = await FileIO.ReadTextAsync(file);
LocalOutputTextBlock.Text = "Local Counter: " + text;
localCounter = int.Parse(text);
}
- catch (Exception)
+ else
{
LocalOutputTextBlock.Text = "Local Counter: ";
}
@@ -113,49 +90,22 @@ async void Increment_LocalCache_Click(Object sender, RoutedEventArgs e)
}
async void Read_LocalCache_Counter()
- {
- try
+ {
+ StorageFile file = (await localCacheFolder.TryGetItemAsync(filename)) as StorageFile;
+ if (file != null)
{
- StorageFile file = await localCacheFolder.GetFileAsync(filename);
string text = await FileIO.ReadTextAsync(file);
LocalCacheOutputTextBlock.Text = "LocalCache Counter: " + text;
localCacheCounter = int.Parse(text);
}
- catch (Exception)
+ else
{
LocalCacheOutputTextBlock.Text = "LocalCache Counter: ";
}
}
- async void Increment_Roaming_Click(Object sender, RoutedEventArgs e)
- {
- roamingCounter++;
-
- StorageFile file = await roamingFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
- await FileIO.WriteTextAsync(file, roamingCounter.ToString());
-
- Read_Roaming_Counter();
- }
-
- async void Read_Roaming_Counter()
- {
- try
- {
- StorageFile file = await roamingFolder.GetFileAsync(filename);
- string text = await FileIO.ReadTextAsync(file);
-
- RoamingOutputTextBlock.Text = "Roaming Counter: " + text;
-
- roamingCounter = int.Parse(text);
- }
- catch (Exception)
- {
- RoamingOutputTextBlock.Text = "Roaming Counter: ";
- }
- }
-
async void Increment_Temporary_Click(Object sender, RoutedEventArgs e)
{
temporaryCounter++;
@@ -168,16 +118,16 @@ async void Increment_Temporary_Click(Object sender, RoutedEventArgs e)
async void Read_Temporary_Counter()
{
- try
+ StorageFile file = (await temporaryFolder.TryGetItemAsync(filename)) as StorageFile;
+ if (file != null)
{
- StorageFile file = await temporaryFolder.GetFileAsync(filename);
string text = await FileIO.ReadTextAsync(file);
TemporaryOutputTextBlock.Text = "Temporary Counter: " + text;
temporaryCounter = int.Parse(text);
}
- catch (Exception)
+ else
{
TemporaryOutputTextBlock.Text = "Temporary Counter: ";
}
@@ -187,17 +137,12 @@ void DisplayOutput()
{
Read_Local_Counter();
Read_LocalCache_Counter();
- Read_Roaming_Counter();
Read_Temporary_Counter();
}
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
+ DisplayOutput();
}
}
-}
\ No newline at end of file
+}
diff --git a/Samples/ApplicationData/cs/Scenario2_Settings.xaml.cs b/Samples/ApplicationData/cs/Scenario2_Settings.xaml.cs
index 54493851a1..6b22b8fa3d 100644
--- a/Samples/ApplicationData/cs/Scenario2_Settings.xaml.cs
+++ b/Samples/ApplicationData/cs/Scenario2_Settings.xaml.cs
@@ -1,4 +1,4 @@
-//*********************************************************
+//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
@@ -11,31 +11,20 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
-using SDKTemplate;
using System;
using Windows.Storage;
-namespace ApplicationDataSample
+namespace SDKTemplate
{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class Settings : Page
+ public sealed partial class Scenario2_Settings : Page
{
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
- MainPage rootPage = MainPage.Current;
- ApplicationDataContainer roamingSettings = null;
+ ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
const string SettingName = "exampleSetting";
- public Settings()
+ public Scenario2_Settings()
{
- this.InitializeComponent();
-
- roamingSettings = ApplicationData.Current.RoamingSettings;
-
- DisplayOutput();
+ InitializeComponent();
}
// Guidance for Settings.
@@ -43,58 +32,40 @@ public Settings()
// Settings are a convenient way of storing small pieces of configuration data
// for your application.
//
- // Settings can be either Local or Roaming.
- //
- // Roaming settings will be synchronized across machines on which the user has
- // signed in with a Microsoft Account. Roaming of settings is not instant; the
- // system weighs several factors when determining when to send the data. Usage
- // of roaming data should be kept below the quota (available via the
- // RoamingStorageQuota property), or else roaming of data will be suspended.
- //
- // User preferences for your application are a great match for roaming settings.
- // User preferences are usually fixed in number and small in size. Users will
- // appreciated that your application is customized the way they prefer across
- // all of their machines.
- //
- // Local settings are not synchronized and remain on the machine on which they
- // were originally written.
+ // There are two storage containers for settings: Local and Roaming. However,
+ // Roaming settings no longer roam, so they are functionally equivalent to Local.
//
// Care should be taken to guard against an excessive volume of data being
// stored in settings. Settings are not intended to be used as a database.
// Large data sets will take longer to load from disk during your application's
// launch.
- // This sample illustrates reading and writing from a roaming setting, though a
- // local setting could be used just as easily.
+ // This sample illustrates reading and writing from a local setting.
void WriteSetting_Click(Object sender, RoutedEventArgs e)
{
- roamingSettings.Values[SettingName] = "Hello World"; // example value
+ localSettings.Values[SettingName] = "Hello World"; // example value
DisplayOutput();
}
void DeleteSetting_Click(Object sender, RoutedEventArgs e)
{
- roamingSettings.Values.Remove(SettingName);
+ localSettings.Values.Remove(SettingName);
DisplayOutput();
}
void DisplayOutput()
{
- Object value = roamingSettings.Values[SettingName];
+ Object value = localSettings.Values[SettingName];
OutputTextBlock.Text = String.Format("Setting: {0}", (value == null ? "" : ("\"" + value + "\"")));
}
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
+ DisplayOutput();
}
}
}
diff --git a/Samples/ApplicationData/cs/Scenario3_SettingContainer.xaml.cs b/Samples/ApplicationData/cs/Scenario3_SettingContainer.xaml.cs
index 5c723836c2..7d51ce4017 100644
--- a/Samples/ApplicationData/cs/Scenario3_SettingContainer.xaml.cs
+++ b/Samples/ApplicationData/cs/Scenario3_SettingContainer.xaml.cs
@@ -1,4 +1,4 @@
-//*********************************************************
+//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
@@ -11,32 +11,25 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
-using SDKTemplate;
using System;
using Windows.Storage;
-namespace ApplicationDataSample
+namespace SDKTemplate
{
///
/// An empty page that can be used on its own or navigated to within a Frame.
///
- public sealed partial class SettingContainer : Page
+ public sealed partial class Scenario3_SettingContainer : Page
{
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
MainPage rootPage = MainPage.Current;
- ApplicationDataContainer localSettings = null;
+ ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
const string containerName = "exampleContainer";
const string settingName = "exampleSetting";
- public SettingContainer()
+ public Scenario3_SettingContainer()
{
- this.InitializeComponent();
-
- localSettings = ApplicationData.Current.LocalSettings;
-
- DisplayOutput();
+ InitializeComponent();
}
void CreateContainer_Click(Object sender, RoutedEventArgs e)
@@ -55,44 +48,32 @@ void DeleteContainer_Click(Object sender, RoutedEventArgs e)
void WriteSetting_Click(Object sender, RoutedEventArgs e)
{
- if (localSettings.Containers.ContainsKey(containerName))
- {
- localSettings.Containers[containerName].Values[settingName] = "Hello World"; // example value
- }
+ localSettings.Containers[containerName].Values[settingName] = "Hello World"; // example value
DisplayOutput();
}
void DeleteSetting_Click(Object sender, RoutedEventArgs e)
{
- if (localSettings.Containers.ContainsKey(containerName))
- {
- localSettings.Containers[containerName].Values.Remove(settingName);
- }
+ localSettings.Containers[containerName].Values.Remove(settingName);
DisplayOutput();
}
void DisplayOutput()
{
- bool hasContainer = localSettings.Containers.ContainsKey(containerName);
- bool hasSetting = hasContainer ? localSettings.Containers[containerName].Values.ContainsKey(settingName) : false;
+ bool hasContainer = localSettings.Containers.TryGetValue(containerName, out ApplicationDataContainer container);
+ bool hasSetting = hasContainer ? container.Values.ContainsKey(settingName) : false;
- String output = String.Format("Container Exists: {0}\n" +
- "Setting Exists: {1}",
- hasContainer ? "true" : "false",
- hasSetting ? "true" : "false");
+ OutputTextBlock.Text = $"Container Exists: {hasContainer}\nSetting Exists: {hasSetting}";
- OutputTextBlock.Text = output;
+ WriteSetting.IsEnabled = hasContainer;
+ DeleteSetting.IsEnabled = hasContainer;
}
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
+ DisplayOutput();
}
}
}
diff --git a/Samples/ApplicationData/cs/Scenario4_CompositeSettings.xaml.cs b/Samples/ApplicationData/cs/Scenario4_CompositeSettings.xaml.cs
index 21500c7e9a..939681595f 100644
--- a/Samples/ApplicationData/cs/Scenario4_CompositeSettings.xaml.cs
+++ b/Samples/ApplicationData/cs/Scenario4_CompositeSettings.xaml.cs
@@ -1,4 +1,4 @@
-//*********************************************************
+//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
@@ -11,56 +11,47 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
-using SDKTemplate;
using System;
using Windows.Storage;
-namespace ApplicationDataSample
+namespace SDKTemplate
{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class CompositeSettings : Page
+ public sealed partial class Scenario4_CompositeSettings : Page
{
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
- MainPage rootPage = MainPage.Current;
- ApplicationDataContainer roamingSettings = null;
+ ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
const string settingName = "exampleCompositeSetting";
const string settingName1 = "one";
const string settingName2 = "hello";
- public CompositeSettings()
+ public Scenario4_CompositeSettings()
{
- this.InitializeComponent();
-
- roamingSettings = ApplicationData.Current.RoamingSettings;
-
- DisplayOutput();
+ InitializeComponent();
}
void WriteCompositeSetting_Click(Object sender, RoutedEventArgs e)
{
+ // Composite settings are used to group multiple settings.
+ // Note that Composite settings may not be nested.
ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue();
composite[settingName1] = 1; // example value
composite[settingName2] = "world"; // example value
- roamingSettings.Values[settingName] = composite;
+ localSettings.Values[settingName] = composite;
DisplayOutput();
}
void DeleteCompositeSetting_Click(Object sender, RoutedEventArgs e)
{
- roamingSettings.Values.Remove(settingName);
+ localSettings.Values.Remove(settingName);
DisplayOutput();
}
void DisplayOutput()
{
- ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)roamingSettings.Values[settingName];
+ ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)localSettings.Values[settingName];
String output;
if (composite == null)
@@ -75,13 +66,9 @@ void DisplayOutput()
OutputTextBlock.Text = output;
}
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
+ DisplayOutput();
}
}
}
diff --git a/Samples/ApplicationData/cs/Scenario5_DataChangedEvent.xaml.cs b/Samples/ApplicationData/cs/Scenario5_DataChangedEvent.xaml.cs
deleted file mode 100644
index f47a74eea6..0000000000
--- a/Samples/ApplicationData/cs/Scenario5_DataChangedEvent.xaml.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-//*********************************************************
-//
-// Copyright (c) Microsoft. All rights reserved.
-// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
-// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
-// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
-// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
-//
-//*********************************************************
-
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Navigation;
-using SDKTemplate;
-using System;
-using Windows.Foundation;
-using Windows.UI.Core;
-using Windows.Storage;
-
-namespace ApplicationDataSample
-{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class DataChangedEvent : Page
- {
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
- MainPage rootPage = MainPage.Current;
- ApplicationData applicationData = null;
- ApplicationDataContainer roamingSettings = null;
- TypedEventHandler dataChangedHandler = null;
-
- const string settingName = "userName";
-
- public DataChangedEvent()
- {
- this.InitializeComponent();
-
- applicationData = ApplicationData.Current;
- roamingSettings = applicationData.RoamingSettings;
-
- DisplayOutput();
- }
-
- void SimulateRoaming_Click(Object sender, RoutedEventArgs e)
- {
- roamingSettings.Values[settingName] = UserName.Text;
-
- // Simulate roaming by intentionally signaling a data changed event.
- applicationData.SignalDataChanged();
- }
-
- async void DataChangedHandler(Windows.Storage.ApplicationData appData, object o)
- {
- // DataChangeHandler may be invoked on a background thread, so use the Dispatcher to invoke the UI-related code on the UI thread.
- await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
- {
- DisplayOutput();
- });
- }
-
- void DisplayOutput()
- {
- Object value = roamingSettings.Values[settingName];
- OutputTextBlock.Text = "Name: " + (value == null ? "" : ("\"" + value + "\"")); ;
- }
-
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
- protected override void OnNavigatedTo(NavigationEventArgs e)
- {
- dataChangedHandler = new TypedEventHandler(DataChangedHandler);
- applicationData.DataChanged += dataChangedHandler;
- }
-
- ///
- /// Invoked immediately before the Page is unloaded and is no longer the current source of a parent Frame.
- ///
- ///
- /// Event data that can be examined by overriding code. The event data is representative
- /// of the navigation that will unload the current Page unless canceled. The
- /// navigation can potentially be canceled by setting Cancel.
- ///
- protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
- {
- base.OnNavigatingFrom(e);
- applicationData.DataChanged -= dataChangedHandler;
- dataChangedHandler = null;
- }
- }
-}
diff --git a/Samples/ApplicationData/cs/Scenario7_Msappdata.xaml.cs b/Samples/ApplicationData/cs/Scenario5_Msappdata.xaml.cs
similarity index 51%
rename from Samples/ApplicationData/cs/Scenario7_Msappdata.xaml.cs
rename to Samples/ApplicationData/cs/Scenario5_Msappdata.xaml.cs
index dc91ae7faa..7bee6542ef 100644
--- a/Samples/ApplicationData/cs/Scenario7_Msappdata.xaml.cs
+++ b/Samples/ApplicationData/cs/Scenario5_Msappdata.xaml.cs
@@ -1,4 +1,4 @@
-//*********************************************************
+//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
@@ -8,41 +8,28 @@
//
//*********************************************************
-using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
-using SDKTemplate;
using System;
using Windows.Storage;
-namespace ApplicationDataSample
+namespace SDKTemplate
{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class Msappdata : Page
+ public sealed partial class Scenario5_Msappdata : Page
{
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
- MainPage rootPage = MainPage.Current;
-
- public Msappdata()
+ public Scenario5_Msappdata()
{
- this.InitializeComponent();
+ InitializeComponent();
}
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
ApplicationData appData = ApplicationData.Current;
+ StorageFile sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///assets/appDataLocal.png"));
try
{
- StorageFile sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///assets/appDataLocal.png"));
await sourceFile.CopyAsync(appData.LocalFolder);
}
catch (Exception)
@@ -51,9 +38,9 @@ protected override async void OnNavigatedTo(NavigationEventArgs e)
// Ignore this error.
}
+ sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///assets/appDataRoaming.png"));
try
{
- StorageFile sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///assets/appDataRoaming.png"));
await sourceFile.CopyAsync(appData.RoamingFolder);
}
catch (Exception)
@@ -62,9 +49,9 @@ protected override async void OnNavigatedTo(NavigationEventArgs e)
// Ignore this error.
}
+ sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///assets/appDataTemp.png"));
try
- {
- StorageFile sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///assets/appDataTemp.png"));
+ {
await sourceFile.CopyAsync(appData.TemporaryFolder);
}
catch (Exception)
@@ -73,9 +60,9 @@ protected override async void OnNavigatedTo(NavigationEventArgs e)
// Ignore this error.
}
- LocalImage.Source = new Windows.UI.Xaml.Media.Imaging.BitmapImage(new Uri("ms-appdata:///local/appDataLocal.png"));
- RoamingImage.Source = new Windows.UI.Xaml.Media.Imaging.BitmapImage(new Uri("ms-appdata:///roaming/appDataRoaming.png"));
- TempImage.Source = new Windows.UI.Xaml.Media.Imaging.BitmapImage(new Uri("ms-appdata:///temp/appDataTemp.png"));
+ LocalImage.Source = new BitmapImage(new Uri("ms-appdata:///local/appDataLocal.png"));
+ RoamingImage.Source = new BitmapImage(new Uri("ms-appdata:///roaming/appDataRoaming.png"));
+ TempImage.Source = new BitmapImage(new Uri("ms-appdata:///temp/appDataTemp.png"));
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
diff --git a/Samples/ApplicationData/cs/Scenario6_ClearScenario.xaml.cs b/Samples/ApplicationData/cs/Scenario6_ClearScenario.xaml.cs
new file mode 100644
index 0000000000..0049f6e37b
--- /dev/null
+++ b/Samples/ApplicationData/cs/Scenario6_ClearScenario.xaml.cs
@@ -0,0 +1,37 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using System;
+
+namespace SDKTemplate
+{
+ public sealed partial class Scenario6_ClearScenario : Page
+ {
+ public Scenario6_ClearScenario()
+ {
+ InitializeComponent();
+ }
+
+ async void Clear_Click(Object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ await Windows.Storage.ApplicationData.Current.ClearAsync();
+ OutputTextBlock.Text = "ApplicationData has been cleared. Visit the other scenarios to see that their data has been cleared.";
+ }
+ catch (Exception)
+ {
+ OutputTextBlock.Text = "Unable to clear settings. This can happen when files are in use.";
+ }
+ }
+ }
+}
diff --git a/Samples/ApplicationData/cs/Scenario6_HighPriority.xaml.cs b/Samples/ApplicationData/cs/Scenario6_HighPriority.xaml.cs
deleted file mode 100644
index 5adfc72595..0000000000
--- a/Samples/ApplicationData/cs/Scenario6_HighPriority.xaml.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-//*********************************************************
-//
-// Copyright (c) Microsoft. All rights reserved.
-// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
-// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
-// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
-// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
-//
-//*********************************************************
-
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Navigation;
-using SDKTemplate;
-using System;
-using Windows.Foundation;
-using Windows.UI.Core;
-using Windows.Storage;
-
-namespace ApplicationDataSample
-{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class HighPriority : Page
- {
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
- MainPage rootPage = MainPage.Current;
- ApplicationDataContainer roamingSettings = null;
- ApplicationData applicationData = null;
- TypedEventHandler dataChangedHandler = null;
-
- public HighPriority()
- {
- this.InitializeComponent();
-
- applicationData = ApplicationData.Current;
- roamingSettings = applicationData.RoamingSettings;
-
- DisplayOutput(false);
- }
-
- // Guidance for using the HighPriority setting.
- //
- // Writing to the HighPriority setting enables a developer to store a small amount of
- // data that will be roamed out to the cloud with higher priority than other roaming
- // data, when possible.
- //
- // Applications should carefully consider which data should be stored in the
- // HighPriority setting. "Context" data such as the user's location within
- // media, or their current game-baord and high-score, can make the most sense to
- // roam with high priority. By using the HighPriority setting, this information has
- // a higher likelihood of being available to the user when they begin to use another
- // machine.
- //
- // Applications should update their HighPriority setting when the user makes
- // a significant change to the data it represents. Examples could include changing
- // music tracks, turning the page in a book, or finishing a level in a game.
-
- void IncrementHighPriority_Click(Object sender, RoutedEventArgs e)
- {
- int counter = Convert.ToInt32(roamingSettings.Values["HighPriority"]);
-
- roamingSettings.Values["HighPriority"] = counter + 1;
-
- DisplayOutput(false);
- }
-
- async void DataChangedHandler(Windows.Storage.ApplicationData appData, object o)
- {
- // DataChangeHandler may be invoked on a background thread, so use the Dispatcher to invoke the UI-related code on the UI thread.
- await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
- {
- DisplayOutput(true);
- });
- }
-
- void DisplayOutput(bool remoteUpdate)
- {
- int counter = Convert.ToInt32(roamingSettings.Values["HighPriority"]);
-
- OutputTextBlock.Text = "Counter: " + counter + (remoteUpdate ? " (updated remotely)" : "");
- }
-
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
- protected override void OnNavigatedTo(NavigationEventArgs e)
- {
- dataChangedHandler = new TypedEventHandler(DataChangedHandler);
- applicationData.DataChanged += dataChangedHandler;
- }
-
- ///
- /// Invoked immediately before the Page is unloaded and is no longer the current source of a parent Frame.
- ///
- ///
- /// Event data that can be examined by overriding code. The event data is representative
- /// of the navigation that will unload the current Page unless canceled. The
- /// navigation can potentially be canceled by setting Cancel.
- ///
- protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
- {
- base.OnNavigatingFrom(e);
- applicationData.DataChanged -= dataChangedHandler;
- dataChangedHandler = null;
- }
- }
-}
diff --git a/Samples/ApplicationData/cs/Scenario9_SetVersion.xaml.cs b/Samples/ApplicationData/cs/Scenario7_SetVersion.xaml.cs
similarity index 71%
rename from Samples/ApplicationData/cs/Scenario9_SetVersion.xaml.cs
rename to Samples/ApplicationData/cs/Scenario7_SetVersion.xaml.cs
index bf1c7185e9..b3ffa987cf 100644
--- a/Samples/ApplicationData/cs/Scenario9_SetVersion.xaml.cs
+++ b/Samples/ApplicationData/cs/Scenario7_SetVersion.xaml.cs
@@ -1,4 +1,4 @@
-//*********************************************************
+//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
@@ -15,30 +15,19 @@
using System;
using Windows.Storage;
-namespace ApplicationDataSample
+namespace SDKTemplate
{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class SetVersion : Page
+ public sealed partial class Scenario7_SetVersion : Page
{
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
- MainPage rootPage = MainPage.Current;
-
- ApplicationData appData = null;
+ ApplicationData appData = ApplicationData.Current;
const string settingName = "SetVersionSetting";
const string settingValue0 = "Data.v0";
const string settingValue1 = "Data.v1";
- public SetVersion()
+ public Scenario7_SetVersion()
{
- this.InitializeComponent();
-
- appData = ApplicationData.Current;
-
- DisplayOutput();
+ InitializeComponent();
}
void SetVersionHandler0(SetVersionRequest request)
@@ -97,13 +86,13 @@ void SetVersionHandler1(SetVersionRequest request)
async void SetVersion0_Click(Object sender, RoutedEventArgs e)
{
- await appData.SetVersionAsync(0, new ApplicationDataSetVersionHandler(SetVersionHandler0));
+ await appData.SetVersionAsync(0, SetVersionHandler0);
DisplayOutput();
}
async void SetVersion1_Click(Object sender, RoutedEventArgs e)
{
- await appData.SetVersionAsync(1, new ApplicationDataSetVersionHandler(SetVersionHandler1));
+ await appData.SetVersionAsync(1, SetVersionHandler1);
DisplayOutput();
}
@@ -112,13 +101,9 @@ void DisplayOutput()
OutputTextBlock.Text = "Version: " + appData.Version;
}
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
+ DisplayOutput();
}
}
}
diff --git a/Samples/ApplicationData/cs/Scenario8_ClearScenario.xaml.cs b/Samples/ApplicationData/cs/Scenario8_ClearScenario.xaml.cs
deleted file mode 100644
index 27f8b7e22d..0000000000
--- a/Samples/ApplicationData/cs/Scenario8_ClearScenario.xaml.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-//*********************************************************
-//
-// Copyright (c) Microsoft. All rights reserved.
-// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
-// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
-// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
-// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
-//
-//*********************************************************
-
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Navigation;
-using SDKTemplate;
-using System;
-using Windows.Storage;
-
-namespace ApplicationDataSample
-{
- ///
- /// An empty page that can be used on its own or navigated to within a Frame.
- ///
- public sealed partial class ClearScenario : Page
- {
- // A pointer back to the main page. This is needed if you want to call methods in MainPage such
- // as NotifyUser()
- MainPage rootPage = MainPage.Current;
-
- public ClearScenario()
- {
- this.InitializeComponent();
- }
-
- async void Clear_Click(Object sender, RoutedEventArgs e)
- {
- try
- {
- await Windows.Storage.ApplicationData.Current.ClearAsync();
- OutputTextBlock.Text = "ApplicationData has been cleared. Visit the other scenarios to see that their data has been cleared.";
- }
- catch (Exception)
- {
- OutputTextBlock.Text = "Unable to clear settings. This can happen when files are in use.";
- }
- }
-
- ///
- /// Invoked when this page is about to be displayed in a Frame.
- ///
- /// Event data that describes how this page was reached. The Parameter
- /// property is typically used to configure the page.
- protected override void OnNavigatedTo(NavigationEventArgs e)
- {
- }
- }
-}
diff --git a/Samples/ApplicationData/cs/SuspensionManager.cs b/Samples/ApplicationData/cs/SuspensionManager.cs
deleted file mode 100644
index 0d8abafc74..0000000000
--- a/Samples/ApplicationData/cs/SuspensionManager.cs
+++ /dev/null
@@ -1,269 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Threading.Tasks;
-using Windows.ApplicationModel;
-using Windows.Storage;
-using Windows.Storage.Streams;
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Controls;
-
-namespace SDKTemplate.Common
-{
- ///
- /// SuspensionManager captures global session state to simplify process lifetime management
- /// for an application. Note that session state will be automatically cleared under a variety
- /// of conditions and should only be used to store information that would be convenient to
- /// carry across sessions, but that should be discarded when an application crashes or is
- /// upgraded.
- ///
- internal sealed class SuspensionManager
- {
- private static Dictionary _sessionState = new Dictionary();
- private static List _knownTypes = new List();
- private const string sessionStateFilename = "_sessionState.xml";
-
- ///
- /// Provides access to global session state for the current session. This state is
- /// serialized by and restored by
- /// , so values must be serializable by
- /// and should be as compact as possible. Strings
- /// and other self-contained data types are strongly recommended.
- ///
- public static Dictionary SessionState
- {
- get { return _sessionState; }
- }
-
- ///
- /// List of custom types provided to the when
- /// reading and writing session state. Initially empty, additional types may be
- /// added to customize the serialization process.
- ///
- public static List KnownTypes
- {
- get { return _knownTypes; }
- }
-
- ///
- /// Save the current . Any instances
- /// registered with will also preserve their current
- /// navigation stack, which in turn gives their active an opportunity
- /// to save its state.
- ///
- /// An asynchronous task that reflects when session state has been saved.
- public static async Task SaveAsync()
- {
- try
- {
- // Save the navigation state for all registered frames
- foreach (var weakFrameReference in _registeredFrames)
- {
- Frame frame;
- if (weakFrameReference.TryGetTarget(out frame))
- {
- SaveFrameNavigationState(frame);
- }
- }
-
- // Serialize the session state synchronously to avoid asynchronous access to shared
- // state
- MemoryStream sessionData = new MemoryStream();
- DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary), _knownTypes);
- serializer.WriteObject(sessionData, _sessionState);
-
- // Get an output stream for the SessionState file and write the state asynchronously
- StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(sessionStateFilename, CreationCollisionOption.ReplaceExisting);
- using (Stream fileStream = await file.OpenStreamForWriteAsync())
- {
- sessionData.Seek(0, SeekOrigin.Begin);
- await sessionData.CopyToAsync(fileStream);
- }
- }
- catch (Exception e)
- {
- throw new SuspensionManagerException(e);
- }
- }
-
- ///
- /// Restores previously saved . Any instances
- /// registered with will also restore their prior navigation
- /// state, which in turn gives their active an opportunity restore its
- /// state.
- ///
- /// An optional key that identifies the type of session.
- /// This can be used to distinguish between multiple application launch scenarios.
- /// An asynchronous task that reflects when session state has been read. The
- /// content of should not be relied upon until this task
- /// completes.
- public static async Task RestoreAsync(String sessionBaseKey = null)
- {
- _sessionState = new Dictionary();
-
- try
- {
- // Get the input stream for the SessionState file
- StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(sessionStateFilename);
- using (IInputStream inStream = await file.OpenSequentialReadAsync())
- {
- // Deserialize the Session State
- DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary), _knownTypes);
- _sessionState = (Dictionary)serializer.ReadObject(inStream.AsStreamForRead());
- }
-
- // Restore any registered frames to their saved state
- foreach (var weakFrameReference in _registeredFrames)
- {
- Frame frame;
- if (weakFrameReference.TryGetTarget(out frame) && (string)frame.GetValue(FrameSessionBaseKeyProperty) == sessionBaseKey)
- {
- frame.ClearValue(FrameSessionStateProperty);
- RestoreFrameNavigationState(frame);
- }
- }
- }
- catch (Exception e)
- {
- throw new SuspensionManagerException(e);
- }
- }
-
- private static DependencyProperty FrameSessionStateKeyProperty =
- DependencyProperty.RegisterAttached("_FrameSessionStateKey", typeof(String), typeof(SuspensionManager), null);
- private static DependencyProperty FrameSessionBaseKeyProperty =
- DependencyProperty.RegisterAttached("_FrameSessionBaseKeyParams", typeof(String), typeof(SuspensionManager), null);
- private static DependencyProperty FrameSessionStateProperty =
- DependencyProperty.RegisterAttached("_FrameSessionState", typeof(Dictionary), typeof(SuspensionManager), null);
- private static List> _registeredFrames = new List>();
-
- ///
- /// Registers a instance to allow its navigation history to be saved to
- /// and restored from . Frames should be registered once
- /// immediately after creation if they will participate in session state management. Upon
- /// registration if state has already been restored for the specified key
- /// the navigation history will immediately be restored. Subsequent invocations of
- /// will also restore navigation history.
- ///
- /// An instance whose navigation history should be managed by
- ///
- /// A unique key into used to
- /// store navigation-related information.
- /// An optional key that identifies the type of session.
- /// This can be used to distinguish between multiple application launch scenarios.
- public static void RegisterFrame(Frame frame, String sessionStateKey, String sessionBaseKey = null)
- {
- if (frame.GetValue(FrameSessionStateKeyProperty) != null)
- {
- throw new InvalidOperationException("Frames can only be registered to one session state key");
- }
-
- if (frame.GetValue(FrameSessionStateProperty) != null)
- {
- throw new InvalidOperationException("Frames must be either be registered before accessing frame session state, or not registered at all");
- }
-
- if (!string.IsNullOrEmpty(sessionBaseKey))
- {
- frame.SetValue(FrameSessionBaseKeyProperty, sessionBaseKey);
- sessionStateKey = sessionBaseKey + "_" + sessionStateKey;
- }
-
- // Use a dependency property to associate the session key with a frame, and keep a list of frames whose
- // navigation state should be managed
- frame.SetValue(FrameSessionStateKeyProperty, sessionStateKey);
- _registeredFrames.Add(new WeakReference(frame));
-
- // Check to see if navigation state can be restored
- RestoreFrameNavigationState(frame);
- }
-
- ///
- /// Disassociates a previously registered by
- /// from . Any navigation state previously captured will be
- /// removed.
- ///
- /// An instance whose navigation history should no longer be
- /// managed.
- public static void UnregisterFrame(Frame frame)
- {
- // Remove session state and remove the frame from the list of frames whose navigation
- // state will be saved (along with any weak references that are no longer reachable)
- SessionState.Remove((String)frame.GetValue(FrameSessionStateKeyProperty));
- _registeredFrames.RemoveAll((weakFrameReference) =>
- {
- Frame testFrame;
- return !weakFrameReference.TryGetTarget(out testFrame) || testFrame == frame;
- });
- }
-
- ///
- /// Provides storage for session state associated with the specified .
- /// Frames that have been previously registered with have
- /// their session state saved and restored automatically as a part of the global
- /// . Frames that are not registered have transient state
- /// that can still be useful when restoring pages that have been discarded from the
- /// navigation cache.
- ///
- /// Apps may choose to rely on to manage
- /// page-specific state instead of working with frame session state directly.
- /// The instance for which session state is desired.
- /// A collection of state subject to the same serialization mechanism as
- /// .
- public static Dictionary SessionStateForFrame(Frame frame)
- {
- var frameState = (Dictionary)frame.GetValue(FrameSessionStateProperty);
-
- if (frameState == null)
- {
- var frameSessionKey = (String)frame.GetValue(FrameSessionStateKeyProperty);
- if (frameSessionKey != null)
- {
- // Registered frames reflect the corresponding session state
- if (!_sessionState.ContainsKey(frameSessionKey))
- {
- _sessionState[frameSessionKey] = new Dictionary();
- }
- frameState = (Dictionary)_sessionState[frameSessionKey];
- }
- else
- {
- // Frames that aren't registered have transient state
- frameState = new Dictionary();
- }
- frame.SetValue(FrameSessionStateProperty, frameState);
- }
- return frameState;
- }
-
- private static void RestoreFrameNavigationState(Frame frame)
- {
- var frameState = SessionStateForFrame(frame);
- if (frameState.ContainsKey("Navigation"))
- {
- frame.SetNavigationState((String)frameState["Navigation"]);
- }
- }
-
- private static void SaveFrameNavigationState(Frame frame)
- {
- var frameState = SessionStateForFrame(frame);
- frameState["Navigation"] = frame.GetNavigationState();
- }
- }
- public class SuspensionManagerException : Exception
- {
- public SuspensionManagerException()
- {
- }
-
- public SuspensionManagerException(Exception e)
- : base("SuspensionManager failed", e)
- {
-
- }
- }
-}
diff --git a/Samples/ApplicationData/shared/Scenario6_ClearScenario.xaml b/Samples/ApplicationData/shared/Scenario6_ClearScenario.xaml
new file mode 100644
index 0000000000..695559c36c
--- /dev/null
+++ b/Samples/ApplicationData/shared/Scenario6_ClearScenario.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+ The ClearAsync method clears data from ApplicationData.
+
+
+
+
+
+
+
+
diff --git a/Samples/ApplicationData/shared/Scenario7_SetVersion.xaml b/Samples/ApplicationData/shared/Scenario7_SetVersion.xaml
new file mode 100644
index 0000000000..0208140d50
--- /dev/null
+++ b/Samples/ApplicationData/shared/Scenario7_SetVersion.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ Versioning enables you to change the application data format used in a
+ future release of your app without causing compatibility problems with
+ previous releases of your app.
+
+
+
+
+
+
+
+
+
diff --git a/Samples/ApplicationData/vb/Assets/appDataLocal.png b/Samples/ApplicationData/vb/Assets/appDataLocal.png
deleted file mode 100644
index ffb7a714d5..0000000000
Binary files a/Samples/ApplicationData/vb/Assets/appDataLocal.png and /dev/null differ
diff --git a/Samples/ApplicationData/vb/Assets/appDataRoaming.png b/Samples/ApplicationData/vb/Assets/appDataRoaming.png
deleted file mode 100644
index 6149388f75..0000000000
Binary files a/Samples/ApplicationData/vb/Assets/appDataRoaming.png and /dev/null differ
diff --git a/Samples/ApplicationData/vb/Assets/appDataTemp.png b/Samples/ApplicationData/vb/Assets/appDataTemp.png
deleted file mode 100644
index f039c31289..0000000000
Binary files a/Samples/ApplicationData/vb/Assets/appDataTemp.png and /dev/null differ
diff --git a/Samples/Geolocation/cppwinrt/Scenario2_GetPosition.cpp b/Samples/Geolocation/cppwinrt/Scenario2_GetPosition.cpp
index b5cc3f369c..38f21a9b79 100644
--- a/Samples/Geolocation/cppwinrt/Scenario2_GetPosition.cpp
+++ b/Samples/Geolocation/cppwinrt/Scenario2_GetPosition.cpp
@@ -136,6 +136,8 @@ namespace winrt::SDKTemplate::implementation
ScenarioOutput_PosPrecision().Text(to_hstring(satelliteData.PositionDilutionOfPrecision()));
ScenarioOutput_HorzPrecision().Text(to_hstring(satelliteData.HorizontalDilutionOfPrecision()));
ScenarioOutput_VertPrecision().Text(to_hstring(satelliteData.VerticalDilutionOfPrecision()));;
+ ScenarioOutput_GeomPrecision().Text(to_hstring(satelliteData.GeometricDilutionOfPrecision()));;
+ ScenarioOutput_TimePrecision().Text(to_hstring(satelliteData.TimeDilutionOfPrecision()));;
ShowSatelliteData(true);
}
else
@@ -152,6 +154,8 @@ namespace winrt::SDKTemplate::implementation
ScenarioOutput_PosPrecision().Visibility(visibility);
ScenarioOutput_HorzPrecision().Visibility(visibility);
ScenarioOutput_VertPrecision().Visibility(visibility);
+ ScenarioOutput_GeomPrecision().Visibility(visibility);
+ ScenarioOutput_TimePrecision().Visibility(visibility);
}
}
diff --git a/Samples/Geolocation/cs/Scenario2_GetPosition.xaml.cs b/Samples/Geolocation/cs/Scenario2_GetPosition.xaml.cs
index 777ed7fb0a..d9151610db 100644
--- a/Samples/Geolocation/cs/Scenario2_GetPosition.xaml.cs
+++ b/Samples/Geolocation/cs/Scenario2_GetPosition.xaml.cs
@@ -153,6 +153,8 @@ private void UpdateLocationData(Geoposition position)
ScenarioOutput_PosPrecision.Text = position.Coordinate.SatelliteData.PositionDilutionOfPrecision.ToString();
ScenarioOutput_HorzPrecision.Text = position.Coordinate.SatelliteData.HorizontalDilutionOfPrecision.ToString();
ScenarioOutput_VertPrecision.Text = position.Coordinate.SatelliteData.VerticalDilutionOfPrecision.ToString();
+ ScenarioOutput_GeomPrecision.Text = position.Coordinate.SatelliteData.GeometricDilutionOfPrecision.ToString();
+ ScenarioOutput_TimePrecision.Text = position.Coordinate.SatelliteData.TimeDilutionOfPrecision.ToString();
ShowSatelliteData(true);
}
else
@@ -169,6 +171,8 @@ private void ShowSatelliteData(bool isVisible)
ScenarioOutput_PosPrecision.Visibility = visibility;
ScenarioOutput_HorzPrecision.Visibility = visibility;
ScenarioOutput_VertPrecision.Visibility = visibility;
+ ScenarioOutput_GeomPrecision.Visibility = visibility;
+ ScenarioOutput_TimePrecision.Visibility = visibility;
}
}
}
diff --git a/Samples/Geolocation/shared/Scenario2_GetPosition.xaml b/Samples/Geolocation/shared/Scenario2_GetPosition.xaml
index fac3c3c865..6b2dc820c5 100644
--- a/Samples/Geolocation/shared/Scenario2_GetPosition.xaml
+++ b/Samples/Geolocation/shared/Scenario2_GetPosition.xaml
@@ -47,6 +47,8 @@
+
+
@@ -57,6 +59,8 @@
+
+
@@ -65,6 +69,8 @@
+
+
Application is not able to get location data. Go to
diff --git a/Samples/PasswordVault/README.md b/Samples/PasswordVault/README.md
index 20593fa431..b3e191cfff 100644
--- a/Samples/PasswordVault/README.md
+++ b/Samples/PasswordVault/README.md
@@ -4,6 +4,7 @@ languages:
- csharp
- cpp
- cppcx
+- cppwinrt
products:
- windows
- windows-uwp
diff --git a/Samples/PasswordVault/cpp/Scenario1_Save.xaml.cpp b/Samples/PasswordVault/cpp/Scenario1_Save.xaml.cpp
index e0537be1e4..a7583f3c3b 100644
--- a/Samples/PasswordVault/cpp/Scenario1_Save.xaml.cpp
+++ b/Samples/PasswordVault/cpp/Scenario1_Save.xaml.cpp
@@ -23,7 +23,7 @@ Scenario1_Save::Scenario1_Save()
InitializeComponent();
}
-void Scenario1_Save::SaveCredential()
+void Scenario1_Save::SaveCredential_Click(Object^, Object^)
{
auto resource = InputResourceValue->Text;
auto username = InputUserNameValue->Text;
diff --git a/Samples/PasswordVault/cpp/Scenario1_Save.xaml.h b/Samples/PasswordVault/cpp/Scenario1_Save.xaml.h
index 15380ff260..909092c4d0 100644
--- a/Samples/PasswordVault/cpp/Scenario1_Save.xaml.h
+++ b/Samples/PasswordVault/cpp/Scenario1_Save.xaml.h
@@ -21,7 +21,10 @@ namespace SDKTemplate
{
public:
Scenario1_Save();
- void SaveCredential();
+
+ internal:
+ void SaveCredential_Click(Platform::Object^, Platform::Object^);
+
private:
MainPage^ rootPage = MainPage::Current;
};
diff --git a/Samples/PasswordVault/cpp/Scenario2_Manage.xaml.cpp b/Samples/PasswordVault/cpp/Scenario2_Manage.xaml.cpp
index c86f9519d5..b92da82dda 100644
--- a/Samples/PasswordVault/cpp/Scenario2_Manage.xaml.cpp
+++ b/Samples/PasswordVault/cpp/Scenario2_Manage.xaml.cpp
@@ -27,7 +27,7 @@ Scenario2_Manage::Scenario2_Manage()
InitializeComponent();
}
-void Scenario2_Manage::RetrieveCredentials()
+void Scenario2_Manage::RetrieveCredentials_Click(Object^, Object^)
{
auto resource = InputResourceValue->Text;
auto userName = InputUserNameValue->Text;
@@ -101,7 +101,7 @@ void Scenario2_Manage::RetrieveCredentials()
}
}
-void Scenario2_Manage::RevealPasswords()
+void Scenario2_Manage::RevealPasswords_Click(Object^, Object^)
{
IVector
@@ -112,6 +115,7 @@
+
Styles\Styles.xaml
@@ -132,6 +136,9 @@
..\shared\Scenario2_WatchUsers.xaml
+
+ ..\shared\Scenario3_CheckUserConsentGroup.xaml
+
Create
pch.h
diff --git a/Samples/UserInfo/cppwinrt/UserInfo.vcxproj.filters b/Samples/UserInfo/cppwinrt/UserInfo.vcxproj.filters
index 0234c021a5..58df651e24 100644
--- a/Samples/UserInfo/cppwinrt/UserInfo.vcxproj.filters
+++ b/Samples/UserInfo/cppwinrt/UserInfo.vcxproj.filters
@@ -10,6 +10,7 @@
+
@@ -20,6 +21,7 @@
+
@@ -30,6 +32,7 @@
+
diff --git a/Samples/UserInfo/cppwinrt/UserViewModel.h b/Samples/UserInfo/cppwinrt/UserViewModel.h
index aee8efa6d1..92444a4314 100644
--- a/Samples/UserInfo/cppwinrt/UserViewModel.h
+++ b/Samples/UserInfo/cppwinrt/UserViewModel.h
@@ -68,9 +68,11 @@ namespace winrt::SDKTemplate::implementation
};
}
+#if 0
namespace winrt::SDKTemplate::factory_implementation
{
struct UserViewModel : UserViewModelT
{
};
-}
\ No newline at end of file
+}
+#endif
diff --git a/Samples/UserInfo/cs/Package.appxmanifest b/Samples/UserInfo/cs/Package.appxmanifest
index 7c747a7039..832fe0d75f 100644
--- a/Samples/UserInfo/cs/Package.appxmanifest
+++ b/Samples/UserInfo/cs/Package.appxmanifest
@@ -22,7 +22,7 @@
-
+
diff --git a/Samples/UserInfo/cs/SampleConfiguration.cs b/Samples/UserInfo/cs/SampleConfiguration.cs
index 17ddf892d8..60af630719 100644
--- a/Samples/UserInfo/cs/SampleConfiguration.cs
+++ b/Samples/UserInfo/cs/SampleConfiguration.cs
@@ -11,13 +11,11 @@
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.ComponentModel;
-using Windows.ApplicationModel;
-using Windows.ApplicationModel.Activation;
+using System.Threading.Tasks;
using Windows.System;
-using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Navigation;
namespace SDKTemplate
{
@@ -29,7 +27,29 @@ public partial class MainPage : Page
{
new Scenario() { Title = "Find users", ClassType = typeof(Scenario1_FindUsers) },
new Scenario() { Title = "Watch users", ClassType = typeof(Scenario2_WatchUsers) },
+ new Scenario() { Title = "Check user consent group", ClassType = typeof(Scenario3_CheckUserConsentGroup) },
};
+
+ public static async Task> GetUserViewModelsAsync()
+ {
+ // Populate the list of users.
+ IReadOnlyList users = await User.FindAllAsync();
+ var observableUsers = new ObservableCollection();
+ int userNumber = 1;
+ foreach (User user in users)
+ {
+ string displayName = (string)await user.GetPropertyAsync(KnownUserProperties.DisplayName);
+
+ // Choose a generic name if we do not have access to the actual name.
+ if (String.IsNullOrEmpty(displayName))
+ {
+ displayName = "User #" + userNumber.ToString();
+ userNumber++;
+ }
+ observableUsers.Add(new UserViewModel(user.NonRoamableId, displayName));
+ }
+ return observableUsers;
+ }
}
public class Scenario
diff --git a/Samples/UserInfo/cs/Scenario1_FindUsers.xaml.cs b/Samples/UserInfo/cs/Scenario1_FindUsers.xaml.cs
index 01899ea797..a5e125cabf 100644
--- a/Samples/UserInfo/cs/Scenario1_FindUsers.xaml.cs
+++ b/Samples/UserInfo/cs/Scenario1_FindUsers.xaml.cs
@@ -36,23 +36,9 @@ protected override async void OnNavigatedTo(NavigationEventArgs e)
rootPage = MainPage.Current;
// Populate the list of users.
- IReadOnlyList users = await User.FindAllAsync();
- var observableUsers = new ObservableCollection();
- int userNumber = 1;
- foreach (User user in users)
- {
- string displayName = (string)await user.GetPropertyAsync(KnownUserProperties.DisplayName);
-
- // Choose a generic name if we do not have access to the actual name.
- if (String.IsNullOrEmpty(displayName))
- {
- displayName = "User #" + userNumber.ToString();
- userNumber++;
- }
- observableUsers.Add(new UserViewModel(user.NonRoamableId, displayName));
- }
+ var observableUsers = await MainPage.GetUserViewModelsAsync();
UserList.DataContext = observableUsers;
- if (users.Count > 0)
+ if (observableUsers.Count > 0)
{
UserList.SelectedIndex = 0;
}
diff --git a/Samples/UserInfo/cs/Scenario3_CheckUserConsentGroup.xaml b/Samples/UserInfo/cs/Scenario3_CheckUserConsentGroup.xaml
new file mode 100644
index 0000000000..8a22a4db4d
--- /dev/null
+++ b/Samples/UserInfo/cs/Scenario3_CheckUserConsentGroup.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Find users and display user consent group
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/UserInfo/cs/Scenario3_CheckUserConsentGroup.xaml.cs b/Samples/UserInfo/cs/Scenario3_CheckUserConsentGroup.xaml.cs
new file mode 100644
index 0000000000..86885802a3
--- /dev/null
+++ b/Samples/UserInfo/cs/Scenario3_CheckUserConsentGroup.xaml.cs
@@ -0,0 +1,95 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using Windows.Foundation.Collections;
+using Windows.Storage.Streams;
+using Windows.System;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media.Imaging;
+using Windows.UI.Xaml.Navigation;
+
+namespace SDKTemplate
+{
+ public sealed partial class Scenario3_CheckUserConsentGroup : Page
+ {
+ private MainPage rootPage = MainPage.Current;
+
+ public Scenario3_CheckUserConsentGroup()
+ {
+ this.InitializeComponent();
+ }
+
+ protected override async void OnNavigatedTo(NavigationEventArgs e)
+ {
+ // Populate the list of users.
+ var observableUsers = await MainPage.GetUserViewModelsAsync();
+ UserList.DataContext = observableUsers;
+ if (observableUsers.Count > 0)
+ {
+ UserList.SelectedIndex = 0;
+ }
+ }
+
+ static string EvaluateConsentResult(UserAgeConsentResult consentResult)
+ {
+ switch (consentResult)
+ {
+ case UserAgeConsentResult.Included:
+ case UserAgeConsentResult.NotEnforced:
+ return "Allowed.";
+ case UserAgeConsentResult.NotIncluded:
+ return "Not allowed.";
+ case UserAgeConsentResult.Unknown:
+ return "Cannot determine. Default to app specific age unknown behavior.";
+ default:
+ case UserAgeConsentResult.Ambiguous:
+ return "Age regulations have changed, the app needs to be updated to reflect new catagories.";
+ }
+ }
+
+ private async void ShowConsentGroups(object sender, RoutedEventArgs e)
+ {
+ var selectedUser = (UserViewModel)UserList.SelectedValue;
+ if (selectedUser != null)
+ {
+ ResultsText.Text = "";
+
+ rootPage.NotifyUser("", NotifyType.StatusMessage);
+ try
+ {
+ User user = User.GetFromId(selectedUser.UserId);
+
+ String result = "";
+
+ UserAgeConsentResult canShowChildContent = await user.CheckUserAgeConsentGroupAsync(UserAgeConsentGroup.Child);
+ result += "Child content: " + EvaluateConsentResult(canShowChildContent) + "\n";
+
+ UserAgeConsentResult canShowMinorContent = await user.CheckUserAgeConsentGroupAsync(UserAgeConsentGroup.Minor);
+ result += "Minor content: " + EvaluateConsentResult(canShowMinorContent) + "\n";
+
+ UserAgeConsentResult canShowAdultContent = await user.CheckUserAgeConsentGroupAsync(UserAgeConsentGroup.Adult);
+ result += "Adult content: " + EvaluateConsentResult(canShowAdultContent) + "\n";
+
+ ResultsText.Text = result;
+ }
+ catch (Exception ex)
+ {
+ // Operations on the "User" object fail if the user signs out.
+ rootPage.NotifyUser(ex.Message, NotifyType.ErrorMessage);
+ }
+ }
+ }
+ }
+}
diff --git a/Samples/UserInfo/cs/UserInfo.csproj b/Samples/UserInfo/cs/UserInfo.csproj
index a02790c992..73ac97afb7 100644
--- a/Samples/UserInfo/cs/UserInfo.csproj
+++ b/Samples/UserInfo/cs/UserInfo.csproj
@@ -109,6 +109,9 @@
Scenario2_WatchUsers.xaml
+
+ Scenario3_CheckUserConsentGroup.xaml
+
@@ -136,6 +139,11 @@
MSBuild:Compile
Designer
+
+ Scenario3_CheckUserConsentGroup.xaml
+ MSBuild:Compile
+ Designer
+
Styles\Styles.xaml
MSBuild:Compile
diff --git a/Samples/UserInfo/cs/UserInfo.sln b/Samples/UserInfo/cs/UserInfo.sln
index 33f1b5c73b..57437e6544 100644
--- a/Samples/UserInfo/cs/UserInfo.sln
+++ b/Samples/UserInfo/cs/UserInfo.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26228.4
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31321.278
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserInfo", "UserInfo.csproj", "{CF00A86D-74DA-5A62-8A1F-4A80EA12B03C}"
EndProject
@@ -37,4 +37,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {A83BF24C-7A3C-48B4-8FC0-48538C481BBC}
+ EndGlobalSection
EndGlobal
diff --git a/Samples/UserInfo/shared/Scenario3_CheckUserConsentGroup.xaml b/Samples/UserInfo/shared/Scenario3_CheckUserConsentGroup.xaml
new file mode 100644
index 0000000000..55e538197c
--- /dev/null
+++ b/Samples/UserInfo/shared/Scenario3_CheckUserConsentGroup.xaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Find users and display user consent group
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/WindowsAudioSession/cpp/Common.h b/Samples/WindowsAudioSession/cpp/Common.h
index b4533b9234..cd0276fdbc 100644
--- a/Samples/WindowsAudioSession/cpp/Common.h
+++ b/Samples/WindowsAudioSession/cpp/Common.h
@@ -157,27 +157,38 @@ enum RenderSampleType
SampleTypeUnknown,
SampleTypeFloat,
SampleType16BitPCM,
+ SampleType24in32BitPCM,
};
//
-// CalculateMixFormatType()
+// GetRenderSampleType()
//
-// Determine IEEE Float or PCM samples based on media type
+// Determine the sample format based on media type
//
-inline RenderSampleType CalculateMixFormatType( WAVEFORMATEX *wfx )
+inline RenderSampleType GetRenderSampleType( WAVEFORMATEX *wfx )
{
+ WAVEFORMATEXTENSIBLE* wfext = reinterpret_cast(wfx);
+
if ( (wfx->wFormatTag == WAVE_FORMAT_PCM) ||
( (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
- (reinterpret_cast(wfx)->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) ) )
+ (wfext->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) ) )
{
if (wfx->wBitsPerSample == 16)
{
return RenderSampleType::SampleType16BitPCM;
}
+ else if (wfx->wBitsPerSample == 32)
+ {
+ if ((wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
+ (wfext->Samples.wValidBitsPerSample == 24))
+ {
+ return RenderSampleType::SampleType24in32BitPCM;
+ }
+ }
}
else if ( (wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) ||
( (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
- (reinterpret_cast(wfx)->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) ) )
+ (wfext->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) ) )
{
return RenderSampleType::SampleTypeFloat;
}
diff --git a/Samples/WindowsAudioSession/cpp/MFSampleGenerator.cpp b/Samples/WindowsAudioSession/cpp/MFSampleGenerator.cpp
index 5f1c248929..ae66413f4c 100644
--- a/Samples/WindowsAudioSession/cpp/MFSampleGenerator.cpp
+++ b/Samples/WindowsAudioSession/cpp/MFSampleGenerator.cpp
@@ -133,19 +133,19 @@ HRESULT MFSampleGenerator::Initialize( IRandomAccessStream^ stream, UINT32 Frame
}
// Specify Source Reader Attributes
- Attributes->SetUnknown( MF_SOURCE_READER_ASYNC_CALLBACK, static_cast(this) );
+ hr = Attributes->SetUnknown( MF_SOURCE_READER_ASYNC_CALLBACK, static_cast(this) );
if (FAILED( hr ))
{
goto exit;
}
- Attributes->SetString( MF_READWRITE_MMCSS_CLASS_AUDIO, L"Audio" );
+ hr = Attributes->SetString( MF_READWRITE_MMCSS_CLASS_AUDIO, L"Audio" );
if (FAILED( hr ))
{
goto exit;
}
- Attributes->SetUINT32( MF_READWRITE_MMCSS_PRIORITY_AUDIO, 0 );
+ hr = Attributes->SetUINT32( MF_READWRITE_MMCSS_PRIORITY_AUDIO, 0 );
if (FAILED( hr ))
{
goto exit;
@@ -235,7 +235,11 @@ HRESULT MFSampleGenerator::ConfigureStreams()
WAVEFORMATEX *pwfx = NULL;
UINT32 cbFormat = 0;
- MFCreateWaveFormatExFromMFMediaType( UncompressedMT, &pwfx, &cbFormat );
+ hr = MFCreateWaveFormatExFromMFMediaType( UncompressedMT, &pwfx, &cbFormat );
+ if ( FAILED( hr ) )
+ {
+ goto exit;
+ }
CoTaskMemFree( pwfx );
@@ -273,13 +277,18 @@ HRESULT MFSampleGenerator::CreateAudioType( IMFMediaType **MediaType )
goto exit;
}
- if (RenderSampleType::SampleType16BitPCM == CalculateMixFormatType( m_MixFormat ))
+ switch (GetRenderSampleType(m_MixFormat))
{
+ case RenderSampleType::SampleType16BitPCM:
+ case RenderSampleType::SampleType24in32BitPCM:
hr = MT->SetGUID( MF_MT_SUBTYPE, MFAudioFormat_PCM );
- }
- else
- {
+ break;
+ case RenderSampleType::SampleTypeFloat:
hr = MT->SetGUID( MF_MT_SUBTYPE, MFAudioFormat_Float );
+ break;
+ default:
+ hr = E_UNEXPECTED;
+ break;
}
if (FAILED( hr ))
@@ -451,6 +460,7 @@ HRESULT MFSampleGenerator::FillSampleBuffer( UINT32 BytesToRead, BYTE *Data, UIN
*cbWritten = SampleBuffer->BufferSize;
m_SampleQueue = m_SampleQueue->Next;
+ SAFE_DELETE( SampleBuffer );
hr = S_OK;
}
}
@@ -568,15 +578,15 @@ HRESULT MFSampleGenerator::AddSamplesToQueue( IMFSample *MFSample )
//
Platform::Boolean MFSampleGenerator::IsPreRollFilled()
{
- DWORD TotalBufferSize = 0;
+ DWORD TotalBytesFilled = 0;
RenderBuffer *SampleBuffer = m_SampleQueue;
while( SampleBuffer != nullptr )
{
- TotalBufferSize += SampleBuffer->BufferSize;
+ TotalBytesFilled += SampleBuffer->BytesFilled;
// For uncompressed formats, nAvgBytesPerSec should equal nSamplesPerSecond * nBlockAlign
- if (TotalBufferSize >= (m_MixFormat->nAvgBytesPerSec * PREROLL_DURATION_SEC))
+ if (TotalBytesFilled >= (m_MixFormat->nAvgBytesPerSec * PREROLL_DURATION_SEC))
{
return true;
}
diff --git a/Samples/WindowsAudioSession/cpp/MFSampleGenerator.h b/Samples/WindowsAudioSession/cpp/MFSampleGenerator.h
index a025300ce1..541ffcc30a 100644
--- a/Samples/WindowsAudioSession/cpp/MFSampleGenerator.h
+++ b/Samples/WindowsAudioSession/cpp/MFSampleGenerator.h
@@ -67,7 +67,7 @@ namespace SDKSample
HRESULT hr = E_NOINTERFACE;
*ppv = NULL;
- if (riid == IID_IMFSourceReaderCallback)
+ if (riid == IID_IMFSourceReaderCallback || riid == IID_IUnknown)
{
*ppv = static_cast(this);
((IUnknown*) *ppv)->AddRef();
diff --git a/Samples/WindowsAudioSession/cpp/Scenario2.xaml.cpp b/Samples/WindowsAudioSession/cpp/Scenario2.xaml.cpp
index 0b9e1738f7..649383421e 100644
--- a/Samples/WindowsAudioSession/cpp/Scenario2.xaml.cpp
+++ b/Samples/WindowsAudioSession/cpp/Scenario2.xaml.cpp
@@ -53,9 +53,24 @@ Scenario2::Scenario2() :
m_CoreDispatcher = CoreWindow::GetForCurrentThread()->Dispatcher;
+ // Register for Media Transport controls. This is required to support background
+ // audio scenarios.
+ m_SystemMediaControls = SystemMediaTransportControls::GetForCurrentView();
+ m_SystemMediaControlsButtonToken = m_SystemMediaControls->ButtonPressed += ref new TypedEventHandler(this, &Scenario2::MediaButtonPressed);
+ m_SystemMediaControls->IsPlayEnabled = true;
+ m_SystemMediaControls->IsPauseEnabled = true;
+ m_SystemMediaControls->IsStopEnabled = true;
+
// Get a string representing the Default Audio Render Device
String^ deviceId = Windows::Media::Devices::MediaDevice::GetDefaultAudioRenderId(Windows::Media::Devices::AudioDeviceRole::Default);
+ // The string is empty if there is no such device.
+ if (deviceId->IsEmpty())
+ {
+ ShowStatusMessage(L"No audio devices available", NotifyType::StatusMessage);
+ return;
+ }
+
auto PropertiesToRetrieve = ref new Platform::Collections::Vector();
PropertiesToRetrieve->Append("System.Devices.AudioDevice.RawProcessingSupported");
// read property store to see if the device supports a RAW processing mode
@@ -79,14 +94,6 @@ Scenario2::Scenario2() :
ShowStatusMessage("Raw Not Supported", NotifyType::StatusMessage);
}
});
-
- // Register for Media Transport controls. This is required to support background
- // audio scenarios.
- m_SystemMediaControls = SystemMediaTransportControls::GetForCurrentView();
- m_SystemMediaControlsButtonToken = m_SystemMediaControls->ButtonPressed += ref new TypedEventHandler(this, &Scenario2::MediaButtonPressed);
- m_SystemMediaControls->IsPlayEnabled = true;
- m_SystemMediaControls->IsPauseEnabled = true;
- m_SystemMediaControls->IsStopEnabled = true;
}
Scenario2::~Scenario2()
@@ -517,6 +524,9 @@ void Scenario2::InitializeDevice()
// Selects the Default Audio Device
m_spRenderer->InitializeAudioDeviceAsync();
+
+ // Set the initial volume.
+ OnSetVolume(static_cast(sliderVolume->Value));
}
}
diff --git a/Samples/WindowsAudioSession/cpp/Scenario3.xaml.cpp b/Samples/WindowsAudioSession/cpp/Scenario3.xaml.cpp
index 3a6481a04a..f55abe2327 100644
--- a/Samples/WindowsAudioSession/cpp/Scenario3.xaml.cpp
+++ b/Samples/WindowsAudioSession/cpp/Scenario3.xaml.cpp
@@ -54,9 +54,24 @@ Scenario3::Scenario3() :
m_CoreDispatcher = CoreWindow::GetForCurrentThread()->Dispatcher;
+ // Register for Media Transport controls. This is required to support background
+ // audio scenarios.
+ m_SystemMediaControls = SystemMediaTransportControls::GetForCurrentView();
+ m_SystemMediaControlsButtonToken = m_SystemMediaControls->ButtonPressed += ref new TypedEventHandler(this, &Scenario3::MediaButtonPressed);
+ m_SystemMediaControls->IsPlayEnabled = true;
+ m_SystemMediaControls->IsPauseEnabled = true;
+ m_SystemMediaControls->IsStopEnabled = true;
+
// Get a string representing the Default Audio Render Device
String^ deviceId = Windows::Media::Devices::MediaDevice::GetDefaultAudioRenderId(Windows::Media::Devices::AudioDeviceRole::Default);
+ // The string is empty if there is no such device.
+ if (deviceId->IsEmpty())
+ {
+ ShowStatusMessage(L"No audio devices available", NotifyType::StatusMessage);
+ return;
+ }
+
auto PropertiesToRetrieve = ref new Platform::Collections::Vector();
PropertiesToRetrieve->Append("System.Devices.AudioDevice.RawProcessingSupported");
@@ -81,14 +96,6 @@ Scenario3::Scenario3() :
ShowStatusMessage("Raw Not Supported", NotifyType::StatusMessage);
}
});
-
- // Register for Media Transport controls. This is required to support background
- // audio scenarios.
- m_SystemMediaControls = SystemMediaTransportControls::GetForCurrentView();
- m_SystemMediaControlsButtonToken = m_SystemMediaControls->ButtonPressed += ref new TypedEventHandler(this, &Scenario3::MediaButtonPressed);
- m_SystemMediaControls->IsPlayEnabled = true;
- m_SystemMediaControls->IsPauseEnabled = true;
- m_SystemMediaControls->IsStopEnabled = true;
}
Scenario3::~Scenario3()
@@ -527,6 +534,9 @@ void Scenario3::InitializeDevice()
// Selects the Default Audio Device
m_spRenderer->InitializeAudioDeviceAsync();
+
+ // Set the initial volume
+ OnSetVolume(static_cast(sliderVolume->Value));
}
}
diff --git a/Samples/WindowsAudioSession/cpp/ToneSampleGenerator.cpp b/Samples/WindowsAudioSession/cpp/ToneSampleGenerator.cpp
index 1987f7a57e..31624a519b 100644
--- a/Samples/WindowsAudioSession/cpp/ToneSampleGenerator.cpp
+++ b/Samples/WindowsAudioSession/cpp/ToneSampleGenerator.cpp
@@ -35,6 +35,18 @@ short Convert(double Value)
return (short)(Value * _I16_MAX);
};
+// 24-bit value stored in the upper bits of a 32-bit integer.
+struct int24in32
+{
+ int value;
+};
+template<>
+int24in32 Convert(double Value)
+{
+ constexpr int _I24_MAX = (1 << 23) - 1;
+ return { (int)(Value * _I24_MAX) << 8 };
+};
+
//
// ToneSampleGenerator()
//
@@ -84,12 +96,16 @@ HRESULT ToneSampleGenerator::GenerateSampleBuffer( DWORD Frequency, UINT32 Frame
return E_OUTOFMEMORY;
}
- switch( CalculateMixFormatType( wfx ) )
+ switch(GetRenderSampleType( wfx ) )
{
case RenderSampleType::SampleType16BitPCM:
GenerateSineSamples( SampleBuffer->Buffer, SampleBuffer->BufferSize, Frequency, wfx->nChannels, wfx->nSamplesPerSec, TONE_AMPLITUDE, &theta);
break;
+ case RenderSampleType::SampleType24in32BitPCM:
+ GenerateSineSamples(SampleBuffer->Buffer, SampleBuffer->BufferSize, Frequency, wfx->nChannels, wfx->nSamplesPerSec, TONE_AMPLITUDE, &theta);
+ break;
+
case RenderSampleType::SampleTypeFloat:
GenerateSineSamples( SampleBuffer->Buffer, SampleBuffer->BufferSize, Frequency, wfx->nChannels, wfx->nSamplesPerSec, TONE_AMPLITUDE, &theta);
break;
@@ -162,6 +178,7 @@ HRESULT ToneSampleGenerator::FillSampleBuffer( UINT32 BytesToRead, BYTE *Data )
CopyMemory( Data, SampleBuffer->Buffer, BytesToRead );
m_SampleQueue = m_SampleQueue->Next;
+ SAFE_DELETE(SampleBuffer);
return S_OK;
}
diff --git a/Samples/WindowsAudioSession/cpp/WASAPICapture.cpp b/Samples/WindowsAudioSession/cpp/WASAPICapture.cpp
index a40d1276ff..e841ce082f 100644
--- a/Samples/WindowsAudioSession/cpp/WASAPICapture.cpp
+++ b/Samples/WindowsAudioSession/cpp/WASAPICapture.cpp
@@ -53,10 +53,6 @@ WASAPICapture::WASAPICapture() :
}
m_DeviceStateChanged = ref new DeviceStateChangedEvent();
- if (nullptr == m_DeviceStateChanged)
- {
- ThrowIfFailed( E_OUTOFMEMORY );
- }
// Register MMCSS work queue
HRESULT hr = S_OK;
@@ -88,6 +84,7 @@ WASAPICapture::~WASAPICapture()
}
MFUnlockWorkQueue( m_dwQueueID );
+ CoTaskMemFree( m_MixFormat );
m_DeviceStateChanged = nullptr;
m_ContentStream = nullptr;
@@ -224,7 +221,7 @@ HRESULT WASAPICapture::ActivateCompleted( IActivateAudioInterfaceAsyncOperation
hr = m_AudioClient->GetSharedModeEnginePeriod(m_MixFormat, &m_DefaultPeriodInFrames, &m_FundamentalPeriodInFrames, &m_MinPeriodInFrames, &m_MaxPeriodInFrames);
if (FAILED(hr))
{
- return hr;
+ goto exit;
}
// Initialize the AudioClient in Shared Mode with the user specified buffer
@@ -318,32 +315,18 @@ HRESULT WASAPICapture::CreateWAVFile()
concurrency::task( KnownFolders::MusicLibrary->CreateFileAsync( AUDIO_FILE_NAME, CreationCollisionOption::GenerateUniqueName )).then(
[this]( StorageFile^ file )
{
- if (nullptr == file)
- {
- ThrowIfFailed( E_INVALIDARG );
- }
-
return file->OpenAsync( FileAccessMode::ReadWrite );
})
// Then create a RandomAccessStream
.then([this]( IRandomAccessStream^ stream )
{
- if (nullptr == stream)
- {
- ThrowIfFailed( E_INVALIDARG );
- }
-
// Get the OutputStream for the file
m_ContentStream = stream;
m_OutputStream = m_ContentStream->GetOutputStreamAt(0);
// Create the DataWriter
m_WAVDataWriter = ref new DataWriter( m_OutputStream );
- if (nullptr == m_WAVDataWriter)
- {
- ThrowIfFailed( E_OUTOFMEMORY );
- }
// Create the WAV header
DWORD header[] = {
@@ -381,10 +364,11 @@ HRESULT WASAPICapture::CreateWAVFile()
})
// Our file is ready to go, so we can now signal that initialization is finished
- .then([this]( bool f )
+ .then([this]( concurrency::task previousTask )
{
try
{
+ previousTask.get();
m_DeviceStateChanged->SetState( DeviceState::DeviceStateInitialized, S_OK, true );
}
catch (Platform::Exception ^e)
@@ -500,10 +484,14 @@ HRESULT WASAPICapture::OnStartCapture( IMFAsyncResult* pResult )
// Start the capture
hr = m_AudioClient->Start();
+ if (SUCCEEDED( hr ))
+ {
+ hr = MFPutWaitingWorkItem( m_SampleReadyEvent, 0, m_SampleReadyAsyncResult, &m_SampleReadyKey );
+ }
+
if (SUCCEEDED( hr ))
{
m_DeviceStateChanged->SetState( DeviceState::DeviceStateCapturing, S_OK, true );
- MFPutWaitingWorkItem( m_SampleReadyEvent, 0, m_SampleReadyAsyncResult, &m_SampleReadyKey );
}
else
{
diff --git a/Samples/WindowsAudioSession/cpp/WASAPIRenderer.cpp b/Samples/WindowsAudioSession/cpp/WASAPIRenderer.cpp
index e189a21412..c17dfb9457 100644
--- a/Samples/WindowsAudioSession/cpp/WASAPIRenderer.cpp
+++ b/Samples/WindowsAudioSession/cpp/WASAPIRenderer.cpp
@@ -23,6 +23,7 @@ using namespace SDKSample::WASAPIAudio;
//
WASAPIRenderer::WASAPIRenderer() :
m_BufferFrames( 0 ),
+ m_ChannelVolume( 1.0f ),
m_DeviceStateChanged( nullptr ),
m_AudioClient( nullptr ),
m_AudioRenderClient( nullptr ),
@@ -68,6 +69,8 @@ WASAPIRenderer::~WASAPIRenderer()
DeleteCriticalSection( &m_CritSec );
+ CoTaskMemFree( m_MixFormat );
+
m_DeviceStateChanged = nullptr;
}
@@ -138,10 +141,10 @@ HRESULT WASAPIRenderer::ActivateCompleted( IActivateAudioInterfaceAsyncOperation
}
// Initialize the AudioClient in Shared Mode with the user specified buffer
- if (m_DeviceProps.IsLowLatency == false)
+ if (!m_DeviceProps.IsLowLatency || m_DeviceProps.IsHWOffload)
{
hr = m_AudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
m_DeviceProps.hnsBufferDuration,
m_DeviceProps.hnsBufferDuration,
m_MixFormat,
@@ -234,6 +237,11 @@ UINT32 WASAPIRenderer::GetBufferFramesPerPeriod()
return m_BufferFrames;
}
+ if (m_DeviceProps.IsLowLatency)
+ {
+ return m_MinPeriodInFrames;
+ }
+
// Get the audio device period
HRESULT hr = m_AudioClient->GetDevicePeriod( &defaultDevicePeriod, &minimumDevicePeriod);
if (FAILED( hr ))
@@ -241,18 +249,7 @@ UINT32 WASAPIRenderer::GetBufferFramesPerPeriod()
return 0;
}
- double devicePeriodInSeconds;
-
- if (m_DeviceProps.IsLowLatency)
- {
- devicePeriodInSeconds = minimumDevicePeriod / (10000.0*1000.0);
- }
- else
- {
- devicePeriodInSeconds = defaultDevicePeriod / (10000.0*1000.0);
- }
-
-
+ double devicePeriodInSeconds = defaultDevicePeriod / (10000.0*1000.0);
return static_cast( m_MixFormat->nSamplesPerSec * devicePeriodInSeconds + 0.5 );
}
@@ -287,6 +284,21 @@ HRESULT WASAPIRenderer::ConfigureDeviceInternal()
return hr;
}
+ // If application already has a preferred source format available,
+ // it can test whether the format is supported by the device:
+ //
+ // WAVEFORMATEX* applicationFormat = ...;
+ // if (S_OK == m_AudioClient->IsFormatSupported(applicationFormat))
+ // {
+ // m_MixFormat = applicationFormat;
+ // }
+ // else
+ // {
+ // //device does not support the application format, so ask the device what format it prefers
+ // m_AudioClient->GetMixFormat( &m_MixFormat );
+ // }
+
+ // In this sample we do not have a format already available, so we go ahead and ask the device which format it prefers
// This sample opens the device is shared mode so we need to find the supported WAVEFORMATEX mix format
hr = m_AudioClient->GetMixFormat( &m_MixFormat );
if (FAILED( hr ))
@@ -294,13 +306,16 @@ HRESULT WASAPIRenderer::ConfigureDeviceInternal()
return hr;
}
- // The wfx parameter below is optional (Its needed only for MATCH_FORMAT clients). Otherwise, wfx will be assumed
- // to be the current engine format based on the processing mode for this stream
- hr = m_AudioClient->GetSharedModeEnginePeriod(m_MixFormat, &m_DefaultPeriodInFrames, &m_FundamentalPeriodInFrames, &m_MinPeriodInFrames, &m_MaxPeriodInFrames);
- if (FAILED( hr ))
- {
- return hr;
- }
+ if (!audioProps.bIsOffload)
+ {
+ // The wfx parameter below is optional (Its needed only for MATCH_FORMAT clients). Otherwise, wfx will be assumed
+ // to be the current engine format based on the processing mode for this stream
+ hr = m_AudioClient->GetSharedModeEnginePeriod(m_MixFormat, &m_DefaultPeriodInFrames, &m_FundamentalPeriodInFrames, &m_MinPeriodInFrames, &m_MaxPeriodInFrames);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
// Verify the user defined value for hardware buffer
hr = ValidateBufferValue();
@@ -348,7 +363,7 @@ HRESULT WASAPIRenderer::ValidateBufferValue()
//
// SetVolumeOnSession()
//
-HRESULT WASAPIRenderer::SetVolumeOnSession( UINT32 volume )
+HRESULT WASAPIRenderer::SetVolumeOnSession(UINT32 volume)
{
if (volume > 100)
{
@@ -356,19 +371,27 @@ HRESULT WASAPIRenderer::SetVolumeOnSession( UINT32 volume )
}
HRESULT hr = S_OK;
- ISimpleAudioVolume *SessionAudioVolume = nullptr;
- float ChannelVolume = 0.0;
+ m_ChannelVolume = volume / (float)100.0;
- hr = m_AudioClient->GetService( __uuidof(ISimpleAudioVolume), reinterpret_cast(&SessionAudioVolume) );
- if (FAILED( hr ))
+ // Set the session volume on the endpoint if we have one.
+ if (m_AudioClient != nullptr)
{
- goto exit;
+ hr = SetAudioClientChannelVolume();
}
+ return hr;
+}
- ChannelVolume = volume / (float)100.0;
+HRESULT WASAPIRenderer::SetAudioClientChannelVolume()
+{
+ ISimpleAudioVolume* SessionAudioVolume = nullptr;
+ HRESULT hr = m_AudioClient->GetService(__uuidof(ISimpleAudioVolume), reinterpret_cast(&SessionAudioVolume));
+ if (FAILED(hr))
+ {
+ goto exit;
+ }
// Set the session volume on the endpoint
- hr = SessionAudioVolume->SetMasterVolume( ChannelVolume, nullptr );
+ hr = SessionAudioVolume->SetMasterVolume( m_ChannelVolume, nullptr );
exit:
SAFE_RELEASE( SessionAudioVolume );
@@ -474,6 +497,9 @@ HRESULT WASAPIRenderer::OnStartPlayback( IMFAsyncResult* pResult )
}
}
+ // Set the initial volume.
+ SetAudioClientChannelVolume();
+
// Actually start the playback
hr = m_AudioClient->Start();
if (SUCCEEDED( hr ))
@@ -597,7 +623,7 @@ HRESULT WASAPIRenderer::OnSampleReady( IMFAsyncResult* pResult )
hr = MFPutWaitingWorkItem( m_SampleReadyEvent, 0, m_SampleReadyAsyncResult, &m_SampleReadyKey );
}
}
- else
+ if (FAILED( hr ))
{
m_DeviceStateChanged->SetState( DeviceState::DeviceStateInError, hr, true );
}
@@ -625,19 +651,9 @@ HRESULT WASAPIRenderer::OnAudioSampleRequested( Platform::Boolean IsSilence )
goto exit;
}
- // Audio frames available in buffer
- if (m_DeviceProps.IsHWOffload)
- {
- // In HW mode, GetCurrentPadding returns the number of available frames in the
- // buffer, so we can just use that directly
- FramesAvailable = PaddingFrames;
- }
- else
- {
- // In non-HW shared mode, GetCurrentPadding represents the number of queued frames
- // so we can subtract that from the overall number of frames we have
- FramesAvailable = m_BufferFrames - PaddingFrames;
- }
+ // GetCurrentPadding represents the number of queued frames
+ // so we can subtract that from the overall number of frames we have
+ FramesAvailable = m_BufferFrames - PaddingFrames;
// Only continue if we have buffer to write data
if (FramesAvailable > 0)
diff --git a/Samples/WindowsAudioSession/cpp/WASAPIRenderer.h b/Samples/WindowsAudioSession/cpp/WASAPIRenderer.h
index 538aeb525d..b64c6fe57f 100644
--- a/Samples/WindowsAudioSession/cpp/WASAPIRenderer.h
+++ b/Samples/WindowsAudioSession/cpp/WASAPIRenderer.h
@@ -91,6 +91,7 @@ namespace SDKSample
HRESULT OnAudioSampleRequested( Platform::Boolean IsSilence = false );
HRESULT ConfigureSource();
UINT32 GetBufferFramesPerPeriod();
+ HRESULT SetAudioClientChannelVolume();
HRESULT GetToneSample( UINT32 FramesAvailable );
HRESULT GetMFSample( UINT32 FramesAvailable );
@@ -107,6 +108,7 @@ namespace SDKSample
UINT32 m_FundamentalPeriodInFrames;
UINT32 m_MaxPeriodInFrames;
UINT32 m_MinPeriodInFrames;
+ float m_ChannelVolume;
IAudioClient3 *m_AudioClient;
IAudioRenderClient *m_AudioRenderClient;
diff --git a/Samples/WindowsAudioSession/cppwinrt/Common.h b/Samples/WindowsAudioSession/cppwinrt/Common.h
new file mode 100644
index 0000000000..febfe7f053
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Common.h
@@ -0,0 +1,186 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+namespace winrt::SDKTemplate
+{
+ // RAII helper class to ensure something happens even in case of exception.
+ template
+ struct scope_exit
+ {
+ scope_exit(Lambda&& lambda) : m_lambda(std::move(lambda)) {}
+ ~scope_exit() { m_lambda(); }
+
+ scope_exit(const scope_exit&) = delete;
+ void operator=(const scope_exit&) = delete;
+
+ Lambda m_lambda;
+ };
+
+ // RAII class to initialize Media Foundation.
+ struct MediaFoundationInitializer
+ {
+ MediaFoundationInitializer()
+ {
+ // Initialize MF
+ check_hresult(MFStartup(MF_VERSION, MFSTARTUP_LITE));
+ }
+
+ ~MediaFoundationInitializer()
+ {
+ MFShutdown();
+ }
+ };
+
+ // RAII class to lock/unlock a shared work queue.
+ struct unique_shared_work_queue
+ {
+ unique_shared_work_queue(PCWSTR className)
+ {
+ DWORD taskId = 0; // 0 means "create a new task group"
+ check_hresult(MFLockSharedWorkQueue(className, 0, &taskId, &m_queueId));
+ }
+
+ ~unique_shared_work_queue()
+ {
+ MFUnlockWorkQueue(m_queueId);
+ }
+
+ unique_shared_work_queue(unique_shared_work_queue const&) = delete;
+ void operator=(unique_shared_work_queue const&) = delete;
+
+ DWORD get() { return m_queueId; }
+ private:
+ DWORD m_queueId = 0;
+ };
+
+ // RAII class analogous to std::unique_ptr, but calls CoTaskMemFree instead of delete.
+ template
+ struct unique_cotaskmem_ptr
+ {
+ unique_cotaskmem_ptr(T* p = nullptr) : m_p(p) {}
+ ~unique_cotaskmem_ptr() { CoTaskMemFree(m_p); }
+
+ unique_cotaskmem_ptr(unique_cotaskmem_ptr const&) = delete;
+ unique_cotaskmem_ptr(unique_cotaskmem_ptr&& other) : m_p(std::exchange(other.m_p, nullptr)) {}
+ unique_cotaskmem_ptr& operator=(unique_cotaskmem_ptr const& other)
+ {
+ CoTaskMemFree(std::exchange(m_p, std::exchange(other.m_p, nullptr)));
+ return *this;
+ }
+
+ T* operator->() { return m_p; }
+ T* get() { return m_p; }
+ T** put() { return &m_p; }
+ T* m_p;
+ };
+
+ // Helper class for allowing a class to implement multiple versions of
+ // IMFAsyncCallback.
+ template
+ struct EmbeddedMFAsyncCallback : ::IMFAsyncCallback
+ {
+ template static Parent* parent_finder(HRESULT(Parent::*)(IMFAsyncResult*)) { return nullptr; }
+ using ParentPtr = decltype(parent_finder(Callback));
+
+ ParentPtr m_parent;
+ DWORD m_queueId = 0;
+
+ EmbeddedMFAsyncCallback(ParentPtr parent) : m_parent(parent) {}
+
+ STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) final
+ {
+ if (is_guid_of<::IMFAsyncCallback, ::IUnknown>(riid))
+ {
+ (*ppvObject) = this;
+ AddRef();
+ return S_OK;
+ }
+ *ppvObject = nullptr;
+ return E_NOINTERFACE;
+ }
+
+ STDMETHOD_(ULONG, AddRef)() final { return m_parent->AddRef(); }
+ STDMETHOD_(ULONG, Release)() final { return m_parent->Release(); }
+
+ STDMETHOD(GetParameters)(DWORD* flags, DWORD* queueId) final
+ {
+ *flags = 0;
+ *queueId = m_queueId;
+ return S_OK;
+ }
+
+ STDMETHOD(Invoke)(IMFAsyncResult* result) final
+ {
+ return (m_parent->*Callback)(result);
+ }
+
+ void SetQueueID(DWORD queueId) { m_queueId = queueId; }
+ };
+
+ struct RenderBuffer
+ {
+ uint32_t BufferSize;
+ uint32_t BytesFilled;
+ std::unique_ptr Buffer;
+
+ RenderBuffer(uint32_t size) :
+ BufferSize(size),
+ BytesFilled(size),
+ Buffer(new BYTE[size])
+ {
+ }
+ };
+
+ enum class RenderSampleType
+ {
+ Unknown,
+ Float,
+ Pcm16Bit,
+ Pcm24In32Bit,
+ };
+
+ //
+ // GetRenderSampleType()
+ //
+ // Determine the sample format based on media type
+ //
+ inline RenderSampleType GetRenderSampleType(WAVEFORMATEX const* wfx)
+ {
+ WAVEFORMATEXTENSIBLE const* wfext = reinterpret_cast(wfx);
+
+ if ((wfx->wFormatTag == WAVE_FORMAT_PCM) ||
+ ((wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
+ (wfext->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)))
+ {
+ if (wfx->wBitsPerSample == 16)
+ {
+ return RenderSampleType::Pcm16Bit;
+ }
+ else if (wfx->wBitsPerSample == 32)
+ {
+ if ((wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
+ (wfext->Samples.wValidBitsPerSample == 24))
+ {
+ return RenderSampleType::Pcm24In32Bit;
+ }
+ }
+ }
+ else if ((wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) ||
+ ((wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
+ (wfext->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
+ {
+ return RenderSampleType::Float;
+ }
+
+ return RenderSampleType::Unknown;
+ }
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/DeviceState.h b/Samples/WindowsAudioSession/cppwinrt/DeviceState.h
new file mode 100644
index 0000000000..652be1608b
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/DeviceState.h
@@ -0,0 +1,61 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "DeviceStateChangedEventArgs.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct DeviceStateChangedEventArgs : DeviceStateChangedEventArgsT
+ {
+ DeviceStateChangedEventArgs(enum DeviceState deviceState, hresult error) : m_deviceState(deviceState), m_error(error) {}
+
+ enum DeviceState DeviceState() { return m_deviceState; }
+ hresult ExtendedError() { return m_error; }
+
+ private:
+ enum DeviceState const m_deviceState;
+ hresult const m_error;
+ };
+
+ template
+ struct DeviceStateSourceT
+ {
+ DeviceState DeviceState() { return m_deviceState; }
+
+ event_token DeviceStateChanged(Windows::Foundation::TypedEventHandler const& handler)
+ {
+ return m_deviceStateChanged.add(handler);
+ }
+ void DeviceStateChanged(event_token token)
+ {
+ return m_deviceStateChanged.remove(token);
+ }
+
+ protected:
+ enum DeviceState m_deviceState = DeviceState::Uninitialized;
+ event> m_deviceStateChanged;
+
+ void SetState(enum DeviceState state, HRESULT error = S_OK)
+ {
+ if (m_deviceState != state)
+ {
+ m_deviceState = state;
+ m_deviceStateChanged(*static_cast(this), make(state, error));
+ }
+ }
+
+ void SetStateNoNotify(enum DeviceState state)
+ {
+ m_deviceState = state;
+ }
+ };
+}
+
diff --git a/Samples/WindowsAudioSession/cppwinrt/MFSampleGenerator.cpp b/Samples/WindowsAudioSession/cppwinrt/MFSampleGenerator.cpp
new file mode 100644
index 0000000000..d6d9bc2020
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/MFSampleGenerator.cpp
@@ -0,0 +1,380 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "MFSampleGenerator.h"
+
+using namespace winrt::Windows::Storage::Streams;
+
+namespace winrt::SDKTemplate
+{
+#define PREROLL_DURATION_SEC 3 // Arbitrary value for seconds of data in preroll buffer
+
+ //
+ // Shutdown()
+ //
+ void MFSampleGenerator::Shutdown()
+ {
+ if (m_isInitialized)
+ {
+ m_audioMediaType = nullptr;
+ m_sourceReader = nullptr;
+
+ m_sampleQueue.clear();
+
+ m_isInitialized = false;
+ }
+ }
+
+ //
+ // StartSource()
+ //
+ // Start the media source to read samples
+ //
+ void MFSampleGenerator::StartSource()
+ {
+ if (!m_isInitialized)
+ {
+ throw hresult_illegal_state_change();
+ }
+
+ // We can be in EOS if this is a resume from pause
+ if ((m_readerState == ReaderState::PreRoll) ||
+ (m_readerState == ReaderState::Playing) ||
+ (m_readerState == ReaderState::EndOfStream))
+ return;
+
+ // This will start the source reader and asynchronously call OnReadSample
+ check_hresult(m_sourceReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, nullptr, nullptr, nullptr));
+ m_readerState = ReaderState::PreRoll;
+ }
+
+ //
+ // StopSource()
+ //
+ // Stops the media source from reading samples
+ //
+ void MFSampleGenerator::StopSource()
+ {
+ // We only really need this if Source is still reading samples, otherwise
+ // we should be in an EndOfStream state and parsing existing samples in the queue
+ m_readerState = ReaderState::Stopped;
+ }
+
+ //
+ // Initialize()
+ //
+ // Configure the Source Reader
+ //
+ void MFSampleGenerator::Initialize(IRandomAccessStream const& stream, UINT32 framesPerPeriod, WAVEFORMATEX* wfx)
+ {
+ m_audioMediaType = nullptr;
+ m_sourceReader = nullptr;
+
+ com_ptr attributes;
+ check_hresult(MFCreateAttributes(attributes.put(), 3));
+
+ // Specify Source Reader Attributes
+ check_hresult(attributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this));
+ check_hresult(attributes->SetString(MF_READWRITE_MMCSS_CLASS_AUDIO, L"Audio"));
+ check_hresult(attributes->SetUINT32(MF_READWRITE_MMCSS_PRIORITY_AUDIO, 0));
+
+ // Create a stream from IRandomAccessStream
+ com_ptr byteStream;
+ check_hresult(MFCreateMFByteStreamOnStreamEx(winrt::get_unknown(stream), byteStream.put()));
+
+ // Create source reader
+ com_ptr sourceReader;
+ check_hresult(MFCreateSourceReaderFromByteStream(byteStream.get(), attributes.get(), sourceReader.put()));
+
+ // Configure media types. If this succeeds, then everything passed and we commit our changes.
+ m_audioMediaType = ConfigureStreams(sourceReader, wfx);
+ m_sourceReader = std::move(sourceReader);
+
+ m_bytesPerPeriod = framesPerPeriod * wfx->nBlockAlign;
+
+ // For uncompressed formats, nAvgBytesPerSec should equal nSamplesPerSecond * nBlockAlign
+ m_bytesPerSecond = wfx->nAvgBytesPerSec;
+
+ m_isInitialized = true;
+ }
+
+
+ //
+ // ConfigureStreams()
+ //
+ // Enables the first audio stream and configures the media type
+ //
+ com_ptr MFSampleGenerator::ConfigureStreams(com_ptr const& reader, WAVEFORMATEX* wfx)
+ {
+ // Disable all streams
+ check_hresult(reader->SetStreamSelection((DWORD)MF_SOURCE_READER_ALL_STREAMS, false));
+
+ // Enable first audio stream
+ check_hresult(reader->SetStreamSelection((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, true));
+
+ com_ptr partialMediaType = CreateAudioType(wfx);
+
+ // Set type on source reader so necessary converters / decoders will be added
+ check_hresult(reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, nullptr, partialMediaType.get()));
+
+ // Verify the media type on stream
+ com_ptr uncompressedMediaType;
+ check_hresult(reader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, uncompressedMediaType.put()));
+
+ unique_cotaskmem_ptr createdWfx;
+ UINT32 cbFormat = 0;
+ check_hresult(MFCreateWaveFormatExFromMFMediaType(uncompressedMediaType.get(), createdWfx.put(), &cbFormat));
+
+ return uncompressedMediaType;
+ }
+
+ //
+ // CreateAudioType()
+ //
+ // Create an audio type based on the default mix format from the renderer
+ //
+ com_ptr MFSampleGenerator::CreateAudioType(WAVEFORMATEX* wfx)
+ {
+ com_ptr mediaType;
+
+ // Create a partial media type for our mix format (PCM or IEEE Float)
+ check_hresult(MFCreateMediaType(mediaType.put()));
+
+ // Set media type attributes
+ check_hresult(mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio));
+
+ switch (GetRenderSampleType(wfx))
+ {
+ case RenderSampleType::Pcm16Bit:
+ case RenderSampleType::Pcm24In32Bit:
+ check_hresult(mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM));
+ break;
+ case RenderSampleType::Float:
+ check_hresult(mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float));
+ break;
+ default:
+ throw hresult_error(E_UNEXPECTED);
+ }
+
+ check_hresult(mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, wfx->nChannels));
+ check_hresult(mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, wfx->nSamplesPerSec));
+ check_hresult(mediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, wfx->nBlockAlign));
+ check_hresult(mediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, wfx->nAvgBytesPerSec));
+ check_hresult(mediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, wfx->wBitsPerSample));
+ check_hresult(mediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, true));
+
+ return mediaType;
+ }
+
+ //
+ // OnEvent()
+ //
+ // Implementation of IMFSourceReaderCallback::OnEvent()
+ //
+ HRESULT MFSampleGenerator::OnEvent([[maybe_unused]] DWORD streamIndex, [[maybe_unused]] IMFMediaEvent* event)
+ {
+ return S_OK;
+ }
+
+ //
+ // OnFlush()
+ //
+ // Implementation of IMFSourceReaderCallback::OnFlush()
+ //
+ HRESULT MFSampleGenerator::OnFlush([[maybe_unused]] DWORD streamIndex)
+ {
+ return S_OK;
+ }
+
+ //
+ // OnReadSample()
+ //
+ // Implementation of IMFSourceReaderCallback::OnReadSample(). When a sample is ready, add it to the sample queue.
+ //
+ HRESULT MFSampleGenerator::OnReadSample(HRESULT error, [[maybe_unused]] DWORD streamIndex, DWORD streamFlags, [[maybe_unused]] LONGLONG timestamp, IMFSample* sample) try
+ {
+ if ((m_readerState != ReaderState::Playing) &&
+ (m_readerState != ReaderState::PreRoll))
+ {
+ return S_OK;
+ }
+
+ // If we have a failure, change in stream format, or hit EOF, then we stop reading samples
+ if ((FAILED(error)) ||
+ (streamFlags & MF_SOURCE_READERF_ENDOFSTREAM) ||
+ (streamFlags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED))
+ {
+ m_readerState = ReaderState::EndOfStream;
+ return S_OK;
+ }
+
+ // If there were no samples read, then ignore the callback.
+ if (!sample)
+ {
+ return S_OK;
+ }
+
+ // Add the data from the Media Sample to our buffer queue
+ AddSamplesToQueue(sample);
+
+ // Pre-roll PREROLL_DURATION seconds worth of data
+ if (m_readerState == ReaderState::PreRoll)
+ {
+ if (IsPreRollFilled())
+ {
+ // Once Pre-roll is filled, audio endpoint will stop rendering silence and start
+ // picking up data from the queue
+ m_readerState = ReaderState::Playing;
+ }
+ }
+
+ // Call ReadSample for next asynchronous sample event
+ check_hresult(m_sourceReader->ReadSample((DWORD)MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, nullptr, nullptr, nullptr, nullptr));
+
+ return S_OK;
+ }
+ catch (...) { return to_hresult(); }
+
+ //
+ // FillSampleBuffer()
+ //
+ // Called by the audio endpoint to get data to render, and will set cbWritten to valid number of
+ // bytes in the buffer. The buffers are zeroed out when initialized so the endpoint could feasibly
+ // treat the data as silence. If there are no more samples to render, will return false.
+ //
+ bool MFSampleGenerator::FillSampleBuffer(array_view buffer, uint32_t* cbWritten)
+ {
+ *cbWritten = 0;
+
+ if (!m_isInitialized)
+ {
+ throw hresult_error(E_UNEXPECTED);
+ }
+
+ // Not going to return any data here while in a pre-roll state.
+ if (m_readerState == ReaderState::PreRoll)
+ {
+ return true;
+ }
+
+ if (m_sampleQueue.empty())
+ {
+ if (m_readerState == ReaderState::EndOfStream)
+ {
+ // We are EOS, should be set from OnReadSample() and the client should check for EOS before
+ // calling FillSampleBuffer()
+ return false;
+ }
+ else
+ {
+ // There shouldn't be a situation where we get here unless the reader has
+ // somehow gotten into the wrong state
+ throw hresult_error(E_FAIL);
+ }
+ }
+ else
+ {
+ RenderBuffer& sampleBuffer = m_sampleQueue.front();
+
+ if (sampleBuffer.BufferSize > buffer.size())
+ {
+ // We don't have enough data in the client audio buffer this pass
+ // Do nothing and wait for the next sample period
+ }
+ else
+ {
+ CopyMemory(buffer.data(), sampleBuffer.Buffer.get(), sampleBuffer.BufferSize);
+
+ *cbWritten = sampleBuffer.BufferSize;
+ m_sampleQueue.pop_front();
+ }
+ }
+ return true;
+ }
+
+ //
+ // AddSamplesToBuffer()
+ //
+ // Data is added to the end of the sample queue
+ //
+ void MFSampleGenerator::AddSamplesToQueue(IMFSample* sample)
+ {
+ com_ptr mediaBuffer;
+
+ // Since we are storing the raw byte data, convert this to a single buffer
+ check_hresult(sample->ConvertToContiguousBuffer(mediaBuffer.put()));
+
+ // Lock the sample
+ BYTE* audioData = nullptr;
+ DWORD cbAudioData = 0;
+ check_hresult(mediaBuffer->Lock(&audioData, NULL, &cbAudioData));
+
+ // Make sure we unlock the buffer.
+ auto unlock = scope_exit([&] { mediaBuffer->Unlock(); });
+
+ DWORD cbBytesCopied = 0;
+
+ // First fill up any partial buffers from the previous sample
+ if ((m_sampleQueueTail != m_sampleQueue.before_begin()) &&
+ (m_sampleQueueTail->BytesFilled < m_sampleQueueTail->BufferSize))
+ {
+ RenderBuffer& PartialBuffer = *m_sampleQueueTail;
+
+ DWORD cbBytesRemaining = PartialBuffer.BufferSize - PartialBuffer.BytesFilled;
+ DWORD cbBytesToCopy = (std::min)(cbAudioData, cbBytesRemaining);
+
+ CopyMemory(PartialBuffer.Buffer.get() + PartialBuffer.BytesFilled, audioData, cbBytesToCopy);
+
+ PartialBuffer.BytesFilled += cbBytesToCopy;
+ cbBytesCopied += cbBytesToCopy;
+ }
+
+ // Create buffers for the remainder of the samples
+ while (cbBytesCopied < cbAudioData)
+ {
+ m_sampleQueueTail = m_sampleQueue.emplace_after(m_sampleQueueTail, m_bytesPerPeriod);
+ RenderBuffer& SampleBuffer = *m_sampleQueueTail;
+
+ DWORD cbBytesRemaining = cbAudioData - cbBytesCopied;
+ DWORD cbBytesToCopy = (std::min)(static_cast(SampleBuffer.BufferSize), cbBytesRemaining);
+
+ SampleBuffer.BytesFilled = 0;
+
+ ZeroMemory(SampleBuffer.Buffer.get(), m_bytesPerPeriod);
+ CopyMemory(SampleBuffer.Buffer.get(), audioData + cbBytesCopied, cbBytesToCopy);
+
+ SampleBuffer.BytesFilled += cbBytesToCopy;
+ cbBytesCopied += cbBytesToCopy;
+ }
+ }
+
+ //
+ // IsPreRollFilled()
+ //
+ // Loops through the queue quickly to see if our pre-roll buffer is filled
+ //
+ bool MFSampleGenerator::IsPreRollFilled()
+ {
+ DWORD totalBytes = 0;
+
+ for (RenderBuffer& sampleBuffer : m_sampleQueue)
+ {
+ totalBytes += sampleBuffer.BytesFilled;
+
+ if (totalBytes >= m_bytesPerSecond * PREROLL_DURATION_SEC)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/MFSampleGenerator.h b/Samples/WindowsAudioSession/cppwinrt/MFSampleGenerator.h
new file mode 100644
index 0000000000..e7cb955df1
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/MFSampleGenerator.h
@@ -0,0 +1,66 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+
+
+namespace winrt::SDKTemplate
+{
+ struct MFSampleGenerator : implements
+ {
+ enum ReaderState
+ {
+ Stopped,
+ PreRoll,
+ Playing,
+ EndOfStream
+ };
+
+ MFSampleGenerator() = default;
+ ~MFSampleGenerator() = default;
+
+ // IMFSourceReaderCallback
+ STDMETHODIMP_(HRESULT) OnEvent(_In_ DWORD streamIndex, _In_ IMFMediaEvent* event);
+ STDMETHODIMP_(HRESULT) OnFlush(_In_ DWORD streamIndex);
+ STDMETHODIMP_(HRESULT) OnReadSample(HRESULT error, DWORD streamIndex, DWORD streamFlags, LONGLONG timestamp, IMFSample* sample);
+
+ // MFSampleGenerator
+ void StartSource();
+ void StopSource();
+
+ void Initialize(Windows::Storage::Streams::IRandomAccessStream const& stream, UINT32 FramesPerPeriod, WAVEFORMATEX* wfx);
+ void Shutdown();
+ bool FillSampleBuffer(array_view buffer, uint32_t* cbWritten);
+
+ bool IsEOF()
+ {
+ return m_sampleQueue.empty() && m_readerState == ReaderState::EndOfStream;
+ }
+
+ private:
+ static com_ptr ConfigureStreams(com_ptr const& reader, WAVEFORMATEX* wfx);
+ static com_ptr CreateAudioType(WAVEFORMATEX* wfx);
+ void AddSamplesToQueue(IMFSample* MFSample);
+ bool IsPreRollFilled();
+
+ private:
+ uint32_t m_bytesPerPeriod;
+ uint32_t m_bytesPerSecond = 0;
+ bool m_isInitialized = false;
+
+ com_ptr m_sourceReader;
+ com_ptr m_audioMediaType;
+ ReaderState m_readerState = ReaderState::Stopped;
+
+ std::forward_list m_sampleQueue;
+ std::forward_list::iterator m_sampleQueueTail = m_sampleQueue.before_begin();
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Package.appxmanifest b/Samples/WindowsAudioSession/cppwinrt/Package.appxmanifest
new file mode 100644
index 0000000000..00e06b7923
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Package.appxmanifest
@@ -0,0 +1,32 @@
+
+
+
+
+
+ Windows Audio Session C++/WinRT Sample
+ Microsoft Corporation
+ Assets\StoreLogo-sdk.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/WindowsAudioSession/cppwinrt/PlotData.h b/Samples/WindowsAudioSession/cppwinrt/PlotData.h
new file mode 100644
index 0000000000..d7bc12527e
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/PlotData.h
@@ -0,0 +1,47 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "PlotDataReadyEventArgs.g.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ // Class for PlotDataReady events
+ struct PlotDataReadyEventArgs : PlotDataReadyEventArgsT
+ {
+ PlotDataReadyEventArgs(Windows::Storage::Streams::IBuffer const& buffer) : m_buffer(buffer) {}
+
+ auto Points() { return m_buffer; }
+
+ private:
+ Windows::Storage::Streams::IBuffer const m_buffer;
+ };
+
+ template
+ struct PlotDataSourceT
+ {
+ event_token PlotDataReady(Windows::Foundation::TypedEventHandler const& handler)
+ {
+ return m_plotDataReady.add(handler);
+ }
+ void PlotDataReady(event_token token)
+ {
+ return m_plotDataReady.remove(token);
+ }
+
+ protected:
+ event> m_plotDataReady;
+
+ void ReportPlotDataReady(Windows::Storage::Streams::IBuffer const& buffer)
+ {
+ m_plotDataReady(*static_cast(this), make(buffer));
+ }
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Project.idl b/Samples/WindowsAudioSession/cppwinrt/Project.idl
new file mode 100644
index 0000000000..985bc7bef7
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Project.idl
@@ -0,0 +1,80 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+namespace SDKTemplate
+{
+ [default_interface]
+ runtimeclass Scenario1 : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario1();
+ }
+
+ [default_interface]
+ runtimeclass Scenario2 : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario2();
+ }
+
+ [default_interface]
+ runtimeclass Scenario3 : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario3();
+ }
+
+ [default_interface]
+ runtimeclass Scenario4 : Windows.UI.Xaml.Controls.Page
+ {
+ Scenario4();
+ }
+
+ // NB: All states >= Initialized will allow some methods
+ // to be called successfully on the Audio Client
+ enum DeviceState
+ {
+ Uninitialized,
+ Error,
+ Discontinuity,
+ Flushing,
+ Activated,
+
+ Initialized,
+ Starting,
+ Playing,
+ Capturing,
+ Pausing,
+ Paused,
+ Stopping,
+ Stopped,
+ };
+
+ runtimeclass DeviceStateChangedEventArgs
+ {
+ DeviceState DeviceState { get; };
+ HRESULT ExtendedError{ get; };
+ }
+
+ interface IDeviceStateSource
+ {
+ DeviceState DeviceState { get; };
+ event Windows.Foundation.TypedEventHandler DeviceStateChanged;
+ }
+
+ runtimeclass PlotDataReadyEventArgs
+ {
+ // Buffer of int16_t data values.
+ Windows.Storage.Streams.IBuffer Points {get; };
+ }
+
+ interface IPlotDataSource
+ {
+ event Windows.Foundation.TypedEventHandler PlotDataReady;
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/SampleConfiguration.cpp b/Samples/WindowsAudioSession/cppwinrt/SampleConfiguration.cpp
new file mode 100644
index 0000000000..5335e0c127
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/SampleConfiguration.cpp
@@ -0,0 +1,32 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include
+#include "MainPage.h"
+#include "SampleConfiguration.h"
+
+using namespace winrt;
+using namespace winrt::SDKTemplate;
+using namespace winrt::Windows::Foundation::Collections;
+
+hstring implementation::MainPage::FEATURE_NAME()
+{
+ return L"Windows Audio Session API (WASAPI) Sample";
+}
+
+IVector implementation::MainPage::scenariosInner = winrt::single_threaded_observable_vector(
+{
+ Scenario{ L"Device Enumeration", xaml_typename () },
+ Scenario{ L"Audio Rendering with Hardware Offload", xaml_typename() },
+ Scenario{ L"Audio Rendering with Low Latency", xaml_typename() },
+ Scenario{ L"PCM Audio Capture", xaml_typename() },
+});
diff --git a/Samples/WindowsAudioSession/cppwinrt/SampleConfiguration.h b/Samples/WindowsAudioSession/cppwinrt/SampleConfiguration.h
new file mode 100644
index 0000000000..ba0eb7c8c2
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/SampleConfiguration.h
@@ -0,0 +1,17 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// This code is licensed under the MIT License (MIT).
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "pch.h"
+
+namespace winrt::SDKTemplate
+{
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario1.cpp b/Samples/WindowsAudioSession/cppwinrt/Scenario1.cpp
new file mode 100644
index 0000000000..9685efe039
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario1.cpp
@@ -0,0 +1,67 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario1.h"
+#include "Scenario1.g.cpp"
+
+using namespace winrt;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Devices::Enumeration;
+using namespace winrt::Windows::Media::Devices;
+using namespace winrt::Windows::UI::Core;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Controls;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario1::Scenario1()
+ {
+ InitializeComponent();
+ }
+
+ fire_and_forget Scenario1::Enumerate_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ DevicesList().Items().Clear();
+
+ // Get the string identifier of the audio renderer
+ hstring AudioSelector = MediaDevice::GetAudioRenderSelector();
+
+ // Custom properties defined in mmdeviceapi.h in the format "{GUID} PID"
+ constexpr wchar_t PKEY_AudioEndpoint_Supports_EventDriven_Mode[] = L"{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 7";
+
+ // Add custom properties to the query
+ DeviceInformationCollection deviceInfoCollection = co_await DeviceInformation::FindAllAsync(AudioSelector, { PKEY_AudioEndpoint_Supports_EventDriven_Mode });
+ try
+ {
+ // Enumerate through the devices and the custom properties
+ for (DeviceInformation&& deviceInfo : deviceInfoCollection)
+ {
+ hstring deviceInfoString = deviceInfo.Name();
+
+ // Pull out the custom property
+ std::optional supportsEventDriven = deviceInfo.Properties().TryLookup(PKEY_AudioEndpoint_Supports_EventDriven_Mode).try_as();
+ if (supportsEventDriven)
+ {
+ deviceInfoString = deviceInfoString + L" --> EventDriven(" + to_hstring(supportsEventDriven.value()) + L")";
+ }
+
+ DevicesList().Items().Append(box_value(deviceInfoString));
+ }
+ rootPage.NotifyUser(L"Enumerated " + to_hstring(deviceInfoCollection.Size()) + L" device(s).", NotifyType::StatusMessage);
+ }
+ catch (...)
+ {
+ rootPage.NotifyUser(to_message(), NotifyType::ErrorMessage);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario1.h b/Samples/WindowsAudioSession/cppwinrt/Scenario1.h
new file mode 100644
index 0000000000..7c58291100
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario1.h
@@ -0,0 +1,34 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#include "Scenario1.g.h"
+#include "MainPage.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario1 : Scenario1T
+ {
+ Scenario1();
+
+ fire_and_forget Enumerate_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+
+ private:
+ SDKTemplate::MainPage rootPage{ MainPage::Current() };
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario1 : Scenario1T
+ {
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario1.xaml b/Samples/WindowsAudioSession/cppwinrt/Scenario1.xaml
new file mode 100644
index 0000000000..636963a662
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario1.xaml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This scenario demonstrates how to enumerate the audio devices attached to the system as well as retrieve additional properties.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario2.cpp b/Samples/WindowsAudioSession/cppwinrt/Scenario2.cpp
new file mode 100644
index 0000000000..0ab0365491
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario2.cpp
@@ -0,0 +1,480 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario2.h"
+#include "Scenario2.g.cpp"
+
+using namespace winrt;
+using namespace winrt::Windows::Devices::Enumeration;
+using namespace winrt::Windows::Media;
+using namespace winrt::Windows::Media::Devices;
+using namespace winrt::Windows::Storage;
+using namespace winrt::Windows::Storage::Pickers;
+using namespace winrt::Windows::Storage::Streams;
+using namespace winrt::Windows::UI;
+using namespace winrt::Windows::UI::Xaml::Controls::Primitives;
+using namespace winrt::Windows::UI::Xaml::Media;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario2::Scenario2()
+ {
+ InitializeComponent();
+ }
+
+ fire_and_forget Scenario2::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ // Register for Media Transport controls. This is required to support background
+ // audio scenarios.
+ m_systemMediaControls = SystemMediaTransportControls::GetForCurrentView();
+ m_systemMediaControlsButtonToken = m_systemMediaControls.ButtonPressed({ get_weak(), &Scenario2::MediaButtonPressed });
+ m_systemMediaControls.IsPlayEnabled(true);
+ m_systemMediaControls.IsPauseEnabled(true);
+ m_systemMediaControls.IsStopEnabled(true);
+
+ UpdateContentUI();
+
+ // Get a string representing the Default Audio Render Device
+ hstring deviceId = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
+
+ // The string is empty if there is no such device.
+ if (deviceId.empty())
+ {
+ rootPage.NotifyUser(L"No audio devices available", NotifyType::StatusMessage);
+ co_return;
+ }
+
+ // read property store to see if the device supports a RAW processing mode
+ static constexpr wchar_t PKEY_AudioDevice_RawProcessingSupported[] = L"System.Devices.AudioDevice.RawProcessingSupported";
+ DeviceInformation deviceInformation = co_await DeviceInformation::CreateFromIdAsync(deviceId, { PKEY_AudioDevice_RawProcessingSupported });
+
+ std::optional obj = deviceInformation.Properties().TryLookup(PKEY_AudioDevice_RawProcessingSupported).try_as();
+ m_deviceSupportsRawMode = (obj == true);
+ toggleRawAudio().IsEnabled(m_deviceSupportsRawMode);
+
+ if (m_deviceSupportsRawMode)
+ {
+ rootPage.NotifyUser(L"Raw Supported", NotifyType::StatusMessage);
+ }
+ else
+ {
+ rootPage.NotifyUser(L"Raw Not Supported", NotifyType::StatusMessage);
+ }
+ }
+
+ void Scenario2::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ StopDevice();
+
+ if (m_deviceStateChangeToken)
+ {
+ m_renderer->DeviceStateChanged(std::exchange(m_deviceStateChangeToken, {}));
+ }
+
+ if (m_systemMediaControlsButtonToken)
+ {
+ m_systemMediaControls.ButtonPressed(m_systemMediaControlsButtonToken);
+ m_systemMediaControls.IsPlayEnabled(false);
+ m_systemMediaControls.IsPauseEnabled(false);
+ m_systemMediaControls.IsStopEnabled(false);
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Closed);
+ }
+ }
+
+#pragma region UI Related Code
+
+ void Scenario2::DisableContentUI()
+ {
+ btnFilePicker().IsEnabled(false);
+ sliderFrequency().IsEnabled(false);
+ radioFile().IsEnabled(false);
+ radioTone().IsEnabled(false);
+ }
+
+ // Updates content controls based on selected option
+ void Scenario2::UpdateContentUI()
+ {
+ // Ignore calls triggered by binding before construction is complete.
+ if (radioFile() == nullptr)
+ {
+ return;
+ }
+
+ radioFile().IsEnabled(true);
+ radioTone().IsEnabled(true);
+
+ switch (m_contentType)
+ {
+ case ContentType::Tone:
+ btnFilePicker().IsEnabled(false);
+ sliderFrequency().IsEnabled(true);
+ UpdateContentProps(to_hstring(sliderFrequency().Value()) + L" Hz");
+ break;
+
+ case ContentType::File:
+ btnFilePicker().IsEnabled(true);
+ sliderFrequency().IsEnabled(false);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Updates transport controls based on current playstate
+ void Scenario2::UpdateMediaControlUI(DeviceState deviceState)
+ {
+ switch (deviceState)
+ {
+ case DeviceState::Playing:
+ btnPlay().IsEnabled(false);
+ btnStop().IsEnabled(true);
+ btnPlayPause().IsEnabled(true);
+ btnPause().IsEnabled(true);
+ break;
+
+ case DeviceState::Stopped:
+ case DeviceState::Error:
+ btnPlay().IsEnabled(true);
+ btnStop().IsEnabled(false);
+ btnPlayPause().IsEnabled(true);
+ btnPause().IsEnabled(false);
+
+ UpdateContentUI();
+ break;
+
+ case DeviceState::Paused:
+ btnPlay().IsEnabled(true);
+ btnStop().IsEnabled(true);
+ btnPlayPause().IsEnabled(true);
+ btnPause().IsEnabled(false);
+ break;
+
+ case DeviceState::Starting:
+ case DeviceState::Stopping:
+ btnPlay().IsEnabled(false);
+ btnStop().IsEnabled(false);
+ btnPlayPause().IsEnabled(false);
+ btnPause().IsEnabled(false);
+
+ DisableContentUI();
+ break;
+ }
+ }
+
+ // Updates textbox
+ void Scenario2::UpdateContentProps(hstring const& text)
+ {
+ // Ignore calls triggered by binding before construction is complete.
+ if (txtContentProps() == nullptr)
+ {
+ return;
+ }
+
+ txtContentProps().Text(text);
+
+ if (text.empty() && (m_contentType == ContentType::File))
+ {
+ txtContentProps().Background(SolidColorBrush({ 0xCC, 0xFF, 0x00, 0x00 }));
+ }
+ else
+ {
+ txtContentProps().Background(nullptr);
+ }
+ }
+
+#pragma endregion
+
+#pragma region UI Event Handlers
+
+ void Scenario2::sliderFrequency_ValueChanged(IInspectable const&, RangeBaseValueChangedEventArgs const& e)
+ {
+ UpdateContentProps(to_hstring(e.NewValue()) + L" Hz");
+ }
+
+ void Scenario2::sliderVolume_ValueChanged(IInspectable const&, RangeBaseValueChangedEventArgs const& e)
+ {
+ OnSetVolume(e.NewValue());
+ }
+
+ void Scenario2::radioTone_Checked(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ m_contentType = ContentType::Tone;
+ UpdateContentProps(L"");
+ m_contentStream = nullptr;
+ UpdateContentUI();
+ }
+
+ void Scenario2::radioFile_Checked(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ m_contentType = ContentType::File;
+ UpdateContentProps(L"");
+ m_contentStream = nullptr;
+ UpdateContentUI();
+ }
+
+ void Scenario2::btnPlay_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ StartDevice();
+ }
+
+ void Scenario2::btnPause_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ PauseDevice();
+ }
+
+ void Scenario2::btnPlayPause_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ PlayPauseToggleDevice();
+ }
+
+ void Scenario2::btnStop_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ StopDevice();
+ }
+
+ void Scenario2::btnFilePicker_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ OnPickFileAsync();
+ }
+
+#pragma endregion
+
+ // Event callback from WASAPI renderer for changes in device state
+ fire_and_forget Scenario2::OnDeviceStateChange(IDeviceStateSource const&, SDKTemplate::DeviceStateChangedEventArgs e)
+ {
+ auto lifetime = get_strong();
+
+ // Handle state specific messages
+ switch (e.DeviceState())
+ {
+ case DeviceState::Initialized:
+ StartDevice();
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Closed);
+ break;
+
+ case DeviceState::Playing:
+ rootPage.NotifyUser(L"Playback Started", NotifyType::StatusMessage);
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Playing);
+ break;
+
+ case DeviceState::Paused:
+ rootPage.NotifyUser(L"Playback Paused", NotifyType::StatusMessage);
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Paused);
+ break;
+
+ case DeviceState::Stopped:
+ if (m_deviceStateChangeToken)
+ {
+ m_renderer->DeviceStateChanged(std::exchange(m_deviceStateChangeToken, {}));
+ }
+ m_renderer = nullptr;
+
+ rootPage.NotifyUser(L"Playback Stopped", NotifyType::StatusMessage);
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Stopped);
+ break;
+
+ case DeviceState::Error:
+ if (m_deviceStateChangeToken)
+ {
+ m_renderer->DeviceStateChanged(std::exchange(m_deviceStateChangeToken, {}));
+ }
+ m_renderer = nullptr;
+
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Closed);
+
+ // Specifically handle a couple of known errors
+ auto error = e.ExtendedError();
+ switch (error)
+ {
+ case AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE:
+ rootPage.NotifyUser(L"ERROR: Endpoint Does Not Support HW Offload", NotifyType::ErrorMessage);
+ break;
+
+ case AUDCLNT_E_RESOURCES_INVALIDATED:
+ rootPage.NotifyUser(L"ERROR: Endpoint Lost Access To Resources", NotifyType::ErrorMessage);
+ break;
+
+ default:
+ rootPage.NotifyUser(L"ERROR: " + hresult_error(error).message(), NotifyType::ErrorMessage);
+ break;
+ }
+ }
+
+ // Update Control Buttons
+ co_await resume_foreground(Dispatcher());
+ UpdateMediaControlUI(e.DeviceState());
+ }
+
+ //
+ // OnPickFileAsync()
+ //
+ // File chooser for MF Source playback. Retrieves a pointer to IRandomAccessStream
+ //
+ fire_and_forget Scenario2::OnPickFileAsync()
+ {
+ auto lifetime = get_strong();
+ FileOpenPicker filePicker;
+ filePicker.ViewMode(PickerViewMode::List);
+ filePicker.SuggestedStartLocation(PickerLocationId::MusicLibrary);
+ filePicker.FileTypeFilter().ReplaceAll({ L".wav", L".mp3", L".wma" });
+
+ StorageFile file = co_await filePicker.PickSingleFileAsync();
+ if (file != nullptr)
+ {
+ // Open the stream
+ IRandomAccessStream stream = co_await file.OpenAsync(FileAccessMode::Read);
+ if (stream != nullptr)
+ {
+ m_contentStream = stream;
+ UpdateContentProps(file.Path());
+ }
+ }
+ }
+
+ //
+ // OnSetVolume()
+ //
+ // Updates the session volume
+ //
+ void Scenario2::OnSetVolume(double volume)
+ {
+ if (m_renderer)
+ {
+ // Updates the Session volume on the AudioClient
+ m_renderer->SetVolumeOnSession(volume);
+ }
+ }
+
+ //
+ // InitializeDevice()
+ //
+ // Sets up a new instance of the WASAPI renderer
+ //
+ void Scenario2::InitializeDevice()
+ {
+ if (m_renderer)
+ {
+ // Already initialized.
+ return;
+ }
+
+ // Create a new WASAPI instance
+ m_renderer = make_self();
+
+ // Register for events
+ m_deviceStateChangeToken = m_renderer->DeviceStateChanged({ get_weak(), &Scenario2::OnDeviceStateChange });
+
+ // Configure user based properties
+
+ m_renderer->SetContentType(m_contentType);
+ m_renderer->SetFrequency(sliderFrequency().Value());
+ m_renderer->SetContentStream(m_contentStream);
+ m_renderer->SetHWOffload(toggleHWOffload().IsOn());
+ m_renderer->SetBackgroundAudio(toggleBackgroundAudio().IsOn());
+ m_renderer->SetRawAudio(m_deviceSupportsRawMode && toggleRawAudio().IsOn());
+
+ int BufferSize = 0;
+ swscanf_s(txtHWBuffer().Text().c_str(), L"%d", &BufferSize);
+ m_renderer->SetBufferDuration(static_cast(BufferSize));
+
+ // Selects the Default Audio Device
+ m_renderer->AsyncInitializeAudioDevice();
+
+ // Set the initial volume.
+ OnSetVolume(sliderVolume().Value());
+ }
+
+ void Scenario2::StartDevice()
+ {
+ if (m_renderer == nullptr)
+ {
+ // Call from main UI thread
+ InitializeDevice();
+ }
+ else
+ {
+ // Starts a work item to begin playback, likely in the paused state
+ m_renderer->StartPlayback();
+ }
+ }
+
+ void Scenario2::StopDevice()
+ {
+ if (m_renderer)
+ {
+ // Set the event to stop playback
+ m_renderer->StopPlaybackAsync();
+ }
+ }
+
+ void Scenario2::PauseDevice()
+ {
+ if (m_renderer)
+ {
+ if (m_renderer->DeviceState() == DeviceState::Playing)
+ {
+ // Starts a work item to pause playback
+ m_renderer->PausePlaybackAsync();
+ }
+ }
+ }
+
+ void Scenario2::PlayPauseToggleDevice()
+ {
+ if (m_renderer)
+ {
+ DeviceState deviceState = m_renderer->DeviceState();
+
+ if (deviceState == DeviceState::Playing)
+ {
+ // Starts a work item to pause playback
+ m_renderer->PausePlaybackAsync();
+ }
+ else if (deviceState == DeviceState::Paused)
+ {
+ // Starts a work item to pause playback
+ m_renderer->StartPlayback();
+ }
+ }
+ else
+ {
+ StartDevice();
+ }
+ }
+
+ fire_and_forget Scenario2::MediaButtonPressed(SystemMediaTransportControls const&, SystemMediaTransportControlsButtonPressedEventArgs e)
+ {
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ switch (e.Button())
+ {
+ case SystemMediaTransportControlsButton::Play:
+ StartDevice();
+ break;
+
+ case SystemMediaTransportControlsButton::Pause:
+ PauseDevice();
+ break;
+
+ case SystemMediaTransportControlsButton::Stop:
+ StopDevice();
+ break;
+
+ default:
+ break;
+ }
+ }
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario2.h b/Samples/WindowsAudioSession/cppwinrt/Scenario2.h
new file mode 100644
index 0000000000..48bec2fb4d
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario2.h
@@ -0,0 +1,74 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "Scenario2.g.h"
+#include "WASAPIRenderer.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario2 : Scenario2T, MediaFoundationInitializer
+ {
+ Scenario2();
+
+ // Navigation handlers
+ fire_and_forget OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+
+ // UI Events
+ void btnPlay_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnPause_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnPlayPause_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnStop_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnFilePicker_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void radioTone_Checked(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void radioFile_Checked(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void sliderFrequency_ValueChanged(IInspectable const& sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e);
+ void sliderVolume_ValueChanged(IInspectable const& sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e);
+
+ // UI Helpers
+ void UpdateContentProps(hstring const& text);
+ void DisableContentUI();
+ void UpdateContentUI();
+ void UpdateMediaControlUI(DeviceState deviceState);
+
+ // Handlers
+ fire_and_forget OnDeviceStateChange(IDeviceStateSource const& sender, SDKTemplate::DeviceStateChangedEventArgs e);
+ fire_and_forget OnPickFileAsync();
+ void OnSetVolume(double volume);
+
+ void InitializeDevice();
+ void StartDevice();
+ void StopDevice();
+ void PauseDevice();
+ void PlayPauseToggleDevice();
+
+ fire_and_forget MediaButtonPressed(Windows::Media::SystemMediaTransportControls const& sender, Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs e);
+
+ private:
+ SDKTemplate::MainPage rootPage{ MainPage::Current() };
+ Windows::Media::SystemMediaTransportControls m_systemMediaControls{ nullptr };
+ event_token m_deviceStateChangeToken;
+ event_token m_systemMediaControlsButtonToken;
+
+ bool m_deviceSupportsRawMode = false;
+
+ Windows::Storage::Streams::IRandomAccessStream m_contentStream{ nullptr };
+ ContentType m_contentType = ContentType::Tone;
+ com_ptr m_renderer;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario2 : Scenario2T
+ {
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario2.xaml b/Samples/WindowsAudioSession/cppwinrt/Scenario2.xaml
new file mode 100644
index 0000000000..c94b32a3c7
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario2.xaml
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This scenario demonstrates how to opt-in to hardware offloading in addition to setting some related parameters
+ on the audio endpoint. It also demonstrates implementing the basic media transport controls.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario3.cpp b/Samples/WindowsAudioSession/cppwinrt/Scenario3.cpp
new file mode 100644
index 0000000000..b4dac515b8
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario3.cpp
@@ -0,0 +1,491 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario3.h"
+#include "Scenario3.g.cpp"
+
+using namespace winrt;
+using namespace winrt::Windows::Devices::Enumeration;
+using namespace winrt::Windows::Media;
+using namespace winrt::Windows::Media::Devices;
+using namespace winrt::Windows::Storage;
+using namespace winrt::Windows::Storage::Pickers;
+using namespace winrt::Windows::Storage::Streams;
+using namespace winrt::Windows::UI::Xaml::Controls::Primitives;
+using namespace winrt::Windows::UI::Xaml::Media;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ Scenario3::Scenario3()
+ {
+ InitializeComponent();
+ }
+
+ fire_and_forget Scenario3::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ auto lifetime = get_strong();
+
+ // Register for Media Transport controls. This is required to support background
+ // audio scenarios.
+ m_systemMediaControls = SystemMediaTransportControls::GetForCurrentView();
+ m_systemMediaControlsButtonToken = m_systemMediaControls.ButtonPressed({ get_weak(), &Scenario3::MediaButtonPressed });
+ m_systemMediaControls.IsPlayEnabled(true);
+ m_systemMediaControls.IsPauseEnabled(true);
+ m_systemMediaControls.IsStopEnabled(true);
+
+ UpdateContentUI();
+
+ // Get a string representing the Default Audio Render Device
+ hstring deviceId = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
+
+ // The string is empty if there is no such device.
+ if (deviceId.empty())
+ {
+ rootPage.NotifyUser(L"No audio devices available", NotifyType::StatusMessage);
+ co_return;
+ }
+
+ // read property store to see if the device supports a RAW processing mode
+ static constexpr wchar_t PKEY_AudioDevice_RawProcessingSupported[] = L"System.Devices.AudioDevice.RawProcessingSupported";
+ DeviceInformation deviceInformation = co_await DeviceInformation::CreateFromIdAsync(deviceId, { PKEY_AudioDevice_RawProcessingSupported });
+
+ std::optional obj = deviceInformation.Properties().TryLookup(PKEY_AudioDevice_RawProcessingSupported).try_as();
+ m_deviceSupportsRawMode = (obj == true);
+ toggleRawAudio().IsEnabled(m_deviceSupportsRawMode);
+
+ if (m_deviceSupportsRawMode)
+ {
+ rootPage.NotifyUser(L"Raw Supported", NotifyType::StatusMessage);
+ }
+ else
+ {
+ rootPage.NotifyUser(L"Raw Not Supported", NotifyType::StatusMessage);
+ }
+ }
+
+ void Scenario3::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ StopDevice();
+
+ if (m_deviceStateChangeToken)
+ {
+ m_renderer->DeviceStateChanged(std::exchange(m_deviceStateChangeToken, {}));
+ }
+
+ if (m_systemMediaControlsButtonToken)
+ {
+ m_systemMediaControls.ButtonPressed(m_systemMediaControlsButtonToken);
+ m_systemMediaControls.IsPlayEnabled(false);
+ m_systemMediaControls.IsPauseEnabled(false);
+ m_systemMediaControls.IsStopEnabled(false);
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Closed);
+ }
+ }
+
+#pragma region UI Related Code
+
+ void Scenario3::DisableContentUI()
+ {
+ btnFilePicker().IsEnabled(false);
+ sliderFrequency().IsEnabled(false);
+ radioFile().IsEnabled(false);
+ radioTone().IsEnabled(false);
+ }
+
+ // Updates content controls based on selected option
+ void Scenario3::UpdateContentUI()
+ {
+ // Ignore calls triggered by binding before construction is complete.
+ if (radioFile() == nullptr)
+ {
+ return;
+ }
+
+ radioFile().IsEnabled(true);
+ radioTone().IsEnabled(true);
+
+ switch (m_contentType)
+ {
+ case ContentType::Tone:
+ btnFilePicker().IsEnabled(false);
+ sliderFrequency().IsEnabled(true);
+ UpdateContentProps(to_hstring(sliderFrequency().Value()) + L" Hz");
+ break;
+
+ case ContentType::File:
+ btnFilePicker().IsEnabled(true);
+ sliderFrequency().IsEnabled(false);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Updates transport controls based on current playstate
+ void Scenario3::UpdateMediaControlUI(DeviceState deviceState)
+ {
+ switch (deviceState)
+ {
+ case DeviceState::Playing:
+ btnPlay().IsEnabled(false);
+ btnStop().IsEnabled(true);
+ btnPlayPause().IsEnabled(true);
+ btnPause().IsEnabled(true);
+ toggleMinimumLatency().IsEnabled(false);
+ break;
+
+ case DeviceState::Stopped:
+ case DeviceState::Error:
+ btnPlay().IsEnabled(true);
+ btnStop().IsEnabled(false);
+ btnPlayPause().IsEnabled(true);
+ btnPause().IsEnabled(false);
+ toggleMinimumLatency().IsEnabled(true);
+
+ UpdateContentUI();
+ break;
+
+ case DeviceState::Paused:
+ btnPlay().IsEnabled(true);
+ btnStop().IsEnabled(true);
+ btnPlayPause().IsEnabled(true);
+ btnPause().IsEnabled(false);
+ break;
+
+ case DeviceState::Starting:
+ case DeviceState::Stopping:
+ btnPlay().IsEnabled(false);
+ btnStop().IsEnabled(false);
+ btnPlayPause().IsEnabled(false);
+ btnPause().IsEnabled(false);
+
+ DisableContentUI();
+ break;
+ }
+ }
+
+ // Updates textbox
+ void Scenario3::UpdateContentProps(hstring const& text)
+ {
+ // Ignore calls triggered by binding before construction is complete.
+ if (txtContentProps() == nullptr)
+ {
+ return;
+ }
+
+ txtContentProps().Text(text);
+
+ if (text.empty() && (m_contentType == ContentType::File))
+ {
+ txtContentProps().Background(SolidColorBrush({ 0xCC, 0xFF, 0x00, 0x00 }));
+ }
+ else
+ {
+ txtContentProps().Background(nullptr);
+ }
+ }
+
+#pragma endregion
+
+#pragma region UI Event Handlers
+ void Scenario3::sliderFrequency_ValueChanged(IInspectable const&, RangeBaseValueChangedEventArgs const& e)
+ {
+ UpdateContentProps(to_hstring(e.NewValue()) + L" Hz");
+ }
+
+ void Scenario3::sliderVolume_ValueChanged(IInspectable const&, RangeBaseValueChangedEventArgs const& e)
+ {
+ OnSetVolume(e.NewValue());
+ }
+
+ void Scenario3::radioTone_Checked(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ m_contentType = ContentType::Tone;
+ UpdateContentProps(L"");
+ m_contentStream = nullptr;
+ UpdateContentUI();
+ }
+
+ void Scenario3::radioFile_Checked(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ m_contentType = ContentType::File;
+ UpdateContentProps(L"");
+ m_contentStream = nullptr;
+ UpdateContentUI();
+ }
+
+ void Scenario3::btnPlay_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ StartDevice();
+ }
+
+ void Scenario3::btnPause_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ PauseDevice();
+ }
+
+ void Scenario3::btnPlayPause_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ PlayPauseToggleDevice();
+ }
+
+ void Scenario3::btnStop_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ StopDevice();
+ }
+
+ void Scenario3::btnFilePicker_Click(IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&)
+ {
+ OnPickFileAsync();
+ }
+
+#pragma endregion
+
+ // Event callback from WASAPI renderer for changes in device state
+ fire_and_forget Scenario3::OnDeviceStateChange(IDeviceStateSource const&, SDKTemplate::DeviceStateChangedEventArgs e)
+ {
+ auto lifetime = get_strong();
+
+ // Handle state specific messages
+ switch (e.DeviceState())
+ {
+ case DeviceState::Initialized:
+ StartDevice();
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Closed);
+ break;
+
+ case DeviceState::Playing:
+ if (m_isMinimumLatency == true)
+ {
+ rootPage.NotifyUser(L"Playback Started (minimum latency)", NotifyType::StatusMessage);
+ }
+ else
+ {
+ rootPage.NotifyUser(L"Playback Started (normal latency)", NotifyType::StatusMessage);
+ }
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Playing);
+ break;
+
+ case DeviceState::Paused:
+ rootPage.NotifyUser(L"Playback Paused", NotifyType::StatusMessage);
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Paused);
+ break;
+
+ case DeviceState::Stopped:
+ if (m_deviceStateChangeToken)
+ {
+ m_renderer->DeviceStateChanged(std::exchange(m_deviceStateChangeToken, {}));
+ }
+ m_renderer = nullptr;
+
+ rootPage.NotifyUser(L"Playback Stopped", NotifyType::StatusMessage);
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Stopped);
+ break;
+
+ case DeviceState::Error:
+ if (m_deviceStateChangeToken)
+ {
+ m_renderer->DeviceStateChanged(std::exchange(m_deviceStateChangeToken, {}));
+ }
+ m_renderer = nullptr;
+
+ m_systemMediaControls.PlaybackStatus(MediaPlaybackStatus::Closed);
+
+ // Specifically handle a couple of known errors
+ auto error = e.ExtendedError();
+ switch (error)
+ {
+ case AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE:
+ rootPage.NotifyUser(L"ERROR: Endpoint Does Not Support HW Offload", NotifyType::ErrorMessage);
+ break;
+
+ case AUDCLNT_E_RESOURCES_INVALIDATED:
+ rootPage.NotifyUser(L"ERROR: Endpoint Lost Access To Resources", NotifyType::ErrorMessage);
+ break;
+
+ default:
+ rootPage.NotifyUser(L"ERROR: " + hresult_error(error).message(), NotifyType::ErrorMessage);
+ break;
+ }
+ }
+
+ // Update Control Buttons
+ co_await resume_foreground(Dispatcher());
+ UpdateMediaControlUI(e.DeviceState());
+ }
+
+ //
+ // OnPickFileAsync()
+ //
+ // File chooser for MF Source playback. Retrieves a pointer to IRandomAccessStream
+ //
+ fire_and_forget Scenario3::OnPickFileAsync()
+ {
+ auto lifetime = get_strong();
+ FileOpenPicker filePicker;
+ filePicker.ViewMode(PickerViewMode::List);
+ filePicker.SuggestedStartLocation(PickerLocationId::MusicLibrary);
+ filePicker.FileTypeFilter().ReplaceAll({ L".wav", L".mp3", L".wma" });
+
+ StorageFile file = co_await filePicker.PickSingleFileAsync();
+ if (file != nullptr)
+ {
+ // Open the stream
+ IRandomAccessStream stream = co_await file.OpenAsync(FileAccessMode::Read);
+ if (stream != nullptr)
+ {
+ m_contentStream = stream;
+ UpdateContentProps(file.Path());
+ }
+ }
+ }
+
+ //
+ // OnSetVolume()
+ //
+ // Updates the session volume
+ //
+ void Scenario3::OnSetVolume(double volume)
+ {
+ if (m_renderer)
+ {
+ // Updates the Session volume on the AudioClient
+ m_renderer->SetVolumeOnSession(volume);
+ }
+ }
+
+ //
+ // InitializeDevice()
+ //
+ // Sets up a new instance of the WASAPI renderer
+ //
+ void Scenario3::InitializeDevice()
+ {
+ if (m_renderer)
+ {
+ // Already initialized.
+ return;
+ }
+
+ // Create a new WASAPI instance
+ m_renderer = make_self();
+
+ // Register for events
+ m_deviceStateChangeToken = m_renderer->DeviceStateChanged({ get_weak(), &Scenario3::OnDeviceStateChange });
+
+ // Configure user based properties
+ m_renderer->SetContentType(m_contentType);
+ m_renderer->SetFrequency(sliderFrequency().Value());
+ m_renderer->SetContentStream(m_contentStream);
+
+ m_isMinimumLatency = toggleMinimumLatency().IsOn();
+ m_renderer->SetLowLatency(m_isMinimumLatency);
+ m_renderer->SetHWOffload(false);
+ m_renderer->SetBackgroundAudio(false);
+ m_renderer->SetRawAudio(m_deviceSupportsRawMode && toggleRawAudio().IsOn());
+
+ // Selects the Default Audio Device
+ m_renderer->AsyncInitializeAudioDevice();
+
+ // Set the initial volume.
+ OnSetVolume(sliderVolume().Value());
+ }
+
+ void Scenario3::StartDevice()
+ {
+ if (m_renderer == nullptr)
+ {
+ // Call from main UI thread
+ InitializeDevice();
+ }
+ else
+ {
+ // Starts a work item to begin playback, likely in the paused state
+ m_renderer->StartPlayback();
+ }
+ }
+
+ void Scenario3::StopDevice()
+ {
+ if (m_renderer)
+ {
+ // Set the event to stop playback
+ m_renderer->StopPlaybackAsync();
+ }
+ }
+
+ void Scenario3::PauseDevice()
+ {
+ if (m_renderer)
+ {
+ if (m_renderer->DeviceState() == DeviceState::Playing)
+ {
+ // Starts a work item to pause playback
+ m_renderer->PausePlaybackAsync();
+ }
+ }
+ }
+
+ //
+ // PlayPauseToggleDevice()
+ //
+ void Scenario3::PlayPauseToggleDevice()
+ {
+ if (m_renderer)
+ {
+ DeviceState deviceState = m_renderer->DeviceState();
+
+ if (deviceState == DeviceState::Playing)
+ {
+ // Starts a work item to pause playback
+ m_renderer->PausePlaybackAsync();
+ }
+ else if (deviceState == DeviceState::Paused)
+ {
+ // Starts a work item to pause playback
+ m_renderer->StartPlayback();
+ }
+ }
+ else
+ {
+ StartDevice();
+ }
+ }
+
+ //
+ // MediaButtonPressed
+ //
+ fire_and_forget Scenario3::MediaButtonPressed(SystemMediaTransportControls const&, SystemMediaTransportControlsButtonPressedEventArgs e)
+ {
+ auto lifetime = get_strong();
+ co_await resume_foreground(Dispatcher());
+
+ switch (e.Button())
+ {
+ case SystemMediaTransportControlsButton::Play:
+ StartDevice();
+ break;
+
+ case SystemMediaTransportControlsButton::Pause:
+ PauseDevice();
+ break;
+
+ case SystemMediaTransportControlsButton::Stop:
+ StopDevice();
+ break;
+
+ default:
+ break;
+ }
+ }
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario3.h b/Samples/WindowsAudioSession/cppwinrt/Scenario3.h
new file mode 100644
index 0000000000..f7a3820d8e
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario3.h
@@ -0,0 +1,75 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "pch.h"
+#include "Scenario3.g.h"
+#include "MainPage.h"
+#include "WASAPIRenderer.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario3 : Scenario3T, MediaFoundationInitializer
+ {
+ Scenario3();
+
+ fire_and_forget OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const& e);
+
+ void btnPlay_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnPause_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnPlayPause_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnStop_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnFilePicker_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void radioTone_Checked(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void radioFile_Checked(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void sliderFrequency_ValueChanged(IInspectable const& sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e);
+ void sliderVolume_ValueChanged(IInspectable const& sender, Windows::UI::Xaml::Controls::Primitives::RangeBaseValueChangedEventArgs const& e);
+
+ // UI Helpers
+ void DisableContentUI();
+ void UpdateContentProps(hstring const& text);
+ void UpdateContentUI();
+ void UpdateMediaControlUI(DeviceState deviceState);
+
+ // Handlers
+ fire_and_forget OnDeviceStateChange(IDeviceStateSource const& sender, SDKTemplate::DeviceStateChangedEventArgs e);
+ fire_and_forget OnPickFileAsync();
+ void OnSetVolume(double volume);
+
+ void InitializeDevice();
+ void StartDevice();
+ void StopDevice();
+ void PauseDevice();
+ void PlayPauseToggleDevice();
+
+ fire_and_forget MediaButtonPressed(Windows::Media::SystemMediaTransportControls const& sender, Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs e);
+
+ private:
+ SDKTemplate::MainPage rootPage{ MainPage::Current() };
+ Windows::Media::SystemMediaTransportControls m_systemMediaControls{ nullptr };
+ event_token m_deviceStateChangeToken;
+ event_token m_systemMediaControlsButtonToken;
+
+ bool m_deviceSupportsRawMode = false;
+ bool m_isMinimumLatency = false;
+
+ Windows::Storage::Streams::IRandomAccessStream m_contentStream{ nullptr };
+ ContentType m_contentType = ContentType::Tone;
+ com_ptr m_renderer;
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario3 : Scenario3T
+ {
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario3.xaml b/Samples/WindowsAudioSession/cppwinrt/Scenario3.xaml
new file mode 100644
index 0000000000..8638a19317
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario3.xaml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This scenario demonstrates how to opt-in to low latency in addition to setting some related parameters
+ on the audio endpoint. It also demonstrates implementing the basic media transport controls.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario4.cpp b/Samples/WindowsAudioSession/cppwinrt/Scenario4.cpp
new file mode 100644
index 0000000000..4ab21f1c2f
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario4.cpp
@@ -0,0 +1,258 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "Scenario4.h"
+#include "Scenario4.g.cpp"
+
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Storage::Streams;
+using namespace winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::UI::Xaml::Navigation;
+
+namespace winrt::SDKTemplate::implementation
+{
+ static constexpr float OSC_START_X = 100.0f;
+ static constexpr float OSC_START_Y = 100.0f;
+ static constexpr float OSC_X_LENGTH = 700.0f;
+ static constexpr float OSC_TOTAL_HEIGHT = 200.0f;
+
+ Scenario4::Scenario4()
+ {
+ InitializeComponent();
+ }
+
+ void Scenario4::OnNavigatedFrom(NavigationEventArgs const&)
+ {
+ ClearCapture();
+ }
+
+ void Scenario4::ClearCapture()
+ {
+ if (m_deviceStateChangeToken)
+ {
+ m_capture->DeviceStateChanged(std::exchange(m_deviceStateChangeToken, {}));
+ }
+
+ if (m_plotDataReadyToken)
+ {
+ m_capture->PlotDataReady(std::exchange(m_plotDataReadyToken, {}));
+ }
+
+ StopCapture();
+ m_capture = nullptr;
+ }
+
+#pragma region UI Related Code
+ // Updates transport controls based on current playstate
+ void Scenario4::UpdateMediaControlUI(DeviceState deviceState)
+ {
+ switch (deviceState)
+ {
+ case DeviceState::Capturing:
+ btnStartCapture().IsEnabled(false);
+ btnStopCapture().IsEnabled(true);
+ toggleMinimumLatency().IsEnabled(false);
+ break;
+
+ case DeviceState::Stopped:
+ btnStartCapture().IsEnabled(true);
+ btnStopCapture().IsEnabled(false);
+ toggleMinimumLatency().IsEnabled(true);
+ break;
+
+ case DeviceState::Initialized:
+ case DeviceState::Starting:
+ case DeviceState::Stopping:
+ case DeviceState::Flushing:
+ case DeviceState::Error:
+ btnStartCapture().IsEnabled(false);
+ btnStopCapture().IsEnabled(false);
+ break;
+ }
+ }
+#pragma endregion
+
+#pragma region UI Event Handlers
+ void Scenario4::btnStartCapture_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ rootPage.NotifyUser(L"", NotifyType::StatusMessage);
+ InitializeCapture();
+ }
+
+ void Scenario4::btnStopCapture_Click(IInspectable const&, RoutedEventArgs const&)
+ {
+ StopCapture();
+ }
+#pragma endregion
+
+ // Event callback from WASAPI capture for changes in device state
+ fire_and_forget Scenario4::OnDeviceStateChange(IDeviceStateSource const&, SDKTemplate::DeviceStateChangedEventArgs e)
+ {
+ auto lifetime = get_strong();
+
+ // Get the current time for messages
+ std::time_t now = clock::to_time_t(clock::now());
+ char buffer[26];
+ ctime_s(buffer, ARRAYSIZE(buffer), &now);
+
+ // Continue on UI thread.
+ co_await resume_foreground(Dispatcher());
+
+ // Update Control Buttons
+ DeviceState state = e.DeviceState();
+ UpdateMediaControlUI(state);
+
+ // Handle state specific messages
+ switch (state)
+ {
+ case DeviceState::Initialized:
+ m_capture->AsyncStartCapture();
+ break;
+
+ case DeviceState::Capturing:
+ if (m_isLowLatency)
+ {
+ rootPage.NotifyUser(L"Capture Started (minimum latency) at " + to_hstring(buffer), NotifyType::StatusMessage);
+ }
+ else
+ {
+ rootPage.NotifyUser(L"Capture Started (normal latency) at " + to_hstring(buffer), NotifyType::StatusMessage);
+ }
+ break;
+
+ case DeviceState::Discontinuity:
+ {
+ m_discontinuityCount++;
+
+ if (m_discontinuityCount > 0)
+ {
+ rootPage.NotifyUser(L"DISCONTINUITY DETECTED: " + to_hstring(buffer) + L" (Count = " + to_hstring(m_discontinuityCount) + L")", NotifyType::StatusMessage);
+ }
+ }
+ break;
+
+ case DeviceState::Flushing:
+ if (m_plotDataReadyToken)
+ {
+ m_capture->PlotDataReady(std::exchange(m_plotDataReadyToken, {}));
+ }
+
+ rootPage.NotifyUser(L"Finalizing WAV Header. This may take a few minutes...", NotifyType::StatusMessage);
+
+ Oscilloscope().Points().ReplaceAll({ { OSC_START_X, OSC_START_Y }, { OSC_X_LENGTH, OSC_START_Y } });
+ break;
+
+ case DeviceState::Stopped:
+ // For the stopped state, completely tear down the audio device
+ ClearCapture();
+
+ rootPage.NotifyUser(L"Capture Stopped", NotifyType::StatusMessage);
+ break;
+
+ case DeviceState::Error:
+ ClearCapture();
+
+ // Specifically handle a couple of known errors
+ switch (hresult error = e.ExtendedError(); error)
+ {
+ case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
+ rootPage.NotifyUser(L"ERROR: Check the Sound control panel for an active recording device.", NotifyType::ErrorMessage);
+ break;
+
+ case AUDCLNT_E_RESOURCES_INVALIDATED:
+ rootPage.NotifyUser(L"ERROR: Endpoint Lost Access To Resources", NotifyType::ErrorMessage);
+ break;
+
+ case E_ACCESSDENIED:
+ rootPage.NotifyUser(L"ERROR: Access Denied. Check 'Settings->Permissions' for access to Microphone.", NotifyType::ErrorMessage);
+ break;
+
+ default:
+ rootPage.NotifyUser(L"ERROR: " + hresult_error(error).message(), NotifyType::ErrorMessage);
+ break;
+ }
+ }
+ }
+
+ // Event callback when visualization data is ready to be plotted
+ fire_and_forget Scenario4::OnPlotDataReady(IPlotDataSource const&, SDKTemplate::PlotDataReadyEventArgs e)
+ {
+ auto lifetime = get_strong();
+
+ co_await resume_foreground(Dispatcher());
+
+ IBuffer buffer = e.Points();
+ size_t pointCount = buffer.Length() / sizeof(int16_t);
+ int16_t* points = reinterpret_cast(buffer.data());
+
+ // Scale the incoming point list so that it fills our scope.
+ float y_range = static_cast((std::numeric_limits::max)()) - std::numeric_limits::lowest();
+ float x_inc = pointCount > 0 ? OSC_X_LENGTH / static_cast(pointCount - 1) : 0.0f;
+
+ UINT32 existingPoints = Oscilloscope().Points().Size();
+
+ for (UINT32 i = 0; i < pointCount; i++)
+ {
+ Point p;
+
+ // Fixup the x and y coordinates and set it back into the collection
+ p.X = OSC_START_X + i * x_inc;
+ p.Y = OSC_START_Y - (points[i] * OSC_TOTAL_HEIGHT) / y_range;
+
+ if (i < existingPoints)
+ {
+ Oscilloscope().Points().SetAt(i, p);
+ }
+ else
+ {
+ Oscilloscope().Points().Append(p);
+ }
+ }
+ }
+
+ //
+ // InitializeCapture()
+ //
+ void Scenario4::InitializeCapture()
+ {
+ m_capture = nullptr;
+
+ // Create a new WASAPI capture instance
+ m_capture = make_self();
+
+ // Register for events
+ m_deviceStateChangeToken = m_capture->DeviceStateChanged({ get_weak(), &Scenario4::OnDeviceStateChange });
+ m_plotDataReadyToken = m_capture->PlotDataReady({ get_weak(), &Scenario4::OnPlotDataReady });
+
+ // There is an initial discontinuity when we start, so reset discontinuity counter
+ // to -1 so that we ignore that initial discontinuity.
+ m_discontinuityCount = -1;
+
+ // Configure whether we are using low-latency capture
+ m_isLowLatency = toggleMinimumLatency().IsOn();
+ m_capture->SetLowLatencyCapture(m_isLowLatency);
+
+ // Perform the initialization
+ m_capture->AsyncInitializeAudioDevice();
+ }
+
+ //
+ // StopCapture()
+ //
+ void Scenario4::StopCapture()
+ {
+ if (m_capture)
+ {
+ // Set the event to stop playback
+ m_capture->AsyncStopCapture();
+ }
+ }
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario4.h b/Samples/WindowsAudioSession/cppwinrt/Scenario4.h
new file mode 100644
index 0000000000..ff92b47e8b
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario4.h
@@ -0,0 +1,54 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "pch.h"
+#include "Scenario4.g.h"
+#include "WASAPICapture.h"
+
+namespace winrt::SDKTemplate::implementation
+{
+ struct Scenario4 : Scenario4T, MediaFoundationInitializer
+ {
+ Scenario4();
+
+ void OnNavigatedFrom(Windows::UI::Xaml::Navigation::NavigationEventArgs const&);
+
+ void btnStartCapture_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+ void btnStopCapture_Click(IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& e);
+
+ private:
+ SDKTemplate::MainPage rootPage{ MainPage::Current() };
+ event_token m_deviceStateChangeToken;
+ event_token m_plotDataReadyToken;
+
+ int m_discontinuityCount;
+ bool m_isLowLatency;
+ com_ptr m_capture;
+
+ // UI Helpers
+ void UpdateMediaControlUI(DeviceState deviceState);
+
+ // Handlers
+ fire_and_forget OnDeviceStateChange(IDeviceStateSource const& sender, SDKTemplate::DeviceStateChangedEventArgs e);
+ fire_and_forget OnPlotDataReady(IPlotDataSource const& sender, SDKTemplate::PlotDataReadyEventArgs e);
+
+ void InitializeCapture();
+ void StopCapture();
+ void ClearCapture();
+ };
+}
+
+namespace winrt::SDKTemplate::factory_implementation
+{
+ struct Scenario4 : Scenario4T
+ {
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/Scenario4.xaml b/Samples/WindowsAudioSession/cppwinrt/Scenario4.xaml
new file mode 100644
index 0000000000..6a469cc544
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Scenario4.xaml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This scenario demonstrates how to activate the default audio capture interface and use WASAPI to capture PCM audio. The user has the option to minimize capture latency by minimizing the size of the capture buffer. A file named WASAPIAudioCapture.wav, appended with a number if the file already exists, will be written to the music library.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/WindowsAudioSession/cppwinrt/Styles.xaml b/Samples/WindowsAudioSession/cppwinrt/Styles.xaml
new file mode 100644
index 0000000000..50602ae5a5
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/Styles.xaml
@@ -0,0 +1,536 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/WindowsAudioSession/cppwinrt/ToneSampleGenerator.cpp b/Samples/WindowsAudioSession/cppwinrt/ToneSampleGenerator.cpp
new file mode 100644
index 0000000000..a03f6cef40
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/ToneSampleGenerator.cpp
@@ -0,0 +1,119 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "ToneSampleGenerator.h"
+
+namespace winrt::SDKTemplate
+{
+ static constexpr int TONE_DURATION_SEC = 30;
+ static constexpr double TONE_AMPLITUDE = 0.5; // Scalar value, should be between 0.0 - 1.0
+
+ //
+ // GenerateSampleBuffer()
+ //
+ // Create a linked list of sample buffers
+ //
+ void ToneSampleGenerator::GenerateSampleBuffer(double Frequency, UINT32 FramesPerPeriod, WAVEFORMATEX* wfx)
+ {
+ uint32_t renderBufferSizeInBytes = FramesPerPeriod * wfx->nBlockAlign;
+ uint64_t renderDataLength = (wfx->nSamplesPerSec * TONE_DURATION_SEC * wfx->nBlockAlign) + (renderBufferSizeInBytes - 1);
+ uint64_t renderBufferCount = renderDataLength / renderBufferSizeInBytes;
+
+ SineSampleInfo info;
+ info.Frequency = Frequency;
+ info.ChannelCount = wfx->nChannels;
+ info.SamplesPerSecond = wfx->nSamplesPerSec;
+ info.Amplitude = TONE_AMPLITUDE;
+ info.Theta = 0; // Updated by GenerateSamples to remember where to resume
+
+ switch (GetRenderSampleType(wfx))
+ {
+ case RenderSampleType::Pcm16Bit:
+ info.SampleSize = sizeof(int16_t);
+ info.StoreSample = [](uint8_t* buffer, double value) { *reinterpret_cast(buffer) = static_cast(value * (std::numeric_limits::max)()); };
+ break;
+
+ case RenderSampleType::Pcm24In32Bit:
+ info.SampleSize = sizeof(int32_t);
+ // Scale to a 24-bit integer, stored in the upper 24 bits of the 32-bit sample.
+ info.StoreSample = [](uint8_t* buffer, double value) { *reinterpret_cast(buffer) = static_cast(value * ((1 << 23) - 1)) << 8; };
+ break;
+
+ case RenderSampleType::Float:
+ info.SampleSize = sizeof(float);
+ info.StoreSample = [](uint8_t* buffer, double value) { *reinterpret_cast(buffer) = static_cast(value); };
+ break;
+
+ default:
+ throw hresult_error(E_UNEXPECTED);
+ }
+
+ std::forward_list::iterator sampleQueueTail = m_sampleQueue.before_begin();
+ for (uint64_t i = 0; i < renderBufferCount; i++)
+ {
+ sampleQueueTail = m_sampleQueue.emplace_after(sampleQueueTail, renderBufferSizeInBytes);
+ RenderBuffer& sampleBuffer = *sampleQueueTail;
+ info.GenerateSamples({ sampleBuffer.Buffer.get(), sampleBuffer.BufferSize });
+ }
+ }
+
+ //
+ // GenerateSamples()
+ //
+ // Generate samples which represent a sine wave that fits into the specified buffer.
+ // The wave begins at the Theta value stored in the SineSampleInfo, and on exit the
+ // value is updated to the first Theta value for the next buffer.
+ //
+ // Buffer - Buffer to hold the samples
+ // BufferLength - Length of the buffer.
+
+ void ToneSampleGenerator::SineSampleInfo::GenerateSamples(array_view buffer) noexcept
+ {
+ // Each sample represents (Frequency * 2 * M_PI / SamplesPerSecond) radians.
+ // To avoid accumulated rounding errors, we track the cumulative Frequency.
+ // To avoid loss of significance, we take the value mod SamplesPerSecond.
+ size_t frames = buffer.size() / SampleSize / ChannelCount;
+ uint8_t* next = buffer.data();
+ for (size_t frame = 0; frame < frames; frame++)
+ {
+ double sinValue = Amplitude * sin(Theta * M_PI * 2 / SamplesPerSecond);
+ for (size_t channel = 0; channel < ChannelCount; channel++)
+ {
+ StoreSample(next, sinValue);
+ next += SampleSize;
+ }
+ Theta += Frequency;
+ if (Theta > SamplesPerSecond)
+ {
+ Theta = Theta - SamplesPerSecond;
+ }
+ }
+ }
+
+ //
+ // FillSampleBuffer()
+ //
+ // File the buffer of size bytesToRead with the first item in the queue. Caller is responsible for allocating and freeing the buffer.
+ //
+ void ToneSampleGenerator::FillSampleBuffer(array_view buffer)
+ {
+ RenderBuffer& sampleBuffer = m_sampleQueue.front();
+
+ if (buffer.size() > sampleBuffer.BufferSize)
+ {
+ throw hresult_invalid_argument();
+ }
+
+ CopyMemory(buffer.data(), sampleBuffer.Buffer.get(), buffer.size());
+
+ m_sampleQueue.pop_front();
+ }
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/ToneSampleGenerator.h b/Samples/WindowsAudioSession/cppwinrt/ToneSampleGenerator.h
new file mode 100644
index 0000000000..0a59d9e914
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/ToneSampleGenerator.h
@@ -0,0 +1,46 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+
+#define _USE_MATH_DEFINES
+#include
+#include
+
+namespace winrt::SDKTemplate
+{
+ class ToneSampleGenerator
+ {
+ public:
+ bool IsEOF() noexcept { return m_sampleQueue.empty(); };
+ uint32_t GetBufferLength() noexcept { return m_sampleQueue.empty() ? 0 : m_sampleQueue.front().BufferSize; };
+ void Flush() { m_sampleQueue.clear(); }
+
+ void GenerateSampleBuffer(double Frequency, UINT32 FramesPerPeriod, WAVEFORMATEX* wfx);
+ void FillSampleBuffer(array_view buffer);
+
+ private:
+ struct SineSampleInfo
+ {
+ double Frequency;
+ WORD ChannelCount;
+ DWORD SamplesPerSecond;
+ double Amplitude;
+ double Theta = 0.0;
+ size_t SampleSize;
+ void (*StoreSample)(uint8_t* buffer, double value);
+
+ void GenerateSamples(array_view buffer) noexcept;
+ };
+
+ private:
+ std::forward_list m_sampleQueue;
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/WASAPICapture.cpp b/Samples/WindowsAudioSession/cppwinrt/WASAPICapture.cpp
new file mode 100644
index 0000000000..fb63ecb617
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/WASAPICapture.cpp
@@ -0,0 +1,602 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "WASAPICapture.h"
+
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Media::Devices;
+using namespace winrt::Windows::Storage;
+using namespace winrt::Windows::Storage::Streams;
+
+using namespace std::literals;
+
+namespace winrt::SDKTemplate
+{
+ static constexpr uint32_t BITS_PER_BYTE = 8;
+ static constexpr TimeSpan FLUSH_INTERVAL = 3s;
+ static constexpr TimeSpan DURATION_TO_VISUALIZE = 20ms;
+ static constexpr wchar_t AUDIO_FILE_NAME[] = L"WASAPIAudioCapture.wav";
+
+ WASAPICapture::WASAPICapture()
+ {
+ // Set the capture event work queue to use the MMCSS queue
+ m_SampleReadyCallback.SetQueueID(m_queueId.get());
+ }
+
+ //
+ // InitializeAudioDeviceAsync()
+ //
+ // Activates the default audio capture on a asynchronous callback thread. This needs
+ // to be called from the main UI thread.
+ //
+ void WASAPICapture::AsyncInitializeAudioDevice() noexcept try
+ {
+ com_ptr asyncOp;
+
+ // Get a string representing the Default Audio Capture Device
+ hstring deviceIdString = MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default);
+
+ // This call must be made on the main UI thread. Async operation will call back to
+ // IActivateAudioInterfaceCompletionHandler::ActivateCompleted, which must be an agile interface implementation
+ check_hresult(ActivateAudioInterfaceAsync(deviceIdString.c_str(), __uuidof(IAudioClient3), nullptr, this, asyncOp.put()));
+ }
+ catch (...)
+ {
+ SetState(DeviceState::Error, to_hresult());
+ }
+
+ //
+ // ActivateCompleted()
+ //
+ // Callback implementation of ActivateAudioInterfaceAsync function. This will be called on MTA thread
+ // when results of the activation are available.
+ //
+ HRESULT WASAPICapture::ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) try
+ {
+ HRESULT status = S_OK;
+ com_ptr<::IUnknown> punkAudioInterface;
+
+ // Check for a successful activation result
+ check_hresult(operation->GetActivateResult(&status, punkAudioInterface.put()));
+ check_hresult(status);
+
+ // Get the pointer for the Audio Client
+ m_audioClient = punkAudioInterface.as();
+
+ check_hresult(m_audioClient->GetMixFormat(m_mixFormat.put()));
+
+ // convert from Float to 16-bit PCM
+ switch (m_mixFormat->wFormatTag)
+ {
+ case WAVE_FORMAT_PCM:
+ // nothing to do
+ break;
+
+ case WAVE_FORMAT_IEEE_FLOAT:
+ m_mixFormat->wFormatTag = WAVE_FORMAT_PCM;
+ m_mixFormat->wBitsPerSample = 16;
+ m_mixFormat->nBlockAlign = m_mixFormat->nChannels * m_mixFormat->wBitsPerSample / BITS_PER_BYTE;
+ m_mixFormat->nAvgBytesPerSec = m_mixFormat->nSamplesPerSec * m_mixFormat->nBlockAlign;
+ break;
+
+ case WAVE_FORMAT_EXTENSIBLE:
+ {
+ WAVEFORMATEXTENSIBLE* pWaveFormatExtensible = reinterpret_cast(m_mixFormat.get());
+ if (pWaveFormatExtensible->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
+ {
+ // nothing to do
+ }
+ else if (pWaveFormatExtensible->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
+ {
+ pWaveFormatExtensible->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ pWaveFormatExtensible->Format.wBitsPerSample = 16;
+ pWaveFormatExtensible->Format.nBlockAlign =
+ pWaveFormatExtensible->Format.nChannels *
+ pWaveFormatExtensible->Format.wBitsPerSample /
+ BITS_PER_BYTE;
+ pWaveFormatExtensible->Format.nAvgBytesPerSec =
+ pWaveFormatExtensible->Format.nSamplesPerSec *
+ pWaveFormatExtensible->Format.nBlockAlign;
+ pWaveFormatExtensible->Samples.wValidBitsPerSample =
+ pWaveFormatExtensible->Format.wBitsPerSample;
+
+ // leave the channel mask as-is
+ }
+ else
+ {
+ // we can only handle float or PCM
+ throw hresult_error(HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
+ }
+ break;
+ }
+
+ default:
+ // we can only handle float or PCM
+ throw hresult_error(HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
+ break;
+ }
+
+ // The wfx parameter below is optional (Its needed only for MATCH_FORMAT clients). Otherwise, wfx will be assumed
+ // to be the current engine format based on the processing mode for this stream
+ check_hresult(m_audioClient->GetSharedModeEnginePeriod(m_mixFormat.get(), &m_defaultPeriodInFrames, &m_fundamentalPeriodInFrames, &m_minPeriodInFrames, &m_maxPeriodInFrames));
+
+ // Initialize the AudioClient in Shared Mode with the user specified buffer
+ if (!m_isLowLatency)
+ {
+ check_hresult(m_audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ TimeSpan{ 20ms }.count(), // hnsBufferDuration
+ 0,
+ m_mixFormat.get(),
+ nullptr));
+ }
+ else
+ {
+ check_hresult(m_audioClient->InitializeSharedAudioStream(
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ m_minPeriodInFrames,
+ m_mixFormat.get(),
+ nullptr));
+ }
+
+ // Get the maximum size of the AudioClient Buffer
+ check_hresult(m_audioClient->GetBufferSize(&m_bufferFrames));
+
+ // Get the capture client
+ m_audioCaptureClient.capture(m_audioClient, &IAudioClient::GetService);
+
+ // Create Async callback for sample events
+ check_hresult(MFCreateAsyncResult(nullptr, &m_SampleReadyCallback, nullptr, m_sampleReadyAsyncResult.put()));
+
+ // Provides the event handle for the system to signal when an audio buffer is ready to be processed by the client
+ check_hresult(m_audioClient->SetEventHandle(m_SampleReadyEvent.get()));
+
+ // Create the visualization array
+ InitializeScopeData();
+
+ // Creates the WAV file asynchronously. If successful, will transition to DeviceState::Initialized
+ CreateWAVFile();
+
+ // Need to return S_OK
+ return S_OK;
+ }
+ catch (...)
+ {
+ SetState(DeviceState::Error, to_hresult());
+ m_audioClient = nullptr;
+ m_audioCaptureClient = nullptr;
+ m_sampleReadyAsyncResult = nullptr;
+
+ // Must return S_OK even on failure.
+ return S_OK;
+ }
+
+ //
+ // CreateWAVFile()
+ //
+ // Creates a WAV file in KnownFolders::MusicLibrary
+ //
+ fire_and_forget WASAPICapture::CreateWAVFile() try
+ {
+ auto lifetime = get_strong();
+
+ // Create the WAV file, appending a number if file already exists
+ StorageFile file = co_await KnownFolders::MusicLibrary().CreateFileAsync(AUDIO_FILE_NAME, CreationCollisionOption::GenerateUniqueName);
+
+ // Then create a RandomAccessStream
+ IRandomAccessStream stream = co_await file.OpenAsync(FileAccessMode::ReadWrite);
+
+ // Get the OutputStream for the file
+ m_contentStream = stream;
+ m_outputStream = stream.GetOutputStreamAt(0);
+
+ // Create the DataWriter
+ m_dataWriter = DataWriter(m_outputStream);
+
+ // Create the WAV header
+ DWORD formatSize = sizeof(WAVEFORMATEX) + m_mixFormat->cbSize; // Size of fmt chunk
+ DWORD header[] = {
+ FCC('RIFF'), // RIFF header
+ 0, // Total size of WAV (will be filled in later)
+ FCC('WAVE'), // WAVE FourCC
+ FCC('fmt '), // Start of 'fmt ' chunk
+ formatSize // Size of fmt chunk
+ };
+
+ DWORD data[] = { FCC('data'), 0 }; // Start of 'data' chunk (total size will be filled in later)
+
+ // Write the header
+ m_dataWriter.WriteBytes({ reinterpret_cast(header), sizeof(header) });
+ m_dataWriter.WriteBytes({ reinterpret_cast(m_mixFormat.get()), formatSize });
+ m_dataWriter.WriteBytes({ reinterpret_cast(data), sizeof(data) });
+
+ m_headerSize = co_await m_dataWriter.StoreAsync();
+ m_dataSize = 0;
+ m_bytesSinceLastFlush = 0;
+
+ // Wait for file data to be written to file
+ co_await m_dataWriter.FlushAsync();
+
+ SetState(DeviceState::Initialized);
+ }
+ catch (...)
+ {
+ SetState(DeviceState::Error, to_hresult());
+ }
+
+ //
+ // FixWAVHeader()
+ //
+ // The size values were not known when we originally wrote the header, so now go through and fix the values
+ //
+ fire_and_forget WASAPICapture::FixWAVHeader() try
+ {
+ auto lifetime = get_strong();
+
+ // Prepare a buffer to write DWORDs into the stream header.
+ Buffer dwordBuffer(sizeof(DWORD));
+ dwordBuffer.Length(sizeof(DWORD));
+ auto dwordBufferPtr = reinterpret_cast(dwordBuffer.data());
+
+ IRandomAccessStream stream = m_contentStream.CloneStream();
+
+ // Write the size of the 'data' chunk first
+ stream.Seek(m_headerSize - sizeof(DWORD));
+ *dwordBufferPtr = m_dataSize;
+ co_await stream.WriteAsync(dwordBuffer);
+
+ // Write the total file size, minus RIFF chunk and size
+ stream.Seek(sizeof(DWORD)); // sizeof(DWORD) == sizeof(FOURCC)
+ *dwordBufferPtr = m_dataSize + m_headerSize - 8; // 8 = RIFF chunk and size
+ co_await stream.WriteAsync(dwordBuffer);
+
+ co_await stream.FlushAsync();
+ stream.Close();
+
+ SetState(DeviceState::Stopped);
+ }
+ catch (...)
+ {
+ SetState(DeviceState::Error, to_hresult());
+ }
+
+ //
+ // InitializeScopeData()
+ //
+ // Setup data structures for sample visualizations
+ //
+ void WASAPICapture::InitializeScopeData()
+ {
+ // Only Support 16 bit Audio for now
+ if (m_mixFormat->wBitsPerSample != 16)
+ {
+ m_plotDataBuffer = nullptr;
+ return;
+ }
+
+ m_plotDataPointsFilled = 0;
+ m_plotDataMaxPoints = static_cast(DURATION_TO_VISUALIZE * m_mixFormat->nSamplesPerSec / 1s);
+ m_plotDataBuffer = Buffer(m_plotDataMaxPoints * sizeof(int16_t));
+ }
+
+ //
+ // AsyncStartCapture()
+ //
+ // Starts asynchronous capture on a separate thread via MF Work Item
+ //
+ void WASAPICapture::AsyncStartCapture()
+ {
+ // We should be in the initialzied state if this is the first time through getting ready to capture.
+ if (m_deviceState == DeviceState::Initialized)
+ {
+ SetState(DeviceState::Starting);
+ MFPutWorkItem2(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, 0, &m_StartCaptureCallback, nullptr);
+ }
+ }
+
+ //
+ // OnStartCapture()
+ //
+ // Callback method to start capture
+ //
+ HRESULT WASAPICapture::OnStartCapture(IMFAsyncResult*) try
+ {
+ // Start the capture
+ check_hresult(m_audioClient->Start());
+ check_hresult(MFPutWaitingWorkItem(m_SampleReadyEvent.get(), 0, m_sampleReadyAsyncResult.get(), &m_sampleReadyKey));
+ SetState(DeviceState::Capturing);
+
+ return S_OK;
+ }
+ catch (...)
+ {
+ SetState(DeviceState::Error, to_hresult());
+ // Must return S_OK.
+ return S_OK;
+ }
+
+ //
+ // AsyncStopCapture()
+ //
+ // Stop capture asynchronously via MF Work Item
+ //
+ void WASAPICapture::AsyncStopCapture()
+ {
+ if ((m_deviceState == DeviceState::Capturing) ||
+ (m_deviceState == DeviceState::Error))
+ {
+ SetState(DeviceState::Stopping);
+
+ MFPutWorkItem2(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, 0, &m_StopCaptureCallback, nullptr);
+ }
+ }
+
+ //
+ // OnStopCapture()
+ //
+ // Callback method to stop capture
+ //
+ HRESULT WASAPICapture::OnStopCapture(IMFAsyncResult*) try
+ {
+ // Stop capture by cancelling Work Item
+ // Cancel the queued work item (if any)
+ if (0 != m_sampleReadyKey)
+ {
+ MFCancelWorkItem(std::exchange(m_sampleReadyKey, 0));
+ }
+
+ m_sampleReadyAsyncResult = nullptr;
+ if (m_audioClient)
+ {
+ m_audioClient->Stop();
+
+ if (m_writing)
+ {
+ // A StoreAsync is already in progress. Let that one complete and finish the capture.
+ }
+ else
+ {
+ SetState(DeviceState::Flushing);
+ AsyncStoreData();
+ }
+ }
+ return S_OK;
+ }
+ catch (...) { return to_hresult(); }
+
+ //
+ // AsyncFinishCapture()
+ //
+ // Finalizes WAV file on a separate thread via MF Work Item
+ //
+ fire_and_forget WASAPICapture::AsyncStoreData()
+ {
+ auto lifetime = get_strong();
+
+ co_await m_dataWriter.StoreAsync();
+ m_writing = false;
+
+ if (m_deviceState == DeviceState::Stopping)
+ {
+ // A Stop request is pending. Transition to Flushing to write out the WAV header.
+ SetState(DeviceState::Flushing);
+ }
+
+ if (m_deviceState == DeviceState::Flushing)
+ {
+ check_hresult(MFPutWorkItem2(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, 0, &m_FinishCaptureCallback, nullptr));
+ }
+ }
+
+ //
+ // OnFinishCapture()
+ //
+ // Because of the asynchronous nature of the MF Work Queues and the DataWriter, there could still be
+ // a sample processing. So this will get called to finalize the WAV header.
+ //
+ HRESULT WASAPICapture::OnFinishCapture(IMFAsyncResult*)
+ {
+ // FixWAVHeader will set the DeviceState::Stopped when all async tasks are complete
+ FixWAVHeader();
+ return S_OK;
+ }
+
+ //
+ // OnSampleReady()
+ //
+ // Callback method when ready to fill sample buffer
+ //
+ HRESULT WASAPICapture::OnSampleReady(IMFAsyncResult*) try
+ {
+ OnAudioSampleRequested();
+
+ // Re-queue work item for next sample
+ if (m_deviceState == DeviceState::Capturing)
+ {
+ check_hresult(MFPutWaitingWorkItem(m_SampleReadyEvent.get(), 0, m_sampleReadyAsyncResult.get(), &m_sampleReadyKey));
+ }
+
+ return S_OK;
+ }
+ catch (...)
+ {
+ hresult error = to_hresult();
+ SetState(DeviceState::Error, error);
+ return error;
+ }
+
+ //
+ // OnAudioSampleRequested()
+ //
+ // Called when audio device fires m_SampleReadyEvent
+ //
+ void WASAPICapture::OnAudioSampleRequested()
+ {
+ auto guard = slim_lock_guard(m_lock);
+
+ // If this flag is set, we have already queued up the async call to finialize the WAV header
+ // So we don't want to grab or write any more data that would possibly give us an invalid size
+ if ((m_deviceState == DeviceState::Stopping) ||
+ (m_deviceState == DeviceState::Flushing))
+ {
+ return;
+ }
+
+ // A word on why we have a loop here:
+ // Suppose it has been 10 milliseconds or so since the last time
+ // this routine was invoked, and that we're capturing 48000 samples per second.
+ //
+ // The audio engine can be reasonably expected to have accumulated about that much
+ // audio data - that is, about 480 samples.
+ //
+ // However, the audio engine is free to accumulate this in various ways:
+ // a. as a single packet of 480 samples, OR
+ // b. as a packet of 80 samples plus a packet of 400 samples, OR
+ // c. as 48 packets of 10 samples each.
+ //
+ // In particular, there is no guarantee that this routine will be
+ // run once for each packet.
+ //
+ // So every time this routine runs, we need to read ALL the packets
+ // that are now available;
+ //
+ // We do this by calling IAudioCaptureClient::GetNextPacketSize
+ // over and over again until it indicates there are no more packets remaining.
+ uint32_t framesAvailable = 0;
+ while (SUCCEEDED(m_audioCaptureClient->GetNextPacketSize(&framesAvailable)) && framesAvailable > 0)
+ {
+ DWORD bytesToCapture = framesAvailable * m_mixFormat->nBlockAlign;
+
+ // WAV files have a 4GB (0xFFFFFFFF) size limit, so likely we have hit that limit when we
+ // overflow here. Time to stop the capture
+ if ((m_dataSize + bytesToCapture) < m_dataSize)
+ {
+ AsyncStopCapture();
+ return;
+ }
+
+ { // Scope for GetBuffer / ReleaseBuffer variables.
+ uint8_t* data = nullptr;
+ DWORD dwCaptureFlags;
+ uint64_t devicePosition = 0;
+ uint64_t qpcPosition = 0;
+
+ // Get sample buffer
+ check_hresult(m_audioCaptureClient->GetBuffer(&data, &framesAvailable, &dwCaptureFlags, &devicePosition, &qpcPosition));
+
+ // Ensure that the buffer is released at scope exit, even if an exception occurs.
+ auto release = scope_exit([&] { m_audioCaptureClient->ReleaseBuffer(framesAvailable); });
+
+ if (dwCaptureFlags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY)
+ {
+ // Pass down a discontinuity flag in case the app is interested and reset back to capturing
+ SetState(DeviceState::Discontinuity);
+ SetStateNoNotify(DeviceState::Capturing);
+ }
+
+ // Zero out sample if silence
+ if (dwCaptureFlags & AUDCLNT_BUFFERFLAGS_SILENT)
+ {
+ memset(data, 0, framesAvailable * m_mixFormat->nBlockAlign);
+ }
+
+ // Update plotter data
+ array_view dataBytes{ data, bytesToCapture };
+ ProcessScopeData(dataBytes);
+
+ // Write File and async store
+ m_dataWriter.WriteBytes(dataBytes);
+
+ // End of scope: Buffer is released back, and GetBuffer variables are no longer valid
+ }
+
+ // Increase the size of our 'data' chunk and bytes since last flush. m_dataSize needs to be accurate but
+ // m_bytesSinceLastFlush need only be an approximation.
+ m_dataSize += bytesToCapture;
+ m_bytesSinceLastFlush += bytesToCapture;
+
+ if ((m_bytesSinceLastFlush > (m_mixFormat->nAvgBytesPerSec * FLUSH_INTERVAL / 1s)) && !m_writing)
+ {
+ // Set this flag when about to commit the async storage operation. We don't want to
+ // accidently call stop and finalize the WAV header or run into a scenario where the
+ // store operation takes longer than FLUSH_INTERVAL as multiple concurrent calls
+ // to StoreAsync() can cause an exception
+ m_writing = true;
+
+ // Reset the counter now since we can process more samples during the async callback
+ m_bytesSinceLastFlush = 0;
+
+ // Save the data we just wrote to the output file.
+ AsyncStoreData();
+ }
+ }
+ }
+
+ //
+ // ProcessScopeData()
+ //
+ // Copies sample data to the buffer array and fires the event
+ //
+ void WASAPICapture::ProcessScopeData(array_view rawBytes)
+ {
+ // There is no buffer if the data format is not one we support.
+ // (For now, the only format we support is 16-bit audio.)
+ if (m_plotDataBuffer == nullptr)
+ {
+ return;
+ }
+
+ uint32_t pointCount = rawBytes.size() / m_mixFormat->nChannels / (m_mixFormat->wBitsPerSample / BITS_PER_BYTE);
+
+ auto plotData = reinterpret_cast(m_plotDataBuffer.data());
+
+ // Read the 16-bit samples from channel 0
+ int16_t* pi16 = reinterpret_cast(rawBytes.data());
+
+ for (DWORD i = 0; m_plotDataPointsFilled < m_plotDataMaxPoints && i < pointCount; i++)
+ {
+ plotData[m_plotDataPointsFilled] = *pi16;
+ pi16 += m_mixFormat->nChannels;
+
+ m_plotDataPointsFilled++;
+ }
+
+ // Send off the event and get ready for the next set of samples
+ if (m_plotDataPointsFilled == m_plotDataMaxPoints)
+ {
+ auto plotDataBuffer = std::exchange(m_plotDataBuffer, nullptr);
+ m_plotDataPointsFilled = 0;
+
+ plotDataBuffer.Length(m_plotDataMaxPoints * sizeof(int16_t));
+ MFPutWorkItem2(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, 0, &m_SendScopeDataCallback, winrt::get_unknown(plotDataBuffer));
+
+ // Create a new buffer to hold the next set of points.
+ m_plotDataBuffer = Buffer(sizeof(int16_t) * m_plotDataMaxPoints);
+ }
+ }
+
+ //
+ // OnSendScopeData()
+ //
+ // Callback method to delivery data for client visualizations
+ //
+ HRESULT WASAPICapture::OnSendScopeData(IMFAsyncResult* pResult) try
+ {
+ com_ptr<::IUnknown> points;
+ check_hresult(pResult->GetState(points.put()));
+ ReportPlotDataReady(points.as());
+ return S_OK;
+ }
+ catch (...)
+ {
+ return S_OK;
+ }
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/WASAPICapture.h b/Samples/WindowsAudioSession/cppwinrt/WASAPICapture.h
new file mode 100644
index 0000000000..b76803baa1
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/WASAPICapture.h
@@ -0,0 +1,85 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "DeviceState.h"
+#include "PlotData.h"
+
+namespace winrt::SDKTemplate
+{
+ // Primary WASAPI Capture Class
+ struct WASAPICapture : winrt::implements,
+ implementation::DeviceStateSourceT,
+ implementation::PlotDataSourceT
+ {
+ public:
+ WASAPICapture();
+
+ void SetLowLatencyCapture(bool value) { m_isLowLatency = value; }
+ void AsyncInitializeAudioDevice() noexcept;
+ void AsyncStartCapture();
+ void AsyncStopCapture();
+
+ // IActivateAudioInterfaceCompletionHandler
+ STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation* operation);
+
+ private:
+ HRESULT OnStartCapture(IMFAsyncResult* pResult);
+ HRESULT OnStopCapture(IMFAsyncResult* pResult);
+ HRESULT OnFinishCapture(IMFAsyncResult* pResult);
+ HRESULT OnSampleReady(IMFAsyncResult* pResult);
+ HRESULT OnSendScopeData(IMFAsyncResult* pResult);
+
+ EmbeddedMFAsyncCallback<&WASAPICapture::OnStartCapture> m_StartCaptureCallback{ this };
+ EmbeddedMFAsyncCallback<&WASAPICapture::OnStopCapture> m_StopCaptureCallback{ this };
+ EmbeddedMFAsyncCallback<&WASAPICapture::OnSampleReady> m_SampleReadyCallback{ this };
+ EmbeddedMFAsyncCallback<&WASAPICapture::OnFinishCapture> m_FinishCaptureCallback{ this };
+ EmbeddedMFAsyncCallback<&WASAPICapture::OnSendScopeData> m_SendScopeDataCallback{ this };
+
+ fire_and_forget CreateWAVFile();
+ fire_and_forget FixWAVHeader();
+ void OnAudioSampleRequested();
+ void InitializeScopeData();
+ void ProcessScopeData(array_view rawBytes);
+ fire_and_forget AsyncStoreData();
+
+ private:
+ uint32_t m_bufferFrames = 0;
+
+ // Event for sample ready or user stop
+ handle m_SampleReadyEvent{ check_pointer(CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS)) };
+
+ MFWORKITEM_KEY m_sampleReadyKey = 0;
+ slim_mutex m_lock;
+ unique_shared_work_queue m_queueId{ L"Capture" };
+
+ uint32_t m_headerSize = 0;
+ uint32_t m_dataSize = 0;
+ uint32_t m_bytesSinceLastFlush = 0;
+ bool m_writing = false;
+ bool m_isLowLatency = false;
+
+ Windows::Storage::Streams::IRandomAccessStream m_contentStream;
+ Windows::Storage::Streams::IOutputStream m_outputStream;
+ Windows::Storage::Streams::DataWriter m_dataWriter{ nullptr };
+ unique_cotaskmem_ptr m_mixFormat;
+ com_ptr m_audioClient;
+ uint32_t m_defaultPeriodInFrames;
+ uint32_t m_fundamentalPeriodInFrames;
+ uint32_t m_maxPeriodInFrames;
+ uint32_t m_minPeriodInFrames;
+ com_ptr m_audioCaptureClient;
+ com_ptr m_sampleReadyAsyncResult;
+
+ Windows::Storage::Streams::IBuffer m_plotDataBuffer;
+ uint32_t m_plotDataMaxPoints;
+ uint32_t m_plotDataPointsFilled;
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/WASAPIRenderer.cpp b/Samples/WindowsAudioSession/cppwinrt/WASAPIRenderer.cpp
new file mode 100644
index 0000000000..3cc69eb31d
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/WASAPIRenderer.cpp
@@ -0,0 +1,616 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#include "pch.h"
+#include "WASAPIRenderer.h"
+
+using namespace winrt::Windows::Media::Devices;
+
+namespace winrt::SDKTemplate
+{
+ //
+ // InitializeAudioDeviceAsync()
+ //
+ // Activates the default audio renderer on a asynchronous callback thread.
+ //
+ void WASAPIRenderer::AsyncInitializeAudioDevice() noexcept try
+ {
+ // Get a string representing the Default Audio Device Renderer
+ m_DeviceIdString = MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
+
+ // This call can be made safely from a background thread because we are asking for the IAudioClient3
+ // interface of an audio device. Async operation will call back to
+ // IActivateAudioInterfaceCompletionHandler::ActivateCompleted, which must be an agile interface implementation
+ com_ptr asyncOp;
+ check_hresult(ActivateAudioInterfaceAsync(m_DeviceIdString.c_str(), __uuidof(IAudioClient3), nullptr, this, asyncOp.put()));
+ }
+ catch (...)
+ {
+ SetState(DeviceState::Error, to_hresult());
+ }
+
+ //
+ // ActivateCompleted()
+ //
+ // Callback implementation of ActivateAudioInterfaceAsync function. This will be called on MTA thread
+ // when results of the activation are available.
+ //
+ HRESULT WASAPIRenderer::ActivateCompleted(IActivateAudioInterfaceAsyncOperation* operation) noexcept try
+ {
+ if (m_deviceState != DeviceState::Uninitialized)
+ {
+ throw hresult_error(E_NOT_VALID_STATE);
+ }
+
+ // Check for a successful activation result
+ HRESULT hrActivateResult = S_OK;
+ com_ptr<::IUnknown> punkAudioInterface;
+ check_hresult(operation->GetActivateResult(&hrActivateResult, punkAudioInterface.put()));
+ check_hresult(hrActivateResult);
+
+ // Remember that we have been activated, but don't raise the event yet.
+ SetStateNoNotify(DeviceState::Activated);
+
+ // Get the pointer for the Audio Client
+ m_AudioClient = punkAudioInterface.as();
+
+ // Configure user defined properties
+ check_hresult(ConfigureDeviceInternal());
+
+ // Initialize the AudioClient in Shared Mode with the user specified buffer
+ if (!m_IsLowLatency || m_IsHWOffload)
+ {
+ check_hresult(m_AudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ m_hnsBufferDuration,
+ m_hnsBufferDuration,
+ m_MixFormat.get(),
+ nullptr));
+ }
+ else
+ {
+ check_hresult(m_AudioClient->InitializeSharedAudioStream(
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ m_MinPeriodInFrames,
+ m_MixFormat.get(),
+ nullptr));
+ }
+
+ // Get the maximum size of the AudioClient Buffer
+ check_hresult(m_AudioClient->GetBufferSize(&m_BufferFrames));
+
+ // Get the render client
+ m_AudioRenderClient.capture(m_AudioClient, &IAudioClient::GetService);
+
+ // Create Async callback for sample events
+ check_hresult(MFCreateAsyncResult(nullptr, &m_SampleReadyCallback, nullptr, m_SampleReadyAsyncResult.put()));
+
+ // Sets the event handle that the system signals when an audio buffer is ready to be processed by the client
+ check_hresult(m_AudioClient->SetEventHandle(m_SampleReadyEvent.get()));
+
+ // Everything succeeded
+ SetState(DeviceState::Initialized, S_OK);
+
+ return S_OK;
+ }
+ catch (...)
+ {
+ SetState(DeviceState::Error, to_hresult());
+ m_AudioClient = nullptr;
+ m_AudioRenderClient = nullptr;
+ m_SampleReadyAsyncResult = nullptr;
+
+ // Must return S_OK even on failure.
+ return S_OK;
+ }
+
+ //
+ // GetBufferFramesPerPeriod()
+ //
+ // Get the time in seconds between passes of the audio device
+ //
+ UINT32 WASAPIRenderer::GetBufferFramesPerPeriod() noexcept
+ {
+ REFERENCE_TIME defaultDevicePeriod = 0;
+ REFERENCE_TIME minimumDevicePeriod = 0;
+
+ if (m_IsHWOffload)
+ {
+ return m_BufferFrames;
+ }
+
+ if (m_IsLowLatency)
+ {
+ return m_MinPeriodInFrames;
+ }
+
+ // Get the audio device period
+ HRESULT hr = m_AudioClient->GetDevicePeriod(&defaultDevicePeriod, &minimumDevicePeriod);
+ if (FAILED(hr))
+ {
+ return 0;
+ }
+
+ double devicePeriodInSeconds = defaultDevicePeriod / (10000.0 * 1000.0);
+ return static_cast(m_MixFormat->nSamplesPerSec * devicePeriodInSeconds + 0.5);
+ }
+
+ //
+ // ConfigureDeviceInternal()
+ //
+ // Sets additional playback parameters and opts into hardware offload
+ //
+ HRESULT WASAPIRenderer::ConfigureDeviceInternal() noexcept try
+ {
+ if (m_deviceState != DeviceState::Activated)
+ {
+ return E_NOT_VALID_STATE;
+ }
+
+ // Opt into HW Offloading. If the endpoint does not support offload it will return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE
+ AudioClientProperties audioProps = { 0 };
+ audioProps.cbSize = sizeof(AudioClientProperties);
+ audioProps.bIsOffload = m_IsHWOffload;
+ audioProps.eCategory = AudioCategory_Media;
+
+ if (m_IsRawAudio)
+ {
+ audioProps.Options = AUDCLNT_STREAMOPTIONS_RAW;
+ }
+
+ check_hresult(m_AudioClient->SetClientProperties(&audioProps));
+
+ // If application already has a preferred source format available,
+ // it can test whether the format is supported by the device:
+ //
+ // unique_cotaskmem_ptr applicationFormat = { ... };
+ // if (S_OK == m_AudioClient->IsFormatSupported(applicationFormat.get()))
+ // {
+ // m_MixFormat = std::move(applicationFormat);
+ // }
+ // else
+ // {
+ // // device does not support the application format, so ask the device what format it prefers
+ // check_hresult(m_AudioClient->GetMixFormat(&m_MixFormat.put()));
+ // }
+
+ // This sample opens the device is shared mode so we need to find the supported WAVEFORMATEX mix format
+ check_hresult(m_AudioClient->GetMixFormat(m_MixFormat.put()));
+
+ if (!audioProps.bIsOffload)
+ {
+ // The wfx parameter below is optional (Its needed only for MATCH_FORMAT clients). Otherwise, wfx will be assumed
+ // to be the current engine format based on the processing mode for this stream
+ check_hresult(m_AudioClient->GetSharedModeEnginePeriod(m_MixFormat.get(), &m_DefaultPeriodInFrames, &m_FundamentalPeriodInFrames, &m_MinPeriodInFrames, &m_MaxPeriodInFrames));
+ }
+
+ // Verify the user defined value for hardware buffer
+ ValidateBufferValue();
+
+ return S_OK;
+ }
+ catch (...) { return to_hresult(); }
+
+ //
+ // ValidateBufferValue()
+ //
+ // Verifies the user specified buffer value for hardware offload
+ // Throws an exception on failure.
+ //
+ void WASAPIRenderer::ValidateBufferValue()
+ {
+ if (!m_IsHWOffload)
+ {
+ // If we aren't using HW Offload, set this to 0 to use the default value
+ m_hnsBufferDuration = 0;
+ return;
+ }
+
+ REFERENCE_TIME hnsMinBufferDuration;
+ REFERENCE_TIME hnsMaxBufferDuration;
+
+ check_hresult(m_AudioClient->GetBufferSizeLimits(m_MixFormat.get(), true, &hnsMinBufferDuration, &hnsMaxBufferDuration));
+ if (m_hnsBufferDuration < hnsMinBufferDuration)
+ {
+ // using MINIMUM size instead
+ m_hnsBufferDuration = hnsMinBufferDuration;
+ }
+ else if (m_hnsBufferDuration > hnsMaxBufferDuration)
+ {
+ // using MAXIMUM size instead
+ m_hnsBufferDuration = hnsMaxBufferDuration;
+ }
+ }
+
+ HRESULT WASAPIRenderer::SetVolumeOnSession(double volumePercent) noexcept try
+ {
+ // Convert [0.100] to [0..1] range and clamp
+ m_channelVolume = (volumePercent < 0.0) ? 0.0f : (volumePercent > 100.0) ? 1.0f : (float)(volumePercent / 100.0);
+
+ // Set the session volume on the endpoint if we have one.
+ if (m_AudioClient)
+ {
+ SetAudioClientChannelVolume();
+ }
+
+ return S_OK;
+ }
+ catch (...) { return to_hresult(); }
+
+ void WASAPIRenderer::SetAudioClientChannelVolume()
+ {
+ check_hresult(capture(m_AudioClient, &IAudioClient3::GetService)->SetMasterVolume(m_channelVolume, nullptr));
+ }
+
+
+ //
+ // ConfigureSource()
+ //
+ // Configures tone or file playback
+ //
+ void WASAPIRenderer::ConfigureSource()
+ {
+ UINT32 FramesPerPeriod = GetBufferFramesPerPeriod();
+
+ switch (m_contentType)
+ {
+ case ContentType::Tone:
+ // Generate the sine wave sample buffer
+ m_ToneSource = std::make_unique();
+ m_ToneSource->GenerateSampleBuffer(m_Frequency, FramesPerPeriod, m_MixFormat.get());
+ break;
+
+ case ContentType::File:
+ m_MFSource = make_self();
+ // This will throw if the stream cannot be decoded.
+ m_MFSource->Initialize(m_ContentStream, FramesPerPeriod, m_MixFormat.get());
+ break;
+
+ default:
+ assert(false);
+ std::terminate();
+ }
+ }
+
+ //
+ // StartPlaybackAsync()
+ //
+ // Starts asynchronous playback on a separate thread via MF Work Item
+ // Errors are reported via the DeviceStateChanged event.
+ //
+ void WASAPIRenderer::StartPlayback() noexcept try
+ {
+ switch (m_deviceState)
+ {
+ // We should be stopped if the user stopped playback, or we should be
+ // initialized if this is the first time through getting ready to playback.
+ case DeviceState::Stopped:
+ case DeviceState::Initialized:
+ // Setup either ToneGeneration or File Playback
+ ConfigureSource();
+
+ SetState(DeviceState::Starting, S_OK);
+ check_hresult(MFPutWorkItem2(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, 0, &m_StartPlaybackCallback, nullptr));
+ break;
+
+ case DeviceState::Paused:
+ check_hresult(MFPutWorkItem2(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, 0, &m_StartPlaybackCallback, nullptr));
+ break;
+
+ default:
+ // Otherwise something else happened
+ throw hresult_error(E_FAIL);
+ }
+ }
+ catch (...)
+ {
+ hresult error = to_hresult();
+ SetState(DeviceState::Error, error);
+ }
+
+ //
+ // OnStartPlayback()
+ //
+ // Callback method to start playback
+ //
+ HRESULT WASAPIRenderer::OnStartPlayback(IMFAsyncResult*) noexcept try
+ {
+ // Pre-Roll the buffer with silence
+ OnAudioSampleRequested(true);
+
+ // For MF Source playback, need to start the source reader
+ if (m_contentType == ContentType::File)
+ {
+ m_MFSource->StartSource();
+ }
+
+ // Set the initial volume.
+ SetAudioClientChannelVolume();
+
+ // Actually start the playback
+ check_hresult(m_AudioClient->Start());
+
+ SetState(DeviceState::Playing, S_OK);
+ check_hresult(MFPutWaitingWorkItem(m_SampleReadyEvent.get(), 0, m_SampleReadyAsyncResult.get(), &m_SampleReadyKey));
+
+ return S_OK;
+ }
+ catch (...)
+ {
+ SetState(DeviceState::Error, to_hresult());
+ // Must return S_OK.
+ return S_OK;
+ }
+
+ //
+ // StopPlaybackAsync()
+ //
+ // Stop playback asynchronously via MF Work Item
+ //
+ HRESULT WASAPIRenderer::StopPlaybackAsync() noexcept
+ {
+ if ((m_deviceState != DeviceState::Playing) &&
+ (m_deviceState != DeviceState::Paused) &&
+ (m_deviceState != DeviceState::Error))
+ {
+ return E_NOT_VALID_STATE;
+ }
+
+ SetState(DeviceState::Stopping, S_OK);
+
+ return MFPutWorkItem2(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, 0, &m_StopPlaybackCallback, nullptr);
+ }
+
+ //
+ // OnStopPlayback()
+ //
+ // Callback method to stop playback
+ //
+ HRESULT WASAPIRenderer::OnStopPlayback(IMFAsyncResult*)
+ {
+ // Stop playback by cancelling Work Item
+ // Cancel the queued work item (if any)
+ if (0 != m_SampleReadyKey)
+ {
+ MFCancelWorkItem(m_SampleReadyKey);
+ m_SampleReadyKey = 0;
+ }
+
+ // Flush anything left in buffer with silence, best effort.
+ try
+ {
+ OnAudioSampleRequested(true);
+ }
+ catch (...) { }
+
+ m_AudioClient->Stop();
+ m_SampleReadyAsyncResult = nullptr;
+
+ switch (m_contentType)
+ {
+ case ContentType::Tone:
+ // Flush remaining buffers
+ m_ToneSource->Flush();
+ break;
+
+ case ContentType::File:
+ // Stop Source and Flush remaining buffers
+ m_MFSource->StopSource();
+ m_MFSource->Shutdown();
+ break;
+ }
+
+ SetState(DeviceState::Stopped);
+
+ return S_OK;
+ }
+
+ //
+ // PausePlaybackAsync()
+ //
+ // Pause playback asynchronously via MF Work Item
+ //
+ HRESULT WASAPIRenderer::PausePlaybackAsync()
+ {
+ if ((m_deviceState != DeviceState::Playing) &&
+ (m_deviceState != DeviceState::Error))
+ {
+ return E_NOT_VALID_STATE;
+ }
+
+ // Change state to stop automatic queueing of samples
+ // Don't notify clients.
+ SetStateNoNotify(DeviceState::Pausing);
+
+ return MFPutWorkItem2(MFASYNC_CALLBACK_QUEUE_MULTITHREADED, 0, &m_PausePlaybackCallback, nullptr);
+
+ }
+
+ //
+ // OnPausePlayback()
+ //
+ // Callback method to pause playback
+ //
+ HRESULT WASAPIRenderer::OnPausePlayback(IMFAsyncResult*)
+ {
+ m_AudioClient->Stop();
+ SetState(DeviceState::Paused, S_OK);
+
+ return S_OK;
+ }
+
+ //
+ // OnSampleReady()
+ //
+ // Callback method when ready to fill sample buffer
+ //
+ HRESULT WASAPIRenderer::OnSampleReady(IMFAsyncResult*) try
+ {
+ OnAudioSampleRequested(false);
+
+ // Re-queue work item for next sample
+ if (m_deviceState == DeviceState::Playing)
+ {
+ check_hresult(MFPutWaitingWorkItem(m_SampleReadyEvent.get(), 0, m_SampleReadyAsyncResult.get(), &m_SampleReadyKey));
+ }
+
+ return S_OK;
+ }
+ catch (...)
+ {
+ hresult error = to_hresult();
+ SetState(DeviceState::Error, error);
+ return error;
+ }
+
+ //
+ // OnAudioSampleRequested()
+ //
+ // Called when audio device fires m_SampleReadyEvent
+ //
+ void WASAPIRenderer::OnAudioSampleRequested(bool IsSilence) try
+ {
+
+ auto guard = slim_lock_guard(m_lock);
+
+ // Get padding in existing buffer
+ UINT32 PaddingFrames = 0;
+ check_hresult(m_AudioClient->GetCurrentPadding(&PaddingFrames));
+
+ // GetCurrentPadding represents the number of queued frames
+ // so we can subtract that from the overall number of frames we have
+ uint32_t framesAvailable = m_BufferFrames - PaddingFrames;
+
+ // Only continue if we have buffer to write data
+ if (framesAvailable == 0)
+ {
+ return;
+ }
+
+ if (IsSilence)
+ {
+ // Fill the buffer with silence
+ uint8_t* data;
+ check_hresult(m_AudioRenderClient->GetBuffer(framesAvailable, &data));
+ check_hresult(m_AudioRenderClient->ReleaseBuffer(framesAvailable, AUDCLNT_BUFFERFLAGS_SILENT));
+ return;
+ }
+
+ // Even if we cancel a work item, this may still fire due to the async
+ // nature of things. There should be a queued work item already to handle
+ // the process of stopping or stopped
+ if (m_deviceState == DeviceState::Playing)
+ {
+ // Fill the buffer with a playback sample
+ switch (m_contentType)
+ {
+ case ContentType::Tone:
+ GetToneSample(framesAvailable);
+ break;
+
+ case ContentType::File:
+ GetMFSample(framesAvailable);
+ break;
+ }
+ }
+ }
+ catch (hresult_error const& error)
+ {
+ if (error.code() != AUDCLNT_E_RESOURCES_INVALIDATED)
+ {
+ throw;
+ }
+
+ // Attempt auto-recovery from loss of resources.
+ SetStateNoNotify(DeviceState::Uninitialized);
+ m_AudioClient = nullptr;
+ m_AudioRenderClient = nullptr;
+ m_SampleReadyAsyncResult = nullptr;
+
+ AsyncInitializeAudioDevice();
+ }
+
+ //
+ // GetToneSample()
+ //
+ // Fills buffer with a tone sample
+ //
+ void WASAPIRenderer::GetToneSample(uint32_t framesAvailable)
+ {
+ uint8_t* data;
+
+ // Post-Roll Silence
+ if (m_ToneSource->IsEOF())
+ {
+ check_hresult(m_AudioRenderClient->GetBuffer(framesAvailable, &data));
+ // Ignore the return
+ m_AudioRenderClient->ReleaseBuffer(framesAvailable, AUDCLNT_BUFFERFLAGS_SILENT);
+
+ StopPlaybackAsync();
+ }
+ else if (m_ToneSource->GetBufferLength() <= (framesAvailable * m_MixFormat->nBlockAlign))
+ {
+ uint32_t actualFramesToRead = m_ToneSource->GetBufferLength() / m_MixFormat->nBlockAlign;
+ uint32_t actualBytesToRead = actualFramesToRead * m_MixFormat->nBlockAlign;
+
+ check_hresult(m_AudioRenderClient->GetBuffer(actualFramesToRead, &data));
+ if (actualBytesToRead > 0)
+ {
+ m_ToneSource->FillSampleBuffer({ data, actualBytesToRead });
+ }
+ check_hresult(m_AudioRenderClient->ReleaseBuffer(actualFramesToRead, 0));
+ }
+ }
+
+ //
+ // GetMFSample()
+ //
+ // Fills buffer with a MF sample
+ //
+ void WASAPIRenderer::GetMFSample(uint32_t framesAvailable)
+ {
+ BYTE* data = nullptr;
+
+ // Post-Roll Silence
+ if (m_MFSource->IsEOF())
+ {
+ check_hresult(m_AudioRenderClient->GetBuffer(framesAvailable, &data));
+ // Ignore the return
+ m_AudioRenderClient->ReleaseBuffer(framesAvailable, AUDCLNT_BUFFERFLAGS_SILENT);
+
+ StopPlaybackAsync();
+ }
+ else
+ {
+ uint32_t actualBytesRead = 0;
+ uint32_t actualBytesToRead = framesAvailable * m_MixFormat->nBlockAlign;
+
+ check_hresult(m_AudioRenderClient->GetBuffer(framesAvailable, &data));
+ if (!m_MFSource->FillSampleBuffer({ data, actualBytesToRead }, &actualBytesRead))
+ {
+ // Hit EOS
+ m_AudioRenderClient->ReleaseBuffer(framesAvailable, AUDCLNT_BUFFERFLAGS_SILENT);
+ StopPlaybackAsync();
+ }
+ else
+ {
+ // This can happen if we are pre-rolling so just insert silence
+ if (0 == actualBytesRead)
+ {
+ check_hresult(m_AudioRenderClient->ReleaseBuffer(framesAvailable, AUDCLNT_BUFFERFLAGS_SILENT));
+ }
+ else
+ {
+ check_hresult(m_AudioRenderClient->ReleaseBuffer(actualBytesRead / m_MixFormat->nBlockAlign, 0));
+ }
+ }
+ }
+ }
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/WASAPIRenderer.h b/Samples/WindowsAudioSession/cppwinrt/WASAPIRenderer.h
new file mode 100644
index 0000000000..003060d12f
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/WASAPIRenderer.h
@@ -0,0 +1,104 @@
+//*********************************************************
+//
+// Copyright (c) Microsoft. All rights reserved.
+// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
+// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
+// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
+//
+//*********************************************************
+
+#pragma once
+#include "DeviceState.h"
+#include "ToneSampleGenerator.h"
+#include "MFSampleGenerator.h"
+
+namespace winrt::SDKTemplate
+{
+ enum class ContentType
+ {
+ Tone,
+ File
+ };
+
+ struct WASAPIRenderer;
+
+ using DeviceStateChangedEventHandler = delegate, com_ptr>;
+
+ // Primary WASAPI Renderering Class
+ struct WASAPIRenderer : winrt::implements, implementation::DeviceStateSourceT
+ {
+ void SetContentType(ContentType value) { m_contentType = value; }
+ void SetFrequency(double value) { m_Frequency = value; }
+ void SetContentStream(Windows::Storage::Streams::IRandomAccessStream const& value) { m_ContentStream = value; }
+ void SetHWOffload(bool value) { m_IsHWOffload = value; }
+ void SetBackgroundAudio(bool value) { m_IsBackground = value; }
+ void SetRawAudio(bool value) { m_IsRawAudio = value; }
+ void SetLowLatency(bool value) { m_IsLowLatency = value; }
+ void SetBufferDuration(REFERENCE_TIME value) { m_hnsBufferDuration = value; }
+
+ void AsyncInitializeAudioDevice() noexcept;
+ void StartPlayback() noexcept;
+ HRESULT StopPlaybackAsync() noexcept;
+ HRESULT PausePlaybackAsync();
+
+ HRESULT SetVolumeOnSession(double volume) noexcept;
+
+ // IActivateAudioInterfaceCompletionHandler
+ STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation* operation) noexcept;
+
+ private:
+ HRESULT OnStartPlayback(IMFAsyncResult* pResult) noexcept;
+ HRESULT OnStopPlayback(IMFAsyncResult* pResult);
+ HRESULT OnPausePlayback(IMFAsyncResult* pResult);
+ HRESULT OnSampleReady(IMFAsyncResult* pResult);
+
+ EmbeddedMFAsyncCallback<&WASAPIRenderer::OnStartPlayback> m_StartPlaybackCallback{ this };
+ EmbeddedMFAsyncCallback<&WASAPIRenderer::OnStopPlayback> m_StopPlaybackCallback{ this };
+ EmbeddedMFAsyncCallback<&WASAPIRenderer::OnPausePlayback> m_PausePlaybackCallback{ this };
+ EmbeddedMFAsyncCallback<&WASAPIRenderer::OnSampleReady> m_SampleReadyCallback{ this };
+
+ HRESULT ConfigureDeviceInternal() noexcept;
+ void ValidateBufferValue();
+ void OnAudioSampleRequested(bool IsSilence = false);
+ void ConfigureSource();
+ UINT32 GetBufferFramesPerPeriod() noexcept;
+ void SetAudioClientChannelVolume();
+
+ void GetToneSample(uint32_t framesAvailable);
+ void GetMFSample(uint32_t framesAvailable);
+
+ private:
+ hstring m_DeviceIdString;
+ uint32_t m_BufferFrames = 0;
+
+ // Event for sample ready or user stop
+ handle m_SampleReadyEvent{ check_pointer(CreateEventEx(nullptr, nullptr, 0, EVENT_ALL_ACCESS)) };
+
+ MFWORKITEM_KEY m_SampleReadyKey;
+ slim_mutex m_lock;
+
+ unique_cotaskmem_ptr m_MixFormat;
+ uint32_t m_DefaultPeriodInFrames;
+ uint32_t m_FundamentalPeriodInFrames;
+ uint32_t m_MaxPeriodInFrames;
+ uint32_t m_MinPeriodInFrames;
+ float m_channelVolume = 1.0f;
+
+ com_ptr m_AudioClient;
+ com_ptr m_AudioRenderClient;
+ com_ptr m_SampleReadyAsyncResult;
+
+ ContentType m_contentType = ContentType::Tone;
+ bool m_IsHWOffload = false;
+ bool m_IsBackground = false;
+ bool m_IsRawAudio = false;
+ bool m_IsLowLatency = false;
+ REFERENCE_TIME m_hnsBufferDuration = 0;
+ double m_Frequency = 0.0;
+ winrt::Windows::Storage::Streams::IRandomAccessStream m_ContentStream = nullptr;
+
+ std::unique_ptr m_ToneSource;
+ com_ptr m_MFSource;
+ };
+}
diff --git a/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.sln b/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.sln
new file mode 100644
index 0000000000..9b60960dae
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.sln
@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26228.4
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsAudioSession", "WindowsAudioSession.vcxproj", "{EC601D92-D047-5EDE-96D3-0EEF8669A48B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|ARM.ActiveCfg = Debug|ARM
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|ARM.Build.0 = Debug|ARM
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|ARM.Deploy.0 = Debug|ARM
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|x64.ActiveCfg = Debug|x64
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|x64.Build.0 = Debug|x64
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|x64.Deploy.0 = Debug|x64
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|x86.ActiveCfg = Debug|Win32
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|x86.Build.0 = Debug|Win32
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Debug|x86.Deploy.0 = Debug|Win32
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|ARM.ActiveCfg = Release|ARM
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|ARM.Build.0 = Release|ARM
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|ARM.Deploy.0 = Release|ARM
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|x64.ActiveCfg = Release|x64
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|x64.Build.0 = Release|x64
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|x64.Deploy.0 = Release|x64
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|x86.ActiveCfg = Release|Win32
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|x86.Build.0 = Release|Win32
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.vcxproj b/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.vcxproj
new file mode 100644
index 0000000000..5127360b5e
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.vcxproj
@@ -0,0 +1,216 @@
+
+
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), LICENSE))\SharedContent
+
+
+ true
+ {EC601D92-D047-5EDE-96D3-0EEF8669A48B}
+ WindowsAudioSession
+ SDKTemplate
+ en-US
+ 15.0
+ true
+ Windows Store
+ 10.0
+ 10.0.19041.0
+ $(WindowsTargetPlatformVersion)
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ Application
+ Unicode
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+ $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);$(SharedContentDir)\cppwinrt
+ true
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+ 4453;28204
+
+
+ MMDevAPI.lib;MFuuid.lib;MFReadWrite.lib;MFplat.lib;uuid.lib;WindowsApp.lib;%(AdditionalDependencies)
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+
+
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+ Scenario1.xaml
+
+
+ Scenario2.xaml
+
+
+ Scenario3.xaml
+
+
+ Scenario4.xaml
+
+
+
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+
+
+ Styles\Styles.xaml
+
+
+
+
+
+ $(SharedContentDir)\xaml\App.xaml
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+ Create
+
+
+
+ Scenario1.xaml
+
+
+ Scenario2.xaml
+
+
+ Scenario3.xaml
+
+
+ Scenario4.xaml
+
+
+
+
+
+ Project.idl
+
+
+
+
+ $(SharedContentDir)\xaml\MainPage.xaml
+
+
+
+
+
+ Designer
+
+
+
+
+ Assets\microsoft-sdk.png
+
+
+ Assets\smallTile-sdk.png
+
+
+ Assets\splash-sdk.png
+
+
+ Assets\squareTile-sdk.png
+
+
+ Assets\storeLogo-sdk.png
+
+
+ Assets\tile-sdk.png
+
+
+ Assets\windows-sdk.png
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
diff --git a/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.vcxproj.filters b/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.vcxproj.filters
new file mode 100644
index 0000000000..3202acdd8c
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/WindowsAudioSession.vcxproj.filters
@@ -0,0 +1,84 @@
+
+
+
+
+ 80bfd669-aa83-4537-9611-027cffe0d8af
+ bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png
+
+
+ {c6978fb6-bc64-498d-97c8-f5b53997e54e}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Styles
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/WindowsAudioSession/cppwinrt/packages.config b/Samples/WindowsAudioSession/cppwinrt/packages.config
new file mode 100644
index 0000000000..06e8a74af7
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Samples/WindowsAudioSession/cppwinrt/pch.cpp b/Samples/WindowsAudioSession/cppwinrt/pch.cpp
new file mode 100644
index 0000000000..ade821753a
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/pch.cpp
@@ -0,0 +1,5 @@
+//
+// Include the standard header and generate the precompiled header.
+//
+
+#include "pch.h"
diff --git a/Samples/WindowsAudioSession/cppwinrt/pch.h b/Samples/WindowsAudioSession/cppwinrt/pch.h
new file mode 100644
index 0000000000..d1bc90c783
--- /dev/null
+++ b/Samples/WindowsAudioSession/cppwinrt/pch.h
@@ -0,0 +1,41 @@
+//
+// Header for standard system include files.
+//
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Common.h"
diff --git a/SharedContent/Templates/UWPSDKSampleCPP/UWPSDKSampleCPP.vcxproj.filters b/SharedContent/Templates/UWPSDKSampleCPP/UWPSDKSampleCPP.vcxproj.filters
index 050f143759..d6bd2697e0 100644
--- a/SharedContent/Templates/UWPSDKSampleCPP/UWPSDKSampleCPP.vcxproj.filters
+++ b/SharedContent/Templates/UWPSDKSampleCPP/UWPSDKSampleCPP.vcxproj.filters
@@ -7,13 +7,13 @@
-
+
-
+
-
+
@@ -22,40 +22,40 @@
-
-
+
+
-
-
+
+
-
+
Assets
-
+
Assets
-
+
Assets
-
+
Assets
-
+
Assets
-
+
Assets
-
+
Assets
@@ -63,6 +63,6 @@
-
+
\ No newline at end of file
diff --git a/archived/ApplicationData/README.md b/archived/ApplicationData/README.md
new file mode 100644
index 0000000000..9c8fc8840f
--- /dev/null
+++ b/archived/ApplicationData/README.md
@@ -0,0 +1,86 @@
+---
+topic: sample
+languages:
+- vb
+products:
+- windows
+- windows-uwp
+urlFragment: ApplicationData
+extendedZipContent:
+- path: SharedContent
+ target: SharedContent
+- path: LICENSE
+ target: LICENSE
+description: "Shows how to store and retrieve data that is specific to each user and app by using the Windows Runtime application data APIs."
+---
+
+
+
+# Application data sample
+
+Shows how to store and retrieve data that is specific to each user and app by using the Windows Runtime application data APIs
+([Windows.Storage.ApplicationData](http://msdn.microsoft.com/library/windows/apps/br241587) and so on).
+
+> **Note:** This sample is part of a large collection of UWP feature samples.
+> You can download this sample as a standalone ZIP file
+> [from docs.microsoft.com](https://docs.microsoft.com/samples/microsoft/windows-universal-samples/applicationdata/),
+> or you can download the entire collection as a single
+> [ZIP file](https://github.com/Microsoft/Windows-universal-samples/archive/master.zip), but be
+> sure to unzip everything to access shared dependencies. For more info on working with the ZIP file,
+> the samples collection, and GitHub, see [Get the UWP samples from GitHub](https://aka.ms/ovu2uq).
+> For more samples, see the [Samples portal](https://aka.ms/winsamples) on the Windows Dev Center.
+
+Application data includes session state, user preferences, and other settings. It is created, read, updated, and deleted when the app is running. The operating system manages these data stores for your app:
+
+- local: Data that exists on the current device and is backed up in the cloud
+- temporary: Data that could be removed by the system any time the app isn't running
+- localcache: Persistent data that exists only on the current device
+
+If you use local data in your app, your users can back up application data in the cloud. This application data can then be restored back on any other device while setting up the device with the same account.
+
+The sample covers these key tasks:
+
+- Reading and writing settings to an app data store
+- Reading and writing files to an app data store
+
+## Concepts
+
+[Store and retrieve settings and other app data](https://msdn.microsoft.com/library/windows/apps/mt299098)
+
+## Reference
+
+[Windows.Storage.ApplicationData](http://msdn.microsoft.com/library/windows/apps/br241587)
+[Windows.Storage.ApplicationDataCompositeValue](http://msdn.microsoft.com/library/windows/apps/br241588)
+[Windows.Storage.ApplicationDataContainer](http://msdn.microsoft.com/library/windows/apps/br241599)
+[Windows.Storage.ApplicationDataContainerSettings](http://msdn.microsoft.com/library/windows/apps/br241600)
+
+## System requirements
+
+**Client:** Windows 10
+
+**Server:** Windows Server 2016
+
+**Phone:** Windows 10
+
+## Build the sample
+
+1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
+2. Start Microsoft Visual Studio and select **File** \> **Open** \> **Project/Solution**.
+3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
+4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
+
+## Run the sample
+
+The next steps depend on whether you just want to deploy the sample or you want to both deploy and run it.
+
+### Deploying the sample
+
+- Select Build > Deploy Solution.
+
+### Deploying and running the sample
+
+- To debug the sample and then run it, press F5 or select Debug > Start Debugging. To run the sample without debugging, press Ctrl+F5 or selectDebug > Start Without Debugging.
+
diff --git a/Samples/ApplicationData/shared/App.xaml b/archived/ApplicationData/vb/App.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/App.xaml
rename to archived/ApplicationData/vb/App.xaml
diff --git a/Samples/ApplicationData/vb/App.xaml.vb b/archived/ApplicationData/vb/App.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/App.xaml.vb
rename to archived/ApplicationData/vb/App.xaml.vb
diff --git a/Samples/ApplicationData/vb/ApplicationData.sln b/archived/ApplicationData/vb/ApplicationData.sln
similarity index 100%
rename from Samples/ApplicationData/vb/ApplicationData.sln
rename to archived/ApplicationData/vb/ApplicationData.sln
diff --git a/Samples/ApplicationData/vb/ApplicationData.vbproj b/archived/ApplicationData/vb/ApplicationData.vbproj
similarity index 94%
rename from Samples/ApplicationData/vb/ApplicationData.vbproj
rename to archived/ApplicationData/vb/ApplicationData.vbproj
index 98f88b01da..c1a358285c 100644
--- a/Samples/ApplicationData/vb/ApplicationData.vbproj
+++ b/archived/ApplicationData/vb/ApplicationData.vbproj
@@ -140,62 +140,62 @@
-
+
App.xaml
MSBuild:Compile
Designer
-
+
MainPage.xaml
MSBuild:Compile
Designer
-
+
Scenario1_Files.xaml
MSBuild:Compile
Designer
-
+
Scenario2_Settings.xaml
MSBuild:Compile
Designer
-
+
Scenario3_SettingContainer.xaml
MSBuild:Compile
Designer
-
+
Scenario4_CompositeSettings.xaml
MSBuild:Compile
Designer
-
+
Scenario5_DataChangedEvent.xaml
MSBuild:Compile
Designer
-
+
Scenario6_HighPriority.xaml
MSBuild:Compile
Designer
-
+
Scenario7_Msappdata.xaml
MSBuild:Compile
Designer
-
+
Scenario8_ClearScenario.xaml
MSBuild:Compile
Designer
-
+
Scenario9_SetVersion.xaml
MSBuild:Compile
Designer
-
+
Styles\Styles.xaml
MSBuild:Compile
Designer
diff --git a/Samples/ApplicationData/cs/Assets/appDataLocal.png b/archived/ApplicationData/vb/Assets/appDataLocal.png
similarity index 100%
rename from Samples/ApplicationData/cs/Assets/appDataLocal.png
rename to archived/ApplicationData/vb/Assets/appDataLocal.png
diff --git a/Samples/ApplicationData/cs/Assets/appDataRoaming.png b/archived/ApplicationData/vb/Assets/appDataRoaming.png
similarity index 100%
rename from Samples/ApplicationData/cs/Assets/appDataRoaming.png
rename to archived/ApplicationData/vb/Assets/appDataRoaming.png
diff --git a/Samples/ApplicationData/cs/Assets/appDataTemp.png b/archived/ApplicationData/vb/Assets/appDataTemp.png
similarity index 100%
rename from Samples/ApplicationData/cs/Assets/appDataTemp.png
rename to archived/ApplicationData/vb/Assets/appDataTemp.png
diff --git a/Samples/ApplicationData/shared/MainPage.xaml b/archived/ApplicationData/vb/MainPage.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/MainPage.xaml
rename to archived/ApplicationData/vb/MainPage.xaml
diff --git a/Samples/ApplicationData/vb/MainPage.xaml.vb b/archived/ApplicationData/vb/MainPage.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/MainPage.xaml.vb
rename to archived/ApplicationData/vb/MainPage.xaml.vb
diff --git a/Samples/ApplicationData/vb/Package.appxmanifest b/archived/ApplicationData/vb/Package.appxmanifest
similarity index 100%
rename from Samples/ApplicationData/vb/Package.appxmanifest
rename to archived/ApplicationData/vb/Package.appxmanifest
diff --git a/Samples/ApplicationData/vb/SampleConfiguration.vb b/archived/ApplicationData/vb/SampleConfiguration.vb
similarity index 100%
rename from Samples/ApplicationData/vb/SampleConfiguration.vb
rename to archived/ApplicationData/vb/SampleConfiguration.vb
diff --git a/Samples/ApplicationData/shared/Scenario1_Files.xaml b/archived/ApplicationData/vb/Scenario1_Files.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario1_Files.xaml
rename to archived/ApplicationData/vb/Scenario1_Files.xaml
diff --git a/Samples/ApplicationData/vb/Scenario1_Files.xaml.vb b/archived/ApplicationData/vb/Scenario1_Files.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario1_Files.xaml.vb
rename to archived/ApplicationData/vb/Scenario1_Files.xaml.vb
diff --git a/Samples/ApplicationData/shared/Scenario2_Settings.xaml b/archived/ApplicationData/vb/Scenario2_Settings.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario2_Settings.xaml
rename to archived/ApplicationData/vb/Scenario2_Settings.xaml
diff --git a/Samples/ApplicationData/vb/Scenario2_Settings.xaml.vb b/archived/ApplicationData/vb/Scenario2_Settings.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario2_Settings.xaml.vb
rename to archived/ApplicationData/vb/Scenario2_Settings.xaml.vb
diff --git a/Samples/ApplicationData/shared/Scenario3_SettingContainer.xaml b/archived/ApplicationData/vb/Scenario3_SettingContainer.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario3_SettingContainer.xaml
rename to archived/ApplicationData/vb/Scenario3_SettingContainer.xaml
diff --git a/Samples/ApplicationData/vb/Scenario3_SettingContainer.xaml.vb b/archived/ApplicationData/vb/Scenario3_SettingContainer.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario3_SettingContainer.xaml.vb
rename to archived/ApplicationData/vb/Scenario3_SettingContainer.xaml.vb
diff --git a/Samples/ApplicationData/shared/Scenario4_CompositeSettings.xaml b/archived/ApplicationData/vb/Scenario4_CompositeSettings.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario4_CompositeSettings.xaml
rename to archived/ApplicationData/vb/Scenario4_CompositeSettings.xaml
diff --git a/Samples/ApplicationData/vb/Scenario4_CompositeSettings.xaml.vb b/archived/ApplicationData/vb/Scenario4_CompositeSettings.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario4_CompositeSettings.xaml.vb
rename to archived/ApplicationData/vb/Scenario4_CompositeSettings.xaml.vb
diff --git a/Samples/ApplicationData/shared/Scenario5_DataChangedEvent.xaml b/archived/ApplicationData/vb/Scenario5_DataChangedEvent.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario5_DataChangedEvent.xaml
rename to archived/ApplicationData/vb/Scenario5_DataChangedEvent.xaml
diff --git a/Samples/ApplicationData/vb/Scenario5_DataChangedEvent.xaml.vb b/archived/ApplicationData/vb/Scenario5_DataChangedEvent.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario5_DataChangedEvent.xaml.vb
rename to archived/ApplicationData/vb/Scenario5_DataChangedEvent.xaml.vb
diff --git a/Samples/ApplicationData/shared/Scenario6_HighPriority.xaml b/archived/ApplicationData/vb/Scenario6_HighPriority.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario6_HighPriority.xaml
rename to archived/ApplicationData/vb/Scenario6_HighPriority.xaml
diff --git a/Samples/ApplicationData/vb/Scenario6_HighPriority.xaml.vb b/archived/ApplicationData/vb/Scenario6_HighPriority.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario6_HighPriority.xaml.vb
rename to archived/ApplicationData/vb/Scenario6_HighPriority.xaml.vb
diff --git a/Samples/ApplicationData/shared/Scenario7_Msappdata.xaml b/archived/ApplicationData/vb/Scenario7_Msappdata.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario7_Msappdata.xaml
rename to archived/ApplicationData/vb/Scenario7_Msappdata.xaml
diff --git a/Samples/ApplicationData/vb/Scenario7_Msappdata.xaml.vb b/archived/ApplicationData/vb/Scenario7_Msappdata.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario7_Msappdata.xaml.vb
rename to archived/ApplicationData/vb/Scenario7_Msappdata.xaml.vb
diff --git a/Samples/ApplicationData/shared/Scenario8_ClearScenario.xaml b/archived/ApplicationData/vb/Scenario8_ClearScenario.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario8_ClearScenario.xaml
rename to archived/ApplicationData/vb/Scenario8_ClearScenario.xaml
diff --git a/Samples/ApplicationData/vb/Scenario8_ClearScenario.xaml.vb b/archived/ApplicationData/vb/Scenario8_ClearScenario.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario8_ClearScenario.xaml.vb
rename to archived/ApplicationData/vb/Scenario8_ClearScenario.xaml.vb
diff --git a/Samples/ApplicationData/shared/Scenario9_SetVersion.xaml b/archived/ApplicationData/vb/Scenario9_SetVersion.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Scenario9_SetVersion.xaml
rename to archived/ApplicationData/vb/Scenario9_SetVersion.xaml
diff --git a/Samples/ApplicationData/vb/Scenario9_SetVersion.xaml.vb b/archived/ApplicationData/vb/Scenario9_SetVersion.xaml.vb
similarity index 100%
rename from Samples/ApplicationData/vb/Scenario9_SetVersion.xaml.vb
rename to archived/ApplicationData/vb/Scenario9_SetVersion.xaml.vb
diff --git a/Samples/ApplicationData/shared/Styles.xaml b/archived/ApplicationData/vb/Styles.xaml
similarity index 100%
rename from Samples/ApplicationData/shared/Styles.xaml
rename to archived/ApplicationData/vb/Styles.xaml
diff --git a/Samples/ApplicationData/vb/SuspensionManager.vb b/archived/ApplicationData/vb/SuspensionManager.vb
similarity index 100%
rename from Samples/ApplicationData/vb/SuspensionManager.vb
rename to archived/ApplicationData/vb/SuspensionManager.vb