node-mac-recorder 2.21.8 → 2.21.10

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.
@@ -12,7 +12,8 @@
12
12
  "Bash(MAC_RECORDER_DEBUG=1 timeout 5 node:*)",
13
13
  "Read(//private/tmp/**)",
14
14
  "Bash(ffprobe:*)",
15
- "Bash(MAC_RECORDER_DEBUG=1 timeout 8 node:*)"
15
+ "Bash(MAC_RECORDER_DEBUG=1 timeout 8 node:*)",
16
+ "Bash(cat:*)"
16
17
  ],
17
18
  "deny": [],
18
19
  "ask": []
package/index.js CHANGED
@@ -152,21 +152,40 @@ class MacRecorder extends EventEmitter {
152
152
  * Kayıt seçeneklerini ayarlar
153
153
  */
154
154
  setOptions(options = {}) {
155
- this.options = {
156
- includeMicrophone: options.includeMicrophone === true, // Explicit true required, default false
157
- includeSystemAudio: options.includeSystemAudio === true, // Explicit true required, default false
158
- captureCursor: options.captureCursor || false,
159
- displayId: options.displayId || null, // null = ana ekran
160
- windowId: options.windowId || null, // null = tam ekran
161
- audioDeviceId: options.audioDeviceId || null, // null = default device
162
- systemAudioDeviceId: options.systemAudioDeviceId || null, // null = auto-detect system audio device
163
- captureArea: options.captureArea || null,
164
- captureCamera: options.captureCamera === true,
165
- cameraDeviceId:
155
+ // Merge options instead of replacing to preserve previously set values
156
+ if (options.includeMicrophone !== undefined) {
157
+ this.options.includeMicrophone = options.includeMicrophone === true;
158
+ }
159
+ if (options.includeSystemAudio !== undefined) {
160
+ this.options.includeSystemAudio = options.includeSystemAudio === true;
161
+ }
162
+ if (options.captureCursor !== undefined) {
163
+ this.options.captureCursor = options.captureCursor || false;
164
+ }
165
+ if (options.displayId !== undefined) {
166
+ this.options.displayId = options.displayId || null;
167
+ }
168
+ if (options.windowId !== undefined) {
169
+ this.options.windowId = options.windowId || null;
170
+ }
171
+ if (options.audioDeviceId !== undefined) {
172
+ this.options.audioDeviceId = options.audioDeviceId || null;
173
+ }
174
+ if (options.systemAudioDeviceId !== undefined) {
175
+ this.options.systemAudioDeviceId = options.systemAudioDeviceId || null;
176
+ }
177
+ if (options.captureArea !== undefined) {
178
+ this.options.captureArea = options.captureArea || null;
179
+ }
180
+ if (options.captureCamera !== undefined) {
181
+ this.options.captureCamera = options.captureCamera === true;
182
+ }
183
+ if (options.cameraDeviceId !== undefined) {
184
+ this.options.cameraDeviceId =
166
185
  typeof options.cameraDeviceId === "string" && options.cameraDeviceId.length > 0
167
186
  ? options.cameraDeviceId
168
- : null,
169
- };
187
+ : null;
188
+ }
170
189
  }
171
190
 
172
191
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-mac-recorder",
3
- "version": "2.21.8",
3
+ "version": "2.21.10",
4
4
  "description": "Native macOS screen recording package for Node.js applications",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -26,23 +26,24 @@ static void* g_avAudioRecorder = nil;
26
26
  static NSString* g_avAudioOutputPath = nil;
27
27
 
28
28
  // AVFoundation screen recording implementation
29
- extern "C" bool startAVFoundationRecording(const std::string& outputPath,
29
+ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
30
30
  CGDirectDisplayID displayID,
31
31
  uint32_t windowID,
32
32
  CGRect captureRect,
33
33
  bool captureCursor,
34
- bool includeMicrophone,
34
+ bool includeMicrophone,
35
35
  bool includeSystemAudio,
36
- NSString* audioDeviceId) {
36
+ NSString* audioDeviceId,
37
+ NSString* audioOutputPath) {
37
38
 
38
39
  if (g_avIsRecording) {
39
40
  NSLog(@"❌ AVFoundation recording already in progress");
40
41
  return false;
41
42
  }
42
-
43
+
43
44
  @try {
44
45
  MRLog(@"🎬 AVFoundation: Starting recording initialization");
45
-
46
+
46
47
  // Create output URL
47
48
  NSString *outputPathStr = [NSString stringWithUTF8String:outputPath.c_str()];
48
49
  NSURL *outputURL = [NSURL fileURLWithPath:outputPathStr];
@@ -210,12 +211,22 @@ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
210
211
  if (includeMicrophone || includeSystemAudio) {
211
212
  MRLog(@"🎤 Starting audio capture (mic=%d, system=%d)", includeMicrophone, includeSystemAudio);
212
213
 
213
- // Generate audio output path
214
- NSString *videoDir = [outputPathStr stringByDeletingLastPathComponent];
215
- NSString *audioFilename = [NSString stringWithFormat:@"avf_audio_%ld.mov", (long)[[NSDate date] timeIntervalSince1970]];
216
- g_avAudioOutputPath = [videoDir stringByAppendingPathComponent:audioFilename];
214
+ // Use provided audio output path or generate one
215
+ if (audioOutputPath && [audioOutputPath length] > 0) {
216
+ g_avAudioOutputPath = audioOutputPath;
217
+ MRLog(@"🎤 Using provided audio path: %@", g_avAudioOutputPath);
218
+ } else {
219
+ NSString *videoDir = [outputPathStr stringByDeletingLastPathComponent];
220
+ NSString *audioFilename = [NSString stringWithFormat:@"avf_audio_%ld.mov", (long)[[NSDate date] timeIntervalSince1970]];
221
+ g_avAudioOutputPath = [videoDir stringByAppendingPathComponent:audioFilename];
222
+ MRLog(@"🎤 Generated audio path: %@", g_avAudioOutputPath);
223
+ }
217
224
 
218
- MRLog(@"🎤 Audio output: %@", g_avAudioOutputPath);
225
+ // Ensure .mov extension
226
+ if (![g_avAudioOutputPath.pathExtension.lowercaseString isEqualToString:@"mov"]) {
227
+ g_avAudioOutputPath = [[g_avAudioOutputPath stringByDeletingPathExtension] stringByAppendingPathExtension:@"mov"];
228
+ MRLog(@"🔧 Fixed audio extension to .mov: %@", g_avAudioOutputPath);
229
+ }
219
230
 
220
231
  // Create audio recorder
221
232
  g_avAudioRecorder = createNativeAudioRecorder();
@@ -225,7 +236,7 @@ extern "C" bool startAVFoundationRecording(const std::string& outputPath,
225
236
  const char* outputPathCStr = [g_avAudioOutputPath UTF8String];
226
237
 
227
238
  if (startNativeAudioRecording(g_avAudioRecorder, deviceIdCStr, outputPathCStr)) {
228
- MRLog(@"✅ Audio recording started");
239
+ MRLog(@"✅ Audio recording started to: %@", g_avAudioOutputPath);
229
240
  } else {
230
241
  NSLog(@"❌ Failed to start audio recording");
231
242
  destroyNativeAudioRecorder(g_avAudioRecorder);
@@ -452,3 +463,7 @@ extern "C" bool stopAVFoundationRecording() {
452
463
  extern "C" bool isAVFoundationRecording() {
453
464
  return g_avIsRecording;
454
465
  }
466
+
467
+ extern "C" NSString* getAVFoundationAudioPath() {
468
+ return g_avAudioOutputPath;
469
+ }
@@ -11,16 +11,18 @@
11
11
 
12
12
  // AVFoundation fallback declarations
13
13
  extern "C" {
14
- bool startAVFoundationRecording(const std::string& outputPath,
14
+ bool startAVFoundationRecording(const std::string& outputPath,
15
15
  CGDirectDisplayID displayID,
16
16
  uint32_t windowID,
17
17
  CGRect captureRect,
18
18
  bool captureCursor,
19
- bool includeMicrophone,
19
+ bool includeMicrophone,
20
20
  bool includeSystemAudio,
21
- NSString* audioDeviceId);
21
+ NSString* audioDeviceId,
22
+ NSString* audioOutputPath);
22
23
  bool stopAVFoundationRecording();
23
24
  bool isAVFoundationRecording();
25
+ NSString* getAVFoundationAudioPath();
24
26
 
25
27
  NSArray<NSDictionary *> *listCameraDevices();
26
28
  bool startCameraRecording(NSString *outputPath, NSString *deviceId, NSError **error);
@@ -196,7 +198,7 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
196
198
 
197
199
  if (info.Length() > 1 && info[1].IsObject()) {
198
200
  Napi::Object options = info[1].As<Napi::Object>();
199
-
201
+
200
202
  // Capture area
201
203
  if (options.Has("captureArea") && options.Get("captureArea").IsObject()) {
202
204
  Napi::Object rectObj = options.Get("captureArea").As<Napi::Object>();
@@ -217,15 +219,15 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
217
219
 
218
220
  // Microphone
219
221
  if (options.Has("includeMicrophone")) {
220
- includeMicrophone = options.Get("includeMicrophone").As<Napi::Boolean>();
222
+ includeMicrophone = options.Get("includeMicrophone").As<Napi::Boolean>().Value();
221
223
  }
222
-
224
+
223
225
  // Audio device ID
224
226
  if (options.Has("audioDeviceId") && !options.Get("audioDeviceId").IsNull()) {
225
227
  std::string deviceId = options.Get("audioDeviceId").As<Napi::String>().Utf8Value();
226
228
  audioDeviceId = [NSString stringWithUTF8String:deviceId.c_str()];
227
229
  }
228
-
230
+
229
231
  // System audio
230
232
  if (options.Has("includeSystemAudio")) {
231
233
  includeSystemAudio = options.Get("includeSystemAudio").As<Napi::Boolean>();
@@ -349,9 +351,7 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
349
351
  BOOL forceAVFoundation = YES;
350
352
 
351
353
  MRLog(@"🔧 CRITICAL: ScreenCaptureKit disabled globally (segfault issue)");
352
- MRLog(@" Using AVFoundation for stability");
353
- MRLog(@" ⚠️ WARNING: Audio capture not available in AVFoundation mode");
354
- MRLog(@" Audio files will be created but will be empty");
354
+ MRLog(@" Using AVFoundation for stability with integrated audio capture");
355
355
 
356
356
  if (isElectron) {
357
357
  MRLog(@"⚡ Electron environment detected - using stable AVFoundation");
@@ -474,20 +474,21 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
474
474
 
475
475
  // AVFoundation recording (either fallback from ScreenCaptureKit or direct)
476
476
  MRLog(@"🎥 Starting AVFoundation recording...");
477
-
477
+
478
478
  @try {
479
479
  // Import AVFoundation recording functions (if available)
480
- extern bool startAVFoundationRecording(const std::string& outputPath,
480
+ extern bool startAVFoundationRecording(const std::string& outputPath,
481
481
  CGDirectDisplayID displayID,
482
482
  uint32_t windowID,
483
483
  CGRect captureRect,
484
484
  bool captureCursor,
485
- bool includeMicrophone,
485
+ bool includeMicrophone,
486
486
  bool includeSystemAudio,
487
- NSString* audioDeviceId);
488
-
489
- bool avResult = startAVFoundationRecording(outputPath, displayID, windowID, captureRect,
490
- captureCursor, includeMicrophone, includeSystemAudio, audioDeviceId);
487
+ NSString* audioDeviceId,
488
+ NSString* audioOutputPath);
489
+
490
+ bool avResult = startAVFoundationRecording(outputPath, displayID, windowID, captureRect,
491
+ captureCursor, includeMicrophone, includeSystemAudio, audioDeviceId, audioOutputPath);
491
492
 
492
493
  if (avResult) {
493
494
  MRLog(@"🎥 RECORDING METHOD: AVFoundation");
@@ -500,16 +501,9 @@ Napi::Value StartRecording(const Napi::CallbackInfo& info) {
500
501
  return Napi::Boolean::New(env, false);
501
502
  }
502
503
 
503
- if (!startAudioIfRequested(captureAnyAudio, audioOutputPath, preferredAudioDeviceId)) {
504
- MRLog(@"❌ Audio start failed - stopping AVFoundation session");
505
- if (captureCamera) {
506
- stopCameraRecording();
507
- }
508
- stopAVFoundationRecording();
509
- g_isRecording = false;
510
- return Napi::Boolean::New(env, false);
511
- }
512
-
504
+ // NOTE: Audio is handled internally by AVFoundation, no need for standalone audio
505
+ // AVFoundation integrates audio recording directly
506
+
513
507
  g_isRecording = true;
514
508
  return Napi::Boolean::New(env, true);
515
509
  } else {
@@ -554,6 +548,7 @@ Napi::Value StopRecording(const Napi::CallbackInfo& info) {
554
548
  // Try AVFoundation fallback (supports both Node.js and Electron)
555
549
  extern bool isAVFoundationRecording();
556
550
  extern bool stopAVFoundationRecording();
551
+ extern NSString* getAVFoundationAudioPath();
557
552
 
558
553
  @try {
559
554
  if (isAVFoundationRecording()) {
@@ -867,6 +862,9 @@ Napi::Value GetAudioRecordingPath(const Napi::CallbackInfo& info) {
867
862
  if (!path || [path length] == 0) {
868
863
  path = currentStandaloneAudioRecordingPath();
869
864
  }
865
+ if (!path || [path length] == 0) {
866
+ path = getAVFoundationAudioPath();
867
+ }
870
868
  if (!path || [path length] == 0) {
871
869
  return env.Null();
872
870
  }