UNPKG

@codelab/nativescript-cast

Version:

NativeScript Chromecast Plugin.

447 lines 17.6 kB
import camelCase from 'lodash/fp/camelCase'; import upperFirst from 'lodash/fp/upperFirst'; import { Utils, Color } from '@nativescript/core'; import { CastButtonBase } from './cast.common'; import { MetadataType, QueueType, RepeatMode, ResumeState, StreamType, } from './cast.types'; import { MediaQueueDelegate } from './media-queue-delegate.ios'; import { RemoteMediaClientListenerImpl } from './remote-media-client-listener.ios'; import { SessionManagerListenerImpl } from './session-manager-listener.ios'; const METADATA_PREFIX = 'kGCKMetadataKey'; export function metadataTypeEnumToString(metadataType) { switch (metadataType) { case 1: return MetadataType.MOVIE; case 2: return MetadataType.TV_SHOW; case 3: return MetadataType.MUSIC_TRACK; case 4: return MetadataType.PHOTO; case 5: return MetadataType.USER; case 100: return MetadataType.USER; default: return MetadataType.GENERIC; } } export function metadataTypeStringToEnum(metadataType) { switch (metadataType) { case MetadataType.MOVIE: return 1; case MetadataType.TV_SHOW: return 2; case MetadataType.MUSIC_TRACK: return 3; case MetadataType.PHOTO: return 4; case MetadataType.AUDIO_BOOK_CHAPTER: return 5; case MetadataType.USER: return 100; default: return 0; } } export function streamTypeEnumToString(streamType) { switch (streamType) { case 1: return StreamType.BUFFERED; case 2: return StreamType.LIVE; case 99: return StreamType.UNKNOWN; default: return StreamType.NONE; } } export function streamTypeStringToEnum(streamType) { switch (streamType) { case StreamType.BUFFERED: return 1; case StreamType.LIVE: return 2; case StreamType.UNKNOWN: return 99; default: return 0; } } export function repeatModeStringToEnum(repeatMode) { switch (repeatMode) { case RepeatMode.OFF: return 1; case RepeatMode.SINGLE: return 2; case RepeatMode.ALL: return 3; case RepeatMode.ALL_AND_SHUFFLE: return 4; default: return 1; } } export function repeatModeEnumToString(repeatMode) { switch (repeatMode) { case 1: return RepeatMode.OFF; case 2: return RepeatMode.SINGLE; case 3: return RepeatMode.ALL; case 4: return RepeatMode.ALL_AND_SHUFFLE; default: return RepeatMode.OFF; } } export function resumeStateStringToEnum(resumeState) { switch (resumeState) { case ResumeState.PLAY: return 1; case ResumeState.PAUSE: return 2; default: return 0; } } export function queueTypeStringToEnum(queueType) { switch (queueType) { case QueueType.ALBUM: return 1; case QueueType.PLAYLIST: return 2; case QueueType.AUDIO_BOOK: return 3; case QueueType.RADIO_STATION: return 4; case QueueType.PODCAST_SERIES: return 5; case QueueType.TV_SERIES: return 6; case QueueType.VIDEO_PLAYLIST: return 7; case QueueType.LIVE_TV: return 8; case QueueType.MOVIE: return 9; default: return 0; } } export function queueTypeEnumToString(queueType) { switch (queueType) { case 1: return QueueType.ALBUM; case 2: return QueueType.PLAYLIST; case 3: return QueueType.AUDIO_BOOK; case 4: return QueueType.RADIO_STATION; case 5: return QueueType.PODCAST_SERIES; case 6: return QueueType.TV_SERIES; case 7: return QueueType.VIDEO_PLAYLIST; case 8: return QueueType.LIVE_TV; case 9: return QueueType.MOVIE; default: return QueueType.GENERIC; } } export function convertMediaInfo(mediaInfo) { if (!mediaInfo) { return null; } const metadata = mediaInfo.metadata; const metaDataKeys = Utils.ios.collections.nsArrayToJSArray(metadata.allKeys()); const images = Utils.ios.collections.nsArrayToJSArray(metadata.images()); let textTracks = []; let textTrackStyle = {}; const castMetadata = { metadataType: metadataTypeEnumToString(metadata.metadataType), images: [], }; metaDataKeys.forEach(key => { const fixedKey = camelCase(key.replace('kGCKMetadataKey', '')); castMetadata[fixedKey] = metadata.objectForKey(key); }); images.forEach(img => { castMetadata.images.push({ url: img.URL.absoluteString, width: img.width, height: img.height }); }); if (mediaInfo.mediaTracks) { const tracks = Utils.ios.collections.nsArrayToJSArray(mediaInfo.mediaTracks); textTracks = tracks .filter((track) => track.type === 1) .map((track) => { return { id: track.identifier, src: track.contentIdentifier, contentType: track.contentType, name: track.name, language: track.languageCode, }; }); } if (mediaInfo.textTrackStyle) { textTrackStyle = { foregroundColor: mediaInfo.textTrackStyle.foregroundColor.CSSString(), backgroundColor: mediaInfo.textTrackStyle.foregroundColor.CSSString(), edgeColor: mediaInfo.textTrackStyle.edgeColor.CSSString(), windowColor: mediaInfo.textTrackStyle.windowColor.CSSString(), fontFamily: mediaInfo.textTrackStyle.fontFamily, customData: mediaInfo.textTrackStyle.customData }; } return { contentId: mediaInfo.contentID, streamType: streamTypeEnumToString(mediaInfo.streamType), contentType: mediaInfo.contentType, metadata: castMetadata, duration: mediaInfo.streamDuration, textTracks: textTracks, textTrackStyle: textTrackStyle, }; } export class CastButton extends CastButtonBase { createNativeView() { const button = new GCKUICastButton(); this.mCastContext = GCKCastContext.sharedInstance(); this.mCastContext.useDefaultExpandedMediaControls = true; this.mSessionManager = this.mCastContext.sessionManager; this.mSessionManagerListener = new SessionManagerListenerImpl(); this.mSessionManagerListener.owner = this; this.mRemoteMediaClientListener = new RemoteMediaClientListenerImpl(); this.mRemoteMediaClientListener.owner = this; this.mMediaQueueDelegate = new MediaQueueDelegate(); this.mMediaQueueDelegate.owner = this; this.addSessionManagerListener(); return button; } getNativeView() { return this.nativeView; } initNativeView() { this.nativeView.owner = this; super.initNativeView(); } disposeNativeView() { this.nativeView.owner = null; this.removeSessionManagerListener(); super.disposeNativeView(); } addSessionManagerListener() { this.mSessionManager.addListener(this.mSessionManagerListener); } removeSessionManagerListener() { this.mSessionManager.removeListener(this.mSessionManagerListener); } getRemoteMediaClient() { return this.mSessionManager.currentCastSession.remoteMediaClient; } buildMediaInfo(mediaInfo) { let metadata; if (mediaInfo.metadata) { const metadataType = metadataTypeStringToEnum(mediaInfo.metadata.metadataType); metadata = GCKMediaMetadata.alloc().initWithMetadataType(metadataType); Object.keys(mediaInfo.metadata).forEach(key => { if (CastButtonBase.validMetadataKeys.indexOf(key) > -1) { const fixedKey = METADATA_PREFIX + upperFirst(key); const value = mediaInfo.metadata[key]; metadata.setStringForKey(value, fixedKey); } }); if (mediaInfo.metadata.images && mediaInfo.metadata.images.length) { mediaInfo.metadata.images.forEach(img => { const uri = NSURL.URLWithString(img.url); metadata.addImage(GCKImage.alloc().initWithURLWidthHeight(uri, img.width, img.height)); }); } } let mediaTracks = null; if (mediaInfo.textTracks && mediaInfo.textTracks.length > 0) { mediaTracks = NSMutableArray.arrayWithCapacity(mediaInfo.textTracks.length); mediaInfo.textTracks.forEach((track, index) => { mediaTracks.addObject(GCKMediaTrack.alloc().initWithIdentifierContentIdentifierContentTypeTypeTextSubtypeNameLanguageCodeCustomData(index + 1, track.src, track.contentType, 1, 1, track.name, track.language, null)); }); } let textTrackStyle = null; if (mediaInfo.textTrackStyle) { textTrackStyle = GCKMediaTextTrackStyle.new(); textTrackStyle.foregroundColor = GCKColor.alloc().initWithCSSString(mediaInfo.textTrackStyle.foregroundColor); textTrackStyle.backgroundColor = GCKColor.alloc().initWithCSSString(mediaInfo.textTrackStyle.backgroundColor); textTrackStyle.edgeColor = GCKColor.alloc().initWithCSSString(mediaInfo.textTrackStyle.edgeColor); textTrackStyle.windowColor = GCKColor.alloc().initWithCSSString(mediaInfo.textTrackStyle.windowColor); textTrackStyle.fontFamily = mediaInfo.textTrackStyle.fontFamily; textTrackStyle.customData = mediaInfo.textTrackStyle.customData; } const streamType = typeof mediaInfo.streamType === 'string' ? streamTypeStringToEnum(mediaInfo.streamType) : mediaInfo.streamType; const mediaInformation = GCKMediaInformationBuilder.alloc().initWithContentID(mediaInfo.contentId); mediaInformation.contentType = mediaInfo.contentType; mediaInformation.customData = mediaInfo.customData; mediaInformation.mediaTracks = mediaTracks; mediaInformation.metadata = metadata; mediaInformation.startAbsoluteTime = mediaInfo.startAbsoluteTime; mediaInformation.streamDuration = mediaInfo.duration; mediaInformation.streamType = streamType; mediaInformation.textTrackStyle = textTrackStyle; return mediaInformation.build(); } buildQueueItem(options) { const builtMediaInfo = this.buildMediaInfo(options.mediaInformation); const builder = GCKMediaQueueItemBuilder.new(); builder.mediaInformation = builtMediaInfo; if (options) { builder.autoplay = options.autoplay || true; builder.customData = options.customData; builder.playbackDuration = options.playbackDuration || Infinity; builder.preloadTime = options.preloadTime; builder.startTime = options.startTime || 0; if (options.activeTrackIds && options.activeTrackIds.length) { builder.activeTrackIDs = NSArray.arrayWithArray(options.activeTrackIds); } } return builder.build(); } loadMedia(media, autoplay = true, position = 0) { const remoteMediaClient = this.getRemoteMediaClient(); remoteMediaClient.addListener(this.mRemoteMediaClientListener); const builtMediaInfo = this.buildMediaInfo(media); const requestData = GCKMediaLoadRequestDataBuilder.new(); requestData.mediaInformation = builtMediaInfo; requestData.autoplay = +autoplay; requestData.startTime = position; remoteMediaClient.loadMediaWithLoadRequestData(requestData.build()); } loadQueue(options) { const queueItems = []; options.items.forEach(item => { const queueItem = this.buildQueueItem(item); if (queueItem) { queueItems.push(queueItem); } else { console.log('queue item not built'); console.log(item); } }); const mediaQueueData = GCKMediaQueueDataBuilder.new(); if (options) { mediaQueueData.queueID = options.queueID; mediaQueueData.name = options.name; mediaQueueData.queueType = queueTypeStringToEnum(options.queueType); mediaQueueData.startIndex = options.startIndex || 0; mediaQueueData.startTime = options.startTime || 0; if (options.repeatMode) { mediaQueueData.repeatMode = repeatModeStringToEnum(options.repeatMode); } } mediaQueueData.items = NSArray.arrayWithArray(queueItems); const remoteMediaClient = this.getRemoteMediaClient(); remoteMediaClient.addListener(this.mRemoteMediaClientListener); this.mMediaQueue = GCKMediaQueue.alloc().initWithRemoteMediaClient(remoteMediaClient); this.mMediaQueue.addDelegate(this.mMediaQueueDelegate); this.mCastContext.defaultExpandedMediaControlsViewController.setButtonTypeAtIndex(3, 1); this.mCastContext.defaultExpandedMediaControlsViewController.setButtonTypeAtIndex(2, 2); const requestData = GCKMediaLoadRequestDataBuilder.new(); requestData.queueData = mediaQueueData.build(); remoteMediaClient.loadMediaWithLoadRequestData(requestData.build()); } showController() { this.mCastContext.presentDefaultExpandedMediaControls(); } showCastInstructions() { this.mCastContext.presentCastInstructionsViewControllerOnceWithCastButton(this.nativeView); } showCastDialog() { this.mCastContext.presentCastDialog(); } getMediaInfo() { const remoteMediaClient = this.getRemoteMediaClient(); if (!remoteMediaClient) { return {}; } const mediaInfo = remoteMediaClient.mediaStatus.mediaInformation; return convertMediaInfo(mediaInfo); } pauseMedia(customData) { this.getRemoteMediaClient().pauseWithCustomData(customData); } playMedia(customData) { this.getRemoteMediaClient().playWithCustomData(customData); } seekMedia(position, resumeState, customData) { this.getRemoteMediaClient().seekToTimeIntervalResumeStateCustomData(position, resumeStateStringToEnum(resumeState), customData); } stopMedia(customData) { this.getRemoteMediaClient().stopWithCustomData(customData); } setActiveTrackIds(trackIds) { this.getRemoteMediaClient().setActiveTrackIDs(trackIds); } setTintColor(color) { const mRouteButton = this.getNativeView(); mRouteButton.tintColor = new Color(color).ios; } setVolume(volume, customData) { const remoteMediaClient = this.getRemoteMediaClient(); remoteMediaClient.setStreamVolumeCustomData(volume, customData); } setMuted(muted, customData) { const remoteMediaClient = this.getRemoteMediaClient(); remoteMediaClient.setStreamMutedCustomData(muted, customData); } queueNextItem() { this.getRemoteMediaClient().queueNextItem(); } queuePreviousItem() { this.getRemoteMediaClient().queuePreviousItem(); } queueSetRepeatMode(repeatMode) { this.getRemoteMediaClient().queueSetRepeatMode(repeatModeStringToEnum(repeatMode)); } queueFetchItemIDs() { console.log('queueFetchItemIDs not implemented'); } queueFetchItemAtIndex(index) { console.log('queueFetchItemAtIndex not implemented'); } queueInsertItem(options) { const queueItem = this.buildQueueItem(options.item); if (options.play) { this.getRemoteMediaClient().queueInsertAndPlayItemBeforeItemWithIDPlayPositionCustomData(queueItem, options.beforeItemID || kGCKMediaQueueInvalidItemID, options.playPosition || 0, options.customData); } else { this.getRemoteMediaClient().queueInsertItemBeforeItemWithID(queueItem, options.beforeItemID || kGCKMediaQueueInvalidItemID); } } queueInsertItems(options) { const queueItems = []; options.items.forEach(item => { const queueItem = this.buildQueueItem(item); queueItems.push(queueItem); }); this.getRemoteMediaClient().queueInsertItemsBeforeItemWithIDCustomData(queueItems, options.beforeItemID || kGCKMediaQueueInvalidItemID, options.customData); } queueRemoveItems(itemIDs, customData) { this.getRemoteMediaClient().queueRemoveItemsWithIDsCustomData(itemIDs, customData); } queueReorderItems(itemIDs, beforeItemID, customData) { this.getRemoteMediaClient().queueReorderItemsWithIDsInsertBeforeItemWithIDCustomData(itemIDs, beforeItemID || kGCKMediaQueueInvalidItemID, customData); } queueJumpToItem(itemID, playPosition, customData) { this.getRemoteMediaClient().queueJumpToItemWithIDPlayPositionCustomData(itemID, playPosition, customData); } queueUpdateItems(options) { console.log('queueUpdateItems not implemented'); } } //# sourceMappingURL=cast.ios.js.map