package org.red5.server.stream;
/*
* RED5 Open Source Flash Server - http://www.osflash.org/red5
*
* Copyright (c) 2006-2009 by respective authors (see below). All rights reserved.
*
* This library 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 library 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 library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.red5.io.IStreamableFileFactory;
import org.red5.io.IStreamableFileService;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.IBasicScope;
import org.red5.server.api.IScope;
import org.red5.server.api.ScopeUtils;
import org.red5.server.api.stream.IBroadcastStream;
import org.red5.server.api.stream.IStreamFilenameGenerator;
import org.red5.server.api.stream.IStreamFilenameGenerator.GenerationType;
import org.red5.server.messaging.IMessageInput;
import org.red5.server.messaging.IPipe;
import org.red5.server.messaging.InMemoryPullPullPipe;
import org.red5.server.stream.provider.FileProvider;
import org.slf4j.Logger;
public class ProviderService implements IProviderService {
private static final Logger log = Red5LoggerFactory.getLogger(ProviderService.class);
/** {@inheritDoc} */
public INPUT_TYPE lookupProviderInput(IScope scope, String name) {
INPUT_TYPE result = INPUT_TYPE.NOT_FOUND;
if (scope.getBasicScope(IBroadcastScope.TYPE, name) != null) {
//we have live input
result = INPUT_TYPE.LIVE;
} else {
try {
File file = getStreamFile(scope, name);
if (file != null) {
//we have vod input
result = INPUT_TYPE.VOD;
//null it to prevent leak or file locking
file = null;
}
} catch (IOException e) {
log.warn("Exception attempting to lookup file: {}", name, e);
e.printStackTrace();
}
}
return result;
}
/** {@inheritDoc} */
public IMessageInput getProviderInput(IScope scope, String name) {
IMessageInput msgIn = getLiveProviderInput(scope, name, false);
if (msgIn == null) {
return getVODProviderInput(scope, name);
}
return msgIn;
}
/** {@inheritDoc} */
public IMessageInput getLiveProviderInput(IScope scope, String name,
boolean needCreate) {
IBasicScope basicScope;
basicScope = scope.getBasicScope(IBroadcastScope.TYPE, name);
if (basicScope == null) {
if (needCreate) {
synchronized (scope) {
// Re-check if another thread already created the scope
basicScope = scope
.getBasicScope(IBroadcastScope.TYPE, name);
if (basicScope == null) {
basicScope = new BroadcastScope(scope, name);
scope.addChildScope(basicScope);
}
}
} else {
return null;
}
}
if (!(basicScope instanceof IBroadcastScope)) {
return null;
}
return (IBroadcastScope) basicScope;
}
/** {@inheritDoc} */
public IMessageInput getVODProviderInput(IScope scope, String name) {
log.debug("getVODProviderInput - scope: {} name: {}", scope, name);
File file = getVODProviderFile(scope, name);
if (file == null) {
return null;
}
IPipe pipe = new InMemoryPullPullPipe();
pipe.subscribe(new FileProvider(scope, file), null);
return pipe;
}
/** {@inheritDoc} */
public File getVODProviderFile(IScope scope, String name) {
log.debug("getVODProviderFile - scope: {} name: {}", scope, name);
File file = null;
try {
log.debug("getVODProviderFile scope path: {} name: {}", scope.getContextPath(), name);
file = getStreamFile(scope, name);
} catch (IOException e) {
log.error("Problem getting file: {}", name, e);
}
if (file == null || !file.exists()) {
//if there is no file extension this is most likely a live stream
if (name.indexOf('.') > 0) {
log.info("File was null or did not exist: {}", name);
} else {
log.debug("VOD file {} was not found, may be live stream", name);
}
return null;
}
return file;
}
/** {@inheritDoc} */
public boolean registerBroadcastStream(IScope scope, String name,
IBroadcastStream bs) {
boolean status = false;
synchronized (scope) {
IBasicScope basicScope = scope.getBasicScope(IBroadcastScope.TYPE,
name);
if (basicScope == null) {
basicScope = new BroadcastScope(scope, name);
scope.addChildScope(basicScope);
}
if (basicScope instanceof IBroadcastScope) {
((IBroadcastScope) basicScope)
.subscribe(bs.getProvider(), null);
status = true;
}
}
return status;
}
/** {@inheritDoc} */
public List<String> getBroadcastStreamNames(IScope scope) {
// TODO: return result of "getBasicScopeNames" when the api has
// changed to not return iterators
List<String> result = new ArrayList<String>();
Iterator<String> it = scope.getBasicScopeNames(IBroadcastScope.TYPE);
while (it.hasNext()) {
result.add(it.next());
}
it = null;
return result;
}
/** {@inheritDoc} */
public boolean unregisterBroadcastStream(IScope scope, String name) {
boolean status = false;
synchronized (scope) {
IBasicScope basicScope = scope.getBasicScope(IBroadcastScope.TYPE,
name);
if (basicScope instanceof IBroadcastScope) {
scope.removeChildScope(basicScope);
status = true;
}
}
return status;
}
private File getStreamFile(IScope scope, String name) throws IOException {
IStreamableFileFactory factory = (IStreamableFileFactory) ScopeUtils
.getScopeService(scope, IStreamableFileFactory.class);
if (name.indexOf(':') == -1 && name.indexOf('.') == -1) {
// Default to .flv files if no prefix and no extension is given.
name = "flv:" + name;
}
log.debug("getStreamFile null check - factory: {} name: {}", factory, name);
for (IStreamableFileService service : factory.getServices()) {
if (name.startsWith(service.getPrefix() + ':')) {
name = service.prepareFilename(name);
break;
}
}
IStreamFilenameGenerator filenameGenerator = (IStreamFilenameGenerator) ScopeUtils
.getScopeService(scope, IStreamFilenameGenerator.class,
DefaultStreamFilenameGenerator.class);
String filename = filenameGenerator.generateFilename(scope, name,
GenerationType.PLAYBACK);
File file;
if (filenameGenerator.resolvesToAbsolutePath()) {
file = new File(filename);
} else {
file = scope.getContext().getResource(filename).getFile();
}
//check files existence
if (file != null && !file.exists()) {
//if it does not exist then null it out
file = null;
}
return file;
}
}