Skip to content

Commit ad79394

Browse files
committed
tvOS: Enable Platform Service extension
This enables PlatformService cobalt extension and adds ‘dev.cobalt.coat.clientloginfo’ which has the same behaviour with C25. Bug: 487879114
1 parent d4ae008 commit ad79394

File tree

7 files changed

+219
-2
lines changed

7 files changed

+219
-2
lines changed

cobalt/shell/browser/shell_platform_delegate_ios.mm

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ @interface ContentShellWindowDelegate : UIViewController <UITextFieldDelegate> {
100100
@property(nonatomic, strong) UIView* contentView;
101101
// Manages tracing and tracing state.
102102
@property(nonatomic, strong) TracingHandler* tracingHandler;
103+
#if BUILDFLAG(IS_IOS_TVOS)
104+
// Used to calculate display refresh rate.
105+
@property(nonatomic, strong) CADisplayLink* displayLink;
106+
#endif
103107

104108
+ (UIColor*)backgroundColorDefault;
105109
+ (UIColor*)backgroundColorTracing;
@@ -183,6 +187,29 @@ - (void)pressesEnded:(NSSet<UIPress*>*)presses
183187
[super pressesEnded:nonMenuPresses withEvent:event];
184188
}
185189
}
190+
191+
- (void)update:(CADisplayLink*)sender {
192+
// Calculate the actual frame rate.
193+
double interval = sender.targetTimestamp - sender.timestamp;
194+
if (interval > 0) {
195+
double lastDisplayRefreshRate = 1.0 / interval;
196+
[SBDGetApplication() updateLastDisplayRefreshRate:lastDisplayRefreshRate];
197+
}
198+
}
199+
200+
- (void)startDisplayLink {
201+
if (!self.displayLink) {
202+
self.displayLink = [CADisplayLink displayLinkWithTarget:self
203+
selector:@selector(update:)];
204+
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop]
205+
forMode:NSRunLoopCommonModes];
206+
}
207+
}
208+
209+
- (void)stopDisplayLink {
210+
[self.displayLink invalidate];
211+
self.displayLink = nil;
212+
}
186213
#endif // BUILDFLAG(IS_IOS_TVOS)
187214

188215
- (void)viewDidLoad {
@@ -286,8 +313,19 @@ - (void)viewDidLoad {
286313
// Once the splash screen web contents are created, the corresponding UIView
287314
// will be added to `_contentView`.
288315
_shell->LoadSplashScreenWebContents();
316+
317+
#if BUILDFLAG(IS_IOS_TVOS)
318+
[self startDisplayLink];
319+
#endif
289320
}
290321

322+
#if BUILDFLAG(IS_IOS_TVOS)
323+
- (void)viewWillDisappear:(BOOL)animated {
324+
[super viewWillDisappear:animated];
325+
[self stopDisplayLink];
326+
}
327+
#endif
328+
291329
- (id)initWithShell:(content::Shell*)shell {
292330
if ((self = [super init])) {
293331
_shell = shell;

starboard/tvos/shared/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ static_library("starboard_platform") {
134134
"media_is_video_supported.mm",
135135
"observer_registry.cc",
136136
"observer_registry.h",
137+
"platform_service.h",
138+
"platform_service.mm",
137139
"run_in_background_thread_and_wait.cc",
138140
"run_in_background_thread_and_wait.h",
139141
"starboard_application.h",

starboard/tvos/shared/application_darwin.mm

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,36 @@ @implementation ObjCApplication {
4949
// Used for checking that certain methods are invoked from the UI thread (so
5050
// that UIKit calls can be made directly, for example).
5151
starboard::ThreadChecker _uiThreadChecker;
52+
53+
// The maximum number of frames per second a screen can render.
54+
NSInteger _maximumFramesPerSecond;
55+
56+
// The last display refresh rate.
57+
std::atomic<double> _lastDisplayRefreshRate;
5258
}
5359

5460
@synthesize drmManager = _drmManager;
5561
@synthesize playerManager = _playerManager;
62+
@synthesize maximumFramesPerSecond = _maximumFramesPerSecond;
5663

5764
- (instancetype)init {
5865
self = [super init];
5966
if (self) {
6067
_drmManager = [[SBDDrmManager alloc] init];
6168
_playerManager = [[SBDPlayerManager alloc] init];
69+
_maximumFramesPerSecond = [[UIScreen mainScreen] maximumFramesPerSecond];
6270
}
6371
return self;
6472
}
6573

74+
- (void)updateLastDisplayRefreshRate:(double)refreshRate {
75+
_lastDisplayRefreshRate = refreshRate;
76+
}
77+
78+
- (double)displayRefreshRate {
79+
return _lastDisplayRefreshRate;
80+
}
81+
6682
- (void)setPlayerContainerView:(UIView*)view {
6783
SB_CHECK(!_playerContainerView);
6884
_playerContainerView = view;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2026 The Cobalt Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef STARBOARD_TVOS_SHARED_PLATFORM_SERVICE_H_
16+
#define STARBOARD_TVOS_SHARED_PLATFORM_SERVICE_H_
17+
18+
namespace starboard {
19+
namespace shared {
20+
21+
const void* GetPlatformServiceApi();
22+
23+
} // namespace shared
24+
} // namespace starboard
25+
26+
#endif // STARBOARD_TVOS_SHARED_PLATFORM_SERVICE_H_
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright 2026 The Cobalt Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "starboard/tvos/shared/platform_service.h"
16+
17+
#import <UIKit/UIKit.h>
18+
19+
#include "starboard/common/log.h"
20+
#include "starboard/common/string.h"
21+
#include "starboard/extension/platform_service.h"
22+
#import "starboard/tvos/shared/starboard_application.h"
23+
24+
typedef struct CobaltExtensionPlatformServicePrivate {
25+
void* Send(void* /*data*/,
26+
uint64_t /*length*/,
27+
uint64_t* output_length,
28+
bool* invalid_state) {
29+
if (!output_length || !invalid_state) {
30+
return NULL;
31+
}
32+
33+
*invalid_state = false;
34+
std::string string = starboard::FormatString(
35+
"MaximumFramesPerSecond:%ld;DisplayRefreshRate:%f;",
36+
SBDGetApplication().maximumFramesPerSecond,
37+
SBDGetApplication().displayRefreshRate);
38+
39+
*output_length = string.size() + 1;
40+
char* output = (char*)malloc(*output_length);
41+
if (!output) {
42+
*invalid_state = true;
43+
return NULL;
44+
}
45+
46+
memcpy(output, string.c_str(), *output_length);
47+
return output; // caller must free()
48+
}
49+
50+
void* context;
51+
ReceiveMessageCallback receive_callback;
52+
} CobaltExtensionPlatformServicePrivate;
53+
54+
namespace starboard {
55+
namespace shared {
56+
57+
namespace {
58+
59+
const char* kClientLogInfoServiceName = "dev.cobalt.coat.clientloginfo";
60+
61+
bool Has(const char* name) {
62+
if (!name) {
63+
return false;
64+
}
65+
66+
if (strcmp(name, kClientLogInfoServiceName) == 0) {
67+
return true;
68+
}
69+
70+
return false;
71+
}
72+
73+
CobaltExtensionPlatformService Open(void* context,
74+
const char* name,
75+
ReceiveMessageCallback receive_callback) {
76+
SB_DCHECK(context);
77+
78+
if (!Has(name)) {
79+
SB_LOG(ERROR) << "Can't open Service " << name;
80+
return kCobaltExtensionPlatformServiceInvalid;
81+
}
82+
83+
CobaltExtensionPlatformService service =
84+
new CobaltExtensionPlatformServicePrivate({context, receive_callback});
85+
return service;
86+
}
87+
88+
void Close(CobaltExtensionPlatformService service) {
89+
if (service == kCobaltExtensionPlatformServiceInvalid) {
90+
return;
91+
}
92+
93+
delete static_cast<CobaltExtensionPlatformServicePrivate*>(service);
94+
}
95+
96+
void* Send(CobaltExtensionPlatformService service,
97+
void* data,
98+
uint64_t length,
99+
uint64_t* output_length,
100+
bool* invalid_state) {
101+
SB_DCHECK(output_length);
102+
SB_DCHECK(invalid_state);
103+
104+
return static_cast<CobaltExtensionPlatformServicePrivate*>(service)->Send(
105+
data, length, output_length, invalid_state);
106+
}
107+
108+
const CobaltExtensionPlatformServiceApi kPlatformServiceApi = {
109+
kCobaltExtensionPlatformServiceName,
110+
1, // API version that's implemented.
111+
&Has,
112+
&Open,
113+
&Close,
114+
&Send};
115+
116+
} // namespace
117+
118+
const void* GetPlatformServiceApi() {
119+
return &kPlatformServiceApi;
120+
}
121+
122+
} // namespace shared
123+
} // namespace starboard

starboard/tvos/shared/starboard_application.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ id<SBDStarboardApplication> SBDGetApplication(void);
5858
*/
5959
@property(nonatomic, readonly) SBDPlayerManager* playerManager;
6060

61+
/**
62+
* @brief Returns display refresh rate.
63+
*/
64+
@property(nonatomic, readonly) double displayRefreshRate;
65+
66+
/**
67+
* @brief Returns the maximum number of frames per second a screen can render.
68+
*/
69+
@property(nonatomic, readonly) NSInteger maximumFramesPerSecond;
70+
6171
// Sets the UIView to which player views will be added to.
6272
- (void)setPlayerContainerView:(UIView*)view;
6373

@@ -78,6 +88,8 @@ id<SBDStarboardApplication> SBDGetApplication(void);
7888
// suspending the application.
7989
- (void)registerMenuPressEnded:(UIPress*)press
8090
pressesEvent:(UIPressesEvent*)pressesEvent;
91+
92+
- (void)updateLastDisplayRefreshRate:(double)lastDisplayRefreshRate;
8193
@end
8294

8395
NS_ASSUME_NONNULL_END

starboard/tvos/shared/system_get_extensions.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "starboard/tvos/shared/accessibility_extension.h"
2626
#include "starboard/tvos/shared/crash_handler.h"
2727
#include "starboard/tvos/shared/media/player_configuration.h"
28+
#include "starboard/tvos/shared/platform_service.h"
2829
#include "starboard/tvos/shared/uikit_media_session_client.h"
2930

3031
const void* SbSystemGetExtension(const char* name) {
@@ -48,8 +49,7 @@ const void* SbSystemGetExtension(const char* name) {
4849
return nullptr;
4950
}
5051
if (strcmp(name, kCobaltExtensionPlatformServiceName) == 0) {
51-
SB_LOG(INFO) << "The platform service extension is not supported on tvOS";
52-
return nullptr;
52+
return starboard::shared::GetPlatformServiceApi();
5353
}
5454
if (strcmp(name, kStarboardExtensionIfaName) == 0) {
5555
SB_LOG(INFO) << "IFA is not supported via Starboard.";

0 commit comments

Comments
 (0)