Commit c3ecab6f authored by Felix Paul Kühne's avatar Felix Paul Kühne

VLCHTTPConnection: Add WebSocket to allow remote playback control

parent e3a50388
/*****************************************************************************
* VLCPlayerControlWebSocket.h
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Felix Paul Kühne <fkuehne # videolan.org>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "WebSocket.h"
@interface VLCPlayerControlWebSocket : WebSocket
@end
/*****************************************************************************
* VLCPlayerControlWebSocket.m
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Felix Paul Kühne <fkuehne # videolan.org>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCPlayerControlWebSocket.h"
@implementation VLCPlayerControlWebSocket
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)didOpen
{
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(playbackStarted)
name:VLCPlaybackControllerPlaybackDidStart
object:nil];
[notificationCenter addObserver:self
selector:@selector(playbackStarted)
name:VLCPlaybackControllerPlaybackDidResume
object:nil];
[notificationCenter addObserver:self
selector:@selector(_respondToPlaying)
name:VLCPlaybackControllerPlaybackMetadataDidChange
object:nil];
[notificationCenter addObserver:self
selector:@selector(playbackPaused)
name:VLCPlaybackControllerPlaybackDidPause
object:nil];
[notificationCenter addObserver:self
selector:@selector(playbackEnded)
name:VLCPlaybackControllerPlaybackDidStop
object:nil];
[notificationCenter addObserver:self
selector:@selector(playbackEnded)
name:VLCPlaybackControllerPlaybackDidFail
object:nil];
[notificationCenter addObserver:self
selector:@selector(playbackSeekTo)
name:VLCPlaybackControllerPlaybackPositionUpdated
object:nil];
APLog(@"web socket did open");
[super didOpen];
}
- (void)didReceiveMessage:(NSString *)msg
{
APLog(@"web socket received message: '%@'", msg);
if ([msg isEqualToString:@"playing"]) {
[self _respondToPlaying];
} else if ([msg isEqualToString:@"play"]) {
[self _respondToPlay];
} else if ([msg isEqualToString:@"pause"]) {
[self _respondToPause];
} else if ([msg isEqualToString:@"ended"]) {
[self _respondToEnded];
} else if ([msg isEqualToString:@"seekTo"]) {
[self _respondToSeek];
} else if ([msg isEqualToString:@"volume"]) {
[self sendMessage:@"VOLUME CONTROL NOT SUPPORTED ON THIS DEVICE"];
} else
[self sendMessage:@"INVALID REQUEST!"];
}
#ifndef NDEBUG
- (void)didClose
{
APLog(@"web socket did close");
[super didClose];
}
#endif
- (void)_respondToPlaying
{
/* JSON response
{
"type": "playing",
"currentTime": 42,
"media": {
"id": "some id",
"title": "some title",
"duration": 120000
}
}
*/
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
NSDictionary *returnDict;
if (vpc.activePlaybackSession) {
VLCMediaPlayer *player = vpc.mediaPlayer;
if (player) {
VLCMedia *media = player.media;
if (media) {
NSString *mediaTitle = vpc.mediaTitle;
if (!mediaTitle)
mediaTitle = @"";
NSDictionary *mediaDict = @{ @"id" : media.url.absoluteString,
@"title" : mediaTitle,
@"duration" : @(media.length.intValue)};
returnDict = @{ @"currentTime" : @(player.time.intValue),
@"type" : @"playing",
@"media" : mediaDict };
}
}
}
if (!returnDict) {
returnDict = [NSDictionary dictionary];
}
NSError *error;
NSData *returnData = [NSJSONSerialization dataWithJSONObject:returnDict options:0 error:&error];
if (error != nil) {
APLog(@"%s: JSON serialization failed %@", __PRETTY_FUNCTION__, error);
}
[self sendData:returnData];
}
#pragma mark - play
- (void)_respondToPlay
{
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
VLCMediaListPlayer *listPlayer = vpc.listPlayer;
if (listPlayer) {
[listPlayer play];
}
}
- (void)playbackStarted
{
/*
{
"type": "play",
"currentTime": 42,
"media": {
"id": 42
}
}
*/
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
VLCMediaPlayer *player = vpc.mediaPlayer;
if (player) {
VLCMedia *media = player.media;
if (media) {
NSDictionary *mediaDict = @{ @"id" : media.url.absoluteString};
NSDictionary *returnDict = @{ @"currentTime" : @(player.time.intValue),
@"type" : @"play",
@"media" : mediaDict };
NSError *error;
NSData *returnData = [NSJSONSerialization dataWithJSONObject:returnDict options:0 error:&error];
if (error != nil) {
APLog(@"%s: JSON serialization failed %@", __PRETTY_FUNCTION__, error);
}
[self sendData:returnData];
}
}
}
#pragma mark - pause
- (void)_respondToPause
{
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
VLCMediaListPlayer *listPlayer = vpc.listPlayer;
if (listPlayer) {
[listPlayer pause];
}
}
- (void)playbackPaused
{
/*
{
"type": "pause",
"currentTime": 42,
"media": {
"id": 42
}
}
*/
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
VLCMediaPlayer *player = vpc.mediaPlayer;
if (player) {
VLCMedia *media = player.media;
if (media) {
NSDictionary *mediaDict = @{ @"id" : media.url.absoluteString};
NSDictionary *returnDict = @{ @"currentTime" : @(player.time.intValue),
@"type" : @"pause",
@"media" : mediaDict };
NSError *error;
NSData *returnData = [NSJSONSerialization dataWithJSONObject:returnDict options:0 error:&error];
if (error != nil) {
APLog(@"%s: JSON serialization failed %@", __PRETTY_FUNCTION__, error);
}
[self sendData:returnData];
}
}
}
#pragma mark - ended
- (void)_respondToEnded
{
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
[vpc stopPlayback];
}
- (void)playbackEnded
{
/*
{
"type": "ended",
"media": {
"id": 42
}
}
*/
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
VLCMediaPlayer *player = vpc.mediaPlayer;
if (player) {
VLCMedia *media = player.media;
if (media) {
NSDictionary *mediaDict = @{ @"id" : media.url.absoluteString};
NSDictionary *returnDict = @{ @"type" : @"ended",
@"media" : mediaDict };
NSError *error;
NSData *returnData = [NSJSONSerialization dataWithJSONObject:returnDict options:0 error:&error];
if (error != nil) {
APLog(@"%s: JSON serialization failed %@", __PRETTY_FUNCTION__, error);
}
[self sendData:returnData];
}
}
}
#pragma mark - seek
- (void)_respondToSeek
{
[self sendMessage:@"VOLUME CONTROL NOT SUPPORTED ON THIS DEVICE"];
}
- (void)playbackSeekTo
{
/*
{
"type": "seekTo",
"currentTime": 42,
"media": {
"id": 42
}
}
*/
VLCPlaybackController *vpc = [VLCPlaybackController sharedInstance];
VLCMediaPlayer *player = vpc.mediaPlayer;
if (player) {
VLCMedia *media = player.media;
if (media) {
NSDictionary *mediaDict = @{ @"id" : media.url.absoluteString};
NSDictionary *returnDict = @{ @"currentTime" : @(player.time.intValue),
@"type" : @"seekTo",
@"media" : mediaDict };
NSError *error;
NSData *returnData = [NSJSONSerialization dataWithJSONObject:returnDict options:0 error:&error];
if (error != nil) {
APLog(@"%s: JSON serialization failed %@", __PRETTY_FUNCTION__, error);
}
[self sendData:returnData];
}
}
}
@end
......@@ -29,6 +29,9 @@
#if TARGET_OS_IOS
#import "VLCThumbnailsCache.h"
#endif
#if TARGET_OS_TV
#import "VLCPlayerControlWebSocket.h"
#endif
@interface VLCHTTPConnection()
{
......@@ -548,6 +551,13 @@
return [super httpResponseForMethod:method URI:path];
}
#if TARGET_OS_TV
- (WebSocket *)webSocketForURI:(NSString *)path
{
return [[VLCPlayerControlWebSocket alloc] initWithRequest:request socket:asyncSocket];
}
#endif
- (void)prepareForBodyWithSize:(UInt64)contentLength
{
// set up mime parser
......
......@@ -19,6 +19,7 @@ extern NSString *const VLCPlaybackControllerPlaybackDidResume;
extern NSString *const VLCPlaybackControllerPlaybackDidStop;
extern NSString *const VLCPlaybackControllerPlaybackDidFail;
extern NSString *const VLCPlaybackControllerPlaybackMetadataDidChange;
extern NSString *const VLCPlaybackControllerPlaybackPositionUpdated;
@class VLCPlaybackController;
......
......@@ -36,6 +36,7 @@ NSString *const VLCPlaybackControllerPlaybackDidResume = @"VLCPlaybackController
NSString *const VLCPlaybackControllerPlaybackDidStop = @"VLCPlaybackControllerPlaybackDidStop";
NSString *const VLCPlaybackControllerPlaybackMetadataDidChange = @"VLCPlaybackControllerPlaybackMetadataDidChange";
NSString *const VLCPlaybackControllerPlaybackDidFail = @"VLCPlaybackControllerPlaybackDidFail";
NSString *const VLCPlaybackControllerPlaybackPositionUpdated = @"VLCPlaybackControllerPlaybackPositionUpdated";
@interface VLCPlaybackController () <VLCMediaPlayerDelegate, VLCMediaDelegate>
{
......@@ -483,6 +484,9 @@ NSString *const VLCPlaybackControllerPlaybackDidFail = @"VLCPlaybackControllerPl
if ([self.delegate respondsToSelector:@selector(playbackPositionUpdated:)])
[self.delegate playbackPositionUpdated:self];
[[NSNotificationCenter defaultCenter] postNotificationName:VLCPlaybackControllerPlaybackPositionUpdated
object:self];
}
- (NSInteger)mediaDuration
......
......@@ -216,6 +216,7 @@
7DF28AE11BA31C580030C944 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DF28AE01BA31C580030C944 /* libc++.tbd */; };
7DF383AC1BF206F100D71A5C /* VLCRemoteBrowsingCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF383AB1BF206F100D71A5C /* VLCRemoteBrowsingCollectionViewController.m */; };
7DF383AE1BF206FB00D71A5C /* VLCRemoteBrowsingCollectionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7DF383AD1BF206FB00D71A5C /* VLCRemoteBrowsingCollectionViewController.xib */; };
7DF383B91BF21E4400D71A5C /* VLCPlayerControlWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF383B81BF21E4400D71A5C /* VLCPlayerControlWebSocket.m */; };
7DF7CA0717650C2A00C61739 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DF7CA0617650C2A00C61739 /* AVFoundation.framework */; };
7DF7E791175F47DC0018858D /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7DF7E790175F47DC0018858D /* MediaPlayer.framework */; };
7DF90B441BE7A5380059C0E3 /* VLCSettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DF90B431BE7A5380059C0E3 /* VLCSettingsTableViewController.m */; };
......@@ -799,6 +800,8 @@
7DF383AA1BF206F100D71A5C /* VLCRemoteBrowsingCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCRemoteBrowsingCollectionViewController.h; sourceTree = "<group>"; };
7DF383AB1BF206F100D71A5C /* VLCRemoteBrowsingCollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCRemoteBrowsingCollectionViewController.m; sourceTree = "<group>"; };
7DF383AD1BF206FB00D71A5C /* VLCRemoteBrowsingCollectionViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = VLCRemoteBrowsingCollectionViewController.xib; sourceTree = "<group>"; };
7DF383B71BF21E4400D71A5C /* VLCPlayerControlWebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCPlayerControlWebSocket.h; path = SharedSources/VLCPlayerControlWebSocket.h; sourceTree = SOURCE_ROOT; };
7DF383B81BF21E4400D71A5C /* VLCPlayerControlWebSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCPlayerControlWebSocket.m; path = SharedSources/VLCPlayerControlWebSocket.m; sourceTree = SOURCE_ROOT; };
7DF7CA0617650C2A00C61739 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
7DF7E790175F47DC0018858D /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; };
7DF90B421BE7A5380059C0E3 /* VLCSettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCSettingsTableViewController.h; sourceTree = "<group>"; };
......@@ -1371,6 +1374,8 @@
7D30F3BF183AB24C00FFC021 /* VLCHTTPFileDownloader.m */,
7D30F3C0183AB24C00FFC021 /* VLCHTTPUploaderController.h */,
7D30F3C1183AB24C00FFC021 /* VLCHTTPUploaderController.m */,
7DF383B71BF21E4400D71A5C /* VLCPlayerControlWebSocket.h */,
7DF383B81BF21E4400D71A5C /* VLCPlayerControlWebSocket.m */,
);
name = "HTTP Connectivity";
path = ../AspenProject;
......@@ -2658,6 +2663,7 @@
7DEC8BDA1BD67112006E1093 /* VLCFrostedGlasView.m in Sources */,
DD8095EB1BE4F04E0065D8E1 /* VLCPlaybackInfoRateTVViewController.m in Sources */,
DD3EAC051BE153B4003668DA /* VLCNetworkImageView.m in Sources */,
7DF383B91BF21E4400D71A5C /* VLCPlayerControlWebSocket.m in Sources */,
7D0C35341BD97C7B0058CD19 /* VLCOneDriveObject.m in Sources */,
7D0C35331BD97C100058CD19 /* VLCOneDriveController.m in Sources */,
7D0EDE061BE774BF00363AA1 /* WhiteRaccoon.m in Sources */,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment