/*
* Flazr <http://flazr.com> Copyright (C) 2009 Peter Thomas.
*
* This file is part of Flazr.
*
* Flazr 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 3 of the License, or
* (at your option) any later version.
*
* Flazr 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 Flazr. If not, see <http://www.gnu.org/licenses/>.
*/
package com.flazr.rtmp.message;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import android.util.Log;
import com.flazr.rtmp.RtmpHeader;
import com.flazr.rtmp.RtmpMessage;
import com.flazr.util.Utils;
import com.flazr.util.ValueToEnum;
public class Control implements RtmpMessage {
public static enum ControlType implements TypeEnum {
STREAM_BEGIN(0),
STREAM_EOF(1),
STREAM_DRY(2),
SET_BUFFER(3),
STREAM_IS_RECORDED(4),
PING_REQUEST(6),
PING_RESPONSE(7),
SWFV_REQUEST(26),
SWFV_RESPONSE(27),
BUFFER_EMPTY(31),
BUFFER_FULL(32);
private final int value;
private ControlType(int value) {
this.value = value;
}
@Override
public int intValue() {
return value;
}
private static final ValueToEnum<ControlType> converter = new ValueToEnum<ControlType>(ControlType.values());
public static ControlType valueToEnum(final int value) {
return converter.valueToEnum(value);
}
}
private ControlType type;
private int streamId;
private int bufferLength;
private int time;
private byte[] bytes;
protected final RtmpHeader header;
public Control(RtmpHeader header, ChannelBuffer in) {
this.header = header;
decode(in);
}
private Control(ControlType type, int time) {
header = new RtmpHeader(getMessageType());
this.type = type;
this.time = time;
}
private Control(int streamId, ControlType type) {
header = new RtmpHeader(getMessageType());
this.streamId = streamId;
this.type = type;
}
@Override
public MessageType getMessageType() {
return MessageType.CONTROL;
}
public static Control setBuffer(int streamId, int bufferLength) {
Control control = new Control(ControlType.SET_BUFFER, 0);
Log.d("Control","BUFFER SIZE at Control " + bufferLength);
control.bufferLength = bufferLength;
control.streamId = streamId;
return control;
}
public static Control pingRequest(int time) {
return new Control(ControlType.PING_REQUEST, time);
}
public static Control pingResponse(int time) {
return new Control(ControlType.PING_RESPONSE, time);
}
public static Control swfvResponse(byte[] bytes) {
Control control = new Control(ControlType.SWFV_RESPONSE, 0);
control.bytes = bytes;
return control;
}
public static Control streamBegin(int streamId) {
Control control = new Control(ControlType.STREAM_BEGIN, 0);
control.streamId = streamId;
return control;
}
public static Control streamIsRecorded(int streamId) {
return new Control(streamId, ControlType.STREAM_IS_RECORDED);
}
public static Control streamEof(int streamId) {
return new Control(streamId, ControlType.STREAM_EOF);
}
public static Control bufferEmpty(int streamId) {
return new Control(streamId, ControlType.BUFFER_EMPTY);
}
public static Control bufferFull(int streamId) {
return new Control(streamId, ControlType.BUFFER_FULL);
}
public ControlType getType() {
return type;
}
public int getTime() {
return time;
}
public int getBufferLength() {
return bufferLength;
}
@Override
public ChannelBuffer encode() {
final int size;
switch(type) {
case SWFV_RESPONSE:
Log.d("Control encode","SWFV_RESPONSE");
size = 44;
break;
case SET_BUFFER:
Log.d("Control encode","SET_BUFFER 10");
size = 10; break;
default: size = 6;
}
ChannelBuffer out = ChannelBuffers.buffer(ChannelBuffers.BIG_ENDIAN,size);
out.writeShort((short) type.value);
switch(type) {
case STREAM_BEGIN:
case STREAM_EOF:
case STREAM_DRY:
case STREAM_IS_RECORDED:
out.writeInt(streamId);
break;
case SET_BUFFER:
Log.d("Control encode","SET_BUFFER " +bufferLength);
out.writeInt(streamId);
out.writeInt(bufferLength);
break;
case PING_REQUEST:
case PING_RESPONSE:
Log.d("Control encode","PING_RESPONSE");
out.writeInt(time);
break;
case SWFV_REQUEST:
break;
case SWFV_RESPONSE:
Log.d("Control encode","SWFV_RESPONSE");
out.writeBytes(bytes,0,bytes.length);
break;
case BUFFER_EMPTY:
Log.d("Control encode","BUFFER_EMPTY");
case BUFFER_FULL:
Log.d("Control encode","BUFFER_FULL");
out.writeInt(streamId);
break;
}
return out;
}
@Override
public void decode(ChannelBuffer in) {
type = ControlType.valueToEnum(in.readShort());
switch(type) {
case STREAM_BEGIN:
case STREAM_EOF:
case STREAM_DRY:
case STREAM_IS_RECORDED:
streamId = in.readInt();
break;
case SET_BUFFER:
streamId = in.readInt();
bufferLength = in.readInt();
break;
case PING_REQUEST:
case PING_RESPONSE:
time = in.readInt();
break;
case SWFV_REQUEST:
// only type (2 bytes)
break;
case SWFV_RESPONSE:
bytes = new byte[42];
in.readBytes(bytes,0,42);
break;
case BUFFER_EMPTY:
case BUFFER_FULL:
streamId = in.readInt();
break;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(super.toString());
sb.append(type);
sb.append(" streamId: ").append(streamId);
switch(type) {
case SET_BUFFER:
sb.append(" bufferLength: ").append(bufferLength);
break;
case PING_REQUEST:
case PING_RESPONSE:
sb.append(" time: ").append(time);
break;
}
if(bytes != null) {
sb.append(" bytes: " + Utils.toHex(bytes,0,bytes.length,false));
}
return sb.toString();
}
@Override
public RtmpHeader getHeader() {
return header;
}
}