I created a app to capture screenshot in background. It works well on iOS 7.x & 8.x, but failed to execute on iOS 9 beta. Here's my code:
CFMutableDictionaryRef sm = IOServiceMatching("AppleH1CLCD");
io_service_t ioService = IOServiceGetMatchingService(kIOMasterPortDefault, sm);
if (!ioService)
{
sm = IOServiceMatching("AppleM2CLCD");
ioService = IOServiceGetMatchingService(kIOMasterPortDefault, sm);
}
if (!ioService)
{
sm = IOServiceMatching("AppleCLCD");
ioService = IOServiceGetMatchingService(kIOMasterPortDefault, sm);
}
IOMobileFramebufferConnection connection = 0;
IOSurfaceRef ptr = nil;
IOMobileFramebufferReturn openMobileFrameBufferResult = IOMobileFramebufferOpen(ioService, mach_task_self(), 0, &connection);
if (openMobileFrameBufferResult)
{
return;
}
IOMobileFramebufferReturn getLayerDefaultSurfaceResult = IOMobileFramebufferGetLayerDefaultSurface(connection, 0, (CoreSurfaceBufferRef*)&ptr);
if (getLayerDefaultSurfaceResult)
{
return; // Here, the getLayerDefaultSurfaceResult is -536870201, not 0!
}
.......
When debugging it step by step, I found that the function IOMobileFramebufferGetLayerDefaultSurface failed to execute with a returning value -536870201 and the value expected was 0.
Who can tell me why this happened and how to resolve it ? thhhhhhhhhhhhhhhx!!
Another user asked a similar question. I did some digging into IOMobileFramebufferGetLayerDefaultSurface on iOS8 vs iOS9 (GM). And the results of what I found are summarized in this answer.
Given these results, I believe it is no longer possible, as of iOS9, to use IOMFB to capture the screen.
Related
I've been working to migrate an older Core MIDI sending implementation to send MIDI 1.0 messages using Apple's newer UMP-aware MIDI Event List API methods.
I've figured out code that runs and should output MIDI clock messages, but when I send it with MIDISendEventList(...) I see nothing being output from my MIDI interface; there's also no error returned from that method to indicate what the problem is.
Here is the code I'm using:
const ByteCount clockMessageSize = 1;
const UInt32 clockMessage[clockMessageSize] = { (UInt32)0xF8 }; // MIDI clock tick
const MIDITimeStamp timeStamp = mach_absolute_time();
MIDIEventList clockMessageEventList = {};
MIDIEventPacket* clockMessageEventListEndPacket = nullptr;
clockMessageEventListEndPacket = MIDIEventListInit(&clockMessageEventList, kMIDIProtocol_1_0);
clockMessageEventListEndPacket = MIDIEventListAdd(&clockMessageEventList, sizeof(MIDIEventList::packet), clockMessageEventListEndPacket, timeStamp, clockMessageSize, clockMessage);
for (NSUInteger endpointRefIndex = 0; endpointRefIndex < endPointRefsCount; ++endpointRefIndex) {
MIDIObjectRef destinationEndpoint = endPointRefs[endpointRefIndex];
OSStatus midiSendError = MIDISendEventList(outputPortRef, destinationEndpoint, &clockMessageEventList);
if (midiSendError != noErr) {
printf("MIDISendEventList error: %i", (int)midiSendError);
}
}
Inspecting clockMessageEventList.packet after it has been configured but before it is sent shows:
(248, 0, 0, [... all zeros to index 63])
Does anyone know where I'm going wrong?
I run this code in iPad mini 4 (Model A1538), iOS 11.2.6
Try to record audio by FFmpeg.
av_register_all();
avcodec_register_all();
avdevice_register_all();
AVFormatContext *pFormatCtx = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options,"list_devices","true",0);
AVInputFormat *iformat = av_find_input_format("avfoundation");
printf("==AVFoundation Device Info===\n");
avformat_open_input(&pFormatCtx,"",iformat,&options);
printf("=============================\n");
if(avformat_open_input(&pFormatCtx,"0",iformat,NULL)!=0){
printf("Couldn't open input stream.\n");
return;
}
pFormatCtx = NULL, and iformat = NULL.
Why should this happen, did I missed anything to set?
inputContext = avformat_alloc_context();
AVDictionary* options = NULL;
av_dict_set(&options, "video_size","960x54", 0);
av_dict_set(&options, "r","30", 0);
AVInputFormat *iformat = av_find_input_format("avfoundation");
int ret = avformat_open_input(&inputContext,"0:0", iformat,&options);
AVFoundation input device.
AVFoundation is the currently recommended framework by Apple for streamgrabbing on OSX >= 10.7 as well as on iOS.
The input filename has to be given in the following syntax:
-i "[[VIDEO]:[AUDIO]]"
I'm using dlsym to load private APIs (required on iOS 9.3) :
handle = dlopen(CORETELPATH, RTLD_LAZY);
_CTServerConnectionCreate = dlsym(handle, "_CTServerConnectionCreate");
When I kill the app (swipe from bottom on multitask mode) and restart app, it crashes on the second line.
The handle is equal to NULL and I didn't succeed in loading the lib twice.
I tried to get the error with dlerror(), but it returns also NULL.
Does anybody got this issue ? How to resolve it ?
Edit :
Here is the full code ; with the if (handle != NULL) the app doesn't crashes, but private frameworks won't load also
#define CORETELPATH "/System/Library/PrivateFrameworks/CoreTelephony.framework/CoreTelephony"
handle = dlopen(CORETELPATH, RTLD_LAZY);
NSLog(#"DL Error : %s", dlerror());
if (handle != NULL) {
_CTServerConnectionCreate = dlsym(handle, "_CTServerConnectionCreate");
CTResultConnection = _CTServerConnectionCreate(NULL, simMonitorCallback, NULL);
_CTServerConnectionAddToRunLoop = dlsym(handle, "_CTServerConnectionAddToRunLoop");
_CTServerConnectionAddToRunLoop(CTResultConnection, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
_CTServerConnectionRegisterForNotification = dlsym(handle, "_CTServerConnectionRegisterForNotification");
_CTServerConnectionUnregisterForNotification = dlsym(handle, "_CTServerConnectionUnregisterForNotification");
_CTServerConnectionRegisterForNotification(CTResultConnection, kCTSIMSupportSIMStatusChangeNotification);
_CTServerConnectionGetSIMStatus = dlsym(handle, "_CTServerConnectionGetSIMStatus");
_CTServerConnectionCopyMobileEquipmentInfo = dlsym(handle, "_CTServerConnectionCopyMobileEquipmentInfo");
}
It seems that changing Private API path to public fix the issue ; and the call to private APIs still works :
#define CORETELPATH "/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony"
ok so i want to detect weather the user has enabled hotspot/tethering or not in a iOS device. I can use private api's knowing it wont make it to the app store.
i was trying to go through private api's list/ runtime headers but there are too many to decide which might be helpful.
or if i could get to know where UIApplicationWillChangeStatusBarFrameNotification gets fired from in private api's(probably called for active call and activated hotspot etc)
i tried this detect personal hotspot and also used CaptiveNetwork but it only returns the connected wi-fi ssid and not the created hotspot.
any knowledge shared will be extremely helpful
Update: #creker
With the above code the compiler shows the error " SCDynamicStoreCreate is unavailable: not available on iOS. So i went into SCDynamicStore.h and changed the following
SCDynamicStoreRef
SCDynamicStoreCreate (
CFAllocatorRef allocator,
CFStringRef name,
SCDynamicStoreCallBack callout,
SCDynamicStoreContext *context
) __OSX_AVAILABLE_STARTING(__MAC_10_1,__IPHONE_NA);
to
SCDynamicStoreRef
SCDynamicStoreCreate (
CFAllocatorRef allocator,
CFStringRef name,
SCDynamicStoreCallBack callout,
SCDynamicStoreContext *context
) __OSX_AVAILABLE_STARTING(__MAC_10_1,__IPHONE_6_0);
now i am able to get the dictionary with the states 1022 and 1023. Just wanted to confirm by changing the file like this(not done before) will i have any problem in archiving build(or any other problem) other then the fact that we know this code won't make it to the app store
Without Private APIs
You can detect active personal hotspot by enumerating network interfaces using C APIs. When hotpost is active and someone is connected to it there will be interface with bridge prefix. On my iPhone 5 it's bridge100. If hotspot is disabled or no one is connected to it that interfaces will not even be in the list.
C APIs will even return you IP address and subnet mask in that network.
That's what I'm using in my applications to detect active hotspot.
To get SSID you need [[UIDevice currentDevice] name] - personal hotspot SSID always matches device name.
With Private APIs
You can obtain all the information about personal hotspot using this code:
SCDynamicStoreRef sc = SCDynamicStoreCreate(NULL, CFSTR("com.apple.wirelessmodemsettings.MISManager"), NULL, NULL);
NSDictionary* info = (__bridge_transfer NSDictionary*)SCDynamicStoreCopyValue(sc, CFSTR("com.apple.MobileInternetSharing"));
CFRelease(sc);
info dictionary will look something like this when hotspot is active and has connections:
{
Errnum = 0;
ExternalInterfaces = (
"pdp_ip0"
);
Hosts = {
Current = 1;
Max = 5;
MoreAllowed = 1;
Type = {
AirPort = 0;
Bluetooth = 0;
Ethernet = 0;
"USB-Ethernet" = 1;
};
};
InternalInterfaces = (
bridge100
);
Reason = 0;
State = 1023;
Version = 2;
}
When hotspot is active but there are no connections:
{
Errnum = 0;
ExternalInterfaces = (
);
Hosts = {
Current = 0;
Max = 5;
MoreAllowed = 1;
Type = {
AirPort = 0;
Bluetooth = 0;
Ethernet = 0;
"USB-Ethernet" = 0;
};
};
InternalInterfaces = (
);
Reason = 0;
State = 1023;
Version = 2;
}
When hotspot is not active:
{
Errnum = 45;
ExternalInterfaces = (
);
Hosts = {
Current = 0;
Max = 5;
MoreAllowed = 1;
Type = {
AirPort = 0;
Bluetooth = 0;
Ethernet = 0;
"USB-Ethernet" = 0;
};
};
InternalInterfaces = (
);
Reason = 0;
State = 1022;
Version = 2;
}
State key will be equal to 1023 when hotspot is active regardless of active connections. I don't know whether that value contains bit-flags or not. iOS is actually checking if value is equal to 1023.
SCDynamicStore APIs are from public SystemConfiguration framework but marked as not available on iOS platform. That means all the headers are there, you just need to copy definitions without __OSX_AVAILABLE_STARTING macro.
You can even observe changes to that setting - you can specify a key which value you want to observe. Read Apple documentation for implementation details.
UPDATE
So i went into SCDynamicStore.h and changed the following
I wouldn't do that. It shouldn't cause any problems but for me changing SDK headers is not a good solution. I suggest the following. Don't include the framework headers. Make your own header where you copy all the methods you need with __OSX_AVAILABLE_STARTING changed or removed.
PROBLEM:
How to print (multiple) receipts without any delay?
As far as I know, there are at least 3 options to print with a T88V on OSX or iOS device. Unfortunately, all 3 of those options has a flaw.
OPTION 1:
I've been playing around with the official OSX driver (latest version 1.2a) and have no problems printing with it. However, between every print command, there's 1 sec delay.
- (IBAction)button1:(id)sender
{
[self TMAppPrint];
}
- (OSStatus)TMAppPrint
{
TMTextView *textWindow = [[TMTextView alloc] init];
NSPrintInfo *printInfo = [NSPrintInfo sharedPrintInfo];
OSStatus err = noErr;
err = [TMPrintSupport TMSetJobTicket:printInfo printerName:#"TM-T88V" documentSize:NSMakeSize(204.0, 841.8) resolution:#"180x180dpi" speed:#"1" blank:#"Off" paperCut:#"DocFeedCut" chashDrwr1:#"Off" chashDrwr2:#"Off" buzzerControl:#"Off" buzzerPattern:#"Internal" buzzerRepeat:#"1"];
NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:textWindow printInfo:printInfo];
[printOperation setCanSpawnSeparateThread:YES];
[printOperation setShowsPrintPanel:NO];
[printOperation runOperation];
return err;
}
OPTION 2:
Using the iOS SDK (latest version 1.3.0) I can also print without problems but it's even worse. After sending the print command, there will be 1 sec delay till it prints.
- (IBAction)button2:(id)sender
{
if (printer != nil)
{
errorStatus = EPOS_OC_SUCCESS;
if (builder != nil)
{
int printStatus = EPOS_OC_SUCCESS;
// create a print document
printStatus = [builder addTextLang: EPOS_OC_LANG_EN];
printStatus = [builder addTextSmooth: EPOS_OC_TRUE];
printStatus = [builder addTextFont: EPOS_OC_FONT_A];
printStatus = [builder addTextSize: 1 Height: 1];
printStatus = [builder addTextStyle: EPOS_OC_FALSE Ul: EPOS_OC_FALSE Em: EPOS_OC_TRUE Color: EPOS_OC_PARAM_UNSPECIFIED];
// specify the print data>
printStatus = [builder addText: #"hello!\n"];
printStatus = [builder addCut: EPOS_OC_CUT_FEED];
// send data>
errorStatus = [printer sendData:builder Timeout:1000 Status: &status];
// end communication with the printer>
errorStatus = [printer closePrinter];
}
}
}
OPTION 3:
The last option is using the ESC/POS commands. I managed to get it to print some basic lines but I still don't understand most of it. There's no delay in printing though.
- (IBAction)button3:(id)sender
{
printer = [[EposPrint alloc] init];
errorStatus = [printer openPrinter:EPOS_OC_DEVTYPE_TCP DeviceName:#"192.168.1.168"];
builder = [[EposBuilder alloc] initWithPrinterModel:#"TM-T88V" Lang:EPOS_OC_MODEL_ANK];
}
I already directly asked Epson about this, but they couldn't give me any answer except it's working as intended... Which means I have to dive into the ESC/POS commands and learn it or are there still other options?