質問するログイン新規登録

質問編集履歴

2

修正・追加

2017/02/23 00:29

投稿

Nefytus
Nefytus

スコア12

title CHANGED
File without changes
body CHANGED
@@ -39,5 +39,172 @@
39
39
  }
40
40
  ```
41
41
 
42
+ 教えていただいたように一番下の部分に追加したところ、19個用意した音声ファイルが複数回選択され、全部で189個のキューが自動で設定されるようになりました。
43
+ これについては、for文の部分で回数の設定などを行うことで19個のキューにすることができるのでしょうか?
42
44
 
45
+ ```Swift
46
+ class PlayerViewController: UIViewController, UICollectionViewDataSource {
47
+ static let assetKeysRequiredToPlay = [
48
+ "playable",
49
+ "hasProtectedContent"
50
+ ]
51
+
52
+ let player = AVQueuePlayer()
53
+
54
+ var currentTime: Double {
55
+ get {
56
+ return CMTimeGetSeconds(player.currentTime())
57
+ }
58
+
59
+ set {
60
+ let newTime = CMTimeMakeWithSeconds(newValue, 1)
61
+ player.seek(to: newTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
62
+ }
63
+ }
64
+
65
+ var duration: Double {
66
+ guard let currentItem = player.currentItem else { return 0.0 }
67
+
68
+ return CMTimeGetSeconds(currentItem.duration)
69
+ }
70
+
71
+ var rate: Float {
72
+ get {
73
+ return player.rate
74
+ }
75
+
76
+ set {
77
+ player.rate = newValue
78
+ }
79
+ }
80
+
81
+ var playerLayer: AVPlayerLayer? {
82
+ return playerView.playerLayer
83
+ }
84
+
85
+ /*
86
+ A formatter for individual date components used to provide an appropriate
87
+ value for the `startTimeLabel` and `durationLabel`.
88
+ */
89
+ let timeRemainingFormatter: DateComponentsFormatter = {
90
+ let formatter = DateComponentsFormatter()
91
+ formatter.zeroFormattingBehavior = .pad
92
+ formatter.allowedUnits = [.minute, .second]
93
+
94
+ return formatter
95
+ }()
96
+
97
+ var timeObserverToken: Any?
98
+
99
+ var assetTitlesAndThumbnails: [URL: (title: String, thumbnail: UIImage)] = [:]
100
+
101
+ var loadedAssets = [String: AVURLAsset]()
102
+
103
+ @IBOutlet weak var timeSlider: UISlider!
104
+ @IBOutlet weak var startTimeLabel: UILabel!
105
+ @IBOutlet weak var durationLabel: UILabel!
106
+ @IBOutlet weak var rewindButton: UIButton!
107
+ @IBOutlet weak var playPauseButton: UIButton!
108
+ @IBOutlet weak var fastForwardButton: UIButton!
109
+ @IBOutlet weak var clearButton: UIButton!
110
+ @IBOutlet weak var collectionView: UICollectionView!
111
+ @IBOutlet weak var queueLabel: UILabel!
112
+ @IBOutlet weak var playerView: PlayerView!
113
+
114
+ override func viewWillAppear(_ animated: Bool) {
115
+ super.viewWillAppear(animated)
116
+
117
+
118
+ addObserver(self, forKeyPath: #keyPath(PlayerViewController.player.currentItem.duration), options: [.new, .initial], context: &playerViewControllerKVOContext)
119
+ addObserver(self, forKeyPath: #keyPath(PlayerViewController.player.rate), options: [.new, .initial], context: &playerViewControllerKVOContext)
120
+ addObserver(self, forKeyPath: #keyPath(PlayerViewController.player.currentItem.status), options: [.new, .initial], context: &playerViewControllerKVOContext)
121
+ addObserver(self, forKeyPath: #keyPath(PlayerViewController.player.currentItem), options: [.new, .initial], context: &playerViewControllerKVOContext)
122
+
123
+ playerView.playerLayer.player = player
124
+
125
+ let manifestURL = Bundle.main.url(forResource: "MediaManifest", withExtension: "json")!
126
+ asynchronouslyLoadURLAssetsWithManifestURL(jsonURL: manifestURL)
127
+
128
+ let interval = CMTimeMake(1, 1)
129
+ timeObserverToken = player.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main) { [unowned self] time in
130
+ let timeElapsed = Float(CMTimeGetSeconds(time))
131
+
132
+ self.timeSlider.value = Float(timeElapsed)
133
+ self.startTimeLabel.text = self.createTimeString(time: timeElapsed)
134
+ }
135
+
136
+ }
137
+
138
+ override func viewDidDisappear(_ animated: Bool) {
139
+ super.viewDidDisappear(animated)
140
+
141
+ if let timeObserverToken = timeObserverToken {
142
+ player.removeTimeObserver(timeObserverToken)
143
+ self.timeObserverToken = nil
144
+ }
145
+
146
+ player.pause()
147
+
148
+ removeObserver(self, forKeyPath: #keyPath(PlayerViewController.player.currentItem.duration), context: &playerViewControllerKVOContext)
149
+ removeObserver(self, forKeyPath: #keyPath(PlayerViewController.player.rate), context: &playerViewControllerKVOContext)
150
+ removeObserver(self, forKeyPath: #keyPath(PlayerViewController.player.currentItem.status), context: &playerViewControllerKVOContext)
151
+ removeObserver(self, forKeyPath: #keyPath(PlayerViewController.player.currentItem), context: &playerViewControllerKVOContext)
152
+ }
153
+
154
+ func asynchronouslyLoadURLAsset(asset: AVURLAsset, title: String, thumbnailResourceName: String) {
155
+
156
+ asset.loadValuesAsynchronously(forKeys: PlayerViewController.assetKeysRequiredToPlay) {
157
+
158
+
159
+ DispatchQueue.main.async() {
160
+
161
+
162
+
163
+ for key in PlayerViewController.assetKeysRequiredToPlay {
164
+ var error: NSError?
165
+
166
+ if asset.statusOfValue(forKey: key, error: &error) == .failed {
167
+ let stringFormat = NSLocalizedString("error.asset_%@_key_%@_failed.description", comment: "Can't use this AVAsset because one of it's keys failed to load")
168
+
169
+ let message = String.localizedStringWithFormat(stringFormat, title, key)
170
+
171
+ self.handleError(with: message, error: error)
172
+
173
+ return
174
+ }
175
+ }
176
+
177
+
178
+ if !asset.isPlayable || asset.hasProtectedContent {
179
+ let stringFormat = NSLocalizedString("error.asset_%@_not_playable.description", comment: "Can't use this AVAsset because it isn't playable or has protected content")
180
+
181
+ let message = String.localizedStringWithFormat(stringFormat, title)
182
+
183
+ self.handleError(with: message)
184
+
185
+ return
186
+ }
187
+
188
+
189
+ self.loadedAssets[title] = asset
190
+
191
+ let name = (thumbnailResourceName as NSString).deletingPathExtension
192
+ let type = (thumbnailResourceName as NSString).pathExtension
193
+ let path = Bundle.main.path(forResource: name, ofType: type)!
194
+
195
+ let thumbnail = UIImage(contentsOfFile: path)!
196
+
197
+ self.assetTitlesAndThumbnails[asset.url] = (title, thumbnail)
198
+
199
+ for (loadedAssetTitle, loadedAsset) in self.loadedAssets {
200
+ let newPlayerItem = AVPlayerItem(asset: loadedAsset)
201
+ self.player.insert(newPlayerItem, after: nil)
202
+ }
203
+
204
+ }
205
+ }
206
+ }
207
+ ```
208
+
209
+
43
210
  よろしくお願いいたします。

1

修正

2017/02/23 00:29

投稿

Nefytus
Nefytus

スコア12

title CHANGED
File without changes
body CHANGED
@@ -4,4 +4,40 @@
4
4
 
5
5
  ここでお尋ねしたいのが、addItemというボタンを使用せずに、アプリを起動した時点ですでにアプリ内に用意された全ての音声ファイルがキューにセットされている状態にする方法です。
6
6
  アプリ起動後、再生ボタンを押すとセットされた音声ファイルが再生されるようにしたいです。
7
+
8
+ 以下にある、addItemのボタンの機能を参考にするのかと考えていますが、自動で全音声ファイルをキューに加える方法が分からず、質問させていただきました。
9
+ ```Swift
10
+ @IBAction func addItemToQueueButtonPressed(_ sender: UIButton) {
11
+ let alertTitle = NSLocalizedString("popover.title.addItem", comment: "Title of popover that adds items to the queue")
12
+
13
+ let alertMessage = NSLocalizedString("popover.message.addItem", comment: "Message on popover that adds items to the queue")
14
+
15
+ let alertController = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .actionSheet)
16
+
17
+ // Populate the sheet with the titles of the assets we have loaded.
18
+ for (loadedAssetTitle, loadedAsset) in loadedAssets {
19
+ let alertAction = UIAlertAction(title:loadedAssetTitle, style: .default) { [unowned self] alertAction in
20
+ let oldItems = self.player.items()
21
+
22
+ let newPlayerItem = AVPlayerItem(asset: loadedAsset)
23
+
24
+ self.player.insert(newPlayerItem, after: nil)
25
+
26
+ self.queueDidChangeWithOldPlayerItems(oldPlayerItems: oldItems, newPlayerItems: self.player.items())
27
+ }
28
+
29
+ alertController.addAction(alertAction)
30
+ }
31
+
32
+ let cancelActionTitle = NSLocalizedString("popover.title.cancel", comment: "Title of popover cancel action")
33
+
34
+ let cancelAction = UIAlertAction(title: cancelActionTitle, style: .cancel, handler: nil)
35
+
36
+ alertController.addAction(cancelAction)
37
+
38
+ presentModalPopoverAlertController(alertController: alertController, sender: sender)
39
+ }
40
+ ```
41
+
42
+
7
43
  よろしくお願いいたします。