Воспроизведение видео Обходной путь предотвращения зеркалирования
Среда
- Xcode @ OS-X Yosemite
- iOS-приложение @ Obj-C
Использование регистра
- Сеанс быстрого зеркалирования устанавливается между iOS и OSX ( Как настроить сеанс зеркального отображения между iOS 8 и Yosemite?)
- Сторонний SDK интегрирован с приложением iOS
- SDK используется для воспроизведения видео
- Когда воспроизводится видео и установлен сеанс зеркального отображения (как внешний дисплей), видео не воспроизводится (только аудио)
- В SDK нет API для управления внешним воспроизведением / включением / выключением зеркалирования при зеркалировании.
Мне нужно иметь возможность зеркально отразить видео на моем рабочем столе OSX, для этого я попытался скрыть зеркальный экран от стороннего SDK следующим образом (однако это не помогло):
namespace NSNotificationCenterS
{
namespace Original
{
IMP addObserver = 0;
}
void addObserver(id self, SEL _cmd, id notificationObserver, SEL notificationSelector, NSString* notificationName, id notificationSender){
if( (YES == [notificationName isEqualToString:UIScreenDidConnectNotification]) ||
(YES == [notificationName isEqualToString:UIScreenDidDisconnectNotification]) ||
(YES == [notificationName isEqualToString:UIScreenModeDidChangeNotification ]) )
{
NSLog(@"NSNotificationCenter addObserver(%@, %@, '%@', %@) SUPRESSED!!!", notificationObserver, NSStringFromSelector(notificationSelector), notificationName, notificationSender);
return;// Supress notifications of this kind of events
}
// NSLog(@"NSNotificationCenter addObserver(%@, %@, '%@', %@)", notificationObserver, NSStringFromSelector(notificationSelector), notificationName, notificationSender);
((void(*)(id, SEL, id, SEL, NSString*,id))Original::addObserver)(self, _cmd, notificationObserver, notificationSelector, notificationName, notificationSender);
}
void initHooks() {
Method method;
method = class_getInstanceMethod([NSNotificationCenter class], @selector(addObserver:selector:name:object:));
Original::addObserver = method_getImplementation(method);
method_setImplementation(method, (IMP)NSNotificationCenterS::addObserver);
}
}
namespace AVPlayerS
{
namespace Original
{
IMP init = 0;
IMP setAllowsExternalPlayback = 0;
IMP setUsesExternalPlaybackWhileExternalScreenIsActive = 0;
IMP setAllowsAirPlayVideo = 0;
IMP setUsesAirPlayVideoWhileAirPlayScreenIsActive = 0;
}
id init(id self, SEL _cmd) {
NSLog(@"AVPlayer init, %@\n", self);
id ret = ((id(*)(id,SEL))Original::init)(self, _cmd);
if(nil == ret)
return nil;
((void(*)(id, SEL, BOOL))Original::setAllowsExternalPlayback)(ret, @selector(setAllowsExternalPlayback:), YES);
((void(*)(id, SEL, BOOL))Original::setUsesExternalPlaybackWhileExternalScreenIsActive)(ret, @selector(setUsesExternalPlaybackWhileExternalScreenIsActive:), YES);
((void(*)(id, SEL, BOOL))Original::setAllowsAirPlayVideo)(ret, @selector(setAllowsAirPlayVideo:), YES);
((void(*)(id, SEL, BOOL))Original::setUsesAirPlayVideoWhileAirPlayScreenIsActive)(ret, @selector(setUsesAirPlayVideoWhileAirPlayScreenIsActive:), YES);
NSLog(@"AVPlayer, %d, %d, %d, %d\n", [ret allowsExternalPlayback], [ret usesExternalPlaybackWhileExternalScreenIsActive], [ret allowsAirPlayVideo], [ret usesAirPlayVideoWhileAirPlayScreenIsActive]);
return ret;
}
UIScreen* mirroredScreen(id self, SEL _cmd) {
return nil;
}
NSArray* getScreens(id self, SEL _cmd) {
return [NSArray arrayWithObject:[UIScreen mainScreen]];
}
void flag_stub(id self, SEL _cmd, BOOL bSet){
NSLog(@"AVPlayer flag_stub(%@, %@, '%s')", self, NSStringFromSelector(_cmd), bSet ? "true" : "false");
}
BOOL ret_YES(id self, SEL _cmd) {
NSLog(@"AVPlayer ret_YES(%@, %@)", self, NSStringFromSelector(_cmd));
return YES;
}
BOOL ret_NO(id self, SEL _cmd) {
NSLog(@"AVPlayer ret_NO(%@, %@)", self, NSStringFromSelector(_cmd));
return NO;
}
void initHooks() {
Method method;
method = class_getInstanceMethod([UIScreen class], @selector(mirroredScreen));
method_setImplementation(method, (IMP)AVPlayerS::mirroredScreen);
method = class_getClassMethod([UIScreen class], @selector(screens));
method_setImplementation(method, (IMP)AVPlayerS::getScreens);
method = class_getInstanceMethod([AVPlayer class], @selector(init));
AVPlayerS::Original::init = method_getImplementation(method);
method_setImplementation(method, (IMP)AVPlayerS::init);
method = class_getInstanceMethod([AVPlayer class], @selector(setAllowsExternalPlayback:));
AVPlayerS::Original::setAllowsExternalPlayback = method_getImplementation(method);
method_setImplementation(method, (IMP)flag_stub);
method = class_getInstanceMethod([AVPlayer class], @selector(setUsesExternalPlaybackWhileExternalScreenIsActive:));
AVPlayerS::Original::setUsesExternalPlaybackWhileExternalScreenIsActive = method_getImplementation(method);
method_setImplementation(method, (IMP)flag_stub);
method = class_getInstanceMethod([AVPlayer class], @selector(setAllowsAirPlayVideo:));
AVPlayerS::Original::setAllowsAirPlayVideo = method_getImplementation(method);
method_setImplementation(method, (IMP)flag_stub);
method = class_getInstanceMethod([AVPlayer class], @selector(setUsesAirPlayVideoWhileAirPlayScreenIsActive:));
AVPlayerS::Original::setUsesAirPlayVideoWhileAirPlayScreenIsActive = method_getImplementation(method);
method_setImplementation(method, (IMP)flag_stub);
method = class_getInstanceMethod([AVPlayer class], @selector(isExternalPlaybackActive));
method_setImplementation(method, (IMP)ret_NO);
method = class_getInstanceMethod([AVPlayer class], @selector(isAirPlayVideoActive));
method_setImplementation(method, (IMP)ret_NO);
method = class_getInstanceMethod([AVPlayer class], @selector(allowsAirPlayVideo));
//method_setImplementation(method, (IMP)ret_YES);
method_setImplementation(method, (IMP)ret_NO);
}
}
Как обойти защиту при воспроизведении видео? Есть ли какой-либо API более низкого уровня, который я должен перехватить?