DeadEnded / MotionEyeAudio

Script to add Audio to MotionEye recordings
67 stars 27 forks source link

PiZero & USB Mic... Unable to identify audio input stream (camera ID blank & no netcam information) #4

Open lapsedtheorist opened 4 years ago

lapsedtheorist commented 4 years ago

I've recently installed a fresh MotionEyeOS 20200606 on a Raspberry Pi Zero W, hooked it up to the native Raspberry Pi camera and a basic USB microphone. The motioneye-audio.sh file doesn't cause audio to be captured, so I've done a few investigations helped by my fork of the repo, in which I've added some debug lines for each of the variables. You may wish to take a look here... https://github.com/lapsedtheorist/MotionEyeAudio

My Video Device > Extra Motion Options says on_movie_start /data/etc/motioneye-audio.sh start %t %f '%$', and my File Storage > Run a Command says /data/etc/motioneye-audio.sh stop %t %f '%$'.

The script definitely runs when it should, however the camera_id variable remains empty, so the config file is not found. If I attempt to manually run the command that would populate it (from a root SSH session), I see the following terminal output. Note I've hardcoded the "1" in the example, which is the value that comes through from the command line into the motion_thread_id variable.

# python -c 'import motioneye.motionctl; print motioneye.motionctl.motion_camera_id_to_camera_id(1)'
ERROR:root:failed to list config dir /etc/motioneye: [Errno 2] No such file or directory: '/etc/motioneye'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/motioneye/motionctl.py", line 28, in <module>
  File "/usr/lib/python2.7/site-packages/motioneye/mediafiles.py", line 38, in <module>
  File "/usr/lib/python2.7/site-packages/motioneye/config.py", line 2085, in <module>
  File "/usr/lib/python2.7/site-packages/motioneye/boardctl.py", line 23, in <module>
  File "/usr/lib/python2.7/site-packages/motioneye/streameyectl.py", line 563, in <module>
  File "/usr/lib/python2.7/site-packages/motioneye/streameyectl.py", line 174, in _get_streameye_enabled
  File "/usr/lib/python2.7/site-packages/motioneye/config.py", line 294, in get_camera_ids
OSError: [Errno 2] No such file or directory: '/etc/motioneye'

Does this help?

Also in the config file /data/etc/camera-1.conf there are no lines containing the word 'netcam'... maybe the native Raspberry Pi camera doesn't present itself that way, I'm not sure?

Anecdotally, I'm looking at variants of the audio capture such as arecord as well as ffmpeg -y -i default:CARD=Device ... and have had a little success with the latter however the output is noisy and the CPU is high. I'll keep on with that and will contribute back if I get something working.

DeadEnded commented 4 years ago

hmm... second person with the camera ID issue on motioneyeOS. I don't have a system with this type of install... could you check for the /data/etc/ and /etc/motioneye/ directories and tell me which exist and where the motioneye.conf file is?

The error sounds like your system doesn't have the /etc/motioneye/ directory... which it shouldn't, but I don't know why it would be trying to look there then if it should be looking in /data/etc/. The only other thing I can think of is maybe the /data/etc/ directory is not readable by all users? If the config files are indeed in /data/etc/ can you tell me what the permissions are for them? Maybe the directory security is the problem.... grasping at straws until we know more.

Once we work through the script issues, we can tackle your specific setup... might need some customization for it to work.

Thanks, DeadEnd

lapsedtheorist commented 4 years ago

Here's some filesystem listings that should hopefully help with those questions. I agree it's a bit perplexing!

Everything with a prefix of "motion" in the name or path...

# find /etc /data -iname motion* -exec ls -ld '{}' \;
-rw-r--r--    1 root     root           555 Jun  6 09:54 /etc/motioneye.conf
-rwx------    1 root     root          3112 Aug 11 21:05 /data/etc/motioneye-audio.sh
-rw-rw-rw-    1 root     root           267 Aug  8 12:56 /data/etc/motion.conf
-rw-r--r--    1 root     root           554 Aug  8 12:56 /data/etc/motioneye.conf
-rw-rw-rw-    1 root     root         57291 Aug 12 19:40 /data/log/motion.log
-rw-r--r--    1 root     root         12887 Aug 12 19:30 /data/log/motioneye.log

Permissions of the directories...

# ls -ld {/etc,/data,/data/etc}
drwxr-xr-x   12 root     root          4096 Aug  7 21:52 /data/
drwxr-xr-x    4 root     root          4096 Jan  1  1970 /data/etc/
drwxr-xr-x   18 root     root          3072 Jun  6 15:32 /etc/

Thanks for your time in looking into this, happy to do what I can to try things and assist with diagnostics.

DeadEnded commented 4 years ago

hmm.. for some reason it is thinking your config files should be in /etc/motioneye/ but that is a normal MotionEye install, not MotionEyeOS. By any chance did you copy your /data/etc/motioneye.conf from the internet somewhere? or another installation?

Either way, check your motioneye.conf (/data/etc not /etc) and look for the conf_path line... it should be either:

conf_path /data/etc

OR

conf_path /etc/motioneye

For MotionEyeOS it should be the first option /data/etc so if it has /etc/motioneye that is the problem - although I can't tell you how it happened (copy pasted file?). With that said... I don't know how anything would be working if it was wrong... so that probably isn't the issue... but need to check it to be sure.

Just for educational purpose, the /data/etc/motioneye.conf should be created from the /boot/motioneye.conf file, but if that isn't present falls back to a secondary /etc/motioneye.conf file. So both of these are basically template or example files to generate the first /data/etc/motioneye.conf file. You could check this file as well and see what it has for the conf_path but again, for MotionEyeOS it should be /data/etc.

DeadEnd

lapsedtheorist commented 4 years ago

The MotionEyeOS install is the default, the only changes I've done to the configuration have been done from within the web UI, perhaps the following is useful...

The two motioneye.conf files are basically identical, but they aren't the same file (neither symlinked nor hardlinked)...

# diff /etc/motioneye.conf /data/etc/motioneye.conf 
--- /etc/motioneye.conf
+++ /data/etc/motioneye.conf
@@ -22,4 +22,3 @@
 zip_timeout 500
 add_remove_cameras true
 password_hook /usr/libexec/meyepasswd
-

Both files have the conf_path of /data/etc...

# grep conf_path /etc/motioneye.conf /data/etc/motioneye.conf 
/etc/motioneye.conf:conf_path /data/etc
/data/etc/motioneye.conf:conf_path /data/etc

Maybe there's some difference between running the python command I did in a shell vs it running in the script, I hope I haven't caused a red herring here. There's no motioneye.conf in /boot (and I don't think there was one when I set up the SSH and WiFi settings from /boot).

DeadEnded commented 4 years ago

Hmm... okay... I just took a look at the MotionEyeOS repo... its a completely different setup. So yes, this script I don't think will work for both... but possibly the original design might work on MotionEyeOS .

So try this: Change line 5 to:

camera_id=$2

then, comment out line 9:

camera_id="$(python -c 'import .......blah blah blah.......

See if that works... I only looked quickly at the code, but I think possibly in MotionEyeOS there isn't an issue with Motion ID vs MotionEye ID... so you might be able to just use it directly without the call to the python class... which doesn't seem to even be used in MotionEyeOS.

So give that a go and let me know. If it works, I'll create a second script to differentiate between MotionEye and MotionEyeOS (or if I am feeling really frisky, write the existing script to handle both)!

Cheers! DeadEnd

lapsedtheorist commented 4 years ago

Potentially a silly question: the parameter %t appears to be the "Camera ID number" according to the Motion docs so can this be used directly? It's read into the variable motion_thread_id in the script... I only have 1 camera so am struggling to test, but are you aware of conditions in which the "Camera ID number" will be mismatched against the name of the camera config file?

lapsedtheorist commented 4 years ago

Apologies - it looks like we cross-posted and potentially have come to the same conclusion

DeadEnded commented 4 years ago

Yes, originally this script just used camera_id=$2 which was the %t variable. One day I found my audio channels were being mapped to the wrong cameras! So after a lot of digging, I came to the conclusion that motion's thread ID was mismatched with the motioneye camera ID. Then I did a bunch of digging and found the bit of code where they do the look ups to match them - and that is why I had to add the python call - to get the correct ID.

But it looks like motioneyeOS doesn't have this - so the script fails because it is trying to call something that isn't used. I think the above fixes might get it working for you - and once you confirm I'll decide to either code two paths, or create two files.

cheers! DeadEnd

lapsedtheorist commented 4 years ago

So, yes, that works in that the camera-specific config file is correctly searched.

I still have no audio, but I think that's back to the netcam thing from my first post. Using the debug flags from my script, I have the following in my debug log from the test just now...

2020-08-12T20:37:18+0000
operation=start
camera_id=1
file_path=/data/output/Camera1/2020-08-12/20-37-08.mp4
camera_name=Camera1
motion_config_dir=/data/etc
motion_camera_conf=/data/etc/camera-1.conf
netcam=netcam_url
extension=mp4
credentials=
stream=
ffmpeg -y -i "" -c:a aac /data/output/Camera1/2020-08-12/20-37-08.mp4.aac
2020-08-12T20:38:06+0000
operation=stop
camera_id=1
file_path=/data/output/Camera1/2020-08-12/20-37-08.mp4
camera_name=Camera1
motion_config_dir=/data/etc
motion_camera_conf=/data/etc/camera-1.conf
netcam=netcam_url
extension=mp4
ffmpeg -y -i /data/output/Camera1/2020-08-12/20-37-08.mp4 -i /data/output/Camera1/2020-08-12/20-37-08.mp4.aac -c:v copy -c:a copy /data/output/Camera1/2020-08-12/20-37-08.mp4.temp.mp4;

Potentially the "netcam" stuff is incompatible with the RPi camera wired in locally - happy to have a new thread for that if it helps, just let me know.

Thanks for working on this, it seems like we're getting somewhere!

DeadEnded commented 4 years ago

Yes, I think this is another issue where MotionEyeOS is different from MotionEye... That is leading me to think that a completely different script needs to be written... The one for MotionEye is really based of a single device feeding audio and video, and we just duplicate the existing feed to pull the audio in and hack it back in after recording ends. With MotionEyeOS I think the audio and video are two different feeds already... so I expect this will require a new script specific to MotionEyeOS.

I'll try digging into it and see where I get. If you could, can you share your camera-1.conf and purge any sensitive data? It would be useful to see how it handles audio/video feed... it may have nothing for audio though... might have to figure that out another way...

Thanks! DeadEnd

lapsedtheorist commented 4 years ago

Sure, it's pretty much defaults and I can't see anything sensitive so you can have all of it...

# @webcam_resolution 100
# @upload_subfolders on
# @upload_server 
# @enabled on
# @network_server 
# @upload_username 
# @motion_detection on
# @upload_port 
# @upload_location 
# @preserve_movies 30
# @network_username 
# @upload_movie on
# @id 1
# @webcam_server_resize off
# @upload_password 
# @manual_record off
# @upload_method post
# @upload_picture on
# @working_schedule_type outside
# @network_password 
# @upload_service ftp
# @preserve_pictures 30
# @storage_device custom-path
# @manual_snapshots on
# @network_share_name 
# @upload_enabled off
# @network_smb_ver 1.0
# @working_schedule 
# @clean_cloud_enabled off

threshold_maximum 0
stream_quality 85
threshold 9600
noise_level 31
pre_capture 1
movie_codec mp4:h264_omx
noise_tune on
smart_mask_speed 0
stream_maxrate 5
stream_localhost off
text_changes off
movie_filename %Y-%m-%d/%H-%M-%S
movie_max_time 0
lightswitch_percent 0
movie_passthrough off
auto_brightness off
stream_port 8081
rotate 0
stream_auth_method 0
threshold_tune off
framerate 2
emulate_motion off
movie_output on
picture_quality 85
snapshot_filename 
despeckle_filter 
snapshot_interval 0
minimum_motion_frames 20
stream_motion off
target_dir /data/output/Camera1
movie_output_motion off
post_capture 1
stream_authentication user:
on_picture_save /usr/lib/python2.7/site-packages/motioneye/scripts/relayevent.sh "/data/etc/motioneye.conf" picture_save %t %f; /data/etc/motioneye-audio.sh stop %t %f '%$'
on_movie_end /usr/lib/python2.7/site-packages/motioneye/scripts/relayevent.sh "/data/etc/motioneye.conf" movie_end %t %f; /data/etc/motioneye-audio.sh stop %t %f '%$'
text_left Camera1
picture_output_motion off
picture_filename 
text_scale 1
locate_motion_style redbox
locate_motion_mode off
mmalcam_name vc.ril.camera
movie_quality 75
picture_output off
on_event_end /usr/lib/python2.7/site-packages/motioneye/scripts/relayevent.sh "/data/etc/motioneye.conf" stop %t
text_right %Y-%m-%d\n%T
on_event_start /usr/lib/python2.7/site-packages/motioneye/scripts/relayevent.sh "/data/etc/motioneye.conf" start %t
camera_name Camera1
event_gap 30
height 600
mask_file 
width 800

on_movie_start /data/etc/motioneye-audio.sh start %t %f '%$'

Given the camera in this case is the Raspberry Pi Camera, which has no audio capability, then I think that tells us the streams have to be separate. Obviously, if there's another way of associating the RPi camera with a USB mic so they are treated as the same "device" that's probably a better solution than capturing and merging the streams.

lapsedtheorist commented 4 years ago

Signing off for the evening now, but just to say I've had some success capturing the default device audio with arecord. There's still some interference but it's not nailing the CPU as much so this seems better than ffmpeg by itself for this purpose. The command line was as follows, if you're interested...

arecord -f cd -D "default:CARD=Device" | ffmpeg -i - -c:a aac -y /data/output/Camera1/2020-08-12/21-20-10.mp4.aac

There's definitely scope for further optimisation here (CD quality audio is totally not necessary, but it was simple for now).

Do have a look in my fork for the latest version of the script I'm using, which seems compatible with a vanilla MotionEyeOS, the default RPi camera and a generic USB microphone.