Bug 1297337 - implement mediaDevices.ondevicechange for Linux; r=jesup
authorMunro Chiang <mchiang@mozilla.com>
Thu, 01 Sep 2016 11:06:49 +0800
changeset 314678 18762ffa1e9219b3a114e7f3e00a4127a4209023
parent 314677 efe0f5cfb537c92e2c420b6a4a3f254c4253221e
child 314679 c633db4655979cde4c7b1723a3897e48781a39ef
push id81947
push usercbook@mozilla.com
push dateWed, 21 Sep 2016 10:08:07 +0000
treeherdermozilla-inbound@a1bbdaf0f9ca [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjesup
bugs1297337
milestone52.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1297337 - implement mediaDevices.ondevicechange for Linux; r=jesup MozReview-Commit-ID: 6cEq7xVUkhf
dom/media/tests/mochitest/mochitest.ini
media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.cc
media/webrtc/trunk/webrtc/modules/video_capture/linux/device_info_linux.h
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -36,17 +36,17 @@ skip-if = toolkit == 'gonk' || buildapp 
 [test_dataChannel_basicVideo.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' || android_version == '18' # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator)
 [test_dataChannel_bug1013809.html]
 skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g emulator seems to be too slow (Bug 1016498 and 1008080)
 [test_dataChannel_noOffer.html]
 [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]
 skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure
 [test_getUserMedia_addtrack_removetrack_events.html]
 [test_getUserMedia_basicAudio.html]
 skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure
 [test_getUserMedia_basicVideo.html]
--- 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
@@ -24,16 +24,18 @@
 #include <sys/videodev2.h>
 #else
 #include <linux/videodev2.h>
 #endif
 
 #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
 {
 namespace videocapturemodule
 {
 VideoCaptureModule::DeviceInfo*
 VideoCaptureImpl::CreateDeviceInfo(const int32_t id)
 {
@@ -42,28 +44,153 @@ VideoCaptureImpl::CreateDeviceInfo(const
     if (!deviceInfo)
     {
         deviceInfo = NULL;
     }
 
     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<DeviceInfoLinux*> (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()
 {
     return 0;
 }
 
 DeviceInfoLinux::~DeviceInfoLinux()
 {
+    ++_isShutdown;
+
+    if (_inotifyEventThread) {
+        _inotifyEventThread->Stop();
+        _inotifyEventThread.reset();
+    }
 }
 
 uint32_t DeviceInfoLinux::NumberOfDevices()
 {
     WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCapture, _id, "%s", __FUNCTION__);
 
     uint32_t count = 0;
     char device[20];
--- 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
@@ -8,16 +8,19 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
 #ifndef WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_DEVICE_INFO_LINUX_H_
 #define WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_DEVICE_INFO_LINUX_H_
 
 #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 <sys/inotify.h>
 
 namespace webrtc
 {
 namespace videocapturemodule
 {
 class DeviceInfoLinux: public DeviceInfoImpl
 {
 public:
@@ -42,12 +45,22 @@ public:
         void* /*parentWindow*/,
         uint32_t /*positionX*/,
         uint32_t /*positionY*/) { return -1;}
     int32_t FillCapabilities(int fd);
     int32_t Init();
 private:
 
     bool IsDeviceNameMatches(const char* name, const char* deviceUniqueIdUTF8);
+
+    void HandleEvent(inotify_event* event);
+    int EventCheck();
+    int HandleEvents();
+    int ProcessInotifyEvents();
+    rtc::scoped_ptr<ThreadWrapper> _inotifyEventThread;
+    static bool InotifyEventThread(void*);
+    bool InotifyProcess();
+    int _fd, _wd_v4l, _wd_snd; /* accessed on InotifyEventThread thread */
+    Atomic32 _isShutdown;
 };
 }  // namespace videocapturemodule
 }  // namespace webrtc
 #endif // WEBRTC_MODULES_VIDEO_CAPTURE_MAIN_SOURCE_LINUX_DEVICE_INFO_LINUX_H_