19 #include <unordered_map> 20 #include <unordered_set> 42 static std::weak_ptr<shaka::JsManager> gJsEngine;
54 void OnBuffering(
bool is_buffering)
override {
79 void OnError(
const std::string &error)
override {
83 void OnSeeking()
override {
87 void OnAttachMse()
override {
91 void OnAttachSource()
override {
95 void OnDetach()
override {
100 void SetClient(id<ShakaPlayerClient> client) {
104 id<ShakaPlayerClient> GetClient() {
109 _shakaPlayer = shakaPlayer;
113 __weak id<ShakaPlayerClient> _client;
119 NetworkFilter(
ShakaPlayer *player, id<ShakaPlayerNetworkFilter> filter)
120 : player_(player), filter_(filter) {}
122 bool ShouldRemove(id<ShakaPlayerNetworkFilter> filter) {
123 return !filter_ || filter_ == filter;
129 id<ShakaPlayerNetworkFilter> filter = filter_;
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(), ^{
136 [filter onPlayer:player
138 ofType:
static_cast<ShakaPlayerRequestType
>(
type)
139 withBlock:MakeBlock(promise, objc, request)];
141 return promise->get_future();
150 id<ShakaPlayerNetworkFilter> filter = filter_;
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(), ^{
157 [filter onPlayer:player
159 ofType:
static_cast<ShakaPlayerRequestType
>(
type)
160 withBlock:MakeBlock(promise, objc, response)];
162 return promise->get_future();
169 using promise_type = std::promise<shaka::optional<shaka::Error>>;
171 template <
typename Objc,
typename Cpp>
177 shaka::Error(error.severity, error.category, error.code, error.message.UTF8String));
180 promise->set_value({});
186 __weak id<ShakaPlayerNetworkFilter> filter_;
220 std::shared_ptr<shaka::JsManager> ret = gJsEngine.lock();
250 - (instancetype)initWithError:(NSError *__autoreleasing *)error {
251 if ((
self = [super init])) {
254 #ifdef SHAKA_SDL_AUDIO 261 _media_player->AddClient(&_client);
265 const auto initResults = _player->Initialize(&_client, _media_player.get());
266 if (initResults.has_error()) {
270 LOG(ERROR) <<
"Error creating player: " << initResults.error().message;
274 _client.SetPlayer(
self);
279 - (void)setClient:(id<ShakaPlayerClient>)
client {
280 _client.SetClient(
client);
283 - (id<ShakaPlayerClient>)
client {
284 return _client.GetClient();
290 _media_player->Play();
294 _media_player->Pause();
298 auto state = _media_player->PlaybackState();
313 return _media_player->Duration();
317 return _media_player->PlaybackRate();
320 - (void)setPlaybackRate:(
double)rate {
321 _media_player->SetPlaybackRate(rate);
325 return _media_player->CurrentTime();
328 - (void)setCurrentTime:(
double)time {
329 _media_player->SetCurrentTime(time);
333 return _media_player->Volume();
336 - (void)setVolume:(
double)
volume {
337 _media_player->SetVolume(
volume);
341 return _media_player->Muted();
344 - (void)setMuted:(BOOL)
muted {
345 _media_player->SetMuted(
muted);
351 if (results.has_error())
352 return ShakaPlayerLogLevelNone;
354 return static_cast<ShakaPlayerLogLevel
>(results.results());
357 - (void)setLogLevel:(ShakaPlayerLogLevel)
logLevel {
360 if (results.has_error()) {
361 _client.OnError(results.error());
367 if (results.has_error())
368 return @"unknown version";
370 return [NSString stringWithCString:results.results().c_str()];
375 auto results = _player->IsAudioOnly();
376 if (results.has_error())
379 return results.results();
383 auto results = _player->IsLive();
384 if (results.has_error())
387 return results.results();
391 auto results = _player->IsTextTrackVisible();
392 if (results.has_error())
395 return results.results();
403 return static_cast<AVPlayer *
>(CFBridgingRelease(_media_player->GetAvPlayer()));
409 auto callback = [weakSelf, block]() {
414 #define GET_VALUE(field, method) \ 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()); \ 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();
437 GET_VALUE(bufferedInfo, GetBufferedInfo);
438 dispatch_async(dispatch_get_main_queue(), ^{
444 "UiInfo", std::move(callback));
448 auto results = _player->GetStats();
449 if (results.has_error()) {
450 _client.OnError(results.error());
453 return [[
ShakaStats alloc] initWithCpp:results.results()];
458 auto results = _player->GetTextTracks();
459 if (results.has_error())
460 return [[NSArray<ShakaTrack *> alloc] init];
466 auto results = _player->GetVariantTracks();
467 if (results.has_error())
468 return [[NSArray<ShakaTrack *> alloc] init];
474 - (void)load:(NSString *)uri {
475 return [
self load:uri withStartTime:NAN];
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());
492 auto loadResults = _player->Load(uri.UTF8String, startTime);
499 auto unloadResults = _player->Unload();
503 - (void)configure:(const NSString *)namePath withBool:(BOOL)value {
504 _player->Configure(namePath.UTF8String, static_cast<bool>(value));
507 - (void)configure:(const NSString *)namePath withDouble:(
double)value {
508 _player->Configure(namePath.UTF8String, value);
511 - (void)configure:(const NSString *)namePath withString:(const NSString *)value {
512 _player->Configure(namePath.UTF8String, value.UTF8String);
515 - (void)configure:(const NSString *)namePath withData:(NSData *)value {
516 _player->Configure(namePath.UTF8String, reinterpret_cast<const uint8_t *>([value bytes]),
520 - (void)configureWithDefault:(const NSString *)namePath {
524 - (BOOL)getConfigurationBool:(const NSString *)namePath {
525 auto results = _player->GetConfigurationBool(namePath.UTF8String);
526 if (results.has_error()) {
529 return results.results();
533 - (double)getConfigurationDouble:(const NSString *)namePath {
534 auto results = _player->GetConfigurationDouble(namePath.UTF8String);
535 if (results.has_error()) {
538 return results.results();
542 - (NSString *)getConfigurationString:(const NSString *)namePath {
543 auto results = _player->GetConfigurationString(namePath.UTF8String);
544 if (results.has_error()) {
547 std::string cppString = results.results();
548 return [NSString stringWithCString:cppString.c_str()];
554 auto results = _player->GetAudioLanguagesAndRoles();
555 if (results.has_error())
556 return [[NSArray<ShakaLanguageRole *> alloc] init];
562 auto results = _player->GetTextLanguagesAndRoles();
563 if (results.has_error())
564 return [[NSArray<ShakaLanguageRole *> alloc] init];
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());
576 - (void)selectAudioLanguage:(NSString *)language {
577 auto results = _player->SelectAudioLanguage(language.UTF8String);
578 if (results.has_error()) {
579 _client.OnError(results.error());
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());
590 - (void)selectTextLanguage:(NSString *)language {
591 auto results = _player->SelectTextLanguage(language.UTF8String);
592 if (results.has_error()) {
593 _client.OnError(results.error());
598 auto results = _player->SelectTextTrack([track toCpp]);
599 if (results.has_error()) {
600 _client.OnError(results.error());
605 auto results = _player->SelectVariantTrack([track toCpp]);
606 if (results.has_error()) {
607 _client.OnError(results.error());
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());
623 - (void)addTextTrack:(NSString *)uri
624 language:(NSString *)lang
625 kind:(NSString *)kind
626 mime:(NSString *)mime {
630 - (void)addTextTrack:(NSString *)uri
631 language:(NSString *)lang
632 kind:(NSString *)kind
633 mime:(NSString *)mime
634 codec:(NSString *)codec {
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());
651 - (void)addNetworkFilter:(
id<ShakaPlayerNetworkFilter>)filter {
652 @
synchronized(
self) {
653 _filters.emplace_back(
self, filter);
654 _player->AddNetworkFilters(&_filters.back());
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);
673 return _player.get();
677 return _media_player.get();
681 return &_video_renderer;
std::shared_ptr< shaka::JsManager > _engine
#define END_ALLOW_COMPLEX_STATICS
ShakaBufferedInfo * bufferedInfo
NSArray< ShakaLanguageRole * > * audioLanguagesAndRoles
NSArray< ShakaLanguageRole * > * textLanguagesAndRoles
void(^ ShakaPlayerAsyncBlock)(ShakaPlayerError *_Nullable)
std::string LicenseServerConfig(const std::string &key_system)
#define GET_VALUE(field, method)
static AsyncResults< LogLevel > GetLogLevel(JsManager *engine)
static AsyncResults< void > SetLogLevel(JsManager *engine, LogLevel level)
id< ShakaPlayerClient > client
ShakaPlayerLogLevel logLevel
shaka::media::DefaultMediaPlayer * mediaPlayer
NSArray< ShakaTrack * > * getTextTracks()
NSArray< ShakaTrack * > * getVariantTracks()
void DispatchObjcEvent(__weak id weak_client, SEL selector, Args... args)
std::unique_ptr< shaka::media::DefaultMediaPlayer > _media_player
NSString * ShakaPlayerAdvancedDrmConfig(const NSString *key_system, const NSString *config)
std::string dynamic_data_dir
void CallBlockForFuture(This that, AsyncResults< Ret > future, Func block)
static JsManagerImpl * Instance()
ShakaBufferedRange * seekRange
bool is_static_relative_to_bundle
std::string static_data_dir
#define BEGIN_ALLOW_COMPLEX_STATICS
void load:withStartTime:andBlock:(NSString *uri, [withStartTime] double startTime, [andBlock] ShakaPlayerAsyncBlock block)
shaka::Player * playerInstance
shaka::media::AppleVideoRenderer _video_renderer
std::shared_ptr< ThreadEvent< impl::RetOf< Func > > > AddInternalTask(TaskPriority priority, const std::string &name, Func &&callback)
NSString * ShakaPlayerLicenseServerConfig(const NSString *key_system)
std::unique_ptr< shaka::Player > _player
std::list< NetworkFilter > _filters
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()
std::unique_ptr< shaka::media::AudioRenderer > _audio_renderer
static AsyncResults< std::string > GetPlayerVersion(JsManager *engine)
std::string AdvancedDrmConfig(const std::string &key_system, const std::string &property)
TaskRunner * MainThread()