Bug 1331648 - detect device connection for the case /dev/v4l hasn't existed; r=jesup

MozReview-Commit-ID: 1erqrFScjr

--HG--
extra : rebase_source : ad4a4adde64f479a84a3f7fa093f71eef319436b
This commit is contained in:
Munro Mengjue Chiang 2017-01-25 14:52:19 +08:00
Родитель 0f5f625a1a
Коммит a50658a789
2 изменённых файлов: 81 добавлений и 35 удалений

Просмотреть файл

@ -52,30 +52,57 @@ VideoCaptureImpl::CreateDeviceInfo(const int32_t id)
} }
#ifdef WEBRTC_LINUX #ifdef WEBRTC_LINUX
void DeviceInfoLinux::HandleEvent(inotify_event* event) void DeviceInfoLinux::HandleEvent(inotify_event* event, int fd)
{ {
switch (event->mask) { if (event->mask & IN_CREATE) {
case IN_CREATE: if (fd == _fd_v4l || fd == _fd_snd) {
DeviceChange(); DeviceChange();
break; } else if ((event->mask & IN_ISDIR) && (fd == _fd_dev)) {
case IN_DELETE: if (_wd_v4l < 0) {
DeviceChange(); // Sometimes inotify_add_watch failed if we call it immediately after receiving this event
break; // Adding 5ms delay to let file system settle down
default: usleep(5*1000);
char* cur_event_filename = NULL; _wd_v4l = inotify_add_watch(_fd_v4l, "/dev/v4l/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF);
int cur_event_wd = event->wd; if (_wd_v4l >= 0) {
if (event->len) { DeviceChange();
cur_event_filename = event->name; }
} }
if (_wd_snd < 0) {
usleep(5*1000);
_wd_snd = inotify_add_watch(_fd_snd, "/dev/snd/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF);
if (_wd_snd >= 0) {
DeviceChange();
}
}
}
} else if (event->mask & IN_DELETE) {
if (fd == _fd_v4l || fd == _fd_snd) {
DeviceChange();
}
} else if (event->mask & IN_DELETE_SELF) {
if (fd == _fd_v4l) {
inotify_rm_watch(_fd_v4l, _wd_v4l);
_wd_v4l = -1;
} else if (fd == _fd_snd) {
inotify_rm_watch(_fd_snd, _wd_snd);
_wd_snd = -1;
} else {
assert(false);
}
} else {
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, WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
"UNKNOWN EVENT OCCURRED for file \"%s\" on WD #%i\n", "UNKNOWN EVENT OCCURRED for file \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd); cur_event_filename, cur_event_wd);
break;
} }
} }
int DeviceInfoLinux::EventCheck() int DeviceInfoLinux::EventCheck(int fd)
{ {
struct timeval timeout; struct timeval timeout;
fd_set rfds; fd_set rfds;
@ -84,16 +111,16 @@ int DeviceInfoLinux::EventCheck()
timeout.tv_usec = 100000; timeout.tv_usec = 100000;
FD_ZERO(&rfds); FD_ZERO(&rfds);
FD_SET(_fd, &rfds); FD_SET(fd, &rfds);
return select(_fd+1, &rfds, NULL, NULL, &timeout); return select(fd+1, &rfds, NULL, NULL, &timeout);
} }
int DeviceInfoLinux::HandleEvents() int DeviceInfoLinux::HandleEvents(int fd)
{ {
char buffer[BUF_LEN]; char buffer[BUF_LEN];
ssize_t r = read(_fd, buffer, BUF_LEN); ssize_t r = read(fd, buffer, BUF_LEN);
if (r <= 0) { if (r <= 0) {
return r; return r;
@ -113,7 +140,7 @@ int DeviceInfoLinux::HandleEvents()
memcpy(event, pevent, eventSize); memcpy(event, pevent, eventSize);
HandleEvent((inotify_event*)(event)); HandleEvent((inotify_event*)(event), fd);
buffer_i += eventSize; buffer_i += eventSize;
count++; count++;
@ -125,8 +152,18 @@ int DeviceInfoLinux::HandleEvents()
int DeviceInfoLinux::ProcessInotifyEvents() int DeviceInfoLinux::ProcessInotifyEvents()
{ {
while (0 == _isShutdown.Value()) { while (0 == _isShutdown.Value()) {
if (EventCheck() > 0) { if (EventCheck(_fd_dev) > 0) {
if (HandleEvents() < 0) { if (HandleEvents(_fd_dev) < 0) {
break;
}
}
if (EventCheck(_fd_v4l) > 0) {
if (HandleEvents(_fd_v4l) < 0) {
break;
}
}
if (EventCheck(_fd_snd) > 0) {
if (HandleEvents(_fd_snd) < 0) {
break; break;
} }
} }
@ -141,21 +178,30 @@ bool DeviceInfoLinux::InotifyEventThread(void* obj)
bool DeviceInfoLinux::InotifyProcess() bool DeviceInfoLinux::InotifyProcess()
{ {
_fd = inotify_init(); _fd_v4l = inotify_init();
if (_fd >= 0) { _fd_snd = inotify_init();
_wd_v4l = inotify_add_watch(_fd, "/dev/v4l/by-path/", IN_CREATE | IN_DELETE); _fd_dev = inotify_init();
_wd_snd = inotify_add_watch(_fd, "/dev/snd/by-path/", IN_CREATE | IN_DELETE); if (_fd_v4l >= 0 && _fd_snd >= 0 && _fd_dev >= 0) {
_wd_v4l = inotify_add_watch(_fd_v4l, "/dev/v4l/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF);
_wd_snd = inotify_add_watch(_fd_snd, "/dev/snd/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF);
_wd_dev = inotify_add_watch(_fd_dev, "/dev/", IN_CREATE);
ProcessInotifyEvents(); ProcessInotifyEvents();
if (_wd_v4l >= 0) { if (_wd_v4l >= 0) {
inotify_rm_watch(_fd, _wd_v4l); inotify_rm_watch(_fd_v4l, _wd_v4l);
} }
if (_wd_snd >= 0) { if (_wd_snd >= 0) {
inotify_rm_watch(_fd, _wd_snd); inotify_rm_watch(_fd_snd, _wd_snd);
} }
close(_fd); if (_wd_dev >= 0) {
inotify_rm_watch(_fd_dev, _wd_dev);
}
close(_fd_v4l);
close(_fd_snd);
close(_fd_dev);
return true; return true;
} else { } else {
return false; return false;

Просмотреть файл

@ -55,14 +55,14 @@ private:
bool IsDeviceNameMatches(const char* name, const char* deviceUniqueIdUTF8); bool IsDeviceNameMatches(const char* name, const char* deviceUniqueIdUTF8);
#ifdef WEBRTC_LINUX #ifdef WEBRTC_LINUX
void HandleEvent(inotify_event* event); void HandleEvent(inotify_event* event, int fd);
int EventCheck(); int EventCheck(int fd);
int HandleEvents(); int HandleEvents(int fd);
int ProcessInotifyEvents(); int ProcessInotifyEvents();
rtc::scoped_ptr<rtc::PlatformThread> _inotifyEventThread; rtc::scoped_ptr<rtc::PlatformThread> _inotifyEventThread;
static bool InotifyEventThread(void*); static bool InotifyEventThread(void*);
bool InotifyProcess(); bool InotifyProcess();
int _fd, _wd_v4l, _wd_snd; /* accessed on InotifyEventThread thread */ int _fd_v4l, _fd_snd, _fd_dev, _wd_v4l, _wd_snd, _wd_dev; /* accessed on InotifyEventThread thread */
Atomic32 _isShutdown; Atomic32 _isShutdown;
#endif #endif
}; };