/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under GNU LESSER GENERAL PUBLIC LICENSE Version 3. */ package com.ttProject.flazr.rtmp.message; import java.util.Map; import org.jboss.netty.buffer.ChannelBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.flazr.rtmp.RtmpHeader; import com.flazr.rtmp.RtmpMessage; import com.flazr.rtmp.message.MetadataAmf0; import com.ttProject.container.flv.amf.Amf0Value; import com.ttProject.container.flv.amf.Amf3Value; import com.ttProject.nio.channels.ByteReadChannel; import com.ttProject.nio.channels.IReadChannel; import com.ttProject.util.BufferUtil; import com.ttProject.util.HexUtil; /** * MetadataAmf3 * TODO now this program deal with only one data for onMetaData order. * I need the sample for multipleData. * @author taktod */ public class MetadataAmf3 implements RtmpMessage { /** logger */ private static final Logger logger = LoggerFactory.getLogger(MetadataAmf3.class); /** rtmpHeader */ private final RtmpHeader header; /** data map */ private Map<String, Object> data = null; /** setting name(onMetaData) */ private String name; /** * constructor * @param header * @param in */ public MetadataAmf3(RtmpHeader header, ChannelBuffer in) { this.header = header; decode(in); } /** * rebuild the data from channelBuffer */ @SuppressWarnings("unchecked") @Override public void decode(ChannelBuffer in) { int length = in.readableBytes(); byte[] bytes = new byte[length]; in.readBytes(bytes); try { IReadChannel channel = new ByteReadChannel(bytes); // check the first several data. // 00 02 00 0A 6F 6E 4D 65 74 61 44 61 74 61 is expected. if(BufferUtil.safeRead(channel, 1).get() != 0x00) { throw new Exception("first data is expected written as AMF0"); } // treat as amf0 String amf0Data = (String)Amf0Value.getValueObject(channel); if(!"onMetaData".equals(amf0Data)) { throw new Exception("header string is not metadata.:" + amf0Data); } name = amf0Data; // 0x11 is expected(amf3) if(BufferUtil.safeRead(channel, 1).get() != 0x11) { // can be 0x00 with data amf0? throw new Exception("data is expected as AMF3"); } // analyze holding data. data = (Map<String, Object>)Amf3Value.getValueObject(channel); // TODO could have multiple data? } catch (Exception e) { logger.error("", e); logger.error("errorData: {}", HexUtil.toHex(bytes, true)); throw new RuntimeException("faced unknown format."); } } /** * {@inheritDoc} */ @Override public ChannelBuffer encode() { throw new RuntimeException("encode is not supported now."); } /** * ref the header */ @Override public RtmpHeader getHeader() { return header; } /** * name(onMetaData) * @return */ public String getName() { return name; } /** * ref the data. * @return */ public Map<String, Object> getData() { return data; } @Override public String toString() { StringBuilder data = new StringBuilder("MetadataAmf3"); data.append(" name:").append(getName()); data.append(" data:").append(getData()); return data.toString(); } public MetadataAmf0 transform() { MetadataAmf0 metadata0 = new MetadataAmf0(name, data); return metadata0; } }