From c86b6515ad902c48bd8cde4779ae75521dee8772 Mon Sep 17 00:00:00 2001 From: Munro Chiang Date: Thu, 1 Sep 2016 11:06:49 +0800 Subject: [PATCH] Bug 1297337 - implement mediaDevices.ondevicechange for Linux; r=jesup MozReview-Commit-ID: 6cEq7xVUkhf --HG-- extra : rebase_source : ee71fea0aa49452bcd403678b3c22c3fe3dd297c --- dom/media/tests/mochitest/mochitest.ini | 2 +- .../video_capture/linux/device_info_linux.cc | 127 ++++++++++++++++++ .../video_capture/linux/device_info_linux.h | 13 ++ 3 files changed, 141 insertions(+), 1 deletion(-) diff --git a/dom/media/tests/mochitest/mochitest.ini b/dom/media/tests/mochitest/mochitest.ini index aa564f425e1c..30a27935b0eb 100644 --- a/dom/media/tests/mochitest/mochitest.ini +++ b/dom/media/tests/mochitest/mochitest.ini @@ -41,7 +41,7 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be to [test_enumerateDevices.html] skip-if = buildapp == 'mulet' [test_ondevicechange.html] -skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == 'linux' || os == 'win' || os == 'android' +skip-if = toolkit == 'gonk' || buildapp == 'mulet' || os == 'win' || os == 'android' [test_getUserMedia_audioCapture.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g emulator seems to be too slow (Bug 1016498 and 1008080), android(Bug 1189784, timeouts on 4.3 emulator) [test_getUserMedia_addTrackRemoveTrack.html] diff --git a/media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.cc b/media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.cc index 6c9295a1c9f2..b3957706d896 100644 --- a/media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.cc +++ b/media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.cc @@ -29,6 +29,8 @@ #include "webrtc/system_wrappers/interface/ref_count.h" #include "webrtc/system_wrappers/interface/trace.h" +#define EVENT_SIZE ( sizeof (struct inotify_event) ) +#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) namespace webrtc { @@ -47,9 +49,128 @@ VideoCaptureImpl::CreateDeviceInfo(const int32_t id) return deviceInfo; } +void DeviceInfoLinux::HandleEvent(inotify_event* event) +{ + switch (event->mask) { + case IN_CREATE: + DeviceChange(); + break; + case IN_DELETE: + DeviceChange(); + break; + default: + char* cur_event_filename = NULL; + int cur_event_wd = event->wd; + if (event->len) { + cur_event_filename = event->name; + } + + WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, + "UNKNOWN EVENT OCCURRED for file \"%s\" on WD #%i\n", + cur_event_filename, cur_event_wd); + break; + } +} + +int DeviceInfoLinux::EventCheck() +{ + struct timeval timeout; + fd_set rfds; + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + FD_ZERO(&rfds); + FD_SET(_fd, &rfds); + + return select(_fd+1, &rfds, NULL, NULL, &timeout); +} + +int DeviceInfoLinux::HandleEvents() +{ + char buffer[BUF_LEN]; + + ssize_t r = read(_fd, buffer, BUF_LEN); + + if (r <= 0) { + return r; + } + + ssize_t buffer_i = 0; + inotify_event* pevent; + size_t eventSize; + int count = 0; + + while (buffer_i < r) + { + pevent = (inotify_event *) (&buffer[buffer_i]); + eventSize = sizeof(inotify_event) + pevent->len; + char event[sizeof(inotify_event) + FILENAME_MAX + 1] // null-terminated + __attribute__ ((aligned(__alignof__(struct inotify_event)))); + + memcpy(event, pevent, eventSize); + + HandleEvent((inotify_event*)(event)); + + buffer_i += eventSize; + count++; + } + + return count; +} + +int DeviceInfoLinux::ProcessInotifyEvents() +{ + while (0 == _isShutdown.Value()) { + if (EventCheck() > 0) { + if (HandleEvents() < 0) { + break; + } + } + } + return 0; +} + +bool DeviceInfoLinux::InotifyEventThread(void* obj) +{ + return static_cast (obj)->InotifyProcess(); +} + +bool DeviceInfoLinux::InotifyProcess() +{ + _fd = inotify_init(); + if (_fd >= 0) { + _wd_v4l = inotify_add_watch(_fd, "/dev/v4l/by-path/", IN_CREATE | IN_DELETE); + _wd_snd = inotify_add_watch(_fd, "/dev/snd/by-path/", IN_CREATE | IN_DELETE); + ProcessInotifyEvents(); + + if (_wd_v4l >= 0) { + inotify_rm_watch(_fd, _wd_v4l); + } + + if (_wd_snd >= 0) { + inotify_rm_watch(_fd, _wd_snd); + } + + close(_fd); + return true; + } else { + return false; + } +} + DeviceInfoLinux::DeviceInfoLinux(const int32_t id) : DeviceInfoImpl(id) + , _isShutdown(0) { + _inotifyEventThread = ThreadWrapper::CreateThread( + InotifyEventThread, this, "InotifyEventThread"); + + if (_inotifyEventThread) + { + _inotifyEventThread->Start(); + _inotifyEventThread->SetPriority(kHighPriority); + } } int32_t DeviceInfoLinux::Init() @@ -59,6 +180,12 @@ int32_t DeviceInfoLinux::Init() DeviceInfoLinux::~DeviceInfoLinux() { + ++_isShutdown; + + if (_inotifyEventThread) { + _inotifyEventThread->Stop(); + _inotifyEventThread.reset(); + } } uint32_t DeviceInfoLinux::NumberOfDevices() diff --git a/media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.h b/media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.h index cffb22256ce2..9261a17f81bd 100644 --- a/media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.h +++ b/media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.h @@ -13,6 +13,9 @@ #include "webrtc/modules/video_capture/device_info_impl.h" #include "webrtc/modules/video_capture/video_capture_impl.h" +#include "webrtc/system_wrappers/interface/thread_wrapper.h" +#include "webrtc/system_wrappers/interface/atomic32.h" +#include namespace webrtc { @@ -47,6 +50,16 @@ public: private: bool IsDeviceNameMatches(const char* name, const char* deviceUniqueIdUTF8); + + void HandleEvent(inotify_event* event); + int EventCheck(); + int HandleEvents(); + int ProcessInotifyEvents(); + rtc::scoped_ptr _inotifyEventThread; + static bool InotifyEventThread(void*); + bool InotifyProcess(); + int _fd, _wd_v4l, _wd_snd; /* accessed on InotifyEventThread thread */ + Atomic32 _isShutdown; }; } // namespace videocapturemodule } // namespace webrtc