Local - Wowza Streaming Engine 4.1.0, Windows 8, Java version 1.7.0_67
Server - The Wowza Streaming Engine AMI here. Java version 1.7.0_65
I have Wowza running locally and on an EC2 instance.
Locally it works fine and I can connect and publish streams to my application without a problem. I cannot connect or publish streams to the application on my server, however.
I removed the .jar (module) that went with the application, and I was able to connect and publish to my app, though it gave me a warning that it couldn't find the associated module, which was to be expected.
I put the module back in, restarted the server, and I was unable to connect.
It appears that my .jar file is stopping the application from loading for some reason.
Here's the source for my module:
package com.xxxxxxxxxxxxxxx.recorder;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.S3ClientOptions;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.wowza.wms.application.*;
import com.wowza.wms.amf.*;
import com.wowza.wms.client.*;
import com.wowza.wms.module.*;
import com.wowza.wms.request.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.rtp.model.*;
import com.wowza.wms.httpstreamer.model.*;
import com.wowza.wms.httpstreamer.cupertinostreaming.httpstreamer.*;
import com.wowza.wms.httpstreamer.smoothstreaming.httpstreamer.*;
public class RecorderModules extends ModuleBase implements AWSCredentialsProvider {
IApplicationInstance appInstance;
private String videoBucket;
private String thumbBucket;
private String videoDistro;
private String thumbnailDistro;
private String region;
private AmazonS3Client s3;
private String dir;
public void onAppStart(IApplicationInstance appInstance) {
String fullname = appInstance.getApplication().getName() + "/"
+ appInstance.getName();
getLogger().info("onAppStart: " + fullname);
this.appInstance = appInstance;
try{
videoBucket = appInstance.getProperties().getPropertyStr("videoBucket");
getLogger().info("Video bucket is " + videoBucket);
thumbBucket = appInstance.getProperties().getPropertyStr("thumbBucket");
getLogger().info("Thumb bucket is " + thumbBucket);
videoDistro = appInstance.getProperties().getPropertyStr("videoDistro");
getLogger().info("Video distro is " + videoDistro);
thumbnailDistro =appInstance.getProperties().getPropertyStr("thumbnailDistro");
getLogger().info("thumbnail distro is " + thumbnailDistro);
region = appInstance.getProperties().getPropertyStr("region");
getLogger().info("region is " + region);
s3 = new AmazonS3Client();
s3.setEndpoint(region);
getLogger().info("AmazonS3Client is created");
}catch(Exception e){
getLogger().info("Could not read config " + e);
}
}
public void doSave(IClient client, RequestFunction function, AMFDataList params) {
getLogger().info("doSave hit ");
new File(dir + params.getString(3) + ".flv").renameTo(new File(dir+params.getString(4)+".flv"));
getLogger().info("Starting upload");
String thumbName = params.getString(4).replace("vid_", "thumb_")+".jpg";
String flvName = params.getString(4)+".flv";
String mp4Name = params.getString(4)+".mp4";
try{
PutObjectRequest p = new PutObjectRequest(videoBucket,flvName, new File(dir+flvName));
p.setRequestCredentials(getCredentials());
p.setCannedAcl(CannedAccessControlList.BucketOwnerFullControl);
getLogger().info("attempting to upload " + flvName + " to " + videoBucket);
s3.putObject(p);
getLogger().info("flv upload complete " + videoBucket + " " + flvName);
PutObjectRequest p2 = new PutObjectRequest(thumbBucket,thumbName, new File(dir+thumbName));
p2.setRequestCredentials(getCredentials());
p2.setCannedAcl(CannedAccessControlList.PublicRead);
getLogger().info("attempting to upload " + thumbName + " to " + thumbBucket);
s3.putObject(p2);
getLogger().info("thumb upload complete " + thumbBucket + " " + thumbName);
String[] info = new String[5];
info[0] = videoDistro+params.getString(4);
info[1] = thumbnailDistro+thumbName;
info[2] = params.getString(4);
info[3] = videoBucket;
info[4] = thumbBucket;
getLogger().info("sending info to client " + info[0]);
//client.call("uploadDone", null,(Object[])info);
}catch(Exception e){
getLogger().info("Upload failed");
getLogger().info(e);
//client.call("uploadFailed")
}
//transcode
//-crf 23 -refs 3 -profile:v baseline -level 3.0 -pix_fmt yuv420p -preset veryslow
String[] command = {"ffmpeg",
"-i", dir+params.getString(4)+".flv",
"-crf", "23",
"-refs","3",
"-profile:v","baseline",
"-level","3.0",
"-pix_fmt","yuv420p",
"-preset","veryslow",
dir+params.getString(4)+".mp4"};
try {
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
getLogger().info("Starting process");
Process process = builder.start();
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
while((line = in.readLine()) != null) {
System.out.println(line);
}
process.waitFor();
PutObjectRequest p = new PutObjectRequest(videoBucket,mp4Name, new File(dir+mp4Name));
p.setRequestCredentials(getCredentials());
p.setCannedAcl(CannedAccessControlList.BucketOwnerFullControl);
getLogger().info("transcoding completed");
s3.putObject(p);
getLogger().info("mp4 file uploaded");
} catch (Exception e) {
getLogger().info("Error running ffmpeg");
e.printStackTrace();
}
deleteFiles(params.getString(4).replace("vid_",""));
}
public void saveThumbnail(IClient client, RequestFunction function, AMFDataList params){
String dir = client.getAppInstance().getStreamStoragePath()+"/"+"thumb_"+params.getString(4).split(",")[2]+".jpg";
getLogger().info(params);
Path path = Paths.get(dir);
byte[] byteArr = (byte[])((AMFDataByteArray)params.get(3)).getValue();
try {
Files.write(path, byteArr, StandardOpenOption.CREATE_NEW);
} catch (IOException e) {
e.printStackTrace();
}
}
public void onAppStop(IApplicationInstance appInstance) {
String fullname = appInstance.getApplication().getName() + "/"
+ appInstance.getName();
getLogger().info("onAppStop: " + fullname);
}
public void onConnect(IClient client, RequestFunction function, AMFDataList params) {
getLogger().info("onConnect: " + client.getClientId());
}
public void onConnectAccept(IClient client) {
getLogger().info("onConnectAccept: " + client.getClientId());
}
public void onConnectReject(IClient client) {
getLogger().info("onConnectReject: " + client.getClientId());
}
public void onDisconnect(IClient client) {
getLogger().info("onDisconnect: " + client.getClientId());
}
public void onStreamCreate(IMediaStream stream) {
getLogger().info("onStreamCreate: " + stream.getSrc());
}
public void onStreamDestroy(IMediaStream stream) {
getLogger().info("onStreamDestroy: " + stream.getSrc());
}
public void onHTTPSessionCreate(IHTTPStreamerSession httpSession) {
getLogger().info("onHTTPSessionCreate: " + httpSession.getSessionId());
}
public void onHTTPSessionDestroy(IHTTPStreamerSession httpSession) {
getLogger().info("onHTTPSessionDestroy: " + httpSession.getSessionId());
}
public void onHTTPCupertinoStreamingSessionCreate(HTTPStreamerSessionCupertino httpSession) {
getLogger().info(
"onHTTPCupertinoStreamingSessionCreate: "
+ httpSession.getSessionId());
}
public void onHTTPCupertinoStreamingSessionDestroy(HTTPStreamerSessionCupertino httpSession) {
getLogger().info(
"onHTTPCupertinoStreamingSessionDestroy: "
+ httpSession.getSessionId());
}
public void onHTTPSmoothStreamingSessionCreate( HTTPStreamerSessionSmoothStreamer httpSession) {
getLogger().info(
"onHTTPSmoothStreamingSessionCreate: "
+ httpSession.getSessionId());
}
public void onHTTPSmoothStreamingSessionDestroy( HTTPStreamerSessionSmoothStreamer httpSession) {
getLogger().info(
"onHTTPSmoothStreamingSessionDestroy: "
+ httpSession.getSessionId());
}
public void onRTPSessionCreate(RTPSession rtpSession) {
getLogger().info("onRTPSessionCreate: " + rtpSession.getSessionId());
}
public void onRTPSessionDestroy(RTPSession rtpSession) {
getLogger().info("onRTPSessionDestroy: " + rtpSession.getSessionId());
}
public void onCall(String handlerName, IClient client, RequestFunction function, AMFDataList params) {
getLogger().info("onCall: " + handlerName);
}
/* Overwritten method: Delete content of the same name before starting */
public void publish(IClient client, RequestFunction function, AMFDataList params) {
getLogger().info("publish hit");
String name = params.getString(3).replace("flv:","").replace("vid_","").replace("_temp", "");
getLogger().info("name:" + name);
dir = appInstance.decodeStorageDir("${com.wowza.wms.AppHome}"+"/content/recorder/");
deleteFiles(name);
invokePrevious(client,function,params);
}
private void deleteFiles(String name){
getLogger().info("deleting " + name);
try {
if(Files.exists(Paths.get(dir+"thumb_"+name+".jpg"))){
getLogger().info("deleting thumbnail");
Files.delete(Paths.get(dir+"thumb_"+name+".jpg"));
}
if(Files.exists((Paths.get(dir+"vid_"+name+".flv")))){
getLogger().info("deleting video");
Files.delete(Paths.get(dir+"vid_"+name+".flv"));
}
if(Files.exists((Paths.get(dir+"vid_"+name+".mp4")))){
getLogger().info("deleting mp4 video");
Files.delete(Paths.get(dir+"vid_"+name+".mp4"));
}
if(Files.exists((Paths.get(dir+"vid_"+name+"_temp.flv")))){
getLogger().info("deleting temp video");
Files.delete(Paths.get(dir+"vid_"+name+"_temp.flv"));
}
} catch (IOException e) {
getLogger().info("Could not delete old files");
}
}
@Override
public AWSCredentials getCredentials() {
getLogger().info("getting credentials");
return new BasicAWSCredentials(appInstance.getProperties().getPropertyStr("accessKey"),appInstance.getProperties().getPropertyStr("secretKey"));
}
@Override
public void refresh() {
// TODO Auto-generated method stub
}
}
It could be related to this: http://www.wowza.com/forums/showthread.php?36693-Aws-plugin-breaks-application-with-no-errors
That might mean that my .jar file isn't being built with the required dependencies (the AWS stuff).
So I included all the dependencies, making sure that the AWS stuff was in the .jar (I looked at it with winrar), and now it gives me "Module class not found or could not be loaded" when the application starts. I can see that the application is there.
This might be related with this error I get in Eclipse when I tried to create a runnable jar with all the dependencies extracted: "Could not find main method from given launch configuration." Even though I got this error, it appeared to work, as the .jar file grew several times in size.
I resolved it by installing everything differently on a new server.
I took by auto-generated .jar file, and the two jar files that it depended on, commons-codec-1.9 and aws-java-sdk-1.4.7, and installed them using the "startup package" method, as opposed to transferring the dependencies later over ftp.
And everything worked fine.