[email protected] | deb232b | 2022-11-28 11:22:16 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
dpapad | 303c9281 | 2023-10-31 02:08:35 | [diff] [blame] | 5 | import {$} from 'chrome://resources/js/util.js'; |
[email protected] | deb232b | 2022-11-28 11:22:16 | [diff] [blame] | 6 | const USER_MEDIA_TAB_ID = 'user-media-tab-id'; |
| 7 | |
| 8 | /** |
| 9 | * A helper function for appending a child element to |parent|. |
| 10 | * |
| 11 | * @param {!Element} parent The parent element. |
| 12 | * @param {string} tag The child element tag. |
| 13 | * @param {string} text The textContent of the new DIV. |
| 14 | * @return {!Element} the new DIV element. |
| 15 | */ |
| 16 | function appendChildWithText(parent, tag, text) { |
| 17 | const child = document.createElement(tag); |
| 18 | child.textContent = text; |
| 19 | parent.appendChild(child); |
| 20 | return child; |
| 21 | } |
| 22 | |
| 23 | export class UserMediaTable { |
| 24 | /** |
| 25 | * @param {Object} tabView the TabView object to add the user media tab to. |
| 26 | */ |
| 27 | constructor(tabView) { |
| 28 | this.tabView = tabView; |
| 29 | } |
| 30 | |
| 31 | /** |
| 32 | * Populate the tab view with a getUserMedia/getDisplayMedia tab. |
| 33 | */ |
| 34 | createTab() { |
| 35 | const container = this.tabView.addTab(USER_MEDIA_TAB_ID, |
Philipp Hancke | 94429ac0 | 2023-03-03 16:03:21 | [diff] [blame] | 36 | 'getUserMedia/getDisplayMedia'); |
[email protected] | deb232b | 2022-11-28 11:22:16 | [diff] [blame] | 37 | // Create the filter input field and label. |
| 38 | appendChildWithText(container, 'label', 'Filter by origin including '); |
| 39 | const input = document.createElement('input'); |
| 40 | input.size = 30; |
| 41 | input.oninput = this.filterUserMedia.bind(this); |
| 42 | container.appendChild(input); |
| 43 | } |
| 44 | |
| 45 | /** |
| 46 | * Apply a filter to the user media table. |
| 47 | * @param event InputEvent from the filter input field. |
| 48 | * @private |
| 49 | */ |
| 50 | filterUserMedia(event) { |
| 51 | const filter = event.target.value; |
| 52 | const requests = $(USER_MEDIA_TAB_ID).childNodes; |
| 53 | for (let i = 0; i < requests.length; ++i) { |
| 54 | if (!requests[i]['data-origin']) { |
| 55 | continue; |
| 56 | } |
| 57 | if (requests[i]['data-origin'].includes(filter)) { |
| 58 | requests[i].style.display = 'block'; |
| 59 | } else { |
| 60 | requests[i].style.display = 'none'; |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | /** |
| 66 | * Adds a getUserMedia/getDisplayMedia request. |
| 67 | * @param {!Object} data The object containing rid {number}, pid {number}, |
| 68 | * origin {string}, request_id {number}, request_type {string}, |
| 69 | * audio {string}, video {string}. |
| 70 | */ |
| 71 | addMedia(data) { |
| 72 | if (!$(USER_MEDIA_TAB_ID)) { |
| 73 | this.createTab(); |
| 74 | } |
| 75 | |
| 76 | const requestDiv = document.createElement('div'); |
| 77 | requestDiv.className = 'user-media-request-div-class'; |
| 78 | requestDiv.id = ['gum', data.rid, data.pid, data.request_id].join('-'); |
| 79 | requestDiv['data-rid'] = data.rid; |
| 80 | requestDiv['data-origin'] = data.origin; |
Philipp Hancke | 6f8193b3 | 2023-09-19 08:05:37 | [diff] [blame] | 81 | // Insert new getUserMedia calls at the top. |
| 82 | $(USER_MEDIA_TAB_ID).insertBefore(requestDiv, |
| 83 | $(USER_MEDIA_TAB_ID).firstChild); |
[email protected] | deb232b | 2022-11-28 11:22:16 | [diff] [blame] | 84 | |
| 85 | appendChildWithText(requestDiv, 'div', 'Caller origin: ' + data.origin); |
| 86 | appendChildWithText(requestDiv, 'div', 'Caller process id: ' + data.pid); |
| 87 | |
| 88 | const el = appendChildWithText(requestDiv, 'span', |
| 89 | data.request_type + ' call'); |
| 90 | el.style.fontWeight = 'bold'; |
| 91 | appendChildWithText(el, 'div', 'Time: ' + |
| 92 | (new Date(data.timestamp).toTimeString())) |
| 93 | .style.fontWeight = 'normal'; |
| 94 | if (data.audio !== undefined) { |
| 95 | appendChildWithText(el, 'div', 'Audio constraints: ' + |
| 96 | (data.audio || 'true')) |
| 97 | .style.fontWeight = 'normal'; |
| 98 | } |
| 99 | if (data.video !== undefined) { |
| 100 | appendChildWithText(el, 'div', 'Video constraints: ' + |
| 101 | (data.video || 'true')) |
| 102 | .style.fontWeight = 'normal'; |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /** |
| 107 | * Update a getUserMedia/getDisplayMedia request with a result or error. |
| 108 | * |
| 109 | * @param {!Object} data The object containing rid {number}, pid {number}, |
| 110 | * request_id {number}, request_type {string}. |
| 111 | * For results there is also the |
| 112 | * stream_id {string}, audio_track_info {string} and |
| 113 | * video_track_info {string}. |
| 114 | * For errors the error {string} and |
| 115 | * error_message {string} fields are set. |
| 116 | */ |
| 117 | updateMedia(data) { |
| 118 | if (!$(USER_MEDIA_TAB_ID)) { |
| 119 | this.createTab(); |
| 120 | } |
| 121 | |
| 122 | const requestDiv = document.getElementById( |
| 123 | ['gum', data.rid, data.pid, data.request_id].join('-')); |
| 124 | if (!requestDiv) { |
| 125 | console.error('Could not update ' + data.request_type + ' request', data); |
| 126 | return; |
| 127 | } |
| 128 | |
| 129 | if (data.error) { |
| 130 | const el = appendChildWithText(requestDiv, 'span', 'Error'); |
| 131 | el.style.fontWeight = 'bold'; |
| 132 | appendChildWithText(el, 'div', 'Time: ' + |
| 133 | (new Date(data.timestamp).toTimeString())) |
| 134 | .style.fontWeight = 'normal'; |
| 135 | appendChildWithText(el, 'div', 'Error: ' + data.error) |
| 136 | .style.fontWeight = 'normal'; |
| 137 | appendChildWithText(el, 'div', 'Error message: ' + data.error_message) |
| 138 | .style.fontWeight = 'normal'; |
| 139 | return; |
| 140 | } |
| 141 | |
| 142 | const el = appendChildWithText(requestDiv, 'span', |
| 143 | data.request_type + ' result'); |
| 144 | el.style.fontWeight = 'bold'; |
| 145 | appendChildWithText(el, 'div', 'Time: ' + |
| 146 | (new Date(data.timestamp).toTimeString())) |
| 147 | .style.fontWeight = 'normal'; |
| 148 | appendChildWithText(el, 'div', 'Stream id: ' + data.stream_id) |
| 149 | .style.fontWeight = 'normal'; |
| 150 | if (data.audio_track_info) { |
| 151 | appendChildWithText(el, 'div', 'Audio track: ' + data.audio_track_info) |
| 152 | .style.fontWeight = 'normal'; |
| 153 | } |
| 154 | if (data.video_track_info) { |
| 155 | appendChildWithText(el, 'div', 'Video track: ' + data.video_track_info) |
| 156 | .style.fontWeight = 'normal'; |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | /** |
| 161 | * Removes the getUserMedia/getDisplayMedia requests from the specified |rid|. |
| 162 | * |
| 163 | * @param {!Object} data The object containing rid {number}, the render id. |
| 164 | */ |
| 165 | removeMediaForRenderer(data) { |
| 166 | const requests = $(USER_MEDIA_TAB_ID).childNodes; |
| 167 | for (let i = 0; i < requests.length; ++i) { |
| 168 | if (!requests[i]['data-origin']) { |
| 169 | continue; |
| 170 | } |
| 171 | if (requests[i]['data-rid'] === data.rid) { |
| 172 | $(USER_MEDIA_TAB_ID).removeChild(requests[i]); |
| 173 | } |
| 174 | } |
| 175 | // Remove the tab when only the search field and its label are left. |
| 176 | if ($(USER_MEDIA_TAB_ID).childNodes.length === 2) { |
| 177 | this.tabView.removeTab(USER_MEDIA_TAB_ID); |
| 178 | } |
| 179 | } |
| 180 | } |