[Singing] Oh, oh, there you are. Sorry, I was
just testing the Plugin. Maui.Audio which now also has the
ability to record audio. So let's check out how to implement
that in your .NET MAUI app. The Plugin.Maui.Audio package already
allowed you to play sound files inside of your .NET
MAUI application. Just install the NuGet. couple of line of code and
you would be good to go to play all kinds of sound files from the
click of a button or wherever you want to implement it. Now since
then a lot, and I mean a lot of people have asked me: hey, can
you also record sound with it? And that wasn't possible. But Shaun
with who I'm working with on this project, my good friend Shaun
Lawrence, he has been working on this for a long time and now it's
finally implemented. You can also record sounds from your .NET MAUI
application with this Plugin.Maui.Audio package. So let's
check out how to do that. Moving over to my screen share, I
created a new .NET MAUI project here in Visual Studio 2022. It
goes without saying you can also do this from VS Code, or on your Mac,
whatever you prefer. But I'm doing it from Windows for
today. And this is just the default template. I
already got a couple of things set up, but I will walk you through that, no
worries. And from there we will start implementing the code. So let's go
over to our Solution Explorer. Right-click on your project and do
Manage NuGet packages. And here under Browse you want to
search for Plugin.Maui. Audio. You should check the Include Prereleases. At the time of recording
tt is released as a prerelease version: 2.0.0-preview2, that's the one that you want to have
at a minimum, if you want to use the recording functionality by the
time that you're watching this, it might already be out in stable. But this is
the minimum version that you will need. So install that, click on the little
install button here and it should be installed on your project. Then from
there you want to also do the permissions. Now this is
all explained on the plugin repository. So if you get confused, I will link the
repository down below. Don't worry, go check that out. But here in the
manifests and that kind of stuff, you want to go over to your
project, Platforms folder. And then for Android you have the
AndroidManifest.xml. For iOS and Mac Catalyst you have the info.plist files right here.
And then for Windows we have the package.appxmanifest file as well. So
I'm just going to show you the ones for Android and iOS. You can
figure the Windows one out yourself, I'm pretty sure of that. But here we
have this info.plist which is for iOS and this is the exact
same thing for Mac Catalyst but just in a different file. So make
sure to do them both if that's the platforms that you're targeting,
you want to do this key right here to use the microphone and
give it a little description. iOS will show a description to the
user with a little explanation that you fill in here with why you want to
have microphone access. So make sure that you put
something valid in here that users will be like: oh yeah, this makes sense for
this app, I'm going to allow that. For Android, same thing, but you need
a couple of extra permissions. Record audio, modify audio settings,
and read and write external storage. Because we
are actually writing an audio file, right, which is actually a
good cue. So recording format is not something
that we can set right now. It's all recorded I think in kind of
like a I'm not an expert on recording audio formats, but I think
we do it in wave format or PCM and I think that all
kind of ties together. So it's in wave format for all the
platforms because that's what they support. That's because why the
file format can be a little bit bigger, but maybe in some
next version we will be able to allow the
file format to be different. Right? I'm not
sure what's supported on all the platforms, but maybe that's something
that we can think about. Let me know on the repository if that's something
that's important to you. Okay, we got that set up then in our main page.
Actually, we don't have to set up anything visually. I'm just going to reuse
what's here. So this will just be the waving .NET Bot, right? We'll see
that in a minute. And I'm just going to reuse the counter button
right here to actually start recording if it iOS recording and stop the
recording and play back the audio if we actually have recorded
something. So I'm just going to go to the code behind right here.
And before we do all this, we want to do it the right
way. Like there with all the plugins we follow. Kind of like the
same pattern as the .NET MAUI Essentials APIs. You can do it in
two ways so you can actually register it for dependency
injection and do it like that, which is the proper way.
That's probably what you want to do. Or you can use the static instance and
just use it that way. I'm going to show you
dependency injection right now and also going to for the playing the audio, I'll
just show you the static implementation. So we will see both flavors right
here. So let's go over to the Solution Explorer and go to my MauiProgram.cs.
And here I can register everything for dependency injection.
So here I can say builder.Services. AddSingleton() because our audio
service can be a singleton, doesn't really have any state or that
kind of stuff, but you can still register as a singleton. And what you
want to do is say AudioManager, which is a type of the audio plugin...
.Current. That is our property for the current
implementation. Now you want to make sure to include
the using Plugin.Maui.Audio; here at the top and then it will
start recognizing that AudioManager and the current property that
comes with it. Now if we want to use that to inject it into our main page,
we also need to register our MainPage. So let's do builder.
Services.AddTransient() which makes more sense for pages. And
we want to do the MainPage right here. Okay, so we got that
set up. We are now ready to go with the dependency injection.
That's all you need to do in .NET MAUI. And now I can just go over to my
MainPage.xaml.cs. And here in my constructor, it's already
selected in the right place. I can say, IAudioManager because we also
use interfaces so you could swap out implementations if
that's what you want for testing purposes or whatnot. So we can use this
IAudioManager. It will automatically pick that up
even though we register the actual implementation here. But it will know
to use that IAudioManager and it will still resolve it, right?
So we can do that. And I'm going to use IAudioManager here, then
create a little field for it. Let's make that
read only because we're not going to change it. IAudioManager _audioManager; so we can use that. And of course, all
this code can be found in a sample repo, which you can find the
link down below. So if you want to review the code, you totally can.
And what I also want to do is have an IAudioRecorder because we
have a special recorder here as well. So we
registered that. Now whenever we get here, I can say _audioManager =
audioManager; that gets injected through dependency
injection. And then from that audio manager I can say
_audioRecorder is _audioManager. CreateRecorder(). I have to create this
recorder, right? So it's going to create the right things. It's going to
initialize it for you and you can actually start recording with that. We got that in
place. We have the AudioManager. The AudioManager creates a recorder
and we have everything set up to actually do the recording. So in
this CounterClicked, this is just a button. If you click
it, we're going to actually not use all of this. So I'm going to
remove it and we're going to check if we're actually
recording yes or no. And then we're going to actually play it back. Of course,
your implementation is going to probably be a little bit more extensive, but
for now, this will get the point across to help you get started with all of
this. So what we want to do first is check the permissions, right?
We still need to get the actual permissions from the
user to be able to access the microphone and
luckily .NET MAUI has stuff for that built in so we can just say if
and I think we need to do await here... Permissions. So we have the Permissions APIs
RequestAsync() and you can here do
Permissions.Microphone and the microphone should be enough
even though Android has a couple of extra things but you should be able to just
do this for the microphone and that should be enough. Not is,
because we get a status back here, PermissionStatus and if
it's not granted then we're going to return right? We're
going to just return. You probably want to to do inform your user because how it typically
works whenever a user denies this once then they have to go through
the app settings and whatnot to actually re-enable the permission. So
you want to inform your user to go through all that and maybe detect
and gracefully fall back in your application. So there we have
that but we are going to go the happy path, so we are just going to have
this granted and go from there. You can see it added the
async here automatically so that's needed async void is not great.
Make sure to wrap this in a try/catch to catch the actual
exceptions that might arise from this but this is just because these event
handlers have to be void but they can be async whole different
topic. Let me know if that's something that you want
to learn more on down in the comments. Then we can check this _audioRecorder
if it is recording is recording yes or no
and if it's not we're going to start the recording. So we're
going to say _audioRecorder. StartAsync(), again async thing. So you might want to await this and we
have a couple of overloads. If you don't specify any parameters
it's going to generate a random file at the default location of the device,
temporary file basically and it's going to start recording from
there you will get to that audio and the contents whenever we stop it. I'll
show you that in a little bit or you can provide your own path and file
name right here and it will start recording in a file
there so options for you to use from there if we stop the recording. So else if we
are recording and it's going to get here
then we have this StopAsync() it already suggested to me
so let's just do that. But what you want to do here is
actually you will get back an audio source an IAudioSource so we are
going to use that... var recordedAudio is this. So now we have captured that
in this variable right here and let's inspect what we have there. And
there is actually just one interesting thing, which is GetAudioStream(). So
you can get the stream from that audio, which is the contents of that
file and that we can use to automatically start playing that back
to the user again whenever we stop it. And here I'm going to show
you the static usage of this API. So I could also definitely use
dependency injection or I don't even need to use dependency
injection. I could just create a new audio player here and I could say
AudioManager.CreatePlayer(). See it's right here. Or CreateAsyncPlayer
if you want to play async things. Highly recommend that you
check out my other video which should pop up on your screen
at the end of this video about playing the audio. I have a full video on that as well.
But this one is about recording. So you could instantiate it that way
or you can just do AudioManager. Current.CreatePlayer() and we have this audio player. So let's create this
player. And then what we can do, I think we
have to specify the stream immediately. So you
can just say recordedAudio. GetAudioStream() and we get the stream
back from this and we can play it from right
here. Now the player has a couple of more APIs. Again, we're
not really interested because we're exploring the recording right
here. But we can just say: hey, play with this thing and we can
now play back the audio. So I'm going to deploy
this to my physical Android device that I have laying right here. And I
mirrored the screen to this app right here. And the application
should come up in a little bit where it's going to be deployed. I
think I have the volume up. Well, let's set it all the way up. I
hope I'm not going to go deaf with my own voice. Here we should
see the default .NET MAUI template, which is not super
impressive, but typically if you click the button then it's
going to increment. Now it's going to start recording and it should ask me for the
permission. So let's click it and you can see it asked me for the permission
because that's what I implemented. Of course the user has all these
options. I'm just going to do only this time and then whenever I keep
continue talking it's just going to record my voice. And when I stop
the button, you're going to hear this again, repeated... [the same audio but repeated from phone] See? So that's how it actually works. You can record audio now with
this plugin inside of your .NET MAUI application with just a couple of
lines of code and that is how easy it is. Now obviously this
also works on iOS, macOS, Windows, you saw all the
platforms that we can specify the permissions for, so we got all that. I think there
is definitely some room to expand the API. So please let me know
down in the comments if you have any questions. Maybe feature requests
are better to go to the plugin repository so the link can be found
below. Go there and please put in your feature requests. And of
course, if you want to know more about playing that audio, check out this
video right here. And now, if you'll excuse me... [singing] I did it my way.