public function get_chunk() { $chunk = null; if (!$this->is_init) { $this->init_channel_songs(); } if ($this->is_init) { // Move to next song while ($this->media == null && ($this->random || $this->song_pos < count($this->songs))) { if ($this->random) { $randsongs = $this->playlist->get_random_items(1); $this->media = new Song($randsongs[0]['object_id']); } else { $this->media = new Song($this->songs[$this->song_pos]); } $this->media->format(); if ($this->media->catalog) { $catalog = Catalog::create_from_id($this->media->catalog); if (make_bool($this->media->enabled)) { if (AmpConfig::get('lock_songs')) { if (!Stream::check_lock_media($this->media->id, 'song')) { debug_event('channel', 'Media ' . $this->media->id . ' locked, skipped.', '3'); $this->media = null; } } } if ($this->media != null) { $this->media = $catalog->prepare_media($this->media); if (!$this->media->file || !Core::is_readable(Core::conv_lc_file($this->media->file))) { debug_event('channel', 'Cannot read media ' . $this->media->id . ' file, skipped.', '3'); $this->media = null; } else { $valid_types = $this->media->get_stream_types(); if (!in_array('transcode', $valid_types)) { debug_event('channel', 'Missing settings to transcode ' . $this->media->file . ', skipped.', '3'); $this->media = null; } else { debug_event('channel', 'Now listening to ' . $this->media->file . '.', '5'); } } } } else { debug_event('channel', 'Media ' . $this->media->id . ' doesn\'t have catalog, skipped.', '3'); $this->media = null; } $this->song_pos++; // Restart from beginning for next song if the channel is 'loop' enabled // and load fresh data from database if ($this->media != null && $this->song_pos == count($this->songs) && $this->loop) { $this->init_channel_songs(); } } if ($this->media != null) { // Stream not yet initialized for this media, start it if (!$this->transcoder) { $options = array('bitrate' => $this->bitrate); $this->transcoder = Stream::start_transcode($this->media, $this->stream_type, null, $options); $this->media_bytes_streamed = 0; } if (is_resource($this->transcoder['handle'])) { if (ftell($this->transcoder['handle']) == 0) { $this->header_chunk = ''; } $chunk = fread($this->transcoder['handle'], $this->chunk_size); $this->media_bytes_streamed += strlen($chunk); if (ftell($this->transcoder['handle']) < 10000 && strtolower($this->stream_type) == "ogg" || $this->header_chunk_remainder) { //debug_event('channel', 'File handle pointer: ' . ftell($this->transcoder['handle']) ,'5'); $clchunk = $chunk; if ($this->header_chunk_remainder) { $this->header_chunk .= substr($clchunk, 0, $this->header_chunk_remainder); if (strlen($clchunk) >= $this->header_chunk_remainder) { $clchunk = substr($clchunk, $this->header_chunk_remainder); $this->header_chunk_remainder = 0; } else { $this->header_chunk_remainder = $this->header_chunk_remainder - strlen($clchunk); $clchunk = ''; } } // see bin/channel_run.inc for explanation what's happening here while ($this->strtohex(substr($clchunk, 0, 4)) == "4F676753") { $hex = $this->strtohex(substr($clchunk, 0, 27)); $ogg_nr_of_segments = hexdec(substr($hex, 26 * 2, 2)); if (substr($clchunk, 27 + $ogg_nr_of_segments + 1, 6) == "vorbis" || substr($clchunk, 27 + $ogg_nr_of_segments, 4) == "Opus") { $hex .= $this->strtohex(substr($clchunk, 27, $ogg_nr_of_segments)); $ogg_sum_segm_laces = 0; for ($segm = 0; $segm < $ogg_nr_of_segments; $segm++) { $ogg_sum_segm_laces += hexdec(substr($hex, 27 * 2 + $segm * 2, 2)); } $this->header_chunk .= substr($clchunk, 0, 27 + $ogg_nr_of_segments + $ogg_sum_segm_laces); if (strlen($clchunk) < 27 + $ogg_nr_of_segments + $ogg_sum_segm_laces) { $this->header_chunk_remainder = (int) (27 + $ogg_nr_of_segments + $ogg_sum_segm_laces - strlen($clchunk)); } $clchunk = substr($clchunk, 27 + $ogg_nr_of_segments + $ogg_sum_segm_laces); } else { //no more interesting headers $clchunk = ''; } } } //debug_event('channel', 'File handle pointer: ' . ftell($this->transcoder['handle']) ,'5'); //debug_event('channel', 'CHUNK : ' . $chunk, '5'); //debug_event('channel', 'Chunk size: ' . strlen($chunk) ,'5'); // End of file, prepare to move on for next call if (feof($this->transcoder['handle'])) { $this->media->set_played(-1, 'Ampache', array()); if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') { fread($this->transcoder['stderr'], 4096); fclose($this->transcoder['stderr']); } fclose($this->transcoder['handle']); Stream::kill_process($this->transcoder); $this->media = null; $this->transcoder = null; } } else { $this->media = null; $this->transcoder = null; } if (!strlen($chunk)) { $chunk = $this->get_chunk(); } } } return $chunk; }
print $buf; if (ob_get_length()) { ob_flush(); flush(); ob_end_flush(); } ob_start(); } } $bytes_streamed += strlen($buf); } } while (!feof($fp) && connection_status() == 0 && ($transcode || $bytes_streamed < $stream_size)); } if ($send_all_in_once && connection_status() == 0) { header("Content-Length: " . strlen($buf_all)); print $buf_all; ob_flush(); } $real_bytes_streamed = $bytes_streamed; // Need to make sure enough bytes were sent. if ($bytes_streamed < $stream_size && connection_status() == 0) { print str_repeat(' ', $stream_size - $bytes_streamed); $bytes_streamed = $stream_size; } if ($transcode && isset($transcoder)) { fclose($fp); Stream::kill_process($transcoder); } else { fclose($fp); } debug_event('play', 'Stream ended at ' . $bytes_streamed . ' (' . $real_bytes_streamed . ') bytes out of ' . $stream_size, 5);
/** * Get a song waveform. * @param int $song_id * @return binary|string|null */ public static function get($song_id) { $song = new Song($song_id); $waveform = null; if ($song->id) { $song->format(); $waveform = $song->waveform; if (!$waveform) { $catalog = Catalog::create_from_id($song->catalog); if ($catalog->get_type() == 'local') { $transcode_to = 'wav'; $transcode_cfg = AmpConfig::get('transcode'); $valid_types = $song->get_stream_types(); if ($song->type != $transcode_to) { $basedir = AmpConfig::get('tmp_dir_path'); if ($basedir) { if ($transcode_cfg != 'never' && in_array('transcode', $valid_types)) { $tmpfile = tempnam($basedir, $transcode_to); $tfp = fopen($tmpfile, 'wb'); if (!is_resource($tfp)) { debug_event('waveform', "Failed to open " . $tmpfile, 3); return null; } $transcoder = Stream::start_transcode($song, $transcode_to); $fp = $transcoder['handle']; if (!is_resource($fp)) { debug_event('waveform', "Failed to open " . $song->file . " for waveform.", 3); return null; } do { $buf = fread($fp, 2048); fwrite($tfp, $buf); } while (!feof($fp)); fclose($fp); fclose($tfp); Stream::kill_process($transcoder); $waveform = self::create_waveform($tmpfile); //$waveform = self::create_waveform("C:\\tmp\\test.wav"); @unlink($tmpfile); } else { debug_event('waveform', 'transcode setting to wav required for waveform.', '3'); } } else { debug_event('waveform', 'tmp_dir_path setting required for waveform.', '3'); } } else { $waveform = self::create_waveform($song->file); } } if ($waveform) { self::save_to_db($song_id, $waveform); } } } return $waveform; }