bowljoman
06-04-2008, 02:16 AM
Hello, this is an action script file which connects to a shoutcast server and begins transmitting a NSV format bitstream.
The files below work. They stream the text "HELLO!!" through the video channel of a shoutcast server.
CHALLENGE! Send images, audio, objects, or anything cool that you want to stream to clients.
Requires a Shoutcast server running on 'localhost' or a server with socket policyfile.
To read and write NSV format easy, I rigged up this class from aol nsv C++ class. Package it into your workspace.
package com.thebitstream.nsv
{
import flash.utils.ByteArray;
import flash.utils.Endian;
public class BitStream
{
public var m_bits:ByteArray=new ByteArray();
public var m_curb:int=0;
public var m_used:int=0;
public var m_bitpos:int=0;
public var m_eof:int=0;
public function BitStream()
{
m_bits.endian=Endian.LITTLE_ENDIAN;
}
public function compact():void
{
//NOT BYTE ALIGNED!
var read:int=int(m_bitpos);
if(read<=0)return;
trace("COMPACTING!!!!! : "+read);
var resized:ByteArray=new ByteArray();
if(m_bits.length>m_bitpos/8)
resized.writeBytes(m_bits,read/8,m_bits.length-read/8);
m_used=resized.length*8;
m_bitpos=0;
m_bits=ByteArray(resized);
}
public function getbits(nbits:int):uint
{
var ret:uint=0;
var t:int=0;
if (nbits <= 0) return ret;
var sh:int=0;
t+=m_bitpos/8;
for (sh = 0; sh < nbits; sh ++)
{
ret|=((m_bits[t]>>(m_bitpos&7))&1) << sh;
if (!((++m_bitpos)&7)) t++;
}
return ret;
}
public function addInt(value:int):void
{
addByte((value)&0xFF);
addByte((value>>8)&0xFF);
addByte((value>>16)&0xFF);
addByte((value>>24)&0xFF);
}
public function readInt():uint
{
var ret:uint=(getbits(8))|
(getbits(8)<<8)|
(getbits(8)<<18)|
(getbits(8)<<24);
return ret;
}
public function readByte():uint
{
return getbits(8);
}
public function addByte(byte:uint):void
{
putbits(8,byte);
}
public function putbits(nbits:int, value:uint):void
{
while (nbits-- > 0)
{
m_curb|=(value&1)<<(m_used&7);
if (!((++m_used)&7))
{
m_bits.writeByte(m_curb);
m_curb=0;
}
value>>=1;
}
}
public function seek( nbits:int):void
{
m_bitpos+=nbits;
if (m_bitpos < 0)
m_bitpos=0;
m_eof=(m_bits.length*8 - m_bitpos>0)?0:1;
}
public function rewind():void
{
m_bitpos=0;
m_eof=0;
}
public function clear():void
{
m_bits=new ByteArray();
m_bits.endian=Endian.LITTLE_ENDIAN;
m_bitpos=0;
m_eof=0;
m_curb=0;
m_used=0
}
public function eof():int
{
return m_eof;
}
public function avail():int
{
if (m_eof)
return 0;
return m_bits.length*8 - m_bitpos;
}
public static function frate2double(fr:int):Number
{
var fratetab:Array=new Array( 30.0, 30.0*1000.0/1001.0,25.0,24.0*1000.0/1001.0);
if (!(fr&0x80)) return fr;
var sc:Number;
var d:int=fr&0x7f>>2;
if (d < 16) sc=1.0/(d+1);
else sc=d-15;
var r:int=fr&3;
return fratetab[r]*sc;
}
}
}
OK More code!
The challenge starts at the Adobe Socket sample.
package{import flash.errors.*;
import flash.events.*;
import flash.net.Socket;
public class CustomSocket extends Socket {
private var response:String;
public function CustomSocket(host:String = null, port:uint = 0) {
super(host, port);
configureListeners();
}
private function configureListeners():void {
addEventListener(Event.CLOSE, closeHandler);
addEventListener(Event.CONNECT, connectHandler);
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
addEventListener(SecurityErrorEvent.SECURITY_ERROR , securityErrorHandler);
addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
}
public function writeln(str:String):void {
str += "\n";
try {
writeUTFBytes(str);
}
catch(e:IOError) {
trace(e);
}
}
private function sendRequest():void {
trace("sendRequest");
response = "";
writeln("changeme\nicy-name:Tests\nicy-genre:Live\nicy-pub:0\nicy-br:160\nicy-url:http://www.saladbowlguitar.com\nicy-reset:1\ncontent-type:video/nsv\n\n");
flush();
}
private function readResponse():void {
var str:String = readUTFBytes(bytesAvailable);
response += str;
}
private function closeHandler(event:Event):void {
trace("closeHandler: " + event);
trace(response.toString());
}
private function connectHandler(event:Event):void {
trace("connectHandler: " + event);
sendRequest();
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
private function securityErrorHandler(event:SecurityErrorEvent):voi d {
trace("securityErrorHandler: " + event);
}
private function socketDataHandler(event:ProgressEvent):void {
trace("socketDataHandler: " + event);
readResponse();
}
}
}
Ok now lets use that class to connect to a Shoutcast server and stream!
Create a new Action script project SocketExample.
package {
import com.thebitstream.nsv.BitStream;
import flash.display.Sprite;
import flash.events.Event;
public class SocketExample extends Sprite {
public var socket:CustomSocket = new CustomSocket();
public function SocketExample() {
socket.connect("localhost",8001);
//socket.connect("localhost",61);
this.addEventListener(Event.ENTER_FRAME,frame);
}
public function frame(e:Event):void
{
if(!socket.connected)return;
var bs:BitStream=new BitStream();
//write sync word
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("S").charCodeAt());
bs.putbits(8,String("V").charCodeAt());
bs.putbits(8,String("s").charCodeAt());
//Write data/video track 1 FourCC code or NONE
bs.putbits(8,String("T").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
bs.putbits(8,String("X").charCodeAt());
bs.putbits(8,String("T").charCodeAt());
//Write data/audio track 2 FourCC code or NONE
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("O").charCodeAt());
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
// video Width+height
bs.putbits(16,320);
bs.putbits(16,240);
// Frame rate
bs.putbits(8,15);
// Track 1 and Track 2 Milliseconds offset
bs.putbits(16,0);
//Num Aux channels.
bs.putbits(4,0);
//video /data length
bs.putbits(20,7);
// audio /data length
bs.putbits(16,0);
//VD Could be a raw data buffer containing H264 or VP61.
bs.putbits(8,String("H").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
bs.putbits(8,String("L").charCodeAt());
bs.putbits(8,String("L").charCodeAt());
bs.putbits(8,String("0").charCodeAt());
bs.putbits(8,String("!").charCodeAt());
bs.putbits(8,String("!").charCodeAt());
//No Audio Data Track; Could be mp3 or aac
//Send Frame
socket.writeBytes(bs.m_bits,0,bs.m_bits.length);
socket.flush();
}
}
}
Run that file and your shoutcast server should signify connection.
The files below work. They stream the text "HELLO!!" through the video channel of a shoutcast server.
CHALLENGE! Send images, audio, objects, or anything cool that you want to stream to clients.
Requires a Shoutcast server running on 'localhost' or a server with socket policyfile.
To read and write NSV format easy, I rigged up this class from aol nsv C++ class. Package it into your workspace.
package com.thebitstream.nsv
{
import flash.utils.ByteArray;
import flash.utils.Endian;
public class BitStream
{
public var m_bits:ByteArray=new ByteArray();
public var m_curb:int=0;
public var m_used:int=0;
public var m_bitpos:int=0;
public var m_eof:int=0;
public function BitStream()
{
m_bits.endian=Endian.LITTLE_ENDIAN;
}
public function compact():void
{
//NOT BYTE ALIGNED!
var read:int=int(m_bitpos);
if(read<=0)return;
trace("COMPACTING!!!!! : "+read);
var resized:ByteArray=new ByteArray();
if(m_bits.length>m_bitpos/8)
resized.writeBytes(m_bits,read/8,m_bits.length-read/8);
m_used=resized.length*8;
m_bitpos=0;
m_bits=ByteArray(resized);
}
public function getbits(nbits:int):uint
{
var ret:uint=0;
var t:int=0;
if (nbits <= 0) return ret;
var sh:int=0;
t+=m_bitpos/8;
for (sh = 0; sh < nbits; sh ++)
{
ret|=((m_bits[t]>>(m_bitpos&7))&1) << sh;
if (!((++m_bitpos)&7)) t++;
}
return ret;
}
public function addInt(value:int):void
{
addByte((value)&0xFF);
addByte((value>>8)&0xFF);
addByte((value>>16)&0xFF);
addByte((value>>24)&0xFF);
}
public function readInt():uint
{
var ret:uint=(getbits(8))|
(getbits(8)<<8)|
(getbits(8)<<18)|
(getbits(8)<<24);
return ret;
}
public function readByte():uint
{
return getbits(8);
}
public function addByte(byte:uint):void
{
putbits(8,byte);
}
public function putbits(nbits:int, value:uint):void
{
while (nbits-- > 0)
{
m_curb|=(value&1)<<(m_used&7);
if (!((++m_used)&7))
{
m_bits.writeByte(m_curb);
m_curb=0;
}
value>>=1;
}
}
public function seek( nbits:int):void
{
m_bitpos+=nbits;
if (m_bitpos < 0)
m_bitpos=0;
m_eof=(m_bits.length*8 - m_bitpos>0)?0:1;
}
public function rewind():void
{
m_bitpos=0;
m_eof=0;
}
public function clear():void
{
m_bits=new ByteArray();
m_bits.endian=Endian.LITTLE_ENDIAN;
m_bitpos=0;
m_eof=0;
m_curb=0;
m_used=0
}
public function eof():int
{
return m_eof;
}
public function avail():int
{
if (m_eof)
return 0;
return m_bits.length*8 - m_bitpos;
}
public static function frate2double(fr:int):Number
{
var fratetab:Array=new Array( 30.0, 30.0*1000.0/1001.0,25.0,24.0*1000.0/1001.0);
if (!(fr&0x80)) return fr;
var sc:Number;
var d:int=fr&0x7f>>2;
if (d < 16) sc=1.0/(d+1);
else sc=d-15;
var r:int=fr&3;
return fratetab[r]*sc;
}
}
}
OK More code!
The challenge starts at the Adobe Socket sample.
package{import flash.errors.*;
import flash.events.*;
import flash.net.Socket;
public class CustomSocket extends Socket {
private var response:String;
public function CustomSocket(host:String = null, port:uint = 0) {
super(host, port);
configureListeners();
}
private function configureListeners():void {
addEventListener(Event.CLOSE, closeHandler);
addEventListener(Event.CONNECT, connectHandler);
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
addEventListener(SecurityErrorEvent.SECURITY_ERROR , securityErrorHandler);
addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
}
public function writeln(str:String):void {
str += "\n";
try {
writeUTFBytes(str);
}
catch(e:IOError) {
trace(e);
}
}
private function sendRequest():void {
trace("sendRequest");
response = "";
writeln("changeme\nicy-name:Tests\nicy-genre:Live\nicy-pub:0\nicy-br:160\nicy-url:http://www.saladbowlguitar.com\nicy-reset:1\ncontent-type:video/nsv\n\n");
flush();
}
private function readResponse():void {
var str:String = readUTFBytes(bytesAvailable);
response += str;
}
private function closeHandler(event:Event):void {
trace("closeHandler: " + event);
trace(response.toString());
}
private function connectHandler(event:Event):void {
trace("connectHandler: " + event);
sendRequest();
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
private function securityErrorHandler(event:SecurityErrorEvent):voi d {
trace("securityErrorHandler: " + event);
}
private function socketDataHandler(event:ProgressEvent):void {
trace("socketDataHandler: " + event);
readResponse();
}
}
}
Ok now lets use that class to connect to a Shoutcast server and stream!
Create a new Action script project SocketExample.
package {
import com.thebitstream.nsv.BitStream;
import flash.display.Sprite;
import flash.events.Event;
public class SocketExample extends Sprite {
public var socket:CustomSocket = new CustomSocket();
public function SocketExample() {
socket.connect("localhost",8001);
//socket.connect("localhost",61);
this.addEventListener(Event.ENTER_FRAME,frame);
}
public function frame(e:Event):void
{
if(!socket.connected)return;
var bs:BitStream=new BitStream();
//write sync word
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("S").charCodeAt());
bs.putbits(8,String("V").charCodeAt());
bs.putbits(8,String("s").charCodeAt());
//Write data/video track 1 FourCC code or NONE
bs.putbits(8,String("T").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
bs.putbits(8,String("X").charCodeAt());
bs.putbits(8,String("T").charCodeAt());
//Write data/audio track 2 FourCC code or NONE
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("O").charCodeAt());
bs.putbits(8,String("N").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
// video Width+height
bs.putbits(16,320);
bs.putbits(16,240);
// Frame rate
bs.putbits(8,15);
// Track 1 and Track 2 Milliseconds offset
bs.putbits(16,0);
//Num Aux channels.
bs.putbits(4,0);
//video /data length
bs.putbits(20,7);
// audio /data length
bs.putbits(16,0);
//VD Could be a raw data buffer containing H264 or VP61.
bs.putbits(8,String("H").charCodeAt());
bs.putbits(8,String("E").charCodeAt());
bs.putbits(8,String("L").charCodeAt());
bs.putbits(8,String("L").charCodeAt());
bs.putbits(8,String("0").charCodeAt());
bs.putbits(8,String("!").charCodeAt());
bs.putbits(8,String("!").charCodeAt());
//No Audio Data Track; Could be mp3 or aac
//Send Frame
socket.writeBytes(bs.m_bits,0,bs.m_bits.length);
socket.flush();
}
}
}
Run that file and your shoutcast server should signify connection.