appium-webdriveragent 16.9.3 → 16.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [16.10.0](https://github.com/appium/WebDriverAgent/compare/v16.9.4...v16.10.0) (2026-08-29)
2
+
3
+ ### Features
4
+
5
+ * add displayId in the wda/screen ([#1238](https://github.com/appium/WebDriverAgent/issues/1238)) ([bfbe6b0](https://github.com/appium/WebDriverAgent/commit/bfbe6b00b196647f87267827627a5ff675496c30))
6
+
7
+ ## [16.9.4](https://github.com/appium/WebDriverAgent/compare/v16.9.3...v16.9.4) (2026-08-29)
8
+
9
+ ### Bug Fixes
10
+
11
+ * drop MJPEG frames for clients that stop draining their socket ([#1227](https://github.com/appium/WebDriverAgent/issues/1227)) ([00cb6b6](https://github.com/appium/WebDriverAgent/commit/00cb6b612a5a1a1d00a386e23de01c4eca811df8))
12
+
1
13
  ## [16.9.3](https://github.com/appium/WebDriverAgent/compare/v16.9.2...v16.9.3) (2026-08-29)
2
14
 
3
15
  ### Bug Fixes
@@ -174,6 +174,7 @@
174
174
  @"statusBarSize": @{@"width": @(statusBarSize.width),
175
175
  @"height": @(statusBarSize.height),
176
176
  },
177
+ @"displayId": @([FBScreen displayID]),
177
178
  @"scale": @([FBScreen scale]),
178
179
  });
179
180
  }
@@ -15,11 +15,11 @@
15
15
  <key>CFBundlePackageType</key>
16
16
  <string>FMWK</string>
17
17
  <key>CFBundleShortVersionString</key>
18
- <string>16.9.3</string>
18
+ <string>16.10.0</string>
19
19
  <key>CFBundleSignature</key>
20
20
  <string>????</string>
21
21
  <key>CFBundleVersion</key>
22
- <string>16.9.3</string>
22
+ <string>16.10.0</string>
23
23
  <key>NSPrincipalClass</key>
24
24
  <string/>
25
25
  </dict>
@@ -22,6 +22,9 @@
22
22
 
23
23
  static const NSUInteger MAX_FPS = 60;
24
24
  static const NSTimeInterval FRAME_TIMEOUT = 1.;
25
+ // nw_connection_send buffers without backpressure, so a client that stops reading would retain
26
+ // every generated frame. Frames past this cap are dropped instead of queued.
27
+ static const NSUInteger MAX_PENDING_FRAMES_PER_CLIENT = 4;
25
28
  static const NSTimeInterval FAILURE_BACKOFF_MIN = 1.0;
26
29
  static const NSTimeInterval FAILURE_BACKOFF_MAX = 10.0;
27
30
 
@@ -44,6 +47,9 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
44
47
  @property (atomic, assign) BOOL isStreaming;
45
48
  @property (nonatomic, assign) NSUInteger sentFramesCount;
46
49
  @property (nonatomic, assign) NSUInteger sentBytesCount;
50
+ @property (nonatomic, assign) NSUInteger droppedFramesCount;
51
+ // Frames submitted but not sent yet, per client. Guarded by @synchronized (self.listeningClients).
52
+ @property (nonatomic, readonly) NSMapTable<id, NSNumber *> *pendingFrameCounts;
47
53
 
48
54
  @end
49
55
 
@@ -58,6 +64,8 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
58
64
  _sentFramesCount = 0;
59
65
  _sentBytesCount = 0;
60
66
  _listeningClients = [NSMutableArray array];
67
+ _pendingFrameCounts = [NSMapTable mapTableWithKeyOptions:(NSPointerFunctionsOptions)(NSMapTableObjectPointerPersonality | NSMapTableStrongMemory)
68
+ valueOptions:(NSPointerFunctionsOptions)NSMapTableStrongMemory];
61
69
  _imageProcessor = [[FBImageProcessor alloc] init];
62
70
  _mainScreenID = [XCUIScreen.mainScreen displayID];
63
71
  dispatch_queue_attr_t queueAttributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
@@ -149,17 +157,38 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
149
157
  return;
150
158
  }
151
159
  NSUInteger clientCount = self.listeningClients.count;
160
+ __weak typeof(self) weakSelf = self;
152
161
  for (nw_connection_t client in self.listeningClients) {
153
- [self.socket writeData:chunk toClient:client];
162
+ NSUInteger pendingFrames = [self.pendingFrameCounts objectForKey:client].unsignedIntegerValue;
163
+ if (pendingFrames >= MAX_PENDING_FRAMES_PER_CLIENT) {
164
+ self.droppedFramesCount++;
165
+ continue;
166
+ }
167
+ [self.pendingFrameCounts setObject:@(pendingFrames + 1) forKey:client];
168
+ [self.socket writeData:chunk toClient:client completion:^{
169
+ __strong typeof(weakSelf) strongSelf = weakSelf;
170
+ if (nil == strongSelf) {
171
+ return;
172
+ }
173
+ @synchronized (strongSelf.listeningClients) {
174
+ NSUInteger stillPending = [strongSelf.pendingFrameCounts objectForKey:client].unsignedIntegerValue;
175
+ if (stillPending > 1) {
176
+ [strongSelf.pendingFrameCounts setObject:@(stillPending - 1) forKey:client];
177
+ } else {
178
+ [strongSelf.pendingFrameCounts removeObjectForKey:client];
179
+ }
180
+ }
181
+ }];
154
182
  }
155
183
  self.sentFramesCount++;
156
184
  self.sentBytesCount += chunk.length * clientCount;
157
185
  NSUInteger framerate = FBNormalizedMjpegFramerate(FBConfiguration.sharedInstance.mjpegServerFramerate);
158
186
  if (0 == self.sentFramesCount % framerate) {
159
- [FBLogger verboseLog:[NSString stringWithFormat:@"MJPEG stats: clients=%@ sentFrames=%@ sentBytes=%@",
187
+ [FBLogger verboseLog:[NSString stringWithFormat:@"MJPEG stats: clients=%@ sentFrames=%@ sentBytes=%@ droppedFrames=%@",
160
188
  @(clientCount),
161
189
  @(self.sentFramesCount),
162
- @(self.sentBytesCount)]];
190
+ @(self.sentBytesCount),
191
+ @(self.droppedFramesCount)]];
163
192
  }
164
193
  }
165
194
  }
@@ -190,6 +219,7 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
190
219
  {
191
220
  @synchronized (self.listeningClients) {
192
221
  [self.listeningClients removeObject:client];
222
+ [self.pendingFrameCounts removeObjectForKey:client];
193
223
  }
194
224
  [FBLogger log:@"Disconnected a client from screenshots broadcast"];
195
225
  }
@@ -200,6 +230,7 @@ static NSUInteger FBNormalizedMjpegFramerate(NSUInteger framerate)
200
230
  @synchronized (self.listeningClients) {
201
231
  NSArray<nw_connection_t> *clients = self.listeningClients.copy;
202
232
  [self.listeningClients removeAllObjects];
233
+ [self.pendingFrameCounts removeAllObjects];
203
234
  for (nw_connection_t client in clients) {
204
235
  nw_connection_cancel(client);
205
236
  }
@@ -12,6 +12,11 @@ NS_ASSUME_NONNULL_BEGIN
12
12
 
13
13
  @interface FBScreen : NSObject
14
14
 
15
+ /**
16
+ The identifier of the main device's display
17
+ */
18
+ + (long long)displayID;
19
+
15
20
  /**
16
21
  The scale factor of the main device's screen
17
22
  */
@@ -13,6 +13,11 @@
13
13
 
14
14
  @implementation FBScreen
15
15
 
16
+ + (long long)displayID
17
+ {
18
+ return XCUIScreen.mainScreen.displayID;
19
+ }
20
+
16
21
  + (double)scale
17
22
  {
18
23
  return [XCUIScreen.mainScreen scale];
@@ -22,10 +22,14 @@
22
22
  [self launchApplication];
23
23
  }
24
24
 
25
+ - (void)testDisplayID
26
+ {
27
+ XCTAssertGreaterThanOrEqual([FBScreen displayID], 0LL);
28
+ }
29
+
25
30
  - (void)testScreenScale
26
31
  {
27
32
  XCTAssertTrue([FBScreen scale] >= 2);
28
33
  }
29
34
 
30
35
  @end
31
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-webdriveragent",
3
- "version": "16.9.3",
3
+ "version": "16.10.0",
4
4
  "description": "Package bundling WebDriverAgent",
5
5
  "keywords": [
6
6
  "Appium",