Skip to content

Commit

Permalink
Add Bonjour service discovery module
Browse files Browse the repository at this point in the history
  • Loading branch information
fkuehne committed Feb 9, 2016
1 parent b31a171 commit 1baae63
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 0 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ Muxers:
Service Discovery:
* New NetBios service discovery using libdsm
* New mDNS services discovery using libmicrodns
* New mDNS services discovery using Bonjour (Mac OS X, tvOS, iOS)
* Rewrite of the UPnP service discovery

Mac OS X Interface
Expand Down
1 change: 1 addition & 0 deletions modules/MODULES_LIST
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ $Id$
* avio: Access and Stream output module using libavformat network
* ball: Augmented reality ball video filter module
* bandlimited_resampler: Bandlimited interpolation audio resampler
* bonjour: mDNS services discovery module based on Bonjour
* blend: a picture filter that blends two pictures
* blendbench: a picture filter that test performance of blending routines
* bluescreen: Bluescreen (weather channel like) video filter
Expand Down
6 changes: 6 additions & 0 deletions modules/services_discovery/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,9 @@ libmicrodns_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)'
sd_LTLIBRARIES += $(LTLIBmicrodns)
EXTRA_LTLIBRARIES += libmicrodns_plugin.la

libbonjour_plugin_la_SOURCES = services_discovery/bonjour.m
libbonjour_plugin_la_OBJCFLAGS = $(AM_CFLAGS) -fobjc-arc
libbonjour_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(sddir)' -Wl,-framework,Foundation
if HAVE_DARWIN
sd_LTLIBRARIES += libbonjour_plugin.la
endif
242 changes: 242 additions & 0 deletions modules/services_discovery/bonjour.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
/*****************************************************************************
* bonjour.m: mDNS services discovery module based on Bonjour
*****************************************************************************
* Copyright (C) 2016 VLC authors, VideoLAN and VideoLabs
*
* Authors: Felix Paul Kühne <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_modules.h>
#include <vlc_services_discovery.h>

#import <Foundation/Foundation.h>

static int Open( vlc_object_t * );
static void Close( vlc_object_t * );

VLC_SD_PROBE_HELPER( "Bonjour", "Bonjour Network Discovery", SD_CAT_LAN )

/*
* Module descriptor
*/
vlc_module_begin()
set_shortname( "bonjour" )
set_description( N_( "Bonjour Network Discovery" ) )
set_category( CAT_PLAYLIST )
set_subcategory( SUBCAT_PLAYLIST_SD )
set_capability( "services_discovery", 0 )
set_callbacks( Open, Close )
VLC_SD_PROBE_SUBMODULE
vlc_module_end ()

NSString *const VLCBonjourProtocolName = @"VLCBonjourProtocolName";
NSString *const VLCBonjourProtocolServiceName = @"VLCBonjourProtocolServiceName";

@interface VLCNetServiceDiscoveryController : NSObject <NSNetServiceBrowserDelegate, NSNetServiceDelegate>
{
NSArray<NSNetServiceBrowser *> *_serviceBrowsers;

NSMutableArray<NSNetService *> *_rawNetServices;
NSMutableArray<NSNetService *> *_resolvedNetServices;
NSMutableArray<NSValue *> *_inputItemsForNetServices;

NSArray *_activeProtocols;
}

@property (readwrite, nonatomic) services_discovery_t *p_sd;

- (void)startDiscovery;
- (void)stopDiscovery;

@end

struct services_discovery_sys_t
{
CFTypeRef _Nullable discoveryController;
};

@implementation VLCNetServiceDiscoveryController

- (void)startDiscovery
{
_rawNetServices = [[NSMutableArray alloc] init];
_resolvedNetServices = [[NSMutableArray alloc] init];
_inputItemsForNetServices = [[NSMutableArray alloc] init];

NSDictionary *VLCFtpProtocol = @{ VLCBonjourProtocolName : @"ftp",
VLCBonjourProtocolServiceName : @"_ftp._tcp." };
NSDictionary *VLCSmbProtocol = @{ VLCBonjourProtocolName : @"smb",
VLCBonjourProtocolServiceName : @"_smb._tcp." };
NSDictionary *VLCNfsProtocol = @{ VLCBonjourProtocolName : @"nfs",
VLCBonjourProtocolServiceName : @"_nfs._tcp." };
NSDictionary *VLCSftpProtocol = @{ VLCBonjourProtocolName : @"sftp",
VLCBonjourProtocolServiceName : @"_sftp-ssh._tcp." };

NSArray *VLCSupportedProtocols = @[VLCFtpProtocol,
VLCSmbProtocol,
VLCNfsProtocol,
VLCSftpProtocol];

NSUInteger count = VLCSupportedProtocols.count;
NSMutableArray *discoverers = [[NSMutableArray alloc] init];
NSMutableArray *protocols = [[NSMutableArray alloc] init];

for (NSUInteger i = 0; i < count; i++) {
NSDictionary *protocol = VLCSupportedProtocols[i];

/* only discover hosts if we actually have a module that can handle those */
if (!module_exists([protocol[VLCBonjourProtocolName] UTF8String]))
continue;

NSNetServiceBrowser *serviceBrowser = [[NSNetServiceBrowser alloc] init];
serviceBrowser.delegate = self;
[serviceBrowser searchForServicesOfType:protocol[VLCBonjourProtocolServiceName] inDomain:@"local."];
[discoverers addObject:serviceBrowser];
[protocols addObject:protocol];
}

_serviceBrowsers = [discoverers copy];
_activeProtocols = [protocols copy];
}

- (void)stopDiscovery
{
[_serviceBrowsers makeObjectsPerformSelector:@selector(stop)];

NSUInteger inputItemCount = _inputItemsForNetServices.count;
for (NSUInteger i = 0; i < inputItemCount; i++) {
input_item_t *p_input_item = [_inputItemsForNetServices[i] pointerValue];
if (p_input_item != NULL) {
services_discovery_RemoveItem(self.p_sd, p_input_item);
input_item_Release(p_input_item);
}
}

[_inputItemsForNetServices removeAllObjects];
[_resolvedNetServices removeAllObjects];
}

#pragma mark - functional delegation

- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
{
msg_Dbg(self.p_sd, "found bonjour service: %s (%s)", [aNetService.name UTF8String], [aNetService.type UTF8String]);
[_rawNetServices addObject:aNetService];
aNetService.delegate = self;
[aNetService resolveWithTimeout:5.];
}

- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing
{
msg_Dbg(self.p_sd, "bonjour service disappeared: %s", [aNetService.name UTF8String]);
if ([_rawNetServices containsObject:aNetService])
[_rawNetServices removeObject:aNetService];

if ([_resolvedNetServices containsObject:aNetService]) {
NSInteger index = [_resolvedNetServices indexOfObject:aNetService];
if (index == NSNotFound)
return;

[_resolvedNetServices removeObjectAtIndex:index];
input_item_t *p_input_item = [_inputItemsForNetServices[index] pointerValue];
if (p_input_item != NULL) {
services_discovery_RemoveItem(self.p_sd, p_input_item);
input_item_Release(p_input_item);
}
}
}

- (void)netServiceDidResolveAddress:(NSNetService *)aNetService
{
if (![_resolvedNetServices containsObject:aNetService]) {
NSString *serviceType = aNetService.type;
NSUInteger count = _activeProtocols.count;
NSString *protocol = nil;
for (NSUInteger i = 0; i < count; i++) {
NSDictionary *protocolDefinition = _activeProtocols[i];
if ([serviceType isEqualToString:protocolDefinition[VLCBonjourProtocolServiceName]]) {
protocol = protocolDefinition[VLCBonjourProtocolName];
}
}

NSString *uri = [NSString stringWithFormat:@"%@://%@:%ld",
protocol,
aNetService.hostName,
aNetService.port];

input_item_t *p_input_item = input_item_NewWithTypeExt([uri UTF8String],
[aNetService.name UTF8String],
0, NULL, 0, -1,
ITEM_TYPE_NODE, true );

if (p_input_item != NULL) {
services_discovery_AddItem(self.p_sd, p_input_item, NULL);
[_inputItemsForNetServices addObject:[NSValue valueWithPointer:p_input_item]];
[_resolvedNetServices addObject:aNetService];
}
}

[_rawNetServices removeObject:aNetService];
}

- (void)netService:(NSNetService *)aNetService didNotResolve:(NSDictionary *)errorDict
{
msg_Dbg(self.p_sd, "failed to resolve: %s", [aNetService.name UTF8String]);
[_rawNetServices removeObject:aNetService];
}

@end

static int Open(vlc_object_t *p_this)
{
services_discovery_t *p_sd = (services_discovery_t *)p_this;
services_discovery_sys_t *p_sys = NULL;

p_sd->p_sys = p_sys = calloc(1, sizeof(services_discovery_sys_t));
if (!p_sys) {
return VLC_ENOMEM;
}

VLCNetServiceDiscoveryController *discoveryController = [[VLCNetServiceDiscoveryController alloc] init];
discoveryController.p_sd = p_sd;

p_sys->discoveryController = CFBridgingRetain(discoveryController);

[discoveryController startDiscovery];

return VLC_SUCCESS;
}

static void Close(vlc_object_t *p_this)
{
services_discovery_t *p_sd = (services_discovery_t *)p_this;
services_discovery_sys_t *p_sys = p_sd->p_sys;

VLCNetServiceDiscoveryController *discoveryController = (__bridge VLCNetServiceDiscoveryController *)(p_sys->discoveryController);
[discoveryController stopDiscovery];

CFBridgingRelease(p_sys->discoveryController);
discoveryController = nil;

free(p_sys);
}
1 change: 1 addition & 0 deletions po/POTFILES.in
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ modules/packetizer/mpeg4video.c
modules/packetizer/mpegvideo.c
modules/packetizer/vc1.c
modules/services_discovery/avahi.c
modules/services_discovery/bonjour.m
modules/services_discovery/mediadirs.c
modules/services_discovery/mtp.c
modules/services_discovery/os2drive.c
Expand Down

0 comments on commit 1baae63

Please sign in to comment.