20

I want to automate a personal workflow that is based on camera usage on my MBP.

Basically I want to know if any of the cameras (built-in or USB) has been turned on or off, so I can run a program or script I'll create.

I think it's OK if I need to poll for the cameras statuses but an event or callback based solution would be ideal

sergiopereira
  • 2,026
  • 2
  • 23
  • 31
  • 7
    I would like to do the same thing so I can connect it to an "On Air" indicator, letting my family know when I'm on a Zoom / Teams call. – Patrick McElhaney Nov 23 '20 at 22:03
  • @PatrickMcElhaney Great idea! – Luca Angioloni Nov 29 '20 at 20:55
  • @PatrickMcElhaney do you have larger snippets of sample code how you monitored the log steam? Your use case is identical to mine. – jonalmeida Dec 10 '20 at 04:23
  • 1
    @jonalmeida I haven’t written any code yet. My answer is a command entered in Terminal and the output. The next challenge is finding a device that I can use for the “On Air” light and control with my computer. Doesn’t have to be anything fancy, I just don’t have experience with that kind of stuff. Once that’s solved, I’ll have no problem connecting the “glue” that connects the log output to the device. – Patrick McElhaney Dec 10 '20 at 12:17
  • @PatrickMcElhaney I have that part setup with an LED strip connected to home-assistant. With the command below though, I'm not sure how multiple on/off states which produce multiple lines of output will work. Cheers. :) – jonalmeida Dec 15 '20 at 17:40
  • @jonalmeida I created a [chat room](https://chat.stackoverflow.com/rooms/225996/diy-on-air-light) so we can discuss next steps. – Patrick McElhaney Dec 15 '20 at 17:48

4 Answers4

15

This seems to work.

❯  log stream | grep "Post event kCameraStream"
2020-12-01 14:58:53.137796-0500 0xXXXXXX   Default     0x0                  XXX    0    VDCAssistant: [com.apple.VDCAssistant:device] [guid:0xXXXXXXXXXXXXXXXX] Post event kCameraStreamStart
2020-12-01 14:58:56.431147-0500 0xXXXXXX   Default     0x0                  XXX    0    VDCAssistant: [com.apple.VDCAssistant:device] [guid:0xXXXXXXXXXXXXXXXX] Post event kCameraStreamStop
2020-12-01 14:58:56.668970-0500 0xXXXXXX   Default     0x0                  XXX    0    VDCAssistant: [com.apple.VDCAssistant:device] [guid:0xXXXXXXXXXXXXXXXX] Post event kCameraStreamStart

Some of the numbers in the output are redacted with Xs because I don't know what they mean. :)

Patrick McElhaney
  • 57,901
  • 40
  • 134
  • 167
  • 3
    This works on my machine too. Good job! If you develop something cool with it let me know! – Luca Angioloni Dec 01 '20 at 21:22
  • 1
    This works great! You can catch KCameraStreamStart and KCameraStreamStop. One hickup, on older hardware the log seems to be different. On my 2013 MBP, the proper log catch would be 'log stream | grep "AppleCameraAssistant: StartHardwareStream"' On my 2018 MBP, it's the KCameraStream* event like Patrick mentioned. This was tested on the exact same version of Catalina. – JP Toto Apr 11 '21 at 14:28
  • 2
    This doesn't seem to work in Monterey, fwiw. – Aaron J Jan 26 '22 at 17:40
9

Big Sur

log stream --predicate 'eventMessage contains "Post event kCameraStream"' only works up to macOS Big Sur

Monterey

On macOS Monterey you'll have to use a slightly different predicate:

$ log stream --predicate 'subsystem contains "com.apple.UVCExtension" and composedMessage contains "Post PowerLog"'

Timestamp                       Thread     Type        Activity             PID    TTL  
2021-10-27 12:21:13.366628+0200 0x147c5    Default     0x0                  353    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:device] UVCExtensionDevice:0x1234005d7 [0x7fe3ce008ca0] Post PowerLog {
    "VDCAssistant_Device_GUID" = "00000000-1432-0000-1234-000022470000";
    "VDCAssistant_Power_State" = On;
}
2021-10-27 12:21:16.946379+0200 0x13dac    Default     0x0                  353    0    UVCAssistant: (UVCExtension) [com.apple.UVCExtension:device] UVCExtensionDevice:0x1234005d7 [0x7fe3ce008ca0] Post PowerLog {
    "VDCAssistant_Device_GUID" = "00000000-1432-0000-1234-000022470000";
    "VDCAssistant_Power_State" = Off;
}

Ventura

Here you can use log stream --predicate 'eventMessage contains "Cameras changed to"', which even gives you a list of active cameras:

Timestamp                       Thread     Type        Activity             PID    TTL  
2023-03-20 14:07:56.340362+0100 0x21ee     Default     0x0                  1144   0    ControlCenter: [com.apple.controlcenter:video-effects] Cameras changed to [ControlCenterApp.VideoCamera(id: "FOO-0176-46F7-B185-BAR", name: "FaceTime HD-kamera", utType: Optional(<UTType 0xFOO1c41BAR> com.apple.macbookpro-16-2023 (not dynamic, declared)), batteryInfo: nil, deskViewID: nil, supportedEffects: [portrait], appEffects: [ControlCenterApp.AppVideoEffects(bundleIDs: Set(["com.apple.PhotoBooth"]), bundleNames: ["com.apple.PhotoBooth": "Photo Booth"], enabledEffects: Set([]), unavailableEffects: Set([]))])]
2023-03-20 14:08:09.114873+0100 0x21ee     Default     0x0                  1144   0    ControlCenter: [com.apple.controlcenter:video-effects] Cameras changed to []
neu242
  • 15,796
  • 20
  • 79
  • 114
  • This works great on Monterey, thanks! I'm using a USB camera and this immediately detected on/off changes. – Aaron J Jan 26 '22 at 17:44
  • I have a 2019 (intel) macbook pro with Ventura installed, and the "Monterey" answer worked for me. – Dudo Mar 27 '23 at 23:44
3

In macOS Ventura I find this incantation works:

log stream --predicate 'sender contains "appleh13camerad" and (composedMessage contains "PowerOnCamera" or composedMessage contains "PowerOffCamera")'
  • This works too, and gives you a list of active cameras: `log stream --predicate 'eventMessage contains "Cameras changed to"'` – neu242 Mar 20 '23 at 13:08
1

As far as I know, you can poll for the camera usage with:

$ lsof -n | grep "AppleCamera"

or change "AppleCamera" with the driver name of an external camera. Other relevant names to try are: "USBVDC" or "VDCAssistant" or "FaceTime" (or "iSight" in older Macs).

You should get one line with the name and pid of the process using the webcam or nothing, which means that it is not in use.

You could check for all of the keywords and decide that the camera is in use if any of these keywords give you something back.

The -n option is to skip resolving DNS names of IP connections and this speeds the command a lot.

As a side note, I use this app to know when any app is using the microphone and/or webcam: OverSight

Luca Angioloni
  • 2,243
  • 2
  • 19
  • 28
  • When I run that command I get no results. It's a 2019 16-inch MBP. Photo Booth is using the camera and the LED is on. Even if that did work, it takes > 10 seconds for the command to run, which is too much lag for what I'm trying to do. I've tried watching the log file of OverSight as well. It seems to be hit and miss. – Patrick McElhaney Nov 30 '20 at 21:08
  • @PatrickMcElhaney I admit I didn't test it thoroughly. I tried with Zoom on my computer and it worked. Further testing and google researches show that the camera usage could be detected also with "USBVDC" or "VDCAssistant" or "FaceTime" (or "iSight" in older Macs). You could have an OR condition with this names. The speed issue can be solved passing the -n parameter. I will update my answer. – Luca Angioloni Nov 30 '20 at 21:44