Contents
.NET MAUIで、AndroidとiOSで、音源を音量指定込みで再生したい、そんな話。
実装準備
音源ファイルはResource/Rawへ
今回はmp3ファイルで実験。
NuGetに追加
この辺は公式サイトに従って準備していく。
<PackageReference Include="CommunityToolkit.Maui" Version="9.0.0" />
<PackageReference Include="CommunityToolkit.Maui.MediaElement" Version="3.1.1" />
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.40" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.40" />
実装
OS別準備
AndroidはAndroidManifestを修正
これも公式に沿って、LaunchMode = “LaunchMode.SingleTask”とResizeableActivity = “true”をつける。
iOSはMauiProgramを修正
using Microsoft.Extensions.Logging;
using CommunityToolkit.Maui;
namespace HogeHoge
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
#if IOS
AVFoundation.AVAudioSession.SharedInstance().SetActive(true);
AVFoundation.AVAudioSession.SharedInstance().SetCategory(AVFoundation.AVAudioSessionCategory.Playback);
#endif
MauiProgramにUseMauiCommunityToolkitMediaElementを追加
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkitMediaElement()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
レイアウトにMediaElementを追加
XAMLに記載するときは、embed://ファイル名で記載する。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="HogehogeSample.MainPage">
<!-- 中略 -->
<toolkit:MediaElement x:Name="mediaElement" Source="embed://AAAA.mp3" ShouldAutoPlay="False"/>
<!-- 以下省略 -->
再生音源を変更しながら再生
プロジェクトを新規作成したときの、OnCounterClickedで実験。
// 音を鳴らしてみる
// 前に鳴らすたものがあれば停止してシークを初期化
mediaElement.Stop();
// 音源を変えてみる
if (count % 2 == 0)
{
mediaElement.Source = MediaSource.FromResource("BBBB.mp3");
}
else
{
mediaElement.Source = MediaSource.FromResource("AAAA.mp3");
}
// いざ再生
mediaElement.Play();
音量調整
ファイル自体の音量と、OSの音量の違いに注意。
前者はmediaElement.Volume = 0~1;で良さそう。
mediaElement.Volume = 0.5;
#if IOS
var musicPlayerController = MPMusicPlayerApplicationController.ApplicationMusicPlayer;
musicPlayerController.Volume = 0.83F;
#elif ANDROID
var audioManager = (AudioManager)Android.App.Application.Context.GetSystemService(Android.Content.Context.AudioService);
// ボリュームを50%に設定
audioManager.SetStreamVolume(Android.Media.Stream.Music, 50, VolumeNotificationFlags.PlaySound);
#endif
一応動くけど、MPMusicPlayerApplicationController.ApplicationMusicPlayer.Volumeは、iOS 7.0以降で廃止されてんぞ警告が出る。
MPVolumeViewを使うらしいが、時間を置く必要があるらしい?
ボリューム変更処理を行うクラスをシングルトンとして、アプリ起動時に作っておけばいっか?
iOSとAndroidで完全に分離した方が良いのか?
まず共通部に宣言しておく
internal partial class MasterVolumeControl
{
private static MasterVolumeControl _singleton = null;
public static MasterVolumeControl GetInstance()
{
if(_singleton == null)
{
_singleton = new MasterVolumeControl();
}
return _singleton;
}
internal partial void setMasterVolume(float orgMasterVolume);
}
Platforms\Androidに実装
internal partial class MasterVolumeControl
{
[SupportedOSPlatformGuard("Android28.0")]
internal static bool Is28OrAbove => Build.VERSION.SdkInt >= BuildVersionCodes.P;
internal partial void setMasterVolume(float orgMasterVolume)
{
var audioManager = Android.App.Application.Context.GetSystemService(Context.AudioService) as AudioManager;
if (audioManager == null)
{
throw new Exception("GetSystemService is failed.");
}
int max = audioManager.GetStreamMaxVolume(Android.Media.Stream.Music);
int min = 0;
if (Is28OrAbove)
{
min = audioManager.GetStreamMinVolume(Android.Media.Stream.Music);
}
else
{
min = audioManager.GetStreamVolume(0);
}
int vol = (int)(min + ((max - min) * (orgMasterVolume / 1.0F)));
audioManager.SetStreamVolume(Android.Media.Stream.Music, vol, VolumeNotificationFlags.PlaySound);
}
}
Platforms\iOSに実装
internal partial class MasterVolumeControl
{
MPVolumeView mPVolumeView;
internal MasterVolumeControl()
{
// 時間を置く必要があるらしいので、最初に作っておく
mPVolumeView = new MPVolumeView();
}
internal partial void setMasterVolume(float orgMasterVolume)
{
/* 下記方法はiOS 7.0以降で廃止された
var musicPlayerController = MPMusicPlayerController.ApplicationMusicPlayer;
musicPlayerController.Volume = orgMasterVolume;
*/
foreach (UIView subview in mPVolumeView.Subviews)
{
if (subview is UISlider)
{
((UISlider)subview).Value = orgMasterVolume;
}
}
}
}
音量調整するなら元に戻さなきゃダメでしょ!
ということは、アプリ起動時あたりで音量を覚えて置く必要があるね。
取得なら素直にできそう。
Androidはこう。
internal partial float getMasterVolume()
{
float orgMasterVolume;
var audioManager = Android.App.Application.Context.GetSystemService(Context.AudioService) as AudioManager;
if (audioManager == null)
{
throw new Exception("GetSystemService is failed.");
}
int max = audioManager.GetStreamMaxVolume(Android.Media.Stream.Music);
int vol = audioManager.GetStreamVolume(Android.Media.Stream.Music);
orgMasterVolume = (float)vol / (float)max;
return orgMasterVolume;
}
iOSはもっとシンプル。
internal partial float getMasterVolume()
{
float orgMasterVolume = AVAudioSession.SharedInstance().OutputVolume;
return orgMasterVolume;
}
他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。