<? // // $ php ./ebs.php > a.mp3 // error_reporting(E_ERROR); define("SERVER_ADDR", "219.240.12.254"); define("SERVER_PORT_CTL", 5056); define("SERVER_PORT_DAT", 5057); // MPEG ADTS, layer III, v2, 64 kBits, 24 kHz, JntStereo define("MP3_MAGIC", pack("C4", 0xff, 0xf3, 0x84, 0x64)); include 'ebs.inc'; $REQ_TOK = array ('0', '0', '0', '0'); $stderr = fopen('php://stderr', 'w'); $stdout = fopen('php://stdout', 'w'); function print_to_stderr($msg) { global $stderr; fwrite($stderr,$msg); } function print_to_stdout($msg) { global $stdout; fwrite($stdout,$msg); } class ebs_conn { private $host, $port, $sock; private function conn_error($msg) { $log = $msg . "(" . $this->host . ":" . $this->port . "): " . socket_strerror(socket_last_error()) . "\n"; print_to_stderr($log); } protected function connect() { $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket === false) { $this->conn_error("socket_create"); return false; } socket_set_block($socket); $ret = socket_connect($socket, $this->host, $this->port); if ($ret === false) { $this->conn_error("socket_connect"); return false; } $this->sock = $socket; return true; } protected function disconnect() { if ($this->sock === false) return; socket_close($this->sock); $this->sock = false; } protected function write($buf, $len) { if ($len <= 0) return 0; $left = $len; while ($left > 0) { $ret = socket_write($this->sock, $buf, $len); if ($ret === false) { $this->conn_error("socket_write"); return -1; } if ($ret == 0) { $this->conn_error("socket_write:disconnected?"); return -1; } $left = $left - $ret; $buf = substr($buf, $ret, $left); } return $len - $left; } protected function read(&$buf, $len) { if ($len <= 0) return 0; $left = $len; $b = ''; while ($left > 0) { $b = socket_read($this->sock, $len, PHP_BINARY_READ); if ($buf === false) { $this->conn_error("socket_read"); return -1; } $ret = strlen($b); if ($ret == 0) { $this->conn_error("socket_read:disconnected?"); return -1; } $left = $left - $ret; $buf .= $b; } return $len - $left; } protected function write_and_read($wr_buf, &$rd_buf) { $ret = $this->write($wr_buf, 288); if ($ret < 0) { return false; } $ret = $this->read($rd_buf, 288); if ($ret < 0) { return false; } return true; } public function __construct($host, $port) { $this->host = $host; $this->port = $port; $this->sock = false; } public function __destruct() { $this->disconnect(); } } class ebs_ctl extends ebs_conn { private $state; public function loop() { global $PACKET_0, $PACKET_1, $PACKET_2, $PACKET_3; global $REQ_TOK; $ret = 0; $dummy_buf = ''; print_to_stderr("ctl_loop:".$this->state."\n"); switch ($this->state) { case 0: $this->disconnect(); $ret = $this->connect(); if ($ret == false) { $this->state = -1; return false; } $ret = $this->write_and_read($PACKET_0, $dummy_buf); if ($ret == false) { $this->state = -1; return false; } $this->state = 1; $ret = 0; break; case 1: $ret = $this->write_and_read($PACKET_1, $dummy_buf); if ($ret == false) { $this->state = -1; return false; } $REQ_TOK[0] = $dummy_buf[20]; $REQ_TOK[1] = $dummy_buf[21]; $REQ_TOK[2] = $dummy_buf[22]; $REQ_TOK[3] = $dummy_buf[23]; print_to_stderr($REQ_TOK); $this->state = 2; $ret = 0; break; case 2: $ret = $this->write_and_read($PACKET_2, $dummy_buf); if ($ret == false) { $this->state = -1; return false; } $this->state = 3; $ret = 0; break; case 3: $ret = $this->write_and_read($PACKET_0, $dummy_buf); if ($ret == false) { $this->state = -1; return false; } $this->state = 4; $ret = 0; break; case 4: $ret = $this->write_and_read($PACKET_3, $dummy_buf); if ($ret == false) { $this->state = -1; return false; } $ret = $this->read($dummy_buf, 288); if ($ret === false) { $this->state = -1; return false; } $this->state = 5; $ret = 1; /* for recv data */ break; case 5: // ping $ret = $this->write_and_read($PACKET_0, $dummy_buf); if ($ret == false) { $this->state = -1; return false; } $ret = $this->write_and_read($PACKET_3, $dummy_buf); if ($ret == false) { $this->state = -1; return false; } $ret = $this->read($dummy_buf, 288); if ($ret <= 0) { $this->state = -1; return false; } $this->state = $this->state; /* self */ $ret = 1; /* for recv data */ break; default: $ret = false; break; } return $ret; } public function __construct() { $this->state = 0; parent::__construct(SERVER_ADDR, SERVER_PORT_CTL); } public function __destruct() { parent::__destruct(); } } class ebs_dat extends ebs_conn { private $state, $count; private function read_and_parse_header() { $dummy_buf = ''; $packet_len = 0; $ret = $this->read($dummy_buf, 32); // EBS header if ($ret < 0) { return -1; } $packet_len = hexdec(bin2hex($dummy_buf[19])); $packet_len *= 256; $packet_len += hexdec(bin2hex($dummy_buf[18])); print_to_stderr("data len = ".$packet_len."\n"); return $packet_len; } private function scan_and_recv_mp3($len) { $dummy_buf = ''; $ret = $this->read($dummy_buf, $len); if ($ret < 0) { return -1; } $pos = strpos($dummy_buf, MP3_MAGIC, 0); if ($pos === false) { print_to_stderr("no mp3 mgic\n"); return -1; } print_to_stderr("@".$pos."\n"); $dummy_buf = substr($dummy_buf, $pos, $ret - $pos); print_to_stdout($dummy_buf); return 0; } private function recv_mp3($len) { $dummy_buf = ''; $ret = $this->read($dummy_buf, $len); if ($ret < 0) { return -1; } print_to_stdout($dummy_buf); return 0; } public function loop() { global $PACKET_R; global $REQ_TOK; $ret = 0; $dummy_buf = ''; print_to_stderr("dat_loop:".$this->state."\n"); switch ($this->state) { case 0: $this->disconnect(); $ret = $this->connect(); if ($ret == false) { $this->state = -1; return false; } $PACKET_R[20] = $REQ_TOK[0]; $PACKET_R[21] = $REQ_TOK[1]; $PACKET_R[22] = $REQ_TOK[2]; $PACKET_R[23] = $REQ_TOK[3]; $ret = $this->write_and_read($PACKET_R, $dummy_buf); if ($ret == false) { $this->state = -1; return false; } $this->state = 1; $ret = 0; break; case 1: $packet_len = $this->read_and_parse_header(); if ($packet_len <= 0) return false; $ret = $this->scan_and_recv_mp3($packet_len); if ($ret < 0) { $this->state = -1; return false; } $this->state = 2; $ret = 0; break; case 2: $packet_len = $this->read_and_parse_header(); if ($packet_len <= 0) return false; $ret = $this->recv_mp3($packet_len); if ($ret < 0) { $this->state = -1; return false; } $this->count = $this->count + 1; if ($this->count > 10) { $this->count = 0; return 1; /* for ctl::ping */ } $this->state = $this->state; /* self */ $ret = 0; break; default: $ret = false; break; } return $ret; } public function __construct() { $this->state = 0; $this->count = 0; parent::__construct(SERVER_ADDR, SERVER_PORT_DAT); } public function __destruct() { parent::__destruct(); } } $ebs_ctl = new ebs_ctl(); $ebs_dat = new ebs_dat(); while (1) { $ret = $ebs_ctl->loop(); if ($ret === false) break; /* error */ if ($ret === 1) { while (1) { $ret = $ebs_dat->loop(); if ($ret !== 0) break; } if ($ret === false) break; /* error */ } } ?>