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
}
}
結果
気づいたこと
- コンテンツが多いコンテナに対して BrowseDirectChildren を実行すると結構待たされる...
- そして SOAP リクエストは並列に処理されないっぽいので時間の掛かるリクエストがあると後続のリクエストが待たされる
- リクエストのキャンセルがない?
Code
- 最低限のコードなので悪しからず...
オワリ