There was user feedback that when a video was played in the Immersive section, it played for about 13-15 seconds and then goes to a black screen. The close video button is still there but the video was not.
First off, how nice it is to get user feedback!
In breaking down the feedback, it’s notable that the Close Video button is still there, which points to the app or OS hadn’t crashed, but rather maybe the video file was interrupted? Corrupted? What if the cloud edge server had connection reset that then caused the file to think it was complete and the app continued to save the file. There isn’t currently a check to see if the integrity of the file is correct.
With this in mind, a basic md5 hash should suffice.
func md5File(from url: URL, bufferSize: Int = 1024 * 1024) throws -> Data {
let file = try FileHandle(forReadingFrom: url)
defer {
file.closeFile()
}
var md5 = CryptoKit.Insecure.MD5()
while autoreleasepool(invoking: {
let data = file.readData(ofLength: bufferSize)
if !data.isEmpty {
md5.update(data: data)
return true
} else {
return false
}
}) {
}
return Data(md5.finalize())
}
https://gist.github.com/whutao/e74c0067cf104f7b975e177f8392adc5
Looks great. This gets plugged into the watchVideo() method in the Button(action: handler and wow now the interface just sort of freezes for a few seconds while the hash is checked before playback starts.
Investigating this revealed a classic blocking the UI thread problem. Hashing is rather intensive, it has to read 1-2GB of file and then run it through the hash function. It still takes 2-3 seconds for some of the longer videos.
func asyncMd5File(from url: URL, bufferSize: Int = 1024 * 1024, completion: @escaping (Data) -> Void) {
DispatchQueue.global(qos: .userInitiated).async {
do {
let data = try self.md5File(from: url, bufferSize: bufferSize)
completion(data)
} catch {
print("Error while calculating md5: ", error)
}
}
}
And now an async method, with a few adjustments to the the button is wired up and now there’s a way to check the integrity and the user gets feedback while its processing for a few seconds.
With this change, the file gets md5 hashed in a separate thread when the user selects play. The UI then goes into spinners and disables the other buttons:
And then once the video hash mismatch occurs, it asks the user what they want to do. Either re-download the video, or play the file anyway.
This “Play anyway” option is rather contentious. On one side, if there is a mismatch and the user downloads again and sees the same error, they may want to play the video anyway because they invested the bandwidth to attempt to download the file. And if it plays fine anyway, that could be an avenue of feedback to write us and help us debug it further.
The copy will get another pass before release, however the spirit of the functionality is captured.
With this change, maybe the user feedback with the black screen will see that the video file needs to be re-downloaded and that workflow will fix their video.
It could also be some other issue, and if with this release the user doesn’t see this message and continues to experience no video after 13-15 seconds then maybe other avenues of being able to collect, then further debugging will be needed to figure out what is going on.
Update with newer copy:
Came out better after a few iterations. The first version was “Cannot Verify Content” and “The content may be corrupted or incomplete.” but with the space limitation, removed the “corrupted or incomplete” and just went with “incomplete” because the button labels give context for the incomplete message to be interpreted.
And the change is out in version 1.2.4!