serve-sim 0.1.25 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,7 +31,7 @@ I develop the Expo framework, but this tool is completely agnostic to React Nati
31
31
 
32
32
  ## Install
33
33
 
34
- Requires macOS with Xcode command line tools (`xcrun simctl`) and Node.js 18+. `bun` is **not** required to run the CLI.
34
+ Requires macOS with Xcode command line tools (`xcrun simctl`) and Node.js 18+. `bun` is **not** required to run the CLI. Camera injection uses a host-side helper built for macOS 14+.
35
35
 
36
36
  ## CLI
37
37
 
@@ -9,7 +9,7 @@ BIN="$OUT_DIR/serve-sim-camera-helper"
9
9
 
10
10
  xcrun --sdk macosx clang \
11
11
  -arch arm64 -arch x86_64 \
12
- -mmacosx-version-min=12.0 \
12
+ -mmacosx-version-min=14.0 \
13
13
  -isysroot "$SDK" \
14
14
  -fobjc-arc -fmodules \
15
15
  -framework Foundation \
@@ -267,20 +267,30 @@ static void RenderPlaceholderFrame(uint8_t *out, uint64_t frameIdx) {
267
267
  }
268
268
 
269
269
  static void StartPlaceholderSource(void) {
270
+ static uint8_t *buf = NULL;
271
+ size_t need = (size_t)gWidth * gHeight * 4;
272
+ if (!buf) buf = calloc(1, need);
273
+ if (!buf) {
274
+ fprintf(stderr, "[serve-sim-camera] placeholder buf alloc failed (%zu bytes)\n", need);
275
+ return;
276
+ }
277
+
278
+ __block uint64_t frameIdx = 0;
279
+ RenderPlaceholderFrame(buf, frameIdx++);
280
+ PublishFrame(buf);
281
+
270
282
  gPlaceholderTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,
271
283
  dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0));
272
284
  uint64_t intervalNs = NSEC_PER_SEC / 30;
273
285
  dispatch_source_set_timer(gPlaceholderTimer,
274
- dispatch_time(DISPATCH_TIME_NOW, 0), intervalNs, intervalNs / 10);
275
- static uint8_t *buf = NULL;
276
- size_t need = (size_t)gWidth * gHeight * 4;
277
- if (!buf) buf = malloc(need);
278
- __block uint64_t frameIdx = 0;
286
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)intervalNs), intervalNs, intervalNs / 10);
279
287
  dispatch_source_set_event_handler(gPlaceholderTimer, ^{
280
288
  RenderPlaceholderFrame(buf, frameIdx++);
281
289
  PublishFrame(buf);
282
290
  });
283
291
  dispatch_resume(gPlaceholderTimer);
292
+ fprintf(stderr, "[serve-sim-camera] placeholder source running @ 30fps (%ux%u, first frame seq=%llu)\n",
293
+ gWidth, gHeight, (unsigned long long)atomic_load(&gFrameSeq));
284
294
  }
285
295
 
286
296
  static void StopPlaceholderSource(void) {
@@ -364,10 +374,10 @@ static BOOL StartImageSource(NSString *path, NSString **err) {
364
374
  CGContextRef ctx = CGBitmapContextCreate(buf, gWidth, gHeight, 8, bpr, cs,
365
375
  kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
366
376
  CGColorSpaceRelease(cs);
367
- // Aspect-fill the source image into the destination buffer.
368
377
  size_t iw = CGImageGetWidth(img), ih = CGImageGetHeight(img);
369
378
  double sx = (double)gWidth / iw, sy = (double)gHeight / ih;
370
- double s = MAX(sx, sy);
379
+ // Aspect-fit file sources so the full source frame remains visible.
380
+ double s = MIN(sx, sy);
371
381
  double dw = iw * s, dh = ih * s;
372
382
  CGContextDrawImage(ctx, CGRectMake((gWidth - dw)/2.0, (gHeight - dh)/2.0, dw, dh), img);
373
383
  CGContextRelease(ctx);
@@ -425,7 +435,7 @@ static AVAssetReaderTrackOutput *MakeVideoOutput(AVAssetReader **outReader,
425
435
  return out;
426
436
  }
427
437
 
428
- // Aspect-fill a source pixel buffer into a transient BGRA buffer sized to
438
+ // Aspect-fit a source pixel buffer into a transient BGRA buffer sized to
429
439
  // the shm region. We allocate once per call so the caller is free to free
430
440
  // the result without worrying about lifetime sharing.
431
441
  static uint8_t *RenderPixelBufferToShmSize(CVPixelBufferRef pb) {
@@ -457,7 +467,8 @@ static uint8_t *RenderPixelBufferToShmSize(CVPixelBufferRef pb) {
457
467
  CGDataProviderRelease(dp);
458
468
 
459
469
  double sx = (double)gWidth / srcW, sy = (double)gHeight / srcH;
460
- double s = MAX(sx, sy);
470
+ // Keep video file playback letterboxed instead of cropping the source.
471
+ double s = MIN(sx, sy);
461
472
  double dw = srcW * s, dh = srcH * s;
462
473
  CGContextDrawImage(ctx, CGRectMake((gWidth - dw)/2.0, (gHeight - dh)/2.0, dw, dh), img);
463
474
  CGImageRelease(img);
@@ -820,14 +831,6 @@ int main(int argc, const char *argv[]) {
820
831
 
821
832
  gSourceQueue = dispatch_queue_create("simcam.helper.source", DISPATCH_QUEUE_SERIAL);
822
833
 
823
- if (socketPath) {
824
- if (OpenControlSocket(socketPath) < 0) {
825
- fprintf(stderr, "[serve-sim-camera] control socket open failed: %s\n", socketPath);
826
- } else {
827
- fprintf(stderr, "[serve-sim-camera] control socket %s\n", socketPath);
828
- }
829
- }
830
-
831
834
  SimCamSourceKind k = ParseSourceName(initialSource);
832
835
  if (k == (SimCamSourceKind)-1) {
833
836
  fprintf(stderr, "[serve-sim-camera] unknown --source %s, defaulting to placeholder\n",
@@ -841,6 +844,14 @@ int main(int argc, const char *argv[]) {
841
844
  (void)SwitchSource(SimCamSourcePlaceholder, nil, NULL);
842
845
  }
843
846
 
847
+ if (socketPath) {
848
+ if (OpenControlSocket(socketPath) < 0) {
849
+ fprintf(stderr, "[serve-sim-camera] control socket open failed: %s\n", socketPath);
850
+ } else {
851
+ fprintf(stderr, "[serve-sim-camera] control socket %s\n", socketPath);
852
+ }
853
+ }
854
+
844
855
  signal(SIGINT, HandleSig);
845
856
  signal(SIGTERM, HandleSig);
846
857
 
@@ -0,0 +1,86 @@
1
+ #pragma once
2
+
3
+ #import <AVFoundation/AVFoundation.h>
4
+ #import <CoreMotion/CoreMotion.h>
5
+
6
+ #pragma mark - Mirror mode
7
+
8
+ typedef NS_ENUM(NSInteger, SimCamMirrorMode) {
9
+ SimCamMirrorAuto = 0,
10
+ SimCamMirrorForceOn,
11
+ SimCamMirrorForceOff,
12
+ };
13
+
14
+ SimCamMirrorMode SimCamGetMirrorMode(void);
15
+ void SimCamSetMirrorMode(SimCamMirrorMode m);
16
+ BOOL SimCamShouldMirror(AVCaptureDevicePosition p);
17
+
18
+ void SimCamReadMirrorModeFromEnv(void);
19
+
20
+ #pragma mark - Position tag
21
+
22
+ AVCaptureDevicePosition SimCamPositionOf(id obj);
23
+ void SimCamSetPosition(id obj, AVCaptureDevicePosition p);
24
+
25
+ #pragma mark - Camera-in-use sticky flag
26
+
27
+ BOOL SimCamCameraIsInUse(void);
28
+ void SimCamMarkCameraInUse(void);
29
+ void SimCamMarkSessionUsingFakeCamera(id session, BOOL usingFakeCamera);
30
+
31
+ #pragma mark - AVF runtime-error notification suppression
32
+
33
+ BOOL SimCamShouldSwallowAVFRuntimeError(NSNotificationName name, id object);
34
+ void SimCamLogSwallowedRuntimeError(NSString *via, id object, NSDictionary *userInfo);
35
+
36
+ #pragma mark - Fake objects
37
+
38
+ @interface SimCamWeakRef : NSObject
39
+ @property (nonatomic, weak) id target;
40
+ @end
41
+
42
+ @interface SimCamFakeFormat : AVCaptureDeviceFormat
43
+ @end
44
+ @interface SimCamFakeDevice : AVCaptureDevice
45
+ @end
46
+ @interface SimCamFakeConnection : AVCaptureConnection
47
+ @end
48
+ @interface SimCamFakeResolvedPhotoSettings : AVCaptureResolvedPhotoSettings
49
+ @end
50
+
51
+ @interface SimCamFakePhoto : AVCapturePhoto
52
+ + (instancetype)photoFromImage:(CGImageRef)cgImage
53
+ jpegQuality:(CGFloat)q
54
+ mirrored:(BOOL)mirrored;
55
+ @end
56
+
57
+ @interface SimCamAttitude : CMAttitude
58
+ @end
59
+ @interface SimCamAccelerometerData : CMAccelerometerData
60
+ @end
61
+ @interface SimCamGyroData : CMGyroData
62
+ @end
63
+ @interface SimCamMagnetometerData : CMMagnetometerData
64
+ @end
65
+ @interface SimCamDeviceMotion : CMDeviceMotion
66
+ @end
67
+
68
+ #pragma mark - Fake-object factories / caches
69
+
70
+ AVCaptureDeviceFormat *SimCamSharedFakeFormat(void);
71
+ AVCaptureDevice *SimCamFakeDeviceForPosition(AVCaptureDevicePosition p);
72
+ AVCaptureDeviceInput *SimCamFakeInputForPosition(AVCaptureDevicePosition p);
73
+
74
+ AVCaptureConnection *SimCamFakeConnectionForOutput(AVCaptureOutput *out);
75
+
76
+ CMAttitude *SimCamSharedAttitude(void);
77
+ CMAccelerometerData *SimCamSharedAccelerometerData(void);
78
+ CMGyroData *SimCamSharedGyroData(void);
79
+ CMMagnetometerData *SimCamSharedMagnetometerData(void);
80
+ CMDeviceMotion *SimCamSharedDeviceMotion(void);
81
+
82
+ #pragma mark - Fake-input marking (used by AVCaptureDeviceInput swizzle)
83
+
84
+ void SimCamMarkFakeInput(id input, AVCaptureDevice *fakeDevice);
85
+ BOOL SimCamIsFakeInput(id input);
86
+ AVCaptureDevice *SimCamFakeInputDevice(id input);