I using Google example for work with Chromecast.
Working with mp4 files is correct.
But if I want to use the m3u8 format, the video will not start playing.
If I rewind the video by 10 seconds ahead, it starts playing. But it doesn't play when rewinding from 0 to 9 seconds, even if you rewind before forward for more than 10 seconds.
This is my code:
func playVideoRemotely() {
GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()
let url = URL(string: "http://www.streambox.fr/playlists/test_001/stream.m3u8")
guard let mediaURL = url else {
print("invalid mediaURL")
return
}
let mediaInfoBuilder = GCKMediaInformationBuilder(contentURL: mediaURL)
mediaInfoBuilder.contentID = "http://www.streambox.fr/playlists/test_001/stream.m3u8"
mediaInfoBuilder.streamType = GCKMediaStreamType.buffered
mediaInfoBuilder.contentType = "video/m3u8"
mediaInformation = mediaInfoBuilder.build()
guard let mediaInfo = mediaInformation else {
print("invalid mediaInformation")
return
}
if let request = sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInfo) {
request.delegate = self
}
}
I have not development on an iOS chromecast sender, but have done it on web. If you want the video to autoplay once it is loaded then I believe you need to set the autoplay field on the load options.
Related
I am having a weird situation and have no clue how to handle this , I am downloading the videos from firestorage and caching into device for future use , meanwhile the background thread is already doing its job , I am passing a video url to the function to play the video. The issue is that sometimes avplayer is playing the right video and sometimes taking some other video url from the cache.
you can find the code in below :
func cacheVideo(for exercise: Exercise) {
print(exercise.imageFileName)
guard let filePath = filePathURL(for: exercise.imageFileName) else { return }
if fileManager.fileExists(atPath: filePath.path) {
// print("already exists")
} else {
exercise.loadRealURL { (url) in
print(url)
self.getFileWith(with: url, saveTo: filePath)
}
}
}
writing file here
func getFileWith(with url: URL, saveTo saveFilePathURL: URL) {
DispatchQueue.global(qos: .background).async {
print(saveFilePathURL.path)
if let videoData = NSData(contentsOf: url) {
videoData.write(to: saveFilePathURL, atomically: true)
DispatchQueue.main.async {
// print("downloaded")
}
} else {
DispatchQueue.main.async {
let error = NSError(domain: "SomeErrorDomain", code: -2001 /* some error code */, userInfo: ["description": "Can't download video"])
print(error.debugDescription)
}
}
}
}
now playing the video using this
func startPlayingVideoOnDemand(url : URL) {
activityIndicatorView.startAnimating()
activityIndicatorView.isHidden = false
print(url)
let cachingPlayerItem = CachingPlayerItem(url: url)
cachingPlayerItem.delegate = self
cachingPlayerItem.download()
// cachingPlayerItem.preferredPeakBitRate = 0
let avasset = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: avasset)
let player = AVPlayer(playerItem: playerItem)
player.automaticallyWaitsToMinimizeStalling = false
initializeVideoLayer(for: player)
}
any suggestions would be highly appreciated.
this was solved because the data model which i was using to download bunch of videos files was accessed in background thread and meanwhile i was trying to assign the url to the same data model class in order to fetch the video and play in avplayer. Hence this was the issue and resolved by simply adding a new attribute into data model for assigning the url to play right away.
I am trying to play a video form my Server but when I try to do so I get a Crossed mark on pay button.
All other files like .ppt,.keynote etc work fine when I use them with my Server url and use a WKWebview to show them but .mp4 files are not working.
I tried 2 methods.
1) Playing directly using WKWebview.
2) Download the file and saving it in a local path and then using AVPlayer to play the file.
In both cases I get same crossed mark on the play button.
func playVideo(url:String){
var newUrl:String = url
if !( url.hasPrefix("http") || url.hasPrefix("https") ){
let host = kGetHostName()
newUrl = host + newUrl
}
do
{
let videoData = NSData(contentsOf: URL(string: newUrl)!)
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let path = URL(fileURLWithPath: documentsDirectory).appendingPathComponent("myMove.mp4")
if videoData == nil{
print("No data in this")
return
}
videoData?.write(toFile: path.absoluteString, atomically: true)
let playeritem = AVPlayerItem(url: path)
let player = AVPlayer(playerItem: playeritem)
let controller = AVPlayerViewController()
controller.player = player
self.present(controller, animated: true) {
player.play()
}
} catch {
print(error)
}
And when trying with WKWebview
func loadWebView(url:String){
var newUrl:String = url
if !( url.hasPrefix("http") || url.hasPrefix("https") ){
let host = kGetHostName()
newUrl = host + newUrl
}
self.webView.load(URLRequest(url: URL(string: newUrl)!))
}
Both cases fail and get this. Is there any way I can play the video without changing my plist settings as I want to download and play ?
1.Screen Shot
2.Screen Shot
We are using video streaming in our Swift IOS application and it works very well. The problem is that we would like to use AVAssetResourceLoader so we can make the requests to the streaming server using our own URLSession rather than whatever AVPlayer uses (I have been completely unable to find out what session AVPlayer uses or how to influence what session it uses.)
The exact behavior is that shouldWaitForLoadingOfRequestedResource is called once for two bytes on on the .m3u8 file then it is called again asking for the whole file, and then (based on the start time) the correct .ts file is requested. After we fetch the .ts file the video player simply doesn't do anything further.
This happens whether or not we use a sample streaming video file "https://tungsten.aaplimg.com/VOD/bipbop_adv_example_v2/master.m3u8" or our own server. The sequence is identical if we don't use AVAssetResourceLoader (we can tell from our server.) right up until the .ts file is requested. At that point when we don't use the custom loader the AvPlayer brings up the video and keeps requesting .ts files. If we comment out all other interactions with the AVPlayer including setting the initial time the behavior is identical so I am only going to include the code from viewDidLoad and shouldWaitForLoadingOfRequestedResource.
Again if we simply remove the "xyzzy" prefix so that AVAssetResourceLoader isn't used, everything works. Also, I guess importantly, if we target a video file that is not a streaming file everything works either way.
One more thing our transformation of the mime type for the .ts file produced some kind of weird dynamic uti, but this doesn't seem to have anything to do with the problem because even if we hardcode the uti the same thing happens.
override func viewDidLoad() {
super.viewDidLoad()
avPlayer = AVPlayer()
avPlayerLayer = AVPlayerLayer(player: avPlayer)
videoView.layer.insertSublayer(avPlayerLayer, at: 0)
videoView.backgroundColor = UIColor.black
url = URL(string: "xyzzy" + currentPatient.videoURL())!
let asset = AVURLAsset(url: url)
asset.resourceLoader.setDelegate(self, queue: DispatchQueue.main)
let item = AVPlayerItem(asset: asset)
let avPlayerItem = item
avPlayer.replaceCurrentItem(with: avPlayerItem)
videoScrollView.delegate = self
videoScrollView.minimumZoomScale = 1.0
videoScrollView.maximumZoomScale = 6.0
}
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
let urlString = loadingRequest.request.url?.absoluteString
let urlComponents = urlString?.components(separatedBy: "xyzzy")
let url = URL(string: urlComponents![1])
let request = loadingRequest.dataRequest!
let infoRequest = loadingRequest.contentInformationRequest
let task = globalSession.dataTask(with: url!) { (data, response, error) in
self.avPlayerThread.async {
if error == nil && data != nil {
let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, response?.mimeType as! CFString, nil)
if let infoRequest = infoRequest {
infoRequest.contentType = uti?.takeRetainedValue() as? String
if request.requestsAllDataToEndOfResource == false {
infoRequest.contentLength = Int64(request.requestedLength)
} else {
infoRequest.contentLength = Int64((data?.count)!)
}
infoRequest.isByteRangeAccessSupported = true
}
if infoRequest == nil || request.requestsAllDataToEndOfResource == true {
loadingRequest.dataRequest?.respond(with: data!)
}
loadingRequest.finishLoading()
} else {
print ("error \(error)")
loadingRequest.finishLoading(with: error)
}
}
}
task.resume()
return true
}
Problem: I am trying to get my audio to continue to play even when the app is in the background. The desired result would be that the audio continues to play even when: the home button is pressed, the phone sleeps/is locked, and to be able to mix with the other sounds (native music app, etc). I have looked at the other examples and have tried implementing them but without success. After starting the app action, my app plays a short sound and then waits a period of time, which it then plays another sound.
Things I have tried -
AVAudioPlayer not responding in the background
How to Play Audio in Background Swift?
Things I have learned so far is that I probably want to use the AVAudioSession with the Ambient category so that my sound mixes with the native music app. I have turned on the background capabilities in the tab and in the plist. I have tried putting the AVAudioSession in multiple places (delegate/VC file).
I am using the code from #2 to start my audioSession. Here is the code that plays the sound
func playComboSound(fileName:String){
if(fileName != "burpees" && fileName != "pushUps" && fileName != "sitUps")
{
let url = NSBundle.mainBundle().URLForResource(fileName, withExtension: "mp3")!
do {
appDelegate.audioPlayer = try AVAudioPlayer(contentsOfURL: url)
//guard let appDelegate.audioPlayer = audioPlayer else { return }
//appDelegate.audioPlayer!.stop()
appDelegate.audioPlayer!.prepareToPlay()
appDelegate.audioPlayer!.play()
} catch let error as NSError {
print(error.description)
}
}
else
{
let numRepAudio: String
switch numReps{
case "THREE":
numRepAudio = "three"
case "FIVE":
numRepAudio = "five"
case "TEN":
numRepAudio = "ten"
default:
numRepAudio = "three"
}
let url1 = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(numRepAudio, ofType: "mp3")!)
let url2 = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(fileName, ofType: "mp3")!)
print(numRepAudio)
print(fileName)
let item1 = AVPlayerItem(URL: url1)
let item2 = AVPlayerItem(URL: url2)
let items: [AVPlayerItem] = [item1, item2]
appDelegate.playerQueue = AVQueuePlayer(items: items)
appDelegate.playerQueue!.play()
}
}
Thank you
New in ios, using Swift 2.0, I have video file in Amazon S3, I use HanekeSwift for download and "cache" that video file and then play it, the issue is that when I play the video, the file written by hakene it isn't yet available, so nothing plays (I'm reusing this player SCPlayer).
How can I get notified when that video file is ready and available for play it?
PS: I've tried using PromiseKit for "play it" in "future" but no luck :(, here the sample of code:
Main call:
// prepare the promise downloads and play first one
when(self.prepareDownloads()).then {
self.playVideo(0)
}
I used this function as a way to know wich videos has been downloaded, and before play the video check if exists inside self.downloaded dictionary
func prepareDownloads() {
if let videos = self.videos {
// iterate the video list for create all the promise
for (index, video) in videos.enumerate() {
let promise = { () -> Promise<NSURL> in
return Promise<NSURL> { fulfill, reject in
log.debug("download video \(index)")
// request the video and cache it
let cache = Shared.dataCache
let resource = NSURL(string: (reaction.objectForKey("resourceURL") as! String))!
cache.fetch(URL: resource).onSuccess { data in
// get the cached file
let location = NSURL(string: DiskCache.basePath())!.URLByAppendingPathComponent("shared-data/original")
let diskCache = DiskCache(path: location.absoluteString)
let file = NSURL(fileURLWithPath: diskCache.pathForKey(resource.absoluteString))
self.downloaded.updateValue(file, forKey: index)
fulfill(file)
}.onFailure { _ in
log.error("error downloading video")
}
}
}
// save it in dictionary
self.downloads.updateValue(promise, forKey: index)
}
}
}
Verify videos before play it
func playVideo(index: Int) {
// hasn't been downloaded?
if (self.downloaded[index] == nil) {
// call the promise to download and then play
if let promise = self.downloads[index] {
promise().then { path in
// play video
self.playMedia(index, filePath: path)
}
}
} else {
// the video has been downloaded
self.playMedia(index, filePath: (self.downloaded[index])!)
}
}
Play the video
func playMedia(index: Int, filePath path: NSURL) {
// play the specific video
self.player.setItemByStringPath(path.absoluteString)
// THIS PRINT "FALSE" CUZ FILE DONT EXISTS YET :/
print(NSFileManager.defaultManager().fileExistsAtPath(path.path!))
self.player.play()
log.debug("playing video \(index)")
}