├── .editorconfig ├── .gitignore ├── LICENSE ├── Plugin.AudioRecorder.Android ├── AudioPlayer.cs ├── AudioRecorderService.cs ├── AudioStream.cs ├── Plugin.AudioRecorder.Android.csproj ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── Plugin.AudioRecorder.NuGet └── Plugin.AudioRecorder.NuGet.nuproj ├── Plugin.AudioRecorder.Shared ├── AudioFunctions.cs ├── AudioPlayer.cs ├── AudioRecorderService.cs ├── AudioStreamDetails.cs ├── IAudioStream.cs ├── Plugin.AudioRecorder.Shared.projitems ├── Plugin.AudioRecorder.Shared.shproj └── WaveRecorder.cs ├── Plugin.AudioRecorder.UWP ├── AudioPlayer.cs ├── AudioRecorderService.cs ├── AudioStream.cs ├── Plugin.AudioRecorder.UWP.csproj └── Properties │ ├── AssemblyInfo.cs │ └── Plugin.AudioRecorder.UWP.rd.xml ├── Plugin.AudioRecorder.iOS ├── AudioPlayer.cs ├── AudioRecorderService.cs ├── AudioStream.cs ├── Plugin.AudioRecorder.iOS.csproj ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── Plugin.AudioRecorder.sln ├── Plugin.AudioRecorder ├── AudioPlayer.cs ├── AudioRecorderService.cs ├── AudioStream.cs └── Plugin.AudioRecorder.csproj ├── README.md ├── Samples ├── Forms │ ├── AudioRecord.Forms.Android │ │ ├── Assets │ │ │ └── AboutAssets.txt │ │ ├── AudioRecord.Forms.Android.csproj │ │ ├── MainActivity.cs │ │ ├── Properties │ │ │ ├── AndroidManifest.xml │ │ │ └── AssemblyInfo.cs │ │ └── Resources │ │ │ ├── AboutResources.txt │ │ │ ├── layout │ │ │ ├── Tabbar.axml │ │ │ └── Toolbar.axml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── icon.xml │ │ │ └── icon_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── Icon.png │ │ │ └── launcher_foreground.png │ │ │ ├── mipmap-mdpi │ │ │ ├── icon.png │ │ │ └── launcher_foreground.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── Icon.png │ │ │ └── launcher_foreground.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── Icon.png │ │ │ └── launcher_foreground.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── Icon.png │ │ │ └── launcher_foreground.png │ │ │ └── values │ │ │ ├── colors.xml │ │ │ └── styles.xml │ ├── AudioRecord.Forms.UWP │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── Assets │ │ │ ├── LargeTile.scale-100.png │ │ │ ├── LargeTile.scale-200.png │ │ │ ├── LargeTile.scale-400.png │ │ │ ├── SmallTile.scale-100.png │ │ │ ├── SmallTile.scale-200.png │ │ │ ├── SmallTile.scale-400.png │ │ │ ├── SplashScreen.scale-100.png │ │ │ ├── SplashScreen.scale-200.png │ │ │ ├── SplashScreen.scale-400.png │ │ │ ├── Square150x150Logo.scale-100.png │ │ │ ├── Square150x150Logo.scale-200.png │ │ │ ├── Square150x150Logo.scale-400.png │ │ │ ├── Square44x44Logo.altform-unplated_targetsize-16.png │ │ │ ├── Square44x44Logo.altform-unplated_targetsize-256.png │ │ │ ├── Square44x44Logo.altform-unplated_targetsize-48.png │ │ │ ├── Square44x44Logo.scale-100.png │ │ │ ├── Square44x44Logo.scale-200.png │ │ │ ├── Square44x44Logo.scale-400.png │ │ │ ├── Square44x44Logo.targetsize-16.png │ │ │ ├── Square44x44Logo.targetsize-256.png │ │ │ ├── Square44x44Logo.targetsize-48.png │ │ │ ├── StoreLogo.backup.png │ │ │ ├── StoreLogo.scale-100.png │ │ │ ├── StoreLogo.scale-200.png │ │ │ ├── StoreLogo.scale-400.png │ │ │ ├── Wide310x150Logo.scale-100.png │ │ │ ├── Wide310x150Logo.scale-200.png │ │ │ └── Wide310x150Logo.scale-400.png │ │ ├── AudioRecord.Forms.UWP.csproj │ │ ├── MainPage.xaml │ │ ├── MainPage.xaml.cs │ │ ├── Package.appxmanifest │ │ └── Properties │ │ │ ├── AssemblyInfo.cs │ │ │ └── Default.rd.xml │ ├── AudioRecord.Forms.iOS │ │ ├── AppDelegate.cs │ │ ├── Assets.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Contents.json │ │ │ │ ├── Icon1024.png │ │ │ │ ├── Icon120.png │ │ │ │ ├── Icon152.png │ │ │ │ ├── Icon167.png │ │ │ │ ├── Icon180.png │ │ │ │ ├── Icon20.png │ │ │ │ ├── Icon29.png │ │ │ │ ├── Icon40.png │ │ │ │ ├── Icon58.png │ │ │ │ ├── Icon60.png │ │ │ │ ├── Icon76.png │ │ │ │ ├── Icon80.png │ │ │ │ └── Icon87.png │ │ ├── AudioRecord.Forms.iOS.csproj │ │ ├── Entitlements.plist │ │ ├── Info.plist │ │ ├── Main.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ └── Resources │ │ │ ├── Default-568h@2x.png │ │ │ ├── Default-Portrait.png │ │ │ ├── Default-Portrait@2x.png │ │ │ ├── Default.png │ │ │ ├── Default@2x.png │ │ │ └── LaunchScreen.storyboard │ └── AudioRecord.Forms │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── AudioRecord.Forms.csproj │ │ ├── MainPage.xaml │ │ └── MainPage.xaml.cs └── Native │ ├── AudioRecord.Android │ ├── Assets │ │ └── AboutAssets.txt │ ├── AudioRecord.Android.csproj │ ├── MainActivity.cs │ ├── Properties │ │ ├── AndroidManifest.xml │ │ └── AssemblyInfo.cs │ └── Resources │ │ ├── AboutResources.txt │ │ ├── layout │ │ └── activity_main.axml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── Strings.xml │ │ ├── colors.xml │ │ ├── ic_launcher_background.xml │ │ └── styles.xml │ ├── AudioRecord.UWP │ ├── App.xaml │ ├── App.xaml.cs │ ├── Assets │ │ ├── LockScreenLogo.scale-200.png │ │ ├── SplashScreen.scale-200.png │ │ ├── Square150x150Logo.scale-200.png │ │ ├── Square44x44Logo.scale-200.png │ │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ │ ├── StoreLogo.png │ │ └── Wide310x150Logo.scale-200.png │ ├── AudioRecord.UWP.csproj │ ├── MainPage.xaml │ ├── MainPage.xaml.cs │ ├── Package.appxmanifest │ └── Properties │ │ ├── AssemblyInfo.cs │ │ └── Default.rd.xml │ └── AudioRecord.iOS │ ├── AppDelegate.cs │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon1024.png │ │ ├── Icon120.png │ │ ├── Icon152.png │ │ ├── Icon167.png │ │ ├── Icon180.png │ │ ├── Icon20.png │ │ ├── Icon29.png │ │ ├── Icon40.png │ │ ├── Icon58.png │ │ ├── Icon60.png │ │ ├── Icon76.png │ │ ├── Icon80.png │ │ └── Icon87.png │ ├── AudioRecord.iOS.csproj │ ├── Entitlements.plist │ ├── Info.plist │ ├── LaunchScreen.storyboard │ ├── Main.cs │ ├── Main.storyboard │ ├── Properties │ └── AssemblyInfo.cs │ ├── Resources │ └── LaunchScreen.xib │ ├── ViewController.cs │ └── ViewController.designer.cs └── logo ├── audiorecorder-github-logo.png ├── horizontalversion.png ├── icon-nuget.png ├── icon.png └── verticalversion.png /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig: http://EditorConfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = crlf 6 | insert_final_newline = true 7 | charset = utf-8 8 | 9 | [*.cs] 10 | indent_style = tab 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | *.userprefs 9 | .vs 10 | 11 | # Xamarin.Android 12 | Resource.[Dd]esigner.cs 13 | Resources.[Dd]esigner.cs 14 | 15 | # Xamarin Components 16 | Components/ 17 | 18 | # Build results 19 | [Dd]ebug/ 20 | [Dd]ebugPublic/ 21 | [Rr]elease/ 22 | x64/ 23 | build/ 24 | bld/ 25 | [Bb]in/ 26 | [Oo]bj/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | #NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | 100 | # NCrunch 101 | *.ncrunch* 102 | _NCrunch_* 103 | .*crunch*.local.xml 104 | 105 | # MightyMoose 106 | *.mm.* 107 | AutoTest.Net/ 108 | 109 | # Web workbench (sass) 110 | .sass-cache/ 111 | 112 | # Installshield output folder 113 | [Ee]xpress/ 114 | 115 | # DocProject is a documentation generator add-in 116 | DocProject/buildhelp/ 117 | DocProject/Help/*.HxT 118 | DocProject/Help/*.HxC 119 | DocProject/Help/*.hhc 120 | DocProject/Help/*.hhk 121 | DocProject/Help/*.hhp 122 | DocProject/Help/Html2 123 | DocProject/Help/html 124 | 125 | # Click-Once directory 126 | publish/ 127 | 128 | # Publish Web Output 129 | *.[Pp]ublish.xml 130 | *.azurePubxml 131 | 132 | # NuGet Packages Directory 133 | packages/ 134 | ## TODO: If the tool you use requires repositories.config uncomment the next line 135 | !packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 138 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 139 | !packages/build/ 140 | 141 | # Windows Azure Build Output 142 | csx/ 143 | *.build.csdef 144 | 145 | # Windows Store app package directory 146 | AppPackages/ 147 | 148 | # Others 149 | sql/ 150 | *.Cache 151 | ClientBin/ 152 | [Ss]tyle[Cc]op.* 153 | ~$* 154 | *~ 155 | *.dbmdl 156 | *.dbproj.schemaview 157 | *.pfx 158 | *.publishsettings 159 | node_modules/ 160 | 161 | # RIA/Silverlight projects 162 | Generated_Code/ 163 | 164 | # Backup & report files from converting an old project file to a newer 165 | # Visual Studio version. Backup files are not needed, because we have git ;-) 166 | _UpgradeReport_Files/ 167 | Backup*/ 168 | UpgradeLog*.XML 169 | UpgradeLog*.htm 170 | *.csproj.bak 171 | 172 | # SQL Server files 173 | *.mdf 174 | *.ldf 175 | 176 | # Business Intelligence projects 177 | *.rdl.data 178 | *.bim.layout 179 | *.bim_*.settings 180 | 181 | # Microsoft Fakes 182 | FakesAssemblies/ 183 | 184 | # Xamarin 185 | #Autosave files 186 | *~ 187 | 188 | #build 189 | [Oo]bj/ 190 | [Bb]in/ 191 | packages/ 192 | TestResults/ 193 | 194 | # globs 195 | Makefile.in 196 | *.DS_Store 197 | *.sln.cache 198 | *.cache 199 | *.pidb 200 | *.userprefs 201 | *.usertasks 202 | config.log 203 | config.make 204 | config.status 205 | aclocal.m4 206 | install-sh 207 | autom4te.cache/ 208 | *.tar.gz 209 | tarballs/ 210 | test-results/ 211 | Thumbs.db 212 | 213 | #Mac bundle stuff 214 | *.dmg 215 | *.app 216 | 217 | #bitrise 218 | .bitrise* 219 | Plugin.AudioRecorder.UWP/project.lock.json 220 | .vs/config/applicationhost.config 221 | .vs/slnx.sqlite 222 | .vs/VSWorkspaceState.json 223 | Samples/AudioRecord.UWP/project.lock.json 224 | Samples/AudioRecord.UWP/project.lock.json 225 | Plugin.AudioRecorder.NuGet/Plugin.AudioRecorder.NuGet.nuget.props 226 | 227 | Plugin.AudioRecorder.NuGet/Plugin.AudioRecorder.NuGet.nuget.targets 228 | Plugin.AudioRecorder.UWP/Plugin.AudioRecorder.UWP.nuget.props 229 | Plugin.AudioRecorder.UWP/Plugin.AudioRecorder.UWP.nuget.props 230 | Samples/Forms/AudioRecord.Forms.UWP/AudioRecord.Forms.UWP.nuget.targets 231 | Samples/Forms/AudioRecord.Forms.UWP/project.lock.json 232 | Samples/Native/AudioRecord.UWP/AudioRecord.UWP.nuget.props 233 | Samples/Native/AudioRecord.UWP/project.lock.json 234 | Samples/Native/AudioRecord.UWP/project.lock.json 235 | Plugin.AudioRecorder.UWP/Plugin.AudioRecorder.UWP.nuget.props 236 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nate Rickard 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Android/AudioPlayer.cs: -------------------------------------------------------------------------------- 1 | using Android.Media; 2 | using System; 3 | 4 | namespace Plugin.AudioRecorder 5 | { 6 | public partial class AudioPlayer 7 | { 8 | private MediaPlayer mediaPlayer; 9 | 10 | public AudioPlayer () 11 | { 12 | } 13 | 14 | public void Play (string pathToAudioFile) 15 | { 16 | if (mediaPlayer != null) 17 | { 18 | mediaPlayer.Completion -= MediaPlayer_Completion; 19 | mediaPlayer.Stop (); 20 | } 21 | 22 | if (pathToAudioFile != null) 23 | { 24 | if (mediaPlayer == null) 25 | { 26 | mediaPlayer = new MediaPlayer (); 27 | 28 | mediaPlayer.Prepared += (sender, args) => 29 | { 30 | mediaPlayer.Start (); 31 | mediaPlayer.Completion += MediaPlayer_Completion; 32 | }; 33 | } 34 | 35 | mediaPlayer.Reset (); 36 | //_mediaPlayer.SetVolume (1.0f, 1.0f); 37 | 38 | mediaPlayer.SetDataSource (pathToAudioFile); 39 | mediaPlayer.PrepareAsync (); 40 | } 41 | } 42 | 43 | void MediaPlayer_Completion (object sender, EventArgs e) 44 | { 45 | FinishedPlaying?.Invoke (this, EventArgs.Empty); 46 | } 47 | 48 | public void Pause () 49 | { 50 | mediaPlayer?.Pause (); 51 | } 52 | 53 | public void Play () 54 | { 55 | mediaPlayer?.Start (); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Android/AudioRecorderService.cs: -------------------------------------------------------------------------------- 1 | using Android.Content; 2 | using Android.Media; 3 | using System; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Threading.Tasks; 7 | 8 | namespace Plugin.AudioRecorder 9 | { 10 | public partial class AudioRecorderService 11 | { 12 | partial void Init () 13 | { 14 | if (Android.OS.Build.VERSION.SdkInt > Android.OS.BuildVersionCodes.JellyBean) 15 | { 16 | try 17 | { 18 | //if the below call to AudioManager is blocking and never returning/taking forever, ensure the emulator has proper access to the system mic input 19 | var audioManager = (AudioManager) Android.App.Application.Context.GetSystemService (Context.AudioService); 20 | var property = audioManager.GetProperty (AudioManager.PropertyOutputSampleRate); 21 | 22 | if (!string.IsNullOrEmpty (property) && int.TryParse (property, out int sampleRate)) 23 | { 24 | Debug.WriteLine ($"Setting PreferredSampleRate to {sampleRate} as reported by AudioManager.PropertyOutputSampleRate"); 25 | PreferredSampleRate = sampleRate; 26 | } 27 | } 28 | catch (Exception ex) 29 | { 30 | Debug.WriteLine ("Error using AudioManager to get AudioManager.PropertyOutputSampleRate: {0}", ex); 31 | Debug.WriteLine ("PreferredSampleRate will remain at the default"); 32 | } 33 | } 34 | } 35 | 36 | Task GetDefaultFilePath () 37 | { 38 | return Task.FromResult (Path.Combine (Path.GetTempPath (), DefaultFileName)); 39 | } 40 | 41 | void OnRecordingStarting () 42 | { 43 | } 44 | 45 | void OnRecordingStopped () 46 | { 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Android/AudioStream.cs: -------------------------------------------------------------------------------- 1 | using Android.Media; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Threading.Tasks; 5 | 6 | namespace Plugin.AudioRecorder 7 | { 8 | internal class AudioStream : IAudioStream 9 | { 10 | readonly int bufferSize; 11 | readonly ChannelIn channels = ChannelIn.Mono; 12 | readonly Encoding audioFormat = Encoding.Pcm16bit; 13 | 14 | /// 15 | /// The audio source. 16 | /// 17 | AudioRecord audioSource; 18 | 19 | /// 20 | /// Occurs when new audio has been streamed. 21 | /// 22 | public event EventHandler OnBroadcast; 23 | 24 | /// 25 | /// Occurs when the audio stream active status changes. 26 | /// 27 | public event EventHandler OnActiveChanged; 28 | 29 | /// 30 | /// Occurs when there's an error while capturing audio. 31 | /// 32 | public event EventHandler OnException; 33 | 34 | /// 35 | /// The default device. 36 | /// 37 | public static readonly AudioSource DefaultDevice = AudioSource.Mic; 38 | 39 | /// 40 | /// Gets the sample rate. 41 | /// 42 | /// 43 | /// The sample rate. 44 | /// 45 | public int SampleRate { get; private set; } = 44100; 46 | 47 | /// 48 | /// Gets bits per sample. 49 | /// 50 | public int BitsPerSample => (audioSource.AudioFormat == Encoding.Pcm16bit) ? 16 : 8; 51 | 52 | /// 53 | /// Gets the channel count. 54 | /// 55 | /// 56 | /// The channel count. 57 | /// 58 | public int ChannelCount => audioSource.ChannelCount; 59 | 60 | /// 61 | /// Gets the average data transfer rate 62 | /// 63 | /// The average data transfer rate in bytes per second. 64 | public int AverageBytesPerSecond => SampleRate * BitsPerSample / 8 * ChannelCount; 65 | 66 | /// 67 | /// Gets a value indicating if the audio stream is active. 68 | /// 69 | public bool Active => audioSource?.RecordingState == RecordState.Recording; 70 | 71 | void Init () 72 | { 73 | Stop (); // just in case 74 | 75 | audioSource = new AudioRecord ( 76 | DefaultDevice, 77 | SampleRate, 78 | channels, 79 | audioFormat, 80 | bufferSize); 81 | 82 | if (audioSource.State == State.Uninitialized) 83 | { 84 | throw new Exception ("Unable to successfully initialize AudioStream; reporting State.Uninitialized. If using an emulator, make sure it has access to the system microphone."); 85 | } 86 | } 87 | 88 | /// 89 | /// Starts the audio stream. 90 | /// 91 | public Task Start () 92 | { 93 | try 94 | { 95 | if (!Active) 96 | { 97 | // not sure this does anything or if should be here... inherited via copied code ¯\_(ツ)_/¯ 98 | Android.OS.Process.SetThreadPriority (Android.OS.ThreadPriority.UrgentAudio); 99 | 100 | Init (); 101 | 102 | audioSource.StartRecording (); 103 | 104 | OnActiveChanged?.Invoke (this, true); 105 | 106 | Task.Run (() => Record ()); 107 | } 108 | 109 | return Task.FromResult (true); 110 | } 111 | catch (Exception ex) 112 | { 113 | Debug.WriteLine ("Error in AudioStream.Start(): {0}", ex.Message); 114 | 115 | Stop (); 116 | throw; 117 | } 118 | } 119 | 120 | /// 121 | /// Stops the audio stream. 122 | /// 123 | public Task Stop () 124 | { 125 | if (Active) 126 | { 127 | audioSource.Stop (); 128 | audioSource.Release (); 129 | 130 | OnActiveChanged?.Invoke (this, false); 131 | } 132 | else // just in case 133 | { 134 | audioSource?.Release (); 135 | } 136 | 137 | return Task.FromResult (true); 138 | } 139 | 140 | /// 141 | /// Initializes a new instance of the class. 142 | /// 143 | /// Sample rate. 144 | /// The value representing the number of channels to record. 145 | /// The format of the recorded audio. 146 | public AudioStream (int sampleRate = 44100, ChannelIn channels = ChannelIn.Mono, Encoding audioFormat = Encoding.Pcm16bit) 147 | { 148 | bufferSize = AudioRecord.GetMinBufferSize (sampleRate, channels, audioFormat); 149 | 150 | if (bufferSize < 0) 151 | { 152 | throw new Exception ("Invalid buffer size calculated; audio settings used may not be supported on this device"); 153 | } 154 | 155 | SampleRate = sampleRate; 156 | this.channels = channels; 157 | this.audioFormat = audioFormat; 158 | } 159 | 160 | /// 161 | /// Record from the microphone and broadcast the buffer. 162 | /// 163 | async Task Record () 164 | { 165 | byte [] data = new byte [bufferSize]; 166 | int readFailureCount = 0; 167 | int readResult = 0; 168 | 169 | Debug.WriteLine ("AudioStream.Record(): Starting background loop to read audio stream"); 170 | 171 | while (Active) 172 | { 173 | try 174 | { 175 | // not sure if this is even a good idea, but we'll try to allow a single bad read, and past that shut it down 176 | if (readFailureCount > 1) 177 | { 178 | Debug.WriteLine ("AudioStream.Record(): Multiple read failures detected, stopping stream"); 179 | await Stop (); 180 | break; 181 | } 182 | 183 | readResult = audioSource.Read (data, 0, bufferSize); // this can block if there are no bytes to read 184 | 185 | // readResult should == the # bytes read, except a few special cases 186 | if (readResult > 0) 187 | { 188 | readFailureCount = 0; 189 | OnBroadcast?.Invoke (this, data); 190 | } 191 | else 192 | { 193 | switch (readResult) 194 | { 195 | case (int) TrackStatus.ErrorInvalidOperation: 196 | case (int) TrackStatus.ErrorBadValue: 197 | case (int) TrackStatus.ErrorDeadObject: 198 | Debug.WriteLine ("AudioStream.Record(): readResult returned error code: {0}", readResult); 199 | await Stop (); 200 | break; 201 | //case (int)TrackStatus.Error: 202 | default: 203 | readFailureCount++; 204 | Debug.WriteLine ("AudioStream.Record(): readResult returned error code: {0}", readResult); 205 | break; 206 | } 207 | } 208 | } 209 | catch (Exception ex) 210 | { 211 | readFailureCount++; 212 | 213 | Debug.WriteLine ("Error in Android AudioStream.Record(): {0}", ex.Message); 214 | 215 | OnException?.Invoke (this, ex); 216 | } 217 | } 218 | } 219 | 220 | /// 221 | /// Flushes any audio bytes in memory but not yet broadcast out to any listeners. 222 | /// 223 | public void Flush () 224 | { 225 | // not needed for this implementation 226 | } 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Android/Plugin.AudioRecorder.Android.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B8C80930-F686-4FB5-8506-BD4EF845FD3D} 8 | {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 9 | Library 10 | Plugin.AudioRecorder 11 | Plugin.AudioRecorder 12 | v8.1 13 | Resources 14 | Assets 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug 21 | DEBUG; 22 | prompt 23 | 4 24 | None 25 | 26 | 27 | true 28 | pdbonly 29 | true 30 | bin\Release 31 | prompt 32 | 4 33 | true 34 | false 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Android/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | 7 | [assembly: AssemblyTitle("Plugin.AudioRecorder.Android")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("")] 12 | [assembly: AssemblyCopyright("${AuthorCopyright}")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 19 | 20 | [assembly: AssemblyVersion("1.0.0.0")] 21 | 22 | // The following attributes are used to specify the signing key for the assembly, 23 | // if desired. See the Mono documentation for more information about signing. 24 | 25 | //[assembly: AssemblyDelaySign(false)] 26 | //[assembly: AssemblyKeyFile("")] 27 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Android/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.NuGet/Plugin.AudioRecorder.NuGet.nuproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AudioRecorder plugin for Xamarin and Windows 6 | Nate Rickard 7 | Copyright © Nate Rickard 8 | https://github.com/NateRickard/Plugin.AudioRecorder 9 | https://github.com/NateRickard/Plugin.AudioRecorder/blob/master/LICENSE 10 | AudioRecorder plugin for Xamarin and Windows 11 | xamarin, pcl, xam.pcl, plugin, plugin for xamarin, android, UWP, universal windows, xamarin.forms, ios, microphone, audio, record 12 | .NETPortable,Version=v4.5,Profile=Profile111 13 | C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\ReferenceAssemblies\Microsoft\Framework\MonoAndroid\v8.1\ 14 | https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/9c4b2606/logo/icon-nuget.png 15 | true 16 | 17 | 18 | Debug 19 | AnyCPU 20 | {7ED9AE4B-267C-47C0-A816-797FBD080188} 21 | Multiplatform library for recording device microphone input 22 | Plugin.AudioRecorder 23 | 1.1.0 24 | Nate Rickard 25 | false 26 | false 27 | Exe 28 | Plugin.AudioRecorder 29 | false 30 | Plugin.AudioRecorder.NuGet 31 | v4.5 32 | 33 | 34 | true 35 | full 36 | bin\Debug 37 | prompt 38 | 39 | 40 | bin\Release 41 | prompt 42 | 43 | 44 | 45 | {B8C80930-F686-4FB5-8506-BD4EF845FD3D} 46 | Plugin.AudioRecorder.Android 47 | 48 | 49 | {818D32EE-A561-4629-ACEA-94871C20D4A8} 50 | Plugin.AudioRecorder.iOS 51 | 52 | 53 | 54 | {E539C217-D04B-49A7-B4DB-80B277FB2210} 55 | Plugin.AudioRecorder 56 | 57 | 58 | 59 | 60 | 0.2.5-dev.1 61 | All 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Shared/AudioFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace Plugin.AudioRecorder 6 | { 7 | /// 8 | /// Contains functions used to work with audio recording. 9 | /// 10 | public static class AudioFunctions 11 | { 12 | static readonly float MAX_8_BITS_SIGNED = byte.MaxValue; 13 | static readonly float MAX_8_BITS_UNSIGNED = 0xff; 14 | static readonly float MAX_16_BITS_SIGNED = short.MaxValue; 15 | static readonly float MAX_16_BITS_UNSIGNED = 0xffff; 16 | 17 | /// 18 | /// Writes a WAV file header using the specified details. 19 | /// 20 | /// The to write the WAV header to. 21 | /// The number of channels in the recorded audio. 22 | /// The sample rate of the recorded audio. 23 | /// The bits per sample of the recorded audio. 24 | /// The length/byte count of the recorded audio, or -1 if recording is still in progress. 25 | public static void WriteWavHeader (Stream stream, int channelCount, int sampleRate, int bitsPerSample, int audioLength = -1) 26 | { 27 | using (var writer = new BinaryWriter (stream, Encoding.UTF8)) 28 | { 29 | WriteWavHeader (writer, channelCount, sampleRate, bitsPerSample, audioLength); 30 | } 31 | } 32 | 33 | internal static void WriteWavHeader (BinaryWriter writer, int channelCount, int sampleRate, int bitsPerSample, int audioLength = -1) 34 | { 35 | var blockAlign = (short) (channelCount * (bitsPerSample / 8)); 36 | var averageBytesPerSecond = sampleRate * blockAlign; 37 | 38 | if (writer.BaseStream.CanSeek) 39 | { 40 | writer.Seek (0, SeekOrigin.Begin); 41 | } 42 | 43 | //chunk ID 44 | writer.Write (Encoding.UTF8.GetBytes ("RIFF")); 45 | 46 | if (audioLength > -1) 47 | { 48 | writer.Write ((Int32)(audioLength - 8)); // Size of the overall file - 8 bytes, in bytes (32-bit integer). 49 | } 50 | else 51 | { 52 | writer.Write (audioLength); // -1 (Unkown size) 53 | } 54 | 55 | //format 56 | writer.Write (Encoding.UTF8.GetBytes ("WAVE")); 57 | 58 | //subchunk 1 ID 59 | writer.Write (Encoding.UTF8.GetBytes ("fmt ")); 60 | 61 | writer.Write (16); //subchunk 1 (fmt) size 62 | writer.Write ((short) 1); //PCM audio format 63 | 64 | writer.Write ((short) channelCount); 65 | writer.Write (sampleRate); 66 | writer.Write (averageBytesPerSecond); 67 | writer.Write (blockAlign); 68 | writer.Write ((short) bitsPerSample); 69 | 70 | //subchunk 2 ID 71 | writer.Write (Encoding.UTF8.GetBytes ("data")); 72 | 73 | //subchunk 2 (data) size 74 | writer.Write (audioLength-44); 75 | } 76 | 77 | // Adapted from http://stackoverflow.com/questions/5800649/detect-silence-when-recording 78 | internal static float CalculateLevel (byte [] buffer, int readPoint = 0, int leftOver = 0, bool use16Bit = true, bool signed = true, bool bigEndian = false) 79 | { 80 | float level; 81 | int max = 0; 82 | 83 | //bool signed = (RECORDER_AUDIO_ENCODING == Android.Media.Encoding. AudioFormat. Encoding.PCM_SIGNED); 84 | //bool bigEndian = false;// (format.isBigEndian()); 85 | 86 | if (use16Bit) 87 | { 88 | for (int i = readPoint; i < buffer.Length - leftOver; i += 2) 89 | { 90 | int value = 0; 91 | // deal with endianness 92 | int hiByte = (bigEndian ? buffer [i] : buffer [i + 1]); 93 | int loByte = (bigEndian ? buffer [i + 1] : buffer [i]); 94 | 95 | if (signed) 96 | { 97 | short shortVal = (short) hiByte; 98 | shortVal = (short) ((shortVal << 8) | (byte) loByte); 99 | value = shortVal; 100 | } 101 | else 102 | { 103 | value = (hiByte << 8) | loByte; 104 | } 105 | max = Math.Max (max, value); 106 | } // for 107 | } 108 | else 109 | { 110 | // 8 bit - no endianness issues, just sign 111 | for (int i = readPoint; i < buffer.Length - leftOver; i++) 112 | { 113 | int value = 0; 114 | 115 | if (signed) 116 | { 117 | value = buffer [i]; 118 | } 119 | else 120 | { 121 | short shortVal = 0; 122 | #pragma warning disable CS0675 // Bitwise-or operator used on a sign-extended operand 123 | shortVal = (short) (shortVal | buffer [i]); 124 | #pragma warning restore CS0675 // Bitwise-or operator used on a sign-extended operand 125 | value = shortVal; 126 | } 127 | 128 | max = Math.Max (max, value); 129 | } // for 130 | } // 8 bit 131 | // express max as float of 0.0 to 1.0 of max value 132 | // of 8 or 16 bits (signed or unsigned) 133 | if (signed) 134 | { 135 | if (use16Bit) { level = (float) max / MAX_16_BITS_SIGNED; } else { level = (float) max / MAX_8_BITS_SIGNED; } 136 | } 137 | else 138 | { 139 | if (use16Bit) { level = (float) max / MAX_16_BITS_UNSIGNED; } else { level = (float) max / MAX_8_BITS_UNSIGNED; } 140 | } 141 | 142 | return level; 143 | } 144 | 145 | /// 146 | /// The bytes that we get from audiograph is in IEEE float, we need to covert that to 16 bit 147 | /// 148 | /// 149 | /// 150 | internal static short FloatToInt16 (float value) 151 | { 152 | float f = value * short.MaxValue; 153 | if (f > short.MaxValue) f = short.MaxValue; 154 | if (f < short.MinValue) f = short.MinValue; 155 | 156 | return (short) f; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Shared/AudioPlayer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Plugin.AudioRecorder 4 | { 5 | public partial class AudioPlayer 6 | { 7 | public event EventHandler FinishedPlaying; 8 | } 9 | } -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Shared/AudioStreamDetails.cs: -------------------------------------------------------------------------------- 1 | namespace Plugin.AudioRecorder 2 | { 3 | /// 4 | /// Represents the details of an , including channel count, sample rate, and bits per sample. 5 | /// 6 | public class AudioStreamDetails 7 | { 8 | /// 9 | /// Gets the sample rate of the underlying audio stream. 10 | /// 11 | public int SampleRate { get; set; } 12 | 13 | /// 14 | /// Gets the channel count of the underlying audio stream. 15 | /// 16 | public int ChannelCount { get; set; } 17 | 18 | /// 19 | /// Gets the bits per sample of the underlying audio stream. 20 | /// 21 | public int BitsPerSample { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Shared/IAudioStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Plugin.AudioRecorder 5 | { 6 | internal interface IAudioStream 7 | { 8 | /// 9 | /// Occurs when new audio has been streamed. 10 | /// 11 | event EventHandler OnBroadcast; 12 | 13 | /// 14 | /// Occurs when the audio stream active status changes. 15 | /// 16 | event EventHandler OnActiveChanged; 17 | 18 | /// 19 | /// Occurs when there's an error while capturing audio. 20 | /// 21 | event EventHandler OnException; 22 | 23 | /// 24 | /// Gets the sample rate. 25 | /// 26 | /// 27 | /// The sample rate. 28 | /// 29 | int SampleRate { get; } 30 | 31 | /// 32 | /// Gets the channel count. 33 | /// 34 | /// 35 | /// The channel count. 36 | /// 37 | int ChannelCount { get; } 38 | 39 | /// 40 | /// Gets bits per sample. 41 | /// 42 | int BitsPerSample { get; } 43 | 44 | /// 45 | /// Gets a value indicating if the audio stream is active. 46 | /// 47 | bool Active { get; } 48 | 49 | /// 50 | /// Starts the audio stream. 51 | /// 52 | Task Start (); 53 | 54 | /// 55 | /// Stops the audio stream. 56 | /// 57 | Task Stop (); 58 | 59 | /// 60 | /// Flushes any audio bytes in memory but not yet broadcast out to any listeners. 61 | /// 62 | void Flush (); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Shared/Plugin.AudioRecorder.Shared.projitems: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | {8EA2B3CD-E80A-420F-B7FC-6F36583C7FD5} 7 | 8 | 9 | Plugin.AudioRecorder 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Shared/Plugin.AudioRecorder.Shared.shproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {8EA2B3CD-E80A-420F-B7FC-6F36583C7FD5} 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.Shared/WaveRecorder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Plugin.AudioRecorder 8 | { 9 | internal class WaveRecorder : IDisposable 10 | { 11 | string audioFilePath; 12 | FileStream fileStream; 13 | StreamWriter streamWriter; 14 | BinaryWriter writer; 15 | int byteCount; 16 | IAudioStream audioStream; 17 | 18 | /// 19 | /// Starts recording WAVE format audio from the audio stream. 20 | /// 21 | /// A that provides the audio data. 22 | /// The full path of the file to record audio to. 23 | public async Task StartRecorder (IAudioStream stream, string filePath) 24 | { 25 | if (stream == null) 26 | { 27 | throw new ArgumentNullException (nameof (stream)); 28 | } 29 | 30 | try 31 | { 32 | //if we're restarting, let's see if we have an existing stream configured that can be stopped 33 | if (audioStream != null) 34 | { 35 | await audioStream.Stop (); 36 | } 37 | 38 | audioFilePath = filePath; 39 | audioStream = stream; 40 | 41 | fileStream = new FileStream (filePath, FileMode.Create, FileAccess.Write, FileShare.Read); 42 | streamWriter = new StreamWriter (fileStream); 43 | writer = new BinaryWriter (streamWriter.BaseStream, Encoding.UTF8); 44 | 45 | byteCount = 0; 46 | audioStream.OnBroadcast += OnStreamBroadcast; 47 | audioStream.OnActiveChanged += StreamActiveChanged; 48 | 49 | if (!audioStream.Active) 50 | { 51 | await audioStream.Start (); 52 | } 53 | } 54 | catch (Exception ex) 55 | { 56 | Debug.WriteLine ("Error in WaveRecorder.StartRecorder(): {0}", ex.Message); 57 | 58 | StopRecorder (); 59 | throw; 60 | } 61 | } 62 | 63 | /// 64 | /// Gets a new to the audio file in readonly mode. 65 | /// 66 | /// A object that can be used to read the audio file from the beginning. 67 | public Stream GetAudioFileStream () 68 | { 69 | //return a new stream to the same audio file, in Read mode 70 | return new FileStream (audioFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 71 | } 72 | 73 | void StreamActiveChanged (object sender, bool active) 74 | { 75 | if (!active) 76 | { 77 | StopRecorder (); 78 | } 79 | } 80 | 81 | void OnStreamBroadcast (object sender, byte [] bytes) 82 | { 83 | try 84 | { 85 | if (writer != null && streamWriter != null) 86 | { 87 | writer.Write (bytes); 88 | byteCount += bytes.Length; 89 | } 90 | } 91 | catch (Exception ex) 92 | { 93 | Debug.WriteLine ("Error in WaveRecorder.OnStreamBroadcast(): {0}", ex.Message); 94 | 95 | StopRecorder (); 96 | } 97 | } 98 | 99 | /// 100 | /// Stops recording WAV audio from the underlying and finishes writing the WAV file. 101 | /// 102 | public void StopRecorder () 103 | { 104 | try 105 | { 106 | if (audioStream != null) 107 | { 108 | audioStream.OnBroadcast -= OnStreamBroadcast; 109 | audioStream.OnActiveChanged -= StreamActiveChanged; 110 | } 111 | 112 | if (writer != null) 113 | { 114 | if (streamWriter.BaseStream.CanWrite) 115 | { 116 | //now that audio is finished recording, write a WAV/RIFF header at the beginning of the file 117 | writer.Seek (0, SeekOrigin.Begin); 118 | AudioFunctions.WriteWavHeader (writer, audioStream.ChannelCount, audioStream.SampleRate, audioStream.BitsPerSample, byteCount); 119 | } 120 | 121 | writer.Dispose (); //this should properly close/dispose the underlying stream as well 122 | writer = null; 123 | fileStream = null; 124 | streamWriter = null; 125 | } 126 | 127 | audioStream = null; 128 | } 129 | catch (Exception ex) 130 | { 131 | Debug.WriteLine ("Error during StopRecorder: {0}", ex.Message); 132 | throw; 133 | } 134 | } 135 | 136 | public void Dispose () 137 | { 138 | StopRecorder (); 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.UWP/AudioPlayer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Windows.ApplicationModel.Core; 4 | using Windows.Media.Core; 5 | using Windows.Media.Playback; 6 | using Windows.Storage; 7 | using Windows.Storage.Streams; 8 | using Windows.UI.Core; 9 | 10 | namespace Plugin.AudioRecorder 11 | { 12 | public partial class AudioPlayer 13 | { 14 | MediaPlayer audioPlayer; 15 | 16 | public AudioPlayer () 17 | { 18 | audioPlayer = new MediaPlayer (); 19 | audioPlayer.MediaEnded += AudioPlayer_MediaEnded; 20 | } 21 | 22 | public void Play (string pathToAudioFile) 23 | { 24 | _ = PlayAudio (pathToAudioFile); 25 | } 26 | 27 | async Task PlayAudio (string pathToAudioFile) 28 | { 29 | StorageFolder temporaryFolder = ApplicationData.Current.TemporaryFolder; 30 | 31 | var storageFile = await StorageFile.GetFileFromPathAsync (pathToAudioFile); 32 | 33 | IRandomAccessStream stream = await storageFile.OpenAsync (FileAccessMode.Read); 34 | audioPlayer.Source = MediaSource.CreateFromStream (stream, storageFile.FileType); 35 | audioPlayer.Play (); 36 | } 37 | 38 | async void AudioPlayer_MediaEnded (MediaPlayer sender, object args) 39 | { 40 | await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync (CoreDispatcherPriority.Normal, () => 41 | { 42 | FinishedPlaying?.Invoke (this, EventArgs.Empty); 43 | }); 44 | } 45 | 46 | public void Pause () 47 | { 48 | audioPlayer?.Pause (); 49 | } 50 | 51 | public void Play () 52 | { 53 | audioPlayer?.Play (); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.UWP/AudioRecorderService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Windows.Storage; 4 | 5 | namespace Plugin.AudioRecorder 6 | { 7 | public partial class AudioRecorderService 8 | { 9 | partial void Init () { } 10 | 11 | async Task GetDefaultFilePath () 12 | { 13 | var temporaryFolder = ApplicationData.Current.TemporaryFolder; 14 | var tempFile = await temporaryFolder.CreateFileAsync (DefaultFileName, CreationCollisionOption.ReplaceExisting); 15 | 16 | return tempFile.Path; 17 | } 18 | 19 | void OnRecordingStarting () 20 | { 21 | } 22 | 23 | void OnRecordingStopped () 24 | { 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.UWP/Plugin.AudioRecorder.UWP.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8803A551-21D1-43AC-866C-39DDA703C237} 8 | Library 9 | Properties 10 | Plugin.AudioRecorder 11 | Plugin.AudioRecorder 12 | en-US 13 | UAP 14 | 10.0.17134.0 15 | 10.0.15063.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | 20 | 21 | AnyCPU 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 27 | prompt 28 | 4 29 | 30 | 31 | AnyCPU 32 | pdbonly 33 | true 34 | bin\Release\ 35 | TRACE;NETFX_CORE;WINDOWS_UWP 36 | prompt 37 | 4 38 | true 39 | 40 | 41 | x86 42 | true 43 | bin\x86\Debug\ 44 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 45 | ;2008 46 | full 47 | x86 48 | false 49 | prompt 50 | true 51 | 52 | 53 | x86 54 | bin\x86\Release\ 55 | TRACE;NETFX_CORE;WINDOWS_UWP 56 | true 57 | ;2008 58 | pdbonly 59 | x86 60 | false 61 | prompt 62 | true 63 | 64 | 65 | ARM 66 | true 67 | bin\ARM\Debug\ 68 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 69 | ;2008 70 | full 71 | ARM 72 | false 73 | prompt 74 | 75 | 76 | ARM 77 | bin\ARM\Release\ 78 | TRACE;NETFX_CORE;WINDOWS_UWP 79 | true 80 | ;2008 81 | pdbonly 82 | ARM 83 | false 84 | prompt 85 | 86 | 87 | x64 88 | true 89 | bin\x64\Debug\ 90 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 91 | ;2008 92 | full 93 | x64 94 | false 95 | prompt 96 | 97 | 98 | x64 99 | bin\x64\Release\ 100 | TRACE;NETFX_CORE;WINDOWS_UWP 101 | true 102 | ;2008 103 | pdbonly 104 | x64 105 | false 106 | prompt 107 | 108 | 109 | PackageReference 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 6.1.7 121 | 122 | 123 | 0.2.5-dev.1 124 | 125 | 126 | 127 | 128 | 14.0 129 | 130 | 131 | 138 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.UWP/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Plugin.AudioRecorder.UWP")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Plugin.AudioRecorder.UWP")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /Plugin.AudioRecorder.UWP/Properties/Plugin.AudioRecorder.UWP.rd.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.iOS/AudioPlayer.cs: -------------------------------------------------------------------------------- 1 | using AVFoundation; 2 | using Foundation; 3 | using System; 4 | using System.Diagnostics; 5 | 6 | namespace Plugin.AudioRecorder 7 | { 8 | public partial class AudioPlayer 9 | { 10 | AVAudioPlayer audioPlayer = null; 11 | NSString currentAVAudioSessionCategory; 12 | 13 | static AVAudioSessionCategory? requestedAVAudioSessionCategory; 14 | 15 | /// 16 | /// If is used to request an AVAudioSession category, this Action will also be run to configure the before playing audio. 17 | /// 18 | public static Action OnPrepareAudioSession; 19 | 20 | /// 21 | /// If is used to request an AVAudioSession category, this Action will also be run to reset or re-configure the after audio playback is complete. 22 | /// 23 | public static Action OnResetAudioSession; 24 | 25 | public AudioPlayer () 26 | { 27 | } 28 | 29 | /// 30 | /// Call this method in your iOS project if you'd like the to set the shared 31 | /// category to the requested before playing audio and return it to its previous value after playback is complete. 32 | /// and will also be called before and after each playback operation to allow for further session configuration. 33 | /// Note that some categories do not support playback. 34 | /// 35 | public static void RequestAVAudioSessionCategory (AVAudioSessionCategory category) 36 | { 37 | requestedAVAudioSessionCategory = category; 38 | } 39 | 40 | public void Play (string pathToAudioFile) 41 | { 42 | // Check if _audioPlayer is currently playing 43 | if (audioPlayer != null) 44 | { 45 | audioPlayer.FinishedPlaying -= Player_FinishedPlaying; 46 | audioPlayer.Stop (); 47 | } 48 | 49 | if (requestedAVAudioSessionCategory.HasValue) 50 | { 51 | // If the user has called RequestAVAudioSessionCategory(), let's attempt to set that category for them 52 | // see: https://developer.apple.com/library/archive/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/AudioSessionCategoriesandModes/AudioSessionCategoriesandModes.html#//apple_ref/doc/uid/TP40007875-CH10 53 | var audioSession = AVAudioSession.SharedInstance (); 54 | 55 | if (!audioSession.Category.ToString ().EndsWith (requestedAVAudioSessionCategory.Value.ToString ())) 56 | { 57 | // track the current category, as long as we haven't already done this (or else we may capture the category we're setting below) 58 | if (currentAVAudioSessionCategory == null) 59 | { 60 | currentAVAudioSessionCategory = audioSession.Category; 61 | } 62 | 63 | var err = audioSession.SetCategory (requestedAVAudioSessionCategory.Value); 64 | 65 | if (err != null) 66 | { 67 | throw new Exception ($"Current AVAudioSession category is ({currentAVAudioSessionCategory}); Application requested an AVAudioSession category of {requestedAVAudioSessionCategory.Value} but received error when attempting to set it: {err}"); 68 | } 69 | } 70 | 71 | // allow for additional audio session config 72 | OnPrepareAudioSession?.Invoke (audioSession); 73 | } 74 | 75 | string localUrl = pathToAudioFile; 76 | audioPlayer = AVAudioPlayer.FromUrl (NSUrl.FromFilename (localUrl)); 77 | audioPlayer.FinishedPlaying += Player_FinishedPlaying; 78 | audioPlayer.Play (); 79 | } 80 | 81 | void Player_FinishedPlaying (object sender, AVStatusEventArgs e) 82 | { 83 | if (currentAVAudioSessionCategory != null) 84 | { 85 | var audioSession = AVAudioSession.SharedInstance (); 86 | 87 | if (audioSession.SetCategory (currentAVAudioSessionCategory, out NSError err)) 88 | { 89 | currentAVAudioSessionCategory = null; //reset this if success, otherwise hang onto it to possibly try again 90 | } 91 | else 92 | { 93 | // we won't error out here as this likely won't prevent us from stopping properly... but we will log an issue 94 | Debug.WriteLine ($"Error attempting to set the AVAudioSession category back to {currentAVAudioSessionCategory} :: {err}"); 95 | } 96 | 97 | // allow for additional audio session reset/config 98 | OnResetAudioSession?.Invoke (audioSession); 99 | } 100 | 101 | FinishedPlaying?.Invoke (this, EventArgs.Empty); 102 | } 103 | 104 | public void Pause () 105 | { 106 | audioPlayer?.Pause (); 107 | } 108 | 109 | public void Play () 110 | { 111 | audioPlayer?.Play (); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.iOS/AudioRecorderService.cs: -------------------------------------------------------------------------------- 1 | using AVFoundation; 2 | using Foundation; 3 | using System; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Threading.Tasks; 7 | 8 | namespace Plugin.AudioRecorder 9 | { 10 | public partial class AudioRecorderService 11 | { 12 | NSString currentAVAudioSessionCategory; 13 | 14 | static AVAudioSessionCategory? requestedAVAudioSessionCategory; 15 | 16 | /// 17 | /// If is used to request an AVAudioSession category, this Action will also be run to configure the before recording audio. 18 | /// 19 | public static Action OnPrepareAudioSession; 20 | 21 | /// 22 | /// If is used to request an AVAudioSession category, this Action will also be run to reset or re-configure the after audio recording is complete. 23 | /// 24 | public static Action OnResetAudioSession; 25 | 26 | partial void Init () { } 27 | 28 | /// 29 | /// Call this method in your iOS project if you'd like the to attempt to set the shared 30 | /// category to the requested before recording audio and return it to its previous value after recording is complete. 31 | /// The default category used will be . Note that some categories do not support recording. 32 | /// 33 | public static void RequestAVAudioSessionCategory (AVAudioSessionCategory category = AVAudioSessionCategory.PlayAndRecord) 34 | { 35 | requestedAVAudioSessionCategory = category; 36 | } 37 | 38 | Task GetDefaultFilePath () 39 | { 40 | return Task.FromResult (Path.Combine (Path.GetTempPath (), DefaultFileName)); 41 | } 42 | 43 | void OnRecordingStarting () 44 | { 45 | if (requestedAVAudioSessionCategory.HasValue) 46 | { 47 | // If the user has called RequestAVAudioSessionCategory(), let's attempt to set that category for them 48 | // see: https://developer.apple.com/library/archive/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/AudioSessionCategoriesandModes/AudioSessionCategoriesandModes.html#//apple_ref/doc/uid/TP40007875-CH10 49 | var audioSession = AVAudioSession.SharedInstance (); 50 | 51 | if (!audioSession.Category.ToString ().EndsWith (requestedAVAudioSessionCategory.Value.ToString ())) 52 | { 53 | // track the current category, as long as we haven't already done this (or else we may capture the category we're setting below) 54 | if (currentAVAudioSessionCategory == null) 55 | { 56 | currentAVAudioSessionCategory = audioSession.Category; 57 | } 58 | 59 | var err = audioSession.SetCategory (requestedAVAudioSessionCategory.Value); 60 | 61 | if (err != null) 62 | { 63 | throw new Exception ($"Current AVAudioSession category is ({currentAVAudioSessionCategory}); Application requested an AVAudioSession category of {requestedAVAudioSessionCategory.Value} but received error when attempting to set it: {err}"); 64 | } 65 | } 66 | 67 | // allow for additional audio session config 68 | OnPrepareAudioSession?.Invoke (audioSession); 69 | } 70 | } 71 | 72 | void OnRecordingStopped () 73 | { 74 | if (currentAVAudioSessionCategory != null) 75 | { 76 | var audioSession = AVAudioSession.SharedInstance (); 77 | 78 | if (audioSession.SetCategory (currentAVAudioSessionCategory, out NSError err)) 79 | { 80 | currentAVAudioSessionCategory = null; //reset this if success, otherwise hang onto it to possibly try again 81 | } 82 | else 83 | { 84 | // we won't error out here as this likely won't prevent us from stopping properly... but we will log an issue 85 | Debug.WriteLine ($"Error attempting to set the AVAudioSession category back to {currentAVAudioSessionCategory} :: {err}"); 86 | } 87 | 88 | // allow for additional audio session reset/config 89 | OnResetAudioSession?.Invoke (audioSession); 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.iOS/AudioStream.cs: -------------------------------------------------------------------------------- 1 | using AudioToolbox; 2 | using System; 3 | using System.Diagnostics; 4 | using System.Runtime.InteropServices; 5 | using System.Threading.Tasks; 6 | 7 | namespace Plugin.AudioRecorder 8 | { 9 | internal class AudioStream : IAudioStream 10 | { 11 | const int CountAudioBuffers = 3; 12 | const int MaxBufferSize = 0x50000; // 320 KB 13 | const float TargetMeasurementTime = 100F; // milliseconds 14 | 15 | InputAudioQueue audioQueue; 16 | 17 | /// 18 | /// Occurs when new audio has been streamed. 19 | /// 20 | public event EventHandler OnBroadcast; 21 | 22 | /// 23 | /// Occurs when the audio stream active status changes. 24 | /// 25 | public event EventHandler OnActiveChanged; 26 | 27 | /// 28 | /// Occurs when there's an error while capturing audio. 29 | /// 30 | public event EventHandler OnException; 31 | 32 | /// 33 | /// Gets the sample rate. 34 | /// 35 | /// 36 | /// The sample rate. 37 | /// 38 | public int SampleRate 39 | { 40 | get; 41 | private set; 42 | } 43 | 44 | /// 45 | /// Gets the channel count. Currently always 1 (Mono). 46 | /// 47 | /// 48 | /// The channel count. 49 | /// 50 | public int ChannelCount => 1; 51 | 52 | /// 53 | /// Gets bits per sample. Currently always 16 (bits). 54 | /// 55 | public int BitsPerSample => 16; 56 | 57 | /// 58 | /// Gets a value indicating if the audio stream is active. 59 | /// 60 | public bool Active => audioQueue?.IsRunning ?? false; 61 | 62 | /// 63 | /// Wrapper function to run success/failure callbacks from an operation that returns an AudioQueueStatus. 64 | /// 65 | /// The function that returns AudioQueueStatus. 66 | /// The Action to run if the result is AudioQueueStatus.Ok. 67 | /// The Action to run if the result is anything other than AudioQueueStatus.Ok. 68 | void BufferOperation (Func bufferFn, Action successAction = null, Action failAction = null) 69 | { 70 | var status = bufferFn (); 71 | 72 | if (status == AudioQueueStatus.Ok) 73 | { 74 | successAction?.Invoke (); 75 | } 76 | else 77 | { 78 | if (failAction != null) 79 | { 80 | failAction (status); 81 | } 82 | else 83 | { 84 | throw new Exception ($"AudioStream buffer error :: buffer operation returned non - Ok status:: {status}"); 85 | } 86 | } 87 | } 88 | 89 | /// 90 | /// Starts the audio stream. 91 | /// 92 | public Task Start () 93 | { 94 | try 95 | { 96 | if (!Active) 97 | { 98 | InitAudioQueue (); 99 | 100 | BufferOperation (() => audioQueue.Start (), 101 | () => OnActiveChanged?.Invoke (this, true), 102 | status => throw new Exception ($"audioQueue.Start() returned non-OK status: {status}")); 103 | } 104 | 105 | return Task.FromResult (true); 106 | } 107 | catch (Exception ex) 108 | { 109 | Debug.WriteLine ("Error in AudioStream.Start(): {0}", ex.Message); 110 | 111 | Stop (); 112 | throw; 113 | } 114 | } 115 | 116 | /// 117 | /// Stops the audio stream. 118 | /// 119 | public Task Stop () 120 | { 121 | if (audioQueue != null) 122 | { 123 | audioQueue.InputCompleted -= QueueInputCompleted; 124 | 125 | if (audioQueue.IsRunning) 126 | { 127 | BufferOperation (() => audioQueue.Stop (true), 128 | () => OnActiveChanged?.Invoke (this, false), 129 | status => Debug.WriteLine ("AudioStream.Stop() :: audioQueue.Stop returned non OK result: {0}", status)); 130 | } 131 | 132 | audioQueue.Dispose (); 133 | audioQueue = null; 134 | } 135 | 136 | return Task.FromResult (true); 137 | } 138 | 139 | /// 140 | /// Initializes a new instance of the class. 141 | /// 142 | /// Sample rate. 143 | public AudioStream (int sampleRate) 144 | { 145 | SampleRate = sampleRate; 146 | } 147 | 148 | void InitAudioQueue () 149 | { 150 | // create our audio queue & configure buffers 151 | var audioFormat = AudioStreamBasicDescription.CreateLinearPCM (SampleRate, (uint) ChannelCount, (uint) BitsPerSample); 152 | 153 | audioQueue = new InputAudioQueue (audioFormat); 154 | audioQueue.InputCompleted += QueueInputCompleted; 155 | 156 | // calculate our buffer size and make sure it's not too big 157 | var bufferByteSize = (int) (TargetMeasurementTime / 1000F/*ms to sec*/ * SampleRate * audioFormat.BytesPerPacket); 158 | bufferByteSize = bufferByteSize < MaxBufferSize ? bufferByteSize : MaxBufferSize; 159 | 160 | for (var index = 0; index < CountAudioBuffers; index++) 161 | { 162 | var bufferPtr = IntPtr.Zero; 163 | 164 | BufferOperation (() => audioQueue.AllocateBuffer (bufferByteSize, out bufferPtr), () => 165 | { 166 | BufferOperation (() => audioQueue.EnqueueBuffer (bufferPtr, bufferByteSize, null), () => Debug.WriteLine ("AudioQueue buffer enqueued :: {0} of {1}", index + 1, CountAudioBuffers)); 167 | }); 168 | } 169 | } 170 | 171 | /// 172 | /// Handles iOS audio buffer queue completed message. 173 | /// 174 | /// Sender object 175 | /// Input completed parameters. 176 | void QueueInputCompleted (object sender, InputCompletedEventArgs e) 177 | { 178 | try 179 | { 180 | // we'll only broadcast if we're actively monitoring audio packets 181 | if (!Active) 182 | { 183 | return; 184 | } 185 | 186 | if (e.Buffer.AudioDataByteSize > 0) 187 | { 188 | var audioBytes = new byte [e.Buffer.AudioDataByteSize]; 189 | Marshal.Copy (e.Buffer.AudioData, audioBytes, 0, (int) e.Buffer.AudioDataByteSize); 190 | 191 | // broadcast the audio data to any listeners 192 | OnBroadcast?.Invoke (this, audioBytes); 193 | 194 | // check if active again, because the auto stop logic may stop the audio queue from within this handler! 195 | if (Active) 196 | { 197 | BufferOperation (() => audioQueue.EnqueueBuffer (e.IntPtrBuffer, null), null, status => 198 | { 199 | Debug.WriteLine ("AudioStream.QueueInputCompleted() :: audioQueue.EnqueueBuffer returned non-Ok status :: {0}", status); 200 | OnException?.Invoke (this, new Exception ($"audioQueue.EnqueueBuffer returned non-Ok status :: {status}")); 201 | }); 202 | } 203 | } 204 | } 205 | catch (Exception ex) 206 | { 207 | Debug.WriteLine ("AudioStream.QueueInputCompleted() :: Error: {0}", ex.Message); 208 | 209 | OnException?.Invoke (this, new Exception ($"AudioStream.QueueInputCompleted() :: Error: {ex.Message}")); 210 | } 211 | } 212 | 213 | /// 214 | /// Flushes any audio bytes in memory but not yet broadcast out to any listeners. 215 | /// 216 | public void Flush () 217 | { 218 | // not needed for this implementation 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.iOS/Plugin.AudioRecorder.iOS.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {818D32EE-A561-4629-ACEA-94871C20D4A8} 8 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 9 | Library 10 | Plugin.AudioRecorder 11 | Plugin.AudioRecorder 12 | Resources 13 | 14 | 15 | true 16 | full 17 | false 18 | bin\Debug 19 | DEBUG; 20 | prompt 21 | 4 22 | iPhone Developer 23 | true 24 | true 25 | true 26 | true 27 | 25459 28 | false 29 | 30 | 31 | pdbonly 32 | true 33 | bin\Release 34 | prompt 35 | 4 36 | iPhone Developer 37 | true 38 | SdkOnly 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.iOS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following attributes. 5 | // Change them to the values specific to your project. 6 | 7 | [assembly: AssemblyTitle("Plugin.AudioRecorder.iOS")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("")] 12 | [assembly: AssemblyCopyright("${AuthorCopyright}")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 19 | 20 | [assembly: AssemblyVersion("1.0.0.0")] 21 | 22 | // The following attributes are used to specify the signing key for the assembly, 23 | // if desired. See the Mono documentation for more information about signing. 24 | 25 | //[assembly: AssemblyDelaySign(false)] 26 | //[assembly: AssemblyKeyFile("")] 27 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder.iOS/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder/AudioPlayer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Plugin.AudioRecorder 4 | { 5 | public partial class AudioPlayer 6 | { 7 | public void Play (string pathToAudioFile) => throw new NotImplementedException (); 8 | 9 | public void Pause () => throw new NotImplementedException (); 10 | 11 | public void Play () => throw new NotImplementedException (); 12 | } 13 | } -------------------------------------------------------------------------------- /Plugin.AudioRecorder/AudioRecorderService.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | 4 | namespace Plugin.AudioRecorder 5 | { 6 | public partial class AudioRecorderService 7 | { 8 | Task GetDefaultFilePath () 9 | { 10 | return Task.FromResult (Path.Combine (Path.GetTempPath (), DefaultFileName)); 11 | } 12 | 13 | void OnRecordingStarting () 14 | { 15 | } 16 | 17 | void OnRecordingStopped () 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder/AudioStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Plugin.AudioRecorder 5 | { 6 | // Dummy implementation - Bait & Switch will be used to force apps to use platform specific dlls. 7 | internal class AudioStream : IAudioStream 8 | { 9 | public int SampleRate => throw new NotImplementedException (); 10 | 11 | public int ChannelCount => throw new NotImplementedException (); 12 | 13 | public int BitsPerSample => throw new NotImplementedException (); 14 | 15 | public bool Active => throw new NotImplementedException (); 16 | 17 | public event EventHandler OnBroadcast; 18 | public event EventHandler OnActiveChanged; 19 | public event EventHandler OnException; 20 | 21 | public AudioStream (int sampleRate) 22 | { 23 | } 24 | 25 | public Task Start () 26 | { 27 | throw new NotImplementedException (); 28 | } 29 | 30 | public Task Stop () 31 | { 32 | throw new NotImplementedException (); 33 | } 34 | 35 | public void Flush () 36 | { 37 | throw new NotImplementedException (); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Plugin.AudioRecorder/Plugin.AudioRecorder.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Assets/AboutAssets.txt: -------------------------------------------------------------------------------- 1 | Any raw assets you want to be deployed with your application can be placed in 2 | this directory (and child directories) and given a Build Action of "AndroidAsset". 3 | 4 | These files will be deployed with you package and will be accessible using Android's 5 | AssetManager, like this: 6 | 7 | public class ReadAsset : Activity 8 | { 9 | protected override void OnCreate (Bundle bundle) 10 | { 11 | base.OnCreate (bundle); 12 | 13 | InputStream input = Assets.Open ("my_asset.txt"); 14 | } 15 | } 16 | 17 | Additionally, some Android functions will automatically load asset files: 18 | 19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf"); 20 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/AudioRecord.Forms.Android.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {CB59A887-9999-4656-BDF0-CD47F3E1B1AA} 7 | {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 8 | {c9e5eea5-ca05-42a1-839b-61506e0a37df} 9 | Library 10 | AudioRecord.Forms.Droid 11 | AudioRecord.Forms.Android 12 | True 13 | Resources\Resource.designer.cs 14 | Resource 15 | Properties\AndroidManifest.xml 16 | Resources 17 | Assets 18 | false 19 | v8.1 20 | 21 | 22 | 23 | 24 | true 25 | full 26 | false 27 | bin\Debug 28 | DEBUG; 29 | prompt 30 | 4 31 | None 32 | 33 | 34 | true 35 | pdbonly 36 | true 37 | bin\Release 38 | prompt 39 | 4 40 | true 41 | false 42 | 43 | 44 | true 45 | bin\x86\Debug\ 46 | DEBUG; 47 | full 48 | x86 49 | Off 50 | prompt 51 | MinimumRecommendedRules.ruleset 52 | 53 | 54 | true 55 | bin\x86\Release\ 56 | true 57 | pdbonly 58 | x86 59 | Off 60 | prompt 61 | MinimumRecommendedRules.ruleset 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 1.1.0 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Designer 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | {64696B44-CFA0-4320-B53F-CD539D3BA5AE} 121 | AudioRecord.Forms 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using Android; 2 | using Android.App; 3 | using Android.Content.PM; 4 | using Android.OS; 5 | using Android.Support.V4.App; 6 | using Android.Support.V4.Content; 7 | using System; 8 | 9 | namespace AudioRecord.Forms.Droid 10 | { 11 | [Activity(Label = "AudioRecord.Forms", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] 12 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity 13 | { 14 | protected override void OnCreate(Bundle bundle) 15 | { 16 | TabLayoutResource = Resource.Layout.Tabbar; 17 | ToolbarResource = Resource.Layout.Toolbar; 18 | 19 | base.OnCreate(bundle); 20 | 21 | global::Xamarin.Forms.Forms.Init(this, bundle); 22 | LoadApplication(new App()); 23 | 24 | if (ContextCompat.CheckSelfPermission (this, Manifest.Permission.RecordAudio) != Permission.Granted) 25 | { 26 | ActivityCompat.RequestPermissions (this, new String []{ Manifest.Permission.RecordAudio }, 1); 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Properties/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using Android.App; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTitle("AudioRecord.Forms.Android")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("AudioRecord.Forms.Android")] 14 | [assembly: AssemblyCopyright("Copyright © 2014")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | [assembly: ComVisible(false)] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: AssemblyVersion("1.0.0.0")] 30 | [assembly: AssemblyFileVersion("1.0.0.0")] 31 | 32 | // Add some common permissions, these can be removed if not needed 33 | [assembly: UsesPermission(Android.Manifest.Permission.Internet)] 34 | [assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)] 35 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/AboutResources.txt: -------------------------------------------------------------------------------- 1 | Images, layout descriptions, binary blobs and string dictionaries can be included 2 | in your application as resource files. Various Android APIs are designed to 3 | operate on the resource IDs instead of dealing with images, strings or binary blobs 4 | directly. 5 | 6 | For example, a sample Android app that contains a user interface layout (main.xml), 7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) 8 | would keep its resources in the "Resources" directory of the application: 9 | 10 | Resources/ 11 | drawable-hdpi/ 12 | icon.png 13 | 14 | drawable-ldpi/ 15 | icon.png 16 | 17 | drawable-mdpi/ 18 | icon.png 19 | 20 | layout/ 21 | main.xml 22 | 23 | values/ 24 | strings.xml 25 | 26 | In order to get the build system to recognize Android resources, set the build action to 27 | "AndroidResource". The native Android APIs do not operate directly with filenames, but 28 | instead operate on resource IDs. When you compile an Android application that uses resources, 29 | the build system will package the resources for distribution and generate a class called 30 | "Resource" that contains the tokens for each one of the resources included. For example, 31 | for the above Resources layout, this is what the Resource class would expose: 32 | 33 | public class Resource { 34 | public class drawable { 35 | public const int icon = 0x123; 36 | } 37 | 38 | public class layout { 39 | public const int main = 0x456; 40 | } 41 | 42 | public class strings { 43 | public const int first_string = 0xabc; 44 | public const int second_string = 0xbcd; 45 | } 46 | } 47 | 48 | You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main 49 | to reference the layout/main.xml file, or Resource.strings.first_string to reference the first 50 | string in the dictionary file values/strings.xml. 51 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/layout/Tabbar.axml: -------------------------------------------------------------------------------- 1 | 2 | 12 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/layout/Toolbar.axml: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-anydpi-v26/icon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-anydpi-v26/icon_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-hdpi/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-hdpi/Icon.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-hdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-hdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-mdpi/icon.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-mdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-mdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xhdpi/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xhdpi/Icon.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xxhdpi/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xxhdpi/Icon.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xxhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xxhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xxxhdpi/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xxxhdpi/Icon.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | #3F51B5 5 | #303F9F 6 | #FF4081 7 | 8 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.Android/Resources/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 26 | 27 | 30 | 31 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.Foundation; 9 | using Windows.Foundation.Collections; 10 | using Windows.UI.Xaml; 11 | using Windows.UI.Xaml.Controls; 12 | using Windows.UI.Xaml.Controls.Primitives; 13 | using Windows.UI.Xaml.Data; 14 | using Windows.UI.Xaml.Input; 15 | using Windows.UI.Xaml.Media; 16 | using Windows.UI.Xaml.Navigation; 17 | 18 | namespace AudioRecord.Forms.UWP 19 | { 20 | /// 21 | /// Provides application-specific behavior to supplement the default Application class. 22 | /// 23 | sealed partial class App : Application 24 | { 25 | /// 26 | /// Initializes the singleton application object. This is the first line of authored code 27 | /// executed, and as such is the logical equivalent of main() or WinMain(). 28 | /// 29 | public App() 30 | { 31 | this.InitializeComponent(); 32 | this.Suspending += OnSuspending; 33 | } 34 | 35 | /// 36 | /// Invoked when the application is launched normally by the end user. Other entry points 37 | /// will be used such as when the application is launched to open a specific file. 38 | /// 39 | /// Details about the launch request and process. 40 | protected override void OnLaunched(LaunchActivatedEventArgs e) 41 | { 42 | 43 | 44 | Frame rootFrame = Window.Current.Content as Frame; 45 | 46 | // Do not repeat app initialization when the Window already has content, 47 | // just ensure that the window is active 48 | if (rootFrame == null) 49 | { 50 | // Create a Frame to act as the navigation context and navigate to the first page 51 | rootFrame = new Frame(); 52 | 53 | rootFrame.NavigationFailed += OnNavigationFailed; 54 | 55 | Xamarin.Forms.Forms.Init(e); 56 | 57 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 58 | { 59 | //TODO: Load state from previously suspended application 60 | } 61 | 62 | // Place the frame in the current Window 63 | Window.Current.Content = rootFrame; 64 | } 65 | 66 | if (rootFrame.Content == null) 67 | { 68 | // When the navigation stack isn't restored navigate to the first page, 69 | // configuring the new page by passing required information as a navigation 70 | // parameter 71 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 72 | } 73 | // Ensure the current window is active 74 | Window.Current.Activate(); 75 | } 76 | 77 | /// 78 | /// Invoked when Navigation to a certain page fails 79 | /// 80 | /// The Frame which failed navigation 81 | /// Details about the navigation failure 82 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 83 | { 84 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 85 | } 86 | 87 | /// 88 | /// Invoked when application execution is being suspended. Application state is saved 89 | /// without knowing whether the application will be terminated or resumed with the contents 90 | /// of memory still intact. 91 | /// 92 | /// The source of the suspend request. 93 | /// Details about the suspend request. 94 | private void OnSuspending(object sender, SuspendingEventArgs e) 95 | { 96 | var deferral = e.SuspendingOperation.GetDeferral(); 97 | //TODO: Save application state and stop any background activity 98 | deferral.Complete(); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/LargeTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/LargeTile.scale-100.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/LargeTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/LargeTile.scale-200.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/LargeTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/LargeTile.scale-400.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/SmallTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/SmallTile.scale-100.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/SmallTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/SmallTile.scale-200.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/SmallTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/SmallTile.scale-400.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/StoreLogo.backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/StoreLogo.backup.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Wide310x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Wide310x150Logo.scale-100.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Assets/Wide310x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.UWP/Assets/Wide310x150Logo.scale-400.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.Foundation; 7 | using Windows.Foundation.Collections; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Controls.Primitives; 11 | using Windows.UI.Xaml.Data; 12 | using Windows.UI.Xaml.Input; 13 | using Windows.UI.Xaml.Media; 14 | using Windows.UI.Xaml.Navigation; 15 | 16 | namespace AudioRecord.Forms.UWP 17 | { 18 | public sealed partial class MainPage 19 | { 20 | public MainPage() 21 | { 22 | this.InitializeComponent(); 23 | 24 | LoadApplication(new AudioRecord.Forms.App()); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | AudioRecord.Forms.UWP 7 | 1bc87961-c437-4be2-aa22-cfa50c414288 8 | Assets\StoreLogo.png 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AudioRecord.Forms.UWP")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AudioRecord.Forms.UWP")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.UWP/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using AVFoundation; 2 | using Foundation; 3 | using Plugin.AudioRecorder; 4 | using UIKit; 5 | 6 | namespace AudioRecord.Forms.iOS 7 | { 8 | // The UIApplicationDelegate for the application. This class is responsible for launching the 9 | // User Interface of the application, as well as listening (and optionally responding) to 10 | // application events from iOS. 11 | [Register("AppDelegate")] 12 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate 13 | { 14 | // 15 | // This method is invoked when the application has loaded and is ready to run. In this 16 | // method you should instantiate the window, load the UI into it and then make the window 17 | // visible. 18 | // 19 | // You have 17 seconds to return from this method, or iOS will terminate your application. 20 | // 21 | public override bool FinishedLaunching(UIApplication app, NSDictionary options) 22 | { 23 | global::Xamarin.Forms.Forms.Init(); 24 | LoadApplication(new App()); 25 | 26 | // The following are all optional settings to change the behavior on iOS 27 | 28 | // this controls whether the library will attempt to set the shared AVAudioSession category, and then reset it after recording completes 29 | AudioRecorderService.RequestAVAudioSessionCategory (AVAudioSessionCategory.PlayAndRecord); 30 | // same thing as above, forces the shared AVAudioSession into recording mode, and then reset it after recording completes 31 | AudioPlayer.RequestAVAudioSessionCategory (AVAudioSessionCategory.PlayAndRecord); 32 | 33 | // allows you to add additional code to configure/change the shared AVAudioSession before each playback instance 34 | // this can be used to alter the cateogry, audio port, check if the system will allow your app to access the session, etc. 35 | // See https://github.com/NateRickard/Plugin.AudioRecorder/issues/27 for additional info 36 | AudioPlayer.OnPrepareAudioSession = audioSession => 37 | { 38 | // maybe force audio to route to the speaker? 39 | var success = audioSession.OverrideOutputAudioPort (AVAudioSessionPortOverride.Speaker, out NSError error); 40 | 41 | // do something else like test if the audio session can go active? 42 | 43 | //if (success) 44 | //{ 45 | // audioSession.SetActive (true, out error); 46 | //} 47 | }; 48 | 49 | // can also do something AFTER audio is played with this callback 50 | //AudioPlayer.OnResetAudioSession = audioSession => ... 51 | 52 | return base.FinishedLaunching(app, options); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "scale": "2x", 5 | "size": "20x20", 6 | "idiom": "iphone", 7 | "filename": "Icon40.png" 8 | }, 9 | { 10 | "scale": "3x", 11 | "size": "20x20", 12 | "idiom": "iphone", 13 | "filename": "Icon60.png" 14 | }, 15 | { 16 | "scale": "2x", 17 | "size": "29x29", 18 | "idiom": "iphone", 19 | "filename": "Icon58.png" 20 | }, 21 | { 22 | "scale": "3x", 23 | "size": "29x29", 24 | "idiom": "iphone", 25 | "filename": "Icon87.png" 26 | }, 27 | { 28 | "scale": "2x", 29 | "size": "40x40", 30 | "idiom": "iphone", 31 | "filename": "Icon80.png" 32 | }, 33 | { 34 | "scale": "3x", 35 | "size": "40x40", 36 | "idiom": "iphone", 37 | "filename": "Icon120.png" 38 | }, 39 | { 40 | "scale": "2x", 41 | "size": "60x60", 42 | "idiom": "iphone", 43 | "filename": "Icon120.png" 44 | }, 45 | { 46 | "scale": "3x", 47 | "size": "60x60", 48 | "idiom": "iphone", 49 | "filename": "Icon180.png" 50 | }, 51 | { 52 | "scale": "1x", 53 | "size": "20x20", 54 | "idiom": "ipad", 55 | "filename": "Icon20.png" 56 | }, 57 | { 58 | "scale": "2x", 59 | "size": "20x20", 60 | "idiom": "ipad", 61 | "filename": "Icon40.png" 62 | }, 63 | { 64 | "scale": "1x", 65 | "size": "29x29", 66 | "idiom": "ipad", 67 | "filename": "Icon29.png" 68 | }, 69 | { 70 | "scale": "2x", 71 | "size": "29x29", 72 | "idiom": "ipad", 73 | "filename": "Icon58.png" 74 | }, 75 | { 76 | "scale": "1x", 77 | "size": "40x40", 78 | "idiom": "ipad", 79 | "filename": "Icon40.png" 80 | }, 81 | { 82 | "scale": "2x", 83 | "size": "40x40", 84 | "idiom": "ipad", 85 | "filename": "Icon80.png" 86 | }, 87 | { 88 | "scale": "1x", 89 | "size": "76x76", 90 | "idiom": "ipad", 91 | "filename": "Icon76.png" 92 | }, 93 | { 94 | "scale": "2x", 95 | "size": "76x76", 96 | "idiom": "ipad", 97 | "filename": "Icon152.png" 98 | }, 99 | { 100 | "scale": "2x", 101 | "size": "83.5x83.5", 102 | "idiom": "ipad", 103 | "filename": "Icon167.png" 104 | }, 105 | { 106 | "scale": "1x", 107 | "size": "1024x1024", 108 | "idiom": "ios-marketing", 109 | "filename": "Icon1024.png" 110 | } 111 | ], 112 | "properties": {}, 113 | "info": { 114 | "version": 1, 115 | "author": "xcode" 116 | } 117 | } -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Entitlements.plist: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIDeviceFamily 6 | 7 | 1 8 | 2 9 | 10 | UISupportedInterfaceOrientations 11 | 12 | UIInterfaceOrientationPortrait 13 | UIInterfaceOrientationLandscapeLeft 14 | UIInterfaceOrientationLandscapeRight 15 | 16 | UISupportedInterfaceOrientations~ipad 17 | 18 | UIInterfaceOrientationPortrait 19 | UIInterfaceOrientationPortraitUpsideDown 20 | UIInterfaceOrientationLandscapeLeft 21 | UIInterfaceOrientationLandscapeRight 22 | 23 | MinimumOSVersion 24 | 8.0 25 | CFBundleDisplayName 26 | AudioRecord.Forms 27 | CFBundleIdentifier 28 | com.companyname.AudioRecord.Forms 29 | CFBundleVersion 30 | 1.0 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | CFBundleName 34 | AudioRecord.Forms 35 | XSAppIconAssets 36 | Assets.xcassets/AppIcon.appiconset 37 | NSMicrophoneUsageDescription 38 | AudioRecord.Forms wants to use your microphone to record audio 39 | 40 | 41 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | using Foundation; 6 | using UIKit; 7 | 8 | namespace AudioRecord.Forms.iOS 9 | { 10 | public class Application 11 | { 12 | // This is the main entry point of the application. 13 | static void Main(string[] args) 14 | { 15 | // if you want to use a different Application Delegate class from "AppDelegate" 16 | // you can specify it here. 17 | UIApplication.Main(args, null, "AppDelegate"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AudioRecord.Forms.iOS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AudioRecord.Forms.iOS")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Resources/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Resources/Default-568h@2x.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Resources/Default-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Resources/Default-Portrait.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Resources/Default-Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Resources/Default-Portrait@2x.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Resources/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Resources/Default.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Resources/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/Samples/Forms/AudioRecord.Forms.iOS/Resources/Default@2x.png -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms.iOS/Resources/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms/App.xaml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xamarin.Forms; 3 | using Xamarin.Forms.Xaml; 4 | 5 | [assembly: XamlCompilation (XamlCompilationOptions.Compile)] 6 | namespace AudioRecord.Forms 7 | { 8 | public partial class App : Application 9 | { 10 | public App () 11 | { 12 | InitializeComponent(); 13 | 14 | MainPage = new MainPage(); 15 | } 16 | 17 | protected override void OnStart () 18 | { 19 | // Handle when your app starts 20 | } 21 | 22 | protected override void OnSleep () 23 | { 24 | // Handle when your app sleeps 25 | } 26 | 27 | protected override void OnResume () 28 | { 29 | // Handle when your app resumes 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms/AudioRecord.Forms.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Samples/Forms/AudioRecord.Forms/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | 9 | 10 | 12 | 46 | 56 | 57 | 58 | 59 | 60 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Samples/Native/AudioRecord.iOS/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("AudioRecord.iOS")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AudioRecord.iOS")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("50c7b8c9-e664-45af-b88e-0c9b8b9c1be1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Samples/Native/AudioRecord.iOS/Resources/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Samples/Native/AudioRecord.iOS/ViewController.cs: -------------------------------------------------------------------------------- 1 | using AVFoundation; 2 | using Plugin.AudioRecorder; 3 | using System; 4 | using System.Threading.Tasks; 5 | using UIKit; 6 | 7 | namespace AudioRecord.iOS 8 | { 9 | public partial class ViewController : UIViewController 10 | { 11 | AudioRecorderService recorder; 12 | AudioPlayer player; 13 | 14 | public ViewController (IntPtr handle) : base (handle) 15 | { 16 | // this controls whether the library will attempt to set the shared AVAudioSession category, and then reset it after recording completes 17 | AudioRecorderService.RequestAVAudioSessionCategory (AVAudioSessionCategory.PlayAndRecord); 18 | } 19 | 20 | public override void ViewDidLoad () 21 | { 22 | base.ViewDidLoad (); 23 | 24 | recorder = new AudioRecorderService 25 | { 26 | StopRecordingOnSilence = TimeoutSwitch.On, 27 | StopRecordingAfterTimeout = false 28 | }; 29 | 30 | player = new AudioPlayer (); 31 | player.FinishedPlaying += Player_FinishedPlaying; 32 | 33 | //alternative event-based API can be used here in lieu of the returned recordTask used below 34 | //recorder.AudioInputReceived += Recorder_AudioInputReceived; 35 | } 36 | 37 | async partial void RecordButton_TouchUpInside (UIButton sender) 38 | { 39 | await RecordAudio (); 40 | } 41 | 42 | async Task RecordAudio () 43 | { 44 | try 45 | { 46 | if (!recorder.IsRecording) 47 | { 48 | recorder.StopRecordingOnSilence = TimeoutSwitch.On; 49 | 50 | RecordButton.Enabled = false; 51 | PlayButton.Enabled = false; 52 | 53 | //the returned Task here will complete once recording is finished 54 | var recordTask = await recorder.StartRecording (); 55 | 56 | RecordButton.SetTitle ("Stop", UIControlState.Normal); 57 | RecordButton.Enabled = true; 58 | 59 | var audioFile = await recordTask; 60 | 61 | //audioFile will contain the path to the recorded audio file 62 | 63 | RecordButton.SetTitle ("Record", UIControlState.Normal); 64 | PlayButton.Enabled = !string.IsNullOrEmpty (audioFile); 65 | } 66 | else 67 | { 68 | RecordButton.Enabled = false; 69 | 70 | await recorder.StopRecording (); 71 | 72 | RecordButton.SetTitle ("Record", UIControlState.Normal); 73 | RecordButton.Enabled = true; 74 | } 75 | } 76 | catch (Exception ex) 77 | { 78 | //blow up the app! 79 | throw ex; 80 | } 81 | } 82 | 83 | private void Recorder_AudioInputReceived (object sender, string audioFile) 84 | { 85 | InvokeOnMainThread (() => 86 | { 87 | RecordButton.SetTitle ("Record", UIControlState.Normal); 88 | 89 | PlayButton.Enabled = !string.IsNullOrEmpty (audioFile); 90 | }); 91 | } 92 | 93 | partial void PlayButton_TouchUpInside (UIButton sender) 94 | { 95 | try 96 | { 97 | var filePath = recorder.GetAudioFilePath (); 98 | 99 | if (filePath != null) 100 | { 101 | PlayButton.Enabled = false; 102 | RecordButton.Enabled = false; 103 | 104 | player.Play (filePath); 105 | } 106 | } 107 | catch (Exception ex) 108 | { 109 | //blow up the app! 110 | throw ex; 111 | } 112 | } 113 | 114 | void Player_FinishedPlaying (object sender, EventArgs e) 115 | { 116 | PlayButton.Enabled = true; 117 | RecordButton.Enabled = true; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Samples/Native/AudioRecord.iOS/ViewController.designer.cs: -------------------------------------------------------------------------------- 1 | // WARNING 2 | // 3 | // This file has been generated automatically by Visual Studio from the outlets and 4 | // actions declared in your storyboard file. 5 | // Manual changes to this file will not be maintained. 6 | // 7 | using Foundation; 8 | using System; 9 | using System.CodeDom.Compiler; 10 | using UIKit; 11 | 12 | namespace AudioRecord.iOS 13 | { 14 | [Register ("ViewController")] 15 | partial class ViewController 16 | { 17 | [Outlet] 18 | [GeneratedCode ("iOS Designer", "1.0")] 19 | UIKit.UIButton PlayButton { get; set; } 20 | 21 | [Outlet] 22 | [GeneratedCode ("iOS Designer", "1.0")] 23 | UIKit.UIButton RecordButton { get; set; } 24 | 25 | [Outlet] 26 | [GeneratedCode ("iOS Designer", "1.0")] 27 | UIKit.UISwitch TimeoutSwitch { get; set; } 28 | 29 | [Action ("PlayButton_TouchUpInside:")] 30 | [GeneratedCode ("iOS Designer", "1.0")] 31 | partial void PlayButton_TouchUpInside (UIKit.UIButton sender); 32 | 33 | [Action ("RecordButton_TouchUpInside:")] 34 | [GeneratedCode ("iOS Designer", "1.0")] 35 | partial void RecordButton_TouchUpInside (UIKit.UIButton sender); 36 | 37 | void ReleaseDesignerOutlets () 38 | { 39 | if (PlayButton != null) { 40 | PlayButton.Dispose (); 41 | PlayButton = null; 42 | } 43 | 44 | if (RecordButton != null) { 45 | RecordButton.Dispose (); 46 | RecordButton = null; 47 | } 48 | 49 | if (TimeoutSwitch != null) { 50 | TimeoutSwitch.Dispose (); 51 | TimeoutSwitch = null; 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /logo/audiorecorder-github-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/logo/audiorecorder-github-logo.png -------------------------------------------------------------------------------- /logo/horizontalversion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/logo/horizontalversion.png -------------------------------------------------------------------------------- /logo/icon-nuget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/logo/icon-nuget.png -------------------------------------------------------------------------------- /logo/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/logo/icon.png -------------------------------------------------------------------------------- /logo/verticalversion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NateRickard/Plugin.AudioRecorder/01e3b765a3f43cd542051de02ffcfcb24dec9c3a/logo/verticalversion.png --------------------------------------------------------------------------------