Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

+[AVURLAsset isPlayableExtendedMIMEType:] behaves differently when unit tested

In my app calling [AVURLAsset isPlayableExtendedMIMEType:@"video/mp4; codecs=\"avc1.64001F, mp4a.40.2\""] returns YES, which is expected.

If I run the exact same code in a unit test, then it returns NO.

Both the app and the unit test are run with Xcode 5.0.2 on the iPhone Retina (4-inch) simulator running iOS 7.0.

- (void) testPlayableExtendedMIMEType
{
    XCTAssertTrue([AVURLAsset class], @"");
    XCTAssertTrue([AVURLAsset isPlayableExtendedMIMEType:@"video/mp4; codecs=\"avc1.64001F, mp4a.40.2\""], @"");
}

The first assert passes but the second assert fails.

Why would this behavior be different in the unit test and in the app?

like image 245
0xced Avatar asked Jan 12 '14 00:01

0xced


1 Answers

After reverse engineering how +[AVURLAsset isPlayableExtendedMIMEType:] is implemented, I found the cause of the problem.

Here is a stack trace of what it is doing:

frame #0: 0x01b2861e CoreMedia`CelestialGetModelSpecificName
frame #1: 0x01b2885a CoreMedia`CelestialCFCreatePropertyListFromBundleIdentifier + 11
frame #2: 0x00050039 AVFoundation`__33+[AVURLAsset _avfValidationPlist]_block_invoke_0 + 39
frame #3: 0x02e99014 libdispatch.dylib`_dispatch_client_callout + 14
frame #4: 0x02e8b09f libdispatch.dylib`dispatch_once_f + 57
frame #5: 0x02e8b061 libdispatch.dylib`dispatch_once + 31
frame #6: 0x00050006 AVFoundation`+[AVURLAsset _avfValidationPlist] + 49
frame #7: 0x00050664 AVFoundation`+[AVURLAsset isPlayableExtendedMIMEType:] + 64

The CelestialCFCreatePropertyListFromBundleIdentifier function tries to read a MediaValidator.plist file inside the MediaToolbox framework. The location of the plist file depends on the device model name. Here are the different MediaValidator.plist files for the iOS 7 simulator.

MediaToolbox.framework
|-- J1
|   `-- MediaValidator.plist
|-- K93
|   `-- MediaValidator.plist
|-- N41
|   `-- MediaValidator.plist
`-- N94
    `-- MediaValidator.plist

When running the app, the CelestialGetModelSpecificName function returns N41, i.e. iPhone 5.
When running the unit tests, the CelestialGetModelSpecificName function returns N88, i.e. iPhone 3GS. As you can see, there is no N88 directory inside the MediaToolbox framework and this is why +[AVURLAsset isPlayableExtendedMIMEType:] eventually fails.

A closer look at the CelestialGetModelSpecificName function reveals the solution. The simulator reads the IPHONE_SIMULATOR_CLASS environment variable in order to know what device is being simulated. If the IPHONE_SIMULATOR_CLASS environment variable is not set, then it defaults to the hardcoded N88 value.

So in order for the test to pass, we just need to manually set the IPHONE_SIMULATOR_CLASS environment variable to N41 since the unit test runner doesn’t set it automatically.

setenv("IPHONE_SIMULATOR_CLASS", "N41", 0);
like image 132
0xced Avatar answered Nov 02 '22 03:11

0xced