Help us understand the problem. What is going on with this article?

iOS upnpx で UPnP デバイスをブラウズ(その2 コンテンツ一覧の取得)

More than 1 year has passed since last update.

iOS upnpx で UPnP デバイスをブラウズ(その1 デバイス発見まで) のつづき

Content Directory Service (CDS)

検出したデバイス (BasicUPnPDevice) のうち、MediaServer (MediaServer1Device) の Content Directory Service (CDS) に対して BrowseDirectChildren を実行する。

import upnpx

class BrowseViewController: UITableViewController {

    var device: MediaServer1Device! // 対象のデバイス
    var containerObject: MediaServer1ContainerObject? // 現在のコンテナ
    var mediaObjects: [MediaServer1BasicObject] = [] { // コンテナ内のオブジェクト一覧
        didSet {
            DispatchQueue.main.async { [weak self] in
                self?.tableView.reloadData()
            }
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        DispatchQueue.global().async { [weak self] in
            self?.browseDirectChildren()
        }
    }

    func browseDirectChildren() {
        let objectId = containerObject?.objectID ?? "0" // containerObject が nil のときは root(="0")
        let result = NSMutableString()
        let numberReturned = NSMutableString()
        let totalMatches = NSMutableString()
        let updateID = NSMutableString()
        device.contentDirectory.browse(
            withObjectID: objectId,
            browseFlag: "BrowseDirectChildren",
            filter: "*",
            startingIndex: "0",
            requestedCount: "0",
            sortCriteria: "",
            outResult: result,
            outNumberReturned: numberReturned,
            outTotalMatches: totalMatches,
            outUpdateID: updateID
        )
        print("result: ", result)
        print("numberReturned: ", numberReturned)
        print("totalMatches: ", totalMatches)
        print("updateID: ", updateID)

        // Parse result
        let didl = (result as String).data(using: .utf8)
        let mediaObjects = NSMutableArray()
        let parser = MediaServerBasicObjectParser(mediaObjectArray: mediaObjects, itemsOnly: false)
        parser?.parse(from: didl)
        self.mediaObjects = mediaObjects.flatMap { $0 as? MediaServer1BasicObject }
    }
    ...
}

取得したオブジェクト (MediaServer1BasicObject) のうち、コンテナは MediaServer1ContainerObject、写真/音楽/動画などのコンテンツは MediaServer1ItemObject になる。MediaServer1ContainerObject の ObjectID を指定して再度 BrowseDirectChildren を実行することでコンテナを掘り進んでいける。

    // MARK: - Table view data source

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return mediaObjects.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "mediaObject", for: indexPath)
        let mediaObject = mediaObjects[indexPath.row]
        cell.textLabel?.text = mediaObject.title
        if let itemObject = mediaObject as? MediaServer1ItemObject {
            cell.detailTextLabel?.text = itemObject.duration
            cell.accessoryType = .none
        } else {
            cell.detailTextLabel?.text = nil
            cell.accessoryType = .disclosureIndicator
        }
        return cell
    }

    // MARK: - Segue

    override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
        guard let indexPath = tableView.indexPathForSelectedRow else { return false }
        return mediaObjects[indexPath.row] as? MediaServer1ContainerObject != nil
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard let indexPath = tableView.indexPathForSelectedRow else { return }
        if let browseViewController = segue.destination as? BrowseViewController,
            let containerObject = mediaObjects[indexPath.row] as? MediaServer1ContainerObject {
            browseViewController.device = device
            browseViewController.containerObject = containerObject
        }
    }

結果

UPnPDeviceBrowser.gif

気づいたこと

  • コンテンツが多いコンテナに対して BrowseDirectChildren を実行すると結構待たされる...
  • そして SOAP リクエストは並列に処理されないっぽいので時間の掛かるリクエストがあると後続のリクエストが待たされる
  • リクエストのキャンセルがない?

Code

https://github.com/imamurh/UPnPDeviceBrowser

  • 最低限のコードなので悪しからず...

オワリ

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away