Shaka Player Embedded
ShakaPlayer.mm
Go to the documentation of this file.
1 // Copyright 2018 Google LLC
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 // https://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 #import "shaka/ShakaPlayer.h"
16 
17 #include <list>
18 #include <memory>
19 #include <unordered_map>
20 #include <unordered_set>
21 #include <utility>
22 
24 
26 #include "src/debug/mutex.h"
29 #include "src/js/stats+Internal.h"
30 #include "src/js/track+Internal.h"
34 #include "src/util/macros.h"
35 #include "src/util/objc_utils.h"
36 #include "src/util/utils.h"
37 
38 
39 namespace {
40 
42 static std::weak_ptr<shaka::JsManager> gJsEngine;
44 
45 class NativeClient final : public shaka::Player::Client, public shaka::media::MediaPlayer::Client {
46  public:
47  NativeClient() {}
48 
49  void OnError(const shaka::Error &error) override {
50  ShakaPlayerError *objc_error = [[ShakaPlayerError alloc] initWithError:error];
51  shaka::util::DispatchObjcEvent(_client, @selector(onPlayer:error:), _shakaPlayer, objc_error);
52  }
53 
54  void OnBuffering(bool is_buffering) override {
55  shaka::util::DispatchObjcEvent(_client, @selector(onPlayer:bufferingChange:), _shakaPlayer,
56  is_buffering);
57  }
58 
59 
60  void OnPlaybackStateChanged(shaka::media::VideoPlaybackState old_state,
61  shaka::media::VideoPlaybackState new_state) override {
62  switch (new_state) {
64  shaka::util::DispatchObjcEvent(_client, @selector(onPlayerPauseEvent:), _shakaPlayer);
65  break;
67  shaka::util::DispatchObjcEvent(_client, @selector(onPlayerPlayingEvent:), _shakaPlayer);
68  break;
70  shaka::util::DispatchObjcEvent(_client, @selector(onPlayerEndedEvent:), _shakaPlayer);
71  break;
72  default:
73  break;
74  }
76  shaka::util::DispatchObjcEvent(_client, @selector(onPlayerSeekedEvent:), _shakaPlayer);
77  }
78 
79  void OnError(const std::string &error) override {
80  OnError(shaka::Error(error));
81  }
82 
83  void OnSeeking() override {
84  shaka::util::DispatchObjcEvent(_client, @selector(onPlayerSeekingEvent:), _shakaPlayer);
85  }
86 
87  void OnAttachMse() override {
88  shaka::util::DispatchObjcEvent(_client, @selector(onPlayerAttachMse:), _shakaPlayer);
89  }
90 
91  void OnAttachSource() override {
92  shaka::util::DispatchObjcEvent(_client, @selector(onPlayerAttachSource:), _shakaPlayer);
93  }
94 
95  void OnDetach() override {
96  shaka::util::DispatchObjcEvent(_client, @selector(onPlayerDetach:), _shakaPlayer);
97  }
98 
99 
100  void SetClient(id<ShakaPlayerClient> client) {
101  _client = client;
102  }
103 
104  id<ShakaPlayerClient> GetClient() {
105  return _client;
106  }
107 
108  void SetPlayer(ShakaPlayer *shakaPlayer) {
109  _shakaPlayer = shakaPlayer;
110  }
111 
112  private:
113  __weak id<ShakaPlayerClient> _client;
114  __weak ShakaPlayer *_shakaPlayer;
115 };
116 
117 class NetworkFilter final : public shaka::NetworkFilters {
118  public:
119  NetworkFilter(ShakaPlayer *player, id<ShakaPlayerNetworkFilter> filter)
120  : player_(player), filter_(filter) {}
121 
122  bool ShouldRemove(id<ShakaPlayerNetworkFilter> filter) {
123  return !filter_ || filter_ == filter;
124  }
125 
126  std::future<shaka::optional<shaka::Error>> OnRequestFilter(shaka::RequestType type,
127  shaka::Request *request) override {
128  // Create strong references here so if this object is destroyed, these callbacks still work.
129  id<ShakaPlayerNetworkFilter> filter = filter_;
130  ShakaPlayer *player = player_;
131  if (filter && [filter respondsToSelector:@selector(onPlayer:
132  networkRequest:ofType:withBlock:)]) {
133  auto promise = std::make_shared<promise_type>();
134  dispatch_async(dispatch_get_main_queue(), ^{
135  auto *objc = [[ShakaPlayerRequest alloc] initWithRequest:*request];
136  [filter onPlayer:player
137  networkRequest:objc
138  ofType:static_cast<ShakaPlayerRequestType>(type)
139  withBlock:MakeBlock(promise, objc, request)];
140  });
141  return promise->get_future();
142  } else {
143  return {};
144  }
145  }
146 
147  std::future<shaka::optional<shaka::Error>> OnResponseFilter(shaka::RequestType type,
148  shaka::Response *response) override {
149  // Create strong references here so if this object is destroyed, these callbacks still work.
150  id<ShakaPlayerNetworkFilter> filter = filter_;
151  ShakaPlayer *player = player_;
152  if (filter && [filter respondsToSelector:@selector(onPlayer:
153  networkResponse:ofType:withBlock:)]) {
154  auto promise = std::make_shared<promise_type>();
155  dispatch_async(dispatch_get_main_queue(), ^{
156  auto *objc = [[ShakaPlayerResponse alloc] initWithResponse:*response];
157  [filter onPlayer:player
158  networkResponse:objc
159  ofType:static_cast<ShakaPlayerRequestType>(type)
160  withBlock:MakeBlock(promise, objc, response)];
161  });
162  return promise->get_future();
163  } else {
164  return {};
165  }
166  }
167 
168  private:
169  using promise_type = std::promise<shaka::optional<shaka::Error>>;
170 
171  template <typename Objc, typename Cpp>
172  static ShakaPlayerAsyncBlock MakeBlock(std::shared_ptr<promise_type> promise, Objc objc,
173  Cpp cpp) {
174  return ^(ShakaPlayerError *error) {
175  if (error) {
176  promise->set_value(
177  shaka::Error(error.severity, error.category, error.code, error.message.UTF8String));
178  } else {
179  [objc finalize:cpp]; // Propagate changes to the C++ object.
180  promise->set_value({});
181  }
182  };
183  }
184 
185  __weak ShakaPlayer *player_;
186  __weak id<ShakaPlayerNetworkFilter> filter_;
187 };
188 
189 } // namespace
190 
191 @implementation ShakaPlayerUiInfo
192 
193 @synthesize paused;
194 @synthesize ended;
195 @synthesize seeking;
196 @synthesize duration;
197 @synthesize playbackRate;
198 @synthesize currentTime;
199 @synthesize volume;
200 @synthesize muted;
201 @synthesize isAudioOnly;
202 @synthesize isLive;
203 @synthesize closedCaptions;
204 @synthesize seekRange;
205 @synthesize bufferedInfo;
206 
207 @end
208 
209 NSString *ShakaPlayerLicenseServerConfig(const NSString *key_system) {
210  const std::string ret = shaka::LicenseServerConfig(key_system.UTF8String);
212 }
213 
214 NSString *ShakaPlayerAdvancedDrmConfig(const NSString *key_system, const NSString *config) {
215  const std::string ret = shaka::AdvancedDrmConfig(key_system.UTF8String, config.UTF8String);
217 }
218 
219 std::shared_ptr<shaka::JsManager> ShakaGetGlobalEngine() {
220  std::shared_ptr<shaka::JsManager> ret = gJsEngine.lock();
221  if (!ret) {
223  options.static_data_dir = "Frameworks/ShakaPlayerEmbedded.framework";
224  options.dynamic_data_dir = std::string(getenv("HOME")) + "/Library";
225  options.is_static_relative_to_bundle = true;
226  ret.reset(new shaka::JsManager(options));
227  gJsEngine = ret;
228  }
229  return ret;
230 }
231 
232 @interface ShakaPlayer () {
233  NativeClient _client;
234  std::list<NetworkFilter> _filters;
235  std::shared_ptr<shaka::JsManager> _engine;
236 
238  std::unique_ptr<shaka::media::AudioRenderer> _audio_renderer;
239 
240  std::unique_ptr<shaka::media::DefaultMediaPlayer> _media_player;
241  std::unique_ptr<shaka::Player> _player;
242 }
243 
244 @end
245 
246 @implementation ShakaPlayer
247 
248 // MARK: setup
249 
250 - (instancetype)initWithError:(NSError *__autoreleasing *)error {
251  if ((self = [super init])) {
252  // Create JS objects.
253  _engine = ShakaGetGlobalEngine();
254 #ifdef SHAKA_SDL_AUDIO
255  _audio_renderer.reset(new shaka::media::SdlAudioRenderer(""));
256 #else
257  _audio_renderer.reset(new shaka::media::AppleAudioRenderer());
258 #endif
259  _media_player.reset(
260  new shaka::media::DefaultMediaPlayer(&_video_renderer, _audio_renderer.get()));
261  _media_player->AddClient(&_client);
262 
263  // Set up player.
264  _player.reset(new shaka::Player(_engine.get()));
265  const auto initResults = _player->Initialize(&_client, _media_player.get());
266  if (initResults.has_error()) {
267  if (error) {
268  *error = [[ShakaPlayerError alloc] initWithError:initResults.error()];
269  } else {
270  LOG(ERROR) << "Error creating player: " << initResults.error().message;
271  }
272  return nil;
273  }
274  _client.SetPlayer(self);
275  }
276  return self;
277 }
278 
279 - (void)setClient:(id<ShakaPlayerClient>)client {
280  _client.SetClient(client);
281 }
282 
283 - (id<ShakaPlayerClient>)client {
284  return _client.GetClient();
285 }
286 
287 // MARK: controls
288 
289 - (void)play {
290  _media_player->Play();
291 }
292 
293 - (void)pause {
294  _media_player->Pause();
295 }
296 
297 - (BOOL)paused {
298  auto state = _media_player->PlaybackState();
302 }
303 
304 - (BOOL)ended {
305  return _media_player->PlaybackState() == shaka::media::VideoPlaybackState::Ended;
306 }
307 
308 - (BOOL)seeking {
309  return _media_player->PlaybackState() == shaka::media::VideoPlaybackState::Seeking;
310 }
311 
312 - (double)duration {
313  return _media_player->Duration();
314 }
315 
316 - (double)playbackRate {
317  return _media_player->PlaybackRate();
318 }
319 
320 - (void)setPlaybackRate:(double)rate {
321  _media_player->SetPlaybackRate(rate);
322 }
323 
324 - (double)currentTime {
325  return _media_player->CurrentTime();
326 }
327 
328 - (void)setCurrentTime:(double)time {
329  _media_player->SetCurrentTime(time);
330 }
331 
332 - (double)volume {
333  return _media_player->Volume();
334 }
335 
336 - (void)setVolume:(double)volume {
337  _media_player->SetVolume(volume);
338 }
339 
340 - (BOOL)muted {
341  return _media_player->Muted();
342 }
343 
344 - (void)setMuted:(BOOL)muted {
345  _media_player->SetMuted(muted);
346 }
347 
348 
349 - (ShakaPlayerLogLevel)logLevel {
350  const auto results = shaka::Player::GetLogLevel(_engine.get());
351  if (results.has_error())
352  return ShakaPlayerLogLevelNone;
353  else
354  return static_cast<ShakaPlayerLogLevel>(results.results());
355 }
356 
357 - (void)setLogLevel:(ShakaPlayerLogLevel)logLevel {
358  auto castedLogLevel = static_cast<shaka::Player::LogLevel>(logLevel);
359  const auto results = shaka::Player::SetLogLevel(_engine.get(), castedLogLevel);
360  if (results.has_error()) {
361  _client.OnError(results.error());
362  }
363 }
364 
365 - (NSString *)playerVersion {
366  const auto results = shaka::Player::GetPlayerVersion(_engine.get());
367  if (results.has_error())
368  return @"unknown version";
369  else
370  return [NSString stringWithCString:results.results().c_str()];
371 }
372 
373 
374 - (BOOL)isAudioOnly {
375  auto results = _player->IsAudioOnly();
376  if (results.has_error())
377  return false;
378  else
379  return results.results();
380 }
381 
382 - (BOOL)isLive {
383  auto results = _player->IsLive();
384  if (results.has_error())
385  return false;
386  else
387  return results.results();
388 }
389 
390 - (BOOL)closedCaptions {
391  auto results = _player->IsTextTrackVisible();
392  if (results.has_error())
393  return false;
394  else
395  return results.results();
396 }
397 
398 - (void)setClosedCaptions:(BOOL)closedCaptions {
399  _player->SetTextTrackVisibility(closedCaptions);
400 }
401 
402 - (AVPlayer *)avPlayer {
403  return static_cast<AVPlayer *>(CFBridgingRelease(_media_player->GetAvPlayer()));
404 }
405 
406 - (void)getUiInfoWithBlock:(void (^)(ShakaPlayerUiInfo *))block {
407  // Use a weak capture to avoid having this callback keep the player alive.
408  __weak ShakaPlayer *weakSelf = self;
409  auto callback = [weakSelf, block]() {
410  ShakaPlayer *player = weakSelf;
411  if (!player)
412  return;
413 
414 #define GET_VALUE(field, method) \
415  do { \
416  auto results = player->_player->method(); \
417  if (!results.has_error()) { \
418  using T = typename std::decay<decltype(results.results())>::type; \
419  ret.field = shaka::util::ObjcConverter<T>::ToObjc(results.results()); \
420  } \
421  } while (false)
422  auto ret = [[ShakaPlayerUiInfo alloc] init];
423  ret.paused = [player paused];
424  ret.ended = [player ended];
425  ret.seeking = [player seeking];
426  ret.duration = player->_media_player->Duration();
427  ret.playbackRate = player->_media_player->PlaybackRate();
428  ret.currentTime = player->_media_player->CurrentTime();
429  ret.volume = player->_media_player->Volume();
430  ret.muted = player->_media_player->Muted();
431  // This callback is run on the JS main thread, so all these should complete
432  // synchronously.
433  GET_VALUE(isAudioOnly, IsAudioOnly);
434  GET_VALUE(isLive, IsLive);
435  GET_VALUE(closedCaptions, IsTextTrackVisible);
436  GET_VALUE(seekRange, SeekRange);
437  GET_VALUE(bufferedInfo, GetBufferedInfo);
438  dispatch_async(dispatch_get_main_queue(), ^{
439  block(ret);
440  });
441 #undef GET_VALUE
442  };
444  "UiInfo", std::move(callback));
445 }
446 
448  auto results = _player->GetStats();
449  if (results.has_error()) {
450  _client.OnError(results.error());
451  return [[ShakaStats alloc] init];
452  } else {
453  return [[ShakaStats alloc] initWithCpp:results.results()];
454  }
455 }
456 
457 - (NSArray<ShakaTrack *> *)getTextTracks {
458  auto results = _player->GetTextTracks();
459  if (results.has_error())
460  return [[NSArray<ShakaTrack *> alloc] init];
461  else
462  return shaka::util::ObjcConverter<std::vector<shaka::Track>>::ToObjc(results.results());
463 }
464 
465 - (NSArray<ShakaTrack *> *)getVariantTracks {
466  auto results = _player->GetVariantTracks();
467  if (results.has_error())
468  return [[NSArray<ShakaTrack *> alloc] init];
469  else
470  return shaka::util::ObjcConverter<std::vector<shaka::Track>>::ToObjc(results.results());
471 }
472 
473 
474 - (void)load:(NSString *)uri {
475  return [self load:uri withStartTime:NAN];
476 }
477 
478 - (void)load:(NSString *)uri withStartTime:(double)startTime {
479  @synchronized(self) {
480  const auto loadResults = _player->Load(uri.UTF8String, startTime);
481  if (loadResults.has_error()) {
482  _client.OnError(loadResults.error());
483  }
484  }
485 }
486 
487 - (void)load:(NSString *)uri withBlock:(ShakaPlayerAsyncBlock)block {
488  [self load:uri withStartTime:NAN andBlock:block];
489 }
490 
491 - (void)load:(NSString *)uri withStartTime:(double)startTime andBlock:(ShakaPlayerAsyncBlock)block {
492  auto loadResults = _player->Load(uri.UTF8String, startTime);
493  shaka::util::CallBlockForFuture(self, std::move(loadResults), ^(ShakaPlayerError *error) {
494  block(error);
495  });
496 }
497 
498 - (void)unloadWithBlock:(ShakaPlayerAsyncBlock)block {
499  auto unloadResults = _player->Unload();
500  shaka::util::CallBlockForFuture(self, std::move(unloadResults), block);
501 }
502 
503 - (void)configure:(const NSString *)namePath withBool:(BOOL)value {
504  _player->Configure(namePath.UTF8String, static_cast<bool>(value));
505 }
506 
507 - (void)configure:(const NSString *)namePath withDouble:(double)value {
508  _player->Configure(namePath.UTF8String, value);
509 }
510 
511 - (void)configure:(const NSString *)namePath withString:(const NSString *)value {
512  _player->Configure(namePath.UTF8String, value.UTF8String);
513 }
514 
515 - (void)configure:(const NSString *)namePath withData:(NSData *)value {
516  _player->Configure(namePath.UTF8String, reinterpret_cast<const uint8_t *>([value bytes]),
517  [value length]);
518 }
519 
520 - (void)configureWithDefault:(const NSString *)namePath {
521  _player->Configure(namePath.UTF8String, shaka::DefaultValue);
522 }
523 
524 - (BOOL)getConfigurationBool:(const NSString *)namePath {
525  auto results = _player->GetConfigurationBool(namePath.UTF8String);
526  if (results.has_error()) {
527  return NO;
528  } else {
529  return results.results();
530  }
531 }
532 
533 - (double)getConfigurationDouble:(const NSString *)namePath {
534  auto results = _player->GetConfigurationDouble(namePath.UTF8String);
535  if (results.has_error()) {
536  return 0;
537  } else {
538  return results.results();
539  }
540 }
541 
542 - (NSString *)getConfigurationString:(const NSString *)namePath {
543  auto results = _player->GetConfigurationString(namePath.UTF8String);
544  if (results.has_error()) {
545  return @"";
546  } else {
547  std::string cppString = results.results();
548  return [NSString stringWithCString:cppString.c_str()];
549  }
550 }
551 
552 
553 - (NSArray<ShakaLanguageRole *> *)audioLanguagesAndRoles {
554  auto results = _player->GetAudioLanguagesAndRoles();
555  if (results.has_error())
556  return [[NSArray<ShakaLanguageRole *> alloc] init];
557  else
558  return shaka::util::ObjcConverter<std::vector<shaka::LanguageRole>>::ToObjc(results.results());
559 }
560 
561 - (NSArray<ShakaLanguageRole *> *)textLanguagesAndRoles {
562  auto results = _player->GetTextLanguagesAndRoles();
563  if (results.has_error())
564  return [[NSArray<ShakaLanguageRole *> alloc] init];
565  else
566  return shaka::util::ObjcConverter<std::vector<shaka::LanguageRole>>::ToObjc(results.results());
567 }
568 
569 - (void)selectAudioLanguage:(NSString *)language withRole:(NSString *)role {
570  auto results = _player->SelectAudioLanguage(language.UTF8String, role.UTF8String);
571  if (results.has_error()) {
572  _client.OnError(results.error());
573  }
574 }
575 
576 - (void)selectAudioLanguage:(NSString *)language {
577  auto results = _player->SelectAudioLanguage(language.UTF8String);
578  if (results.has_error()) {
579  _client.OnError(results.error());
580  }
581 }
582 
583 - (void)selectTextLanguage:(NSString *)language withRole:(NSString *)role {
584  auto results = _player->SelectTextLanguage(language.UTF8String, role.UTF8String);
585  if (results.has_error()) {
586  _client.OnError(results.error());
587  }
588 }
589 
590 - (void)selectTextLanguage:(NSString *)language {
591  auto results = _player->SelectTextLanguage(language.UTF8String);
592  if (results.has_error()) {
593  _client.OnError(results.error());
594  }
595 }
596 
597 - (void)selectTextTrack:(const ShakaTrack *)track {
598  auto results = _player->SelectTextTrack([track toCpp]);
599  if (results.has_error()) {
600  _client.OnError(results.error());
601  }
602 }
603 
604 - (void)selectVariantTrack:(const ShakaTrack *)track {
605  auto results = _player->SelectVariantTrack([track toCpp]);
606  if (results.has_error()) {
607  _client.OnError(results.error());
608  }
609 }
610 
611 - (void)selectVariantTrack:(const ShakaTrack *)track withClearBuffer:(BOOL)clear {
612  auto results = _player->SelectVariantTrack([track toCpp], clear);
613  if (results.has_error()) {
614  _client.OnError(results.error());
615  }
616 }
617 
618 - (void)destroy {
619  if (_player)
620  _player->Destroy();
621 }
622 
623 - (void)addTextTrack:(NSString *)uri
624  language:(NSString *)lang
625  kind:(NSString *)kind
626  mime:(NSString *)mime {
627  [self addTextTrack:uri language:lang kind:kind mime:mime codec:@"" label:@""];
628 }
629 
630 - (void)addTextTrack:(NSString *)uri
631  language:(NSString *)lang
632  kind:(NSString *)kind
633  mime:(NSString *)mime
634  codec:(NSString *)codec {
635  [self addTextTrack:uri language:lang kind:kind mime:mime codec:codec label:@""];
636 }
637 
638 - (void)addTextTrack:(NSString *)uri
639  language:(NSString *)lang
640  kind:(NSString *)kind
641  mime:(NSString *)mime
642  codec:(NSString *)codec
643  label:(NSString *)label {
644  auto results = _player->AddTextTrack(uri.UTF8String, lang.UTF8String, kind.UTF8String,
645  mime.UTF8String, codec.UTF8String, label.UTF8String);
646  if (results.has_error()) {
647  _client.OnError(results.error());
648  }
649 }
650 
651 - (void)addNetworkFilter:(id<ShakaPlayerNetworkFilter>)filter {
652  @synchronized(self) {
653  _filters.emplace_back(self, filter);
654  _player->AddNetworkFilters(&_filters.back());
655  }
656 }
657 
658 - (void)removeNetworkFilter:(id<ShakaPlayerNetworkFilter>)filter {
659  @synchronized(self) {
660  for (auto it = _filters.begin(); it != _filters.end();) {
661  if (it->ShouldRemove(filter)) {
662  _player->RemoveNetworkFilters(&*it);
663  it = _filters.erase(it);
664  } else {
665  it++;
666  }
667  }
668  }
669 }
670 
671 // MARK: +Internal
673  return _player.get();
674 }
675 
677  return _media_player.get();
678 }
679 
681  return &_video_renderer;
682 }
683 
684 @end
double volume
Definition: ShakaPlayer.h:268
std::shared_ptr< shaka::JsManager > _engine
Definition: ShakaPlayer.mm:235
double duration
Definition: ShakaPlayer.h:259
#define END_ALLOW_COMPLEX_STATICS
Definition: macros.h:43
ShakaBufferedInfo * bufferedInfo
Definition: ShakaPlayer.h:218
double playbackRate
Definition: ShakaPlayer.h:262
NSArray< ShakaLanguageRole * > * audioLanguagesAndRoles
Definition: ShakaPlayer.h:293
double currentTime
Definition: ShakaPlayer.h:265
NSArray< ShakaLanguageRole * > * textLanguagesAndRoles
Definition: ShakaPlayer.h:296
void(^ ShakaPlayerAsyncBlock)(ShakaPlayerError *_Nullable)
Definition: ShakaPlayer.h:36
BOOL closedCaptions
Definition: ShakaPlayer.h:290
std::string LicenseServerConfig(const std::string &key_system)
Definition: utils.h:272
#define GET_VALUE(field, method)
BOOL isAudioOnly
Definition: ShakaPlayer.h:284
static AsyncResults< LogLevel > GetLogLevel(JsManager *engine)
Definition: player.cc:334
static AsyncResults< void > SetLogLevel(JsManager *engine, LogLevel level)
Definition: player.cc:328
id< ShakaPlayerClient > client
Definition: ShakaPlayer.h:241
ShakaPlayerLogLevel logLevel
Definition: ShakaPlayer.h:278
shaka::media::DefaultMediaPlayer * mediaPlayer
NSArray< ShakaTrack * > * getTextTracks()
Definition: ShakaPlayer.mm:457
ExceptionCode type
NSArray< ShakaTrack * > * getVariantTracks()
Definition: ShakaPlayer.mm:465
void DispatchObjcEvent(__weak id weak_client, SEL selector, Args... args)
Definition: objc_utils.h:140
std::unique_ptr< shaka::media::DefaultMediaPlayer > _media_player
Definition: ShakaPlayer.mm:240
NSString * ShakaPlayerAdvancedDrmConfig(const NSString *key_system, const NSString *config)
Definition: ShakaPlayer.mm:214
void CallBlockForFuture(This that, AsyncResults< Ret > future, Func block)
Definition: objc_utils.h:179
ShakaBufferedRange * seekRange
Definition: ShakaPlayer.h:215
#define BEGIN_ALLOW_COMPLEX_STATICS
Definition: macros.h:42
void load:withStartTime:andBlock:(NSString *uri, [withStartTime] double startTime, [andBlock] ShakaPlayerAsyncBlock block)
Definition: ShakaPlayer.mm:491
shaka::Player * playerInstance
shaka::media::AppleVideoRenderer _video_renderer
Definition: ShakaPlayer.mm:237
std::shared_ptr< ThreadEvent< impl::RetOf< Func > > > AddInternalTask(TaskPriority priority, const std::string &name, Func &&callback)
Definition: task_runner.h:219
NSString * playerVersion
Definition: ShakaPlayer.h:281
NSString * ShakaPlayerLicenseServerConfig(const NSString *key_system)
Definition: ShakaPlayer.mm:209
std::unique_ptr< shaka::Player > _player
Definition: ShakaPlayer.mm:241
RequestType
Definition: net.h:38
ShakaStats * getStats()
Definition: ShakaPlayer.mm:447
std::list< NetworkFilter > _filters
Definition: ShakaPlayer.mm:234
AVPlayer * avPlayer
Definition: ShakaPlayer.h:303
void addTextTrack:language:kind:mime:codec:label:(NSString *uri, [language] NSString *lang, [kind] NSString *kind, [mime] NSString *mime, [codec] nullable NSString *codec, [label] nullable NSString *label)
shaka::media::AppleVideoRenderer * videoRenderer
const DefaultValueType DefaultValue
std::shared_ptr< shaka::JsManager > ShakaGetGlobalEngine()
Definition: ShakaPlayer.mm:219
std::unique_ptr< shaka::media::AudioRenderer > _audio_renderer
Definition: ShakaPlayer.mm:238
static AsyncResults< std::string > GetPlayerVersion(JsManager *engine)
Definition: player.cc:340
NativeClient _client
Definition: ShakaPlayer.mm:233
std::string AdvancedDrmConfig(const std::string &key_system, const std::string &property)
Definition: utils.h:284
TaskRunner * MainThread()