Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DMM TVのSDカードダウンロード機能を実装した話

DMM TVのSDカードダウンロード機能を実装した話

2023/06/20 DMM Android勉強会にて発表

Yuta Tomiyama

June 23, 2023
Tweet

More Decks by Yuta Tomiyama

Other Decks in Programming

Transcript

  1. DMM TVのSDカード
    ダウンロード機能を実装した話
    #dmm_android勉強会

    View Slide

  2. 自己紹介
    HN: マヤミト
    本名: 富山 雄太
    GitHub: https://github.com/yt8492
    趣味: Kotlin, Twitter, ウマ娘
    22新卒
    動画配信事業部
    Androidエンジニア
    Twitter: yt8492

    View Slide

  3. DMM TVの開発をしています

    View Slide

  4. SDカード対応をしたのでその話をします

    View Slide

  5. DMM TVのダウンロード仕様について
    ● 配信形式
    ○ MPEG-DASH
    ● コンテンツ保護
    ○ Widevine
    → MP4などの動画ファイルを単純にダウンロードして保存して終わり!ではない

    View Slide

  6. ExoPlayerのダウンロード関連の主要な登場人物
    ● Cache
    ○ ExoPlayerのCache。ダウンロードの保存先の情報をもつ。
    ● Download
    ○ ダウンロードしたデータ。
    ● DownloadIndex
    ○ Downloadを保存・取得する。
    ● DownloadManager
    ○ Downloadを管理する。CacheとDownloadIndexをもつ。Downloadを取得したり、Download中
    のものをキャンセルしたりする。
    ● DownloadRequest
    ○ ダウンロードするために必要な情報。ダウンロードしたい URIやライセンスキーなどを持つ。
    ● DownloadService
    ○ DownloadをするService。

    View Slide

  7. ExoPlayerでダウンロードして再生するまで
    1. DownloadRequest を組み立てる
    2. DownloadService.sendAddDownload を呼び出しダウンロードする
    3. DownloadManager から DownloadIndex を取得し、ダウンロードしたデータを
    表す Download のインスタンスを取得する
    4. Download のインスタンスから MediaItem を生成する
    5. CacheDataSource.Factory を MediaSource.Factory (DMM TVの場合は
    DashMediaSource.Factory)に渡す
    6. MediaSource.Factory の createMediaSource メソッドに4の MediaItem を
    渡し、MediaSource を取得する
    7. MediaSource をExoPlayer で再生する

    View Slide

  8. MediaItemの設定
    ● uriは動画のURL
    ● ここで使っているUtilはExoPlayer側で用意されているもの

    View Slide

  9. DownloadHelperの設定
    ● DownloadHelper.forMediaItemで先程のmediaItemを渡し、
    DownloadHelperを取得する

    View Slide

  10. DownloadRequestの取得
    ● 先程の downloadHelper の getDownloadRequest を呼び出し、
    DownloadRequest を取得する
    ● 引数にuniqueなidを渡す(今回は動画のid)

    View Slide

  11. DownloadService.sendAddDownload を呼び出す
    ● requestは先程の DownloadRequest
    ● DownloadManager を返すメソッドを実装した DownloadService のclassオブ
    ジェクトを渡す

    View Slide

  12. Downloadのインスタンスを取得する
    ● DownloadRequest の取得の際に設定したidをもとに Download を取得する

    View Slide

  13. MediaSource を取得する
    ● CacheDataSource.Factory を設定する
    ● DashMediaSource.Factory を設定する
    ● createMediaSource で生成する
    ● あとはExoPlayerに渡して再生する

    View Slide

  14. ExoPlayerのダウンロード関連の主要な登場人物(復習)
    ● Cache
    ○ ExoPlayerのCache。ダウンロードの保存先の情報をもつ。
    ● Download
    ○ ダウンロードしたデータ。
    ● DownloadIndex
    ○ Downloadを保存・取得する。
    ● DownloadManager
    ○ Downloadを管理する。CacheとDownloadIndexをもつ。Downloadを取得したり、Download中
    のものをキャンセルしたりする。
    ● DownloadRequest
    ○ ダウンロードするために必要な情報。ダウンロードしたい URIやライセンスキーなどを持つ。
    ● DownloadService
    ○ DownloadをするService。

    View Slide

  15. ここまでが事前知識

    View Slide

  16. DMM TVではダウンロードをどのように実装していたか
    ● もともとはSDカードに対応しておらず、内部ストレージへのみのダウンロード機能
    だった
    ● Cache, DownloadManagerをDIコンテナ(Koin)でシングルトンで管理し、使うとこ
    ろにDIしていた

    View Slide

  17. SDカード対応でどうなったか
    ● もともとはSDカードに対応しておらず、内部ストレージへのみのダウンロード機能
    だった
    ● Cache, DownloadManagerをDIコンテナ(Koin)でシングルトンで管理し、使うとこ
    ろにDIしていた
    → CacheとDownloadManagerは複数の保存先に対応していない😇
    SDカードに対応させるには、内部ストレージ用とSDカード用でCacheと
    DownloadManagerを別々に用意し、必要に応じて出し分ける必要がある😇
    SDカードの状態も考えると直接DIするとまずいので結構直さなきゃいけない😇

    View Slide

  18. やったこと
    1. 保存先の設定の項目をアプリに追加する
    2. 必要に応じて出し分けるProviderクラスを用意
    3. Cache, DownloadManagerを直接DIするのをやめ、ProviderをDIする
    4. 保存時は保存先の設定を見てどちらのDownloadManagerを使うか決める
    5. 再生時は両方のDownloadManagerから取得を試み、取得できたほうを使う

    View Slide

  19. 必要に応じてCacheを出し分けるProviderの実装
    1. 保存先の設定をもとに保存先のディレクトリを取得する処理の実装
    2. 保存先の設定を受け取り、Cacheのインスタンスを生成するFactoryの実装
    3. Cacheのインスタンスを管理するProviderの実装

    View Slide

  20. 保存先のディレクトリを
    取得する処理の実装

    View Slide

  21. Cacheのインスタンスを生成するFactoryの実装
    ● SDカードが挿入されていない場合、downloadDirectoryがnullになる

    View Slide

  22. Cacheのインスタンスを管理するProviderの実装
    ● 同じ保存先ディレクトリのCacheは2
    つ以上同時に保持するとエラーになる
    ため、synchronizedで対策

    View Slide

  23. DownloadManagerを出し分けるProviderの実装
    1. DownloadIndexインスタンスを内部ストレージとSDカードで分ける
    2. 保存先の設定を受け取り、DownloadManagerインスタンスを生成するFactoryの
    実装
    3. DownloadManagerのインスタンスを管理するProviderの実装

    View Slide

  24. DownloadIndexを内部ストレージとSDカードで分ける
    ● 内部ストレージとSDカードどちらに保存しているかの判断のために分ける

    View Slide

  25. DownloadManagerを
    生成するFactoryの実装

    View Slide

  26. DownloadManagerを管理する
    Providerの実装

    View Slide

  27. DownloadService.sendAddDownload呼び出し修正前
    ● DownloadManagerを返すDownloadServiceのメソッドで直接DIコンテナから取
    得している
    ● DownloadService.sendAddDownloadに内部ストレージのDownloadService
    のclassオブジェクトを固定で渡している

    View Slide

  28. DownloadService.sendAddDownload呼び出し修正
    ● DownloadManagerを返すDownloadServiceのメソッドでProviderから取得して
    いる
    ● DownloadService.sendAddDownloadで渡すclassオブジェクトを設定から出し
    分ける

    View Slide

  29. Downloadインスタンス取得の修正前
    ● 直接DIした内部ストレージのDownloadManagerから単純に取得する

    View Slide

  30. Downloadインスタンス取得の修正
    ● 内部ストレージとSDカード両方から取得を試み、どちらに保存されているか判断

    View Slide

  31. MediaSource取得の修正前
    ● 直接DIした内部ストレージのCacheをDataSourceに使う

    View Slide

  32. MediaSource取得の修正
    ● 前述の処理で判定した保存先をもとに、cacheを取得するように修正

    View Slide

  33. これでSDカードでも
    保存・再生できるように🎉

    View Slide

  34. まとめ
    ● ExoPlayerのCacheやDownloadManagerは、複数の保存先を管理するような仕
    組みがない
    ● そのため、内部ストレージとSDカードでCacheとDownloadManagerを分ける必要
    がある
    ● CacheとDownloadManagerを管理するProviderを実装すると便利
    ● もっといいやり方あれば教えてください󰢛

    View Slide

  35. ありがとうございました!

    View Slide