メディアの中断の作成、スケジュール、管理

この記事では、メディア再生アプリ用にメディアの中断を作成、スケジュール、管理する方法について説明します。 通常、メディアの中断は、オーディオ広告やビデオ広告をメディア コンテンツに挿入する目的で使います。 Windows 10 バージョン 1607 以降では、MediaBreakManager クラスを使って、MediaPlayer で再生する任意の MediaPlaybackItem にメディアの中断を簡単かつ迅速に追加できます。

メディアの中断を 1 つ以上スケジュールすると、再生中の指定した時間に、システムがメディア コンテンツを自動的に再生します。 MediaBreakManager では、ユーザーがメディアを中断、終了、またはスキップしたときにアプリが反応できるように、イベントが提供されています。 MediaPlaybackSession にアクセスしてメディアの中断を確認し、ダウンロードや進行状況の更新のバッファリングなどのイベントを監視することもできます。

メディアの中断のスケジュール

MediaPlaybackItem オブジェクトには、アイテムの再生時に再生されるメディアの中断の構成に使う独自の MediaBreakSchedule があります。 アプリでメディアの中断を使うための最初の手順は、メイン再生コンテンツ用の MediaPlaybackItem の作成です。

MediaPlaybackItem moviePlaybackItem =
    new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/movie.mkv")));

MediaPlaybackItemMediaPlaybackList、他の基本的なメディアの再生 API の操作の参照については、「メディア項目、プレイリスト、トラック」を参照してください。

次の例は、MediaPlaybackItem にプリロール区切りを追加する方法を示しています。これは、区切りが属する再生アイテムを再生する前に、システムがメディアの中断を再生することを意味します。 まず、新しい MediaBreak オブジェクトがインスタンス化されます。 この例では、コンストラクター MediaBreakInsertionMethod.Interrupt と共に呼び出されます。つまり、区切りコンテンツの再生中はメイン コンテンツが一時停止されます。

次に、区切り中に再生されるコンテンツ (広告など) 用に新しい MediaPlaybackItem が作成されます。 この再生アイテムの CanSkip プロパティは false に設定されます。 つまり、ユーザーは組み込みのメディア コントロールを使ってアイテムをスキップできません。 ただし、SkipCurrentBreak を呼び出すことで、広告をプログラムによりスキップすることを選ぶことはできます。

メディアの中断の PlaybackList プロパティは、複数のメディア アイテムをプレイリストとして再生できるようにする MediaPlaybackList です。 一覧の Items コレクションから 1 つまたは複数の MediaPlaybackItem オブジェクトを追加し、メディアの中断のプレイリストに含めます。

最後に、メイン コンテンツ再生アイテムの BreakSchedule プロパティを使ってメディアの中断をスケジュールします。 プリロール区切りにする中断を、スケジュール オブジェクトの PrerollBreak プロパティに割り当てることで指定します。

MediaBreak preRollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
MediaPlaybackItem prerollAd = 
    new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/preroll_ad.mp4")));
prerollAd.CanSkip = false;
preRollMediaBreak.PlaybackList.Items.Add(prerollAd);

moviePlaybackItem.BreakSchedule.PrerollBreak = preRollMediaBreak;

これで、メイン メディア アイテムを再生できるようになりました。作成したメディアの中断は、メイン コンテンツの前に再生されます。 新しい MediaPlayer オブジェクトを作成し、オプションで AutoPlay プロパティをtrue に設定して再生を自動的に開始します。 MediaPlayerSource プロパティをメイン コンテンツ再生アイテムに設定します。 必須ではありませんが、MediaPlayerMediaPlayerElement に割り当てて XAML ページでメディアをレンダリングできます。 MediaPlayer の使い方について詳しくは、「MediaPlayer を使ったオーディオとビデオの再生」をご覧ください。

_mediaPlayer = new MediaPlayer();
_mediaPlayer.AutoPlay = true;
_mediaPlayer.Source = moviePlaybackItem;
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);

プリロール区切りを同じ手法を使って、メイン コンテンツを含む MediaPlaybackItem の再生が終わったら再生されるポストロール区切りを追加します。ただし、MediaBreak オブジェクトをPostrollBreak プロパティに再生する点が異なります。

MediaBreak postrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
MediaPlaybackItem postRollAd =
    new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/postroll_ad.mp4")));
postrollMediaBreak.PlaybackList.Items.Add(postRollAd);

moviePlaybackItem.BreakSchedule.PostrollBreak = postrollMediaBreak;

メイン コンテンツの再生中の指定した時点で再生されるミッドロール区切りを 1 つ以上スケジュールすることもできます。 次の例では、メイン メディア アイテムの再生中に区切りが生成される時間を指定する TimeSpan オブジェクトを受け入れるコンストラクター オーバーロードを使って MediaBreak が作成されます。 ここでも、MediaBreakInsertionMethod.Interrupt が指定され、区切りの生成中にメイン コンテンツの再生が一時停止されることが示されます。 InsertMidrollBreak を呼び出すことで、ミッドロール区切りがスケジュールに追加されます。 MidrollBreaks プロパティにアクセスすることで、スケジュールに含まれている現在のミッドロール区切りの読み取り専用一覧を取得できます。

MediaBreak midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt, TimeSpan.FromMinutes(10));
midrollMediaBreak.PlaybackList.Items.Add(
    new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_1.mp4"))));
midrollMediaBreak.PlaybackList.Items.Add(
    new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_2.mp4"))));
moviePlaybackItem.BreakSchedule.InsertMidrollBreak(midrollMediaBreak);

次のミッドロール区切りの例では、MediaBreakInsertionMethod.Replace 挿入メソッドを使います。つまり、区切りの再生中もメイン コンテンツの再生が続けられます。 このオプションは通常、広告の再生中にライブ ストリームを一時停止して遅れを生じさせたくないライブ ストリーミング メディア アプリにより使われます。

この例では、2 つの TimeSpan パラメーターを受け入れる MediaPlaybackItem コンストラクターのオーバーロードも使います。 最初のパラメーターは、メディアの中断アイテム内の、再生が開始される開始点を指定します。 2 番目のパラメーターは、メディアの中断アイテムが再生される時間の長さを指定します。 したがって、次の例では、20 分の時点でメイン コンテンツに対して MediaBreak が再生を開始します。 再生されると、区切りメディア アイテムの先頭から 30 秒後にメディア アイテムが開始され、15 秒間再生されてからメイン メディア コンテンツが再生を再開します。

midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Replace, TimeSpan.FromMinutes(20));
MediaPlaybackItem ad = 
    new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_3.mp4")),
    TimeSpan.FromSeconds(30),
    TimeSpan.FromSeconds(15));
ad.CanSkip = false;
midrollMediaBreak.PlaybackList.Items.Add(ad);

メディアの中断のスキップ

この記事で既に説明したように、MediaPlaybackItemCanSkip プロパティを設定し、ユーザーが組み込みコントロールを使ってコンテンツをスキップできないようにすることができます。 ただし、いつでもコードから SkipCurrentBreak を呼び出すと現在の中断をスキップできます。

private void SkipButton_Click(object sender, RoutedEventArgs e) => _mediaPlayer.BreakManager.SkipCurrentBreak();

MediaBreak イベントの処理

メディアの中断の状態の変化に基づいてアクションを実行するために登録できる、メディアの中断に関連するいくつかのイベントがあります。

_mediaPlayer.BreakManager.BreakStarted += BreakManager_BreakStarted;
_mediaPlayer.BreakManager.BreakEnded += BreakManager_BreakEnded;
_mediaPlayer.BreakManager.BreakSkipped += BreakManager_BreakSkipped;
_mediaPlayer.BreakManager.BreaksSeekedOver += BreakManager_BreaksSeekedOver;

BreakStarted は、メディアの中断が開始すると発生します。 メディア コンテンツを再生していることがユーザーにわかるように UI を更新できます。 この例では、ハンドラーに渡された MediaBreakStartedEventArgs を使って、開始されたメディアの中断への参照を取得します。 次に、CurrentItemIndex プロパティを使って、メディアの中断のプレイリストにある再生メディア アイテムが決定されます。 その後、UI が更新され、現在の広告インデックスと中断中の残りの広告数がユーザーに表示されます。 UI の更新は UI スレッドに加える必要があるため、RunAsync の呼び出し内で呼び出しを行う必要がある点に注意してください。

private async void BreakManager_BreakStarted(MediaBreakManager sender, MediaBreakStartedEventArgs args)
{
    MediaBreak currentBreak = sender.CurrentBreak;
    var currentIndex = currentBreak.PlaybackList.CurrentItemIndex;
    var itemCount = currentBreak.PlaybackList.Items.Count;

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>            
        statusTextBlock.Text = $"Playing ad {currentIndex + 1} of {itemCount}");
}

BreakEnded は、中断内のすべてのメディア アイテムが再生を終えるか、スキップされたときに発生します。 このイベントのハンドラーを使って UI を更新し、メディアの中断コンテンツがそれ以上再生されないことを示すことができます。

private async void BreakManager_BreakEnded(MediaBreakManager sender, MediaBreakEndedEventArgs args)
{
    // Update UI to show that the MediaBreak is no longer playing
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => statusTextBlock.Text = "");

    args.MediaBreak.CanStart = false;
}

BreakSkipped イベントは、CanSkip が true になっているアイテムの再生中ユーザーが組み込み UI の [次へ] ボタンを押したとき、または SkipCurrentBreak を呼び出すことでコードで中断をスキップしたときに発生します。

次の例では、MediaPlayerSource プロパティを使って、メイン コンテンツのメディア アイテムへの参照を取得します。 スキップされたメディアの中断は、このアイテムの中断スケジュールに属しています。 次に、スキップされたメディアの中断がスケジュールの PrerollBreak プロパティに設定されたメディアの中断と同じであるかどうかをコードがチェックします。 同じである場合、プリロール区切りがスキップされた中断であることを意味します。この場合、新しいミッドロール区切りが作成され、メイン コンテンツの 10 分の時点で再生されるようにスケジュールされます。

private async void BreakManager_BreakSkipped(MediaBreakManager sender, MediaBreakSkippedEventArgs args)
{
    // Update UI to show that the MediaBreak is no longer playing
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => statusTextBlock.Text = "");

    MediaPlaybackItem currentItem = _mediaPlayer.Source as MediaPlaybackItem;
    if(!(currentItem.BreakSchedule.PrerollBreak is  null) 
        && currentItem.BreakSchedule.PrerollBreak == args.MediaBreak)
    {
        MediaBreak mediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt, TimeSpan.FromMinutes(10));
        mediaBreak.PlaybackList.Items.Add(await GetAdPlaybackItem());
        currentItem.BreakSchedule.InsertMidrollBreak(mediaBreak);
    }
}

BreaksSeekedOver は、メイン メディア アイテムの再生位置が、1 つ以上のメディアの中断のスケジュールされた時間を超えたときに発生します。 次の例では、1 つ以上のメディアの中断が要求されたかどうか、再生位置が先に移動されたかどうか、先に移動された時間が 10 分未満であるかどうかがチェックされます。 その場合、要求された最初の中断 (イベント引数により開示された SeekedOverBreaks コレクションから取得されます) が、MediaPlayer.BreakManagerPlayBreak メソッドを呼び出すことですぐに再生されます。

private void BreakManager_BreaksSeekedOver(MediaBreakManager sender, MediaBreakSeekedOverEventArgs args)
{
    if(args.SeekedOverBreaks.Count > 1
        && args.NewPosition.TotalMinutes > args.OldPosition.TotalMinutes
        && args.NewPosition.TotalMinutes - args.OldPosition.TotalMinutes < 10.0)
        _mediaPlayer.BreakManager.PlayBreak(args.SeekedOverBreaks[0]);
}

現在の再生セッションへのアクセス

MediaPlaybackSession オブジェクトは、MediaPlayer クラスを使って、現在再生中のメディア コンテンツに関連するデータとイベントを提供します。 MediaBreakManager にも、再生中のメディアの中断コンテンツに特に関連するデータとイベントを取得するためにアクセスできる MediaPlaybackSession があります。 再生セッションから入手できる情報には、現在の再生状態、再生中か一時停止中か、コンテンツ内の現在の再生位置などがあります。 メディアの中断コンテンツの縦横比がメイン コンテンツと異なる場合、NaturalVideoWidth プロパティおよび NaturalVideoHeight プロパティと NaturalVideoSizeChanged を使って、ビデオ UI を調整することができます。 アプリのパフォーマンスに関する貴重な利用統計情報を示す、BufferingStartedBufferingEndedDownloadProgressChanged などのイベントを受け取ることもできます。

次の例では、BufferingProgressChanged イベントのハンドラーを登録します。イベント ハンドラーでは、UI が更新されて現在のバッファリングの進行状況が表示されます。

_mediaPlayer.BreakManager.PlaybackSession.BufferingProgressChanged += PlaybackSession_BufferingProgressChanged;
private async void PlaybackSession_BufferingProgressChanged(MediaPlaybackSession sender, object args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        bufferingProgressBar.Value = sender.BufferingProgress);
}