Skip to content

Commit 1979edc

Browse files
fix concurrancy issue if lid closed during photo
1 parent 36a0f23 commit 1979edc

File tree

2 files changed

+87
-83
lines changed

2 files changed

+87
-83
lines changed

memoryio/memoryio/ImageSnap.m

Lines changed: 64 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,6 @@ @interface ImageSnap()
1919
@property (nonatomic, strong) AVCaptureStillImageOutput *captureStillImageOutput;
2020
@property (nonatomic, assign) CVImageBufferRef currentImageBuffer;
2121
@property (nonatomic, strong) AVCaptureConnection *videoConnection;
22-
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
23-
24-
#if OS_OBJECT_HAVE_OBJC_SUPPORT == 1
25-
@property (nonatomic, strong) dispatch_queue_t imageQueue;
26-
#else
27-
@property (nonatomic, assign) dispatch_queue_t imageQueue;
28-
#endif
2922

3023
@end
3124

@@ -76,11 +69,30 @@ + (AVCaptureDevice *)deviceNamed:(NSString *)name {
7669
return result;
7770
}
7871

72+
+ (NSURL *)NSURLfromPath:(NSString *)path andDate:(NSDate *)now{
73+
74+
NSDateFormatter *dateFormatter;
75+
dateFormatter = [NSDateFormatter new];
76+
dateFormatter.dateFormat = @"yyyy-MM-dd_HH-mm-ss.SSS";
77+
78+
NSString *nowstr = [dateFormatter stringFromDate:now];
79+
80+
NSString *pathAndFilename = [NSString stringWithFormat:@"%@%@%@", path, nowstr, @".jpg"];
81+
82+
return [NSURL fileURLWithPath:pathAndFilename isDirectory:NO];
83+
}
84+
7985
+ (void)saveSingleSnapshotFrom:(AVCaptureDevice *)device
8086
toPath:(NSString *)path
8187
withWarmup:(NSNumber *)warmup
8288
withCallbackBlock:(void (^)(NSURL *imageURL, NSError *error))callbackBlock{
8389

90+
NSOperationQueue *queue = [NSOperationQueue new];
91+
queue.maxConcurrentOperationCount =1;
92+
93+
NSDate *now = [NSDate date];
94+
NSURL *imageURL = [self NSURLfromPath:path andDate:now];
95+
8496
verbose("Starting device...");
8597

8698
NSError *error;
@@ -126,6 +138,30 @@ + (void)saveSingleSnapshotFrom:(AVCaptureDevice *)device
126138

127139
verbose("Device started.\n");
128140

141+
void (^stopSession)(void) = ^void(void) {
142+
verbose("Stopping session...\n");
143+
144+
// Make sure we've stopped
145+
while (captureSession != nil) {
146+
verbose("\tCaptureSession != nil\n");
147+
148+
verbose("\tStopping CaptureSession...");
149+
[captureSession stopRunning];
150+
verbose("Done.\n");
151+
152+
if ([captureSession isRunning]) {
153+
verbose("[captureSession isRunning]");
154+
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
155+
} else {
156+
verbose("\tShutting down 'stopSession(..)'" );
157+
158+
captureSession = nil;
159+
captureDeviceInput = nil;
160+
captureStillImageOutput = nil;
161+
}
162+
}
163+
};
164+
129165
if (warmup == nil) {
130166
// Skip warmup
131167
verbose("Skipping warmup period.\n");
@@ -136,61 +172,32 @@ + (void)saveSingleSnapshotFrom:(AVCaptureDevice *)device
136172
verbose("Warmup complete.\n");
137173
}
138174

139-
[captureStillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection
140-
completionHandler:
141-
^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
142-
143-
NSDateFormatter *dateFormatter;
144-
dateFormatter = [NSDateFormatter new];
145-
dateFormatter.dateFormat = @"yyyy-MM-dd_HH-mm-ss.SSS";
146-
147-
NSDate *now = [NSDate date];
148-
NSString *nowstr = [dateFormatter stringFromDate:now];
149-
150-
NSString *pathAndFilename = [NSString stringWithFormat:@"%@%@%@", path, nowstr, @".jpg"];
151-
152-
NSURL *imageURL = [NSURL fileURLWithPath:pathAndFilename isDirectory:NO];
153-
154-
NSLog(@"Making exif data");
155-
ExifContainer *container = [[ExifContainer alloc] init];
156-
[container addCreationDate:now];
157-
[container addDigitizedDate:now];
158-
159-
NSData *rawImageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
175+
void(^saveImage)(CMSampleBufferRef imageDataSampleBuffer, NSError *error) = ^void(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
160176

161-
NSData *imageData = [NSImage getAppendedDataForImageData:rawImageData exif:container];
162-
163-
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
164-
165-
[imageData writeToURL:imageURL atomically:YES];
166-
167-
verbose("Stopping session...\n" );
168-
169-
// Make sure we've stopped
170-
while (captureSession != nil) {
171-
verbose("\tCaptureSession != nil\n");
172-
173-
verbose("\tStopping CaptureSession...");
174-
[captureSession stopRunning];
175-
verbose("Done.\n");
177+
// usually happens if you close lid while its grabbing a photos
178+
if(error){
179+
[queue addOperationWithBlock:stopSession];
180+
callbackBlock(NULL, error);
181+
return;
182+
}
176183

177-
if ([captureSession isRunning]) {
178-
verbose("[captureSession isRunning]");
179-
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
180-
} else {
181-
verbose("\tShutting down 'stopSession(..)'" );
184+
verbose("Making exif data");
185+
ExifContainer *container = [[ExifContainer alloc] init];
186+
[container addCreationDate:now];
187+
[container addDigitizedDate:now];
182188

183-
captureSession = nil;
184-
captureDeviceInput = nil;
185-
captureStillImageOutput = nil;
186-
}
187-
}
189+
NSData *rawImageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
190+
NSData *imageData = [NSImage getAppendedDataForImageData:rawImageData exif:container];
188191

189-
});
192+
[queue addOperationWithBlock:^void(void) {
193+
[imageData writeToURL:imageURL atomically:YES];
194+
}];
195+
[queue addOperationWithBlock:stopSession];
196+
callbackBlock(imageURL, error);
197+
};
190198

191-
verbose("Callback...\n" );
192-
callbackBlock(imageURL, error);
193-
}];
199+
[captureStillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection
200+
completionHandler:saveImage];
194201
}
195202

196203
@end

memoryio/memoryio/TSAppDelegate.m

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ - (void)awakeFromNib
2929
{
3030
case kIOMessageDeviceHasPoweredOn :
3131
// mainly for when the display goesto sleep and wakes up
32-
NSLog(@"powerMessageReceived: got a kIOMessageDeviceHasPoweredOn - device powered on");
32+
verbose("powerMessageReceived: got a kIOMessageDeviceHasPoweredOn - device powered on");
3333
break;
3434
case kIOMessageSystemHasPoweredOn:
3535
// mainly for when the system goes to sleep and wakes up
36-
NSLog(@"powerMessageReceived: got a kIOMessageSystemHasPoweredOn - system powered on");
36+
verbose("powerMessageReceived: got a kIOMessageSystemHasPoweredOn - system powered on");
3737
[weakSelf takePhotoWithDelay:2.0f];
3838
break;
3939
}
@@ -158,7 +158,7 @@ -(IBAction)setPhoto:(NSImage*)backgroundImage
158158

159159
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
160160
{
161-
NSLog(@"Starting memoryio");
161+
verbose("Starting memoryio");
162162

163163
[notificationManager subscribeDisplayNotifications];
164164
[notificationManager subscribePowerNotifications];
@@ -176,15 +176,15 @@ - (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNot
176176
[center removeDeliveredNotification:notification];
177177
switch (notification.activationType) {
178178
case NSUserNotificationActivationTypeActionButtonClicked:
179-
NSLog(@"Reply Button was clicked -> quick reply");
179+
verbose("Reply Button was clicked -> quick reply");
180180
break;
181181
case NSUserNotificationActivationTypeContentsClicked:
182-
NSLog(@"Notification body was clicked -> redirect to item");
182+
verbose("Notification body was clicked -> redirect to item");
183183
[self preview:nil];
184184
[NSApp activateIgnoringOtherApps:YES];
185185
break;
186186
default:
187-
NSLog(@"Notfiication appears to have been dismissed!");
187+
verbose("Notfiication appears to have been dismissed!");
188188
break;
189189
}
190190
}
@@ -228,31 +228,28 @@ - (void) postNotification:(NSString *) informativeText withActionBoolean:(BOOL)h
228228

229229
- (void) takePhotoWithDelay: (float) delay {
230230

231-
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
231+
NSString *path = [NSString stringWithFormat:@"%@%@", NSHomeDirectory(), @"/Pictures/memoryIO/"];
232232

233-
NSString *path = [NSString stringWithFormat:@"%@%@", NSHomeDirectory(), @"/Pictures/memoryIO/"];
233+
// create directory if it doesnt exist
234+
NSFileManager *fileManager= [NSFileManager defaultManager];
235+
NSError *error = nil;
236+
[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
234237

235-
NSFileManager *fileManager= [NSFileManager defaultManager];
236-
NSError *error = nil;
237-
[fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
238+
typeof(self) __weak weakSelf = self;
239+
[ImageSnap saveSingleSnapshotFrom:[ImageSnap defaultVideoDevice]
240+
toPath:path
241+
withWarmup:[NSNumber numberWithInt:delay]
242+
withCallbackBlock:^(NSURL *imageURL, NSError *error) {
238243

239-
typeof(self) __weak weakSelf = self;
240-
[ImageSnap saveSingleSnapshotFrom:[ImageSnap defaultVideoDevice]
241-
toPath:path
242-
withWarmup:[NSNumber numberWithInt:delay]
243-
withCallbackBlock:^(NSURL *imageURL, NSError *error) {
244+
if(error)
245+
{
246+
[weakSelf postNotification:@"There was a problem taking that shot :(" withActionBoolean:false];
247+
} else {
248+
[weakSelf postNotification:@"Well, Look at you!" withActionBoolean:true];
249+
}
244250

245-
dispatch_async(dispatch_get_main_queue(), ^{
246-
if(error)
247-
{
248-
[weakSelf postNotification:@"There was a problem taking that shot :(" withActionBoolean:false];
249-
} else {
250-
[weakSelf postNotification:@"Well, Look at you!" withActionBoolean:true];
251-
}
252-
}); // end of dispatch_async main thread
253251

254-
}]; // end of callback Block
255-
}); // end of dispatch_async main thread
252+
}]; // end of callback Block
256253
}
257254

258255
@end

0 commit comments

Comments
 (0)