// // Radegast Metaverse Client // Copyright (c) 2009-2014, Radegast Development Team // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the application "Radegast", nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // $Id: Sound.cs 502 2010-03-14 23:13:46Z latifer $ // using System; using System.Runtime.InteropServices; using System.Threading; using FMOD; using OpenMetaverse; namespace Radegast.Media { public class StreamInfoArgs : EventArgs { public string Key; public string Value; public StreamInfoArgs(string key, string value) { Key = key; Value = value; } } public class Stream : MediaObject { /// /// Fired when a stream meta data is received /// /// Sender /// Key, value are sent in e public delegate void StreamInfoCallback(object sender, StreamInfoArgs e); /// /// Fired when a stream meta data is received /// public event StreamInfoCallback OnStreamInfo; Timer updateTimer = null; uint updateIntervl = 500; /// /// Creates a new sound object /// /// Sound system public Stream() : base() { } /// /// Releases resources of this sound object /// public override void Dispose() { StopStream(); base.Dispose(); } public void StopStream() { if (updateTimer != null) { updateTimer.Dispose(); updateTimer = null; } if (channel != null) { ManualResetEvent stopped = new ManualResetEvent(false); invoke(new SoundDelegate( delegate { try { FMODExec(channel.stop()); channel = null; UnRegisterSound(); FMODExec(sound.release()); sound = null; } catch { } stopped.Set(); })); stopped.WaitOne(); } } /// /// Plays audio stream /// /// URL of the stream public void PlayStream(string url) { // Stop old stream first. StopStream(); extraInfo.format = SOUND_FORMAT.PCM16; invoke(new SoundDelegate( delegate { try { FMODExec( system.setStreamBufferSize(4 * 128 * 128, TIMEUNIT.RAWBYTES)); FMODExec( system.createSound(url, (MODE.HARDWARE | MODE._2D | MODE.CREATESTREAM), ref extraInfo, ref sound), "Stream load"); // Register for callbacks. RegisterSound(sound); // Allocate a channel and set initial volume. FMODExec(system.playSound( CHANNELINDEX.FREE, sound, false, ref channel), "Stream channel"); FMODExec(channel.setVolume(volume), "Stream volume"); if (updateTimer == null) { updateTimer = new Timer(Update); } updateTimer.Change(0, updateIntervl); } catch (Exception ex) { Logger.Log("Error playing stream: " + ex.ToString(), Helpers.LogLevel.Debug); } })); } private void Update(object sender) { if (sound == null) return; invoke(new SoundDelegate(() => { try { FMODExec(system.update()); TAG tag = new TAG(); int numTags = 0; int numTagsUpdated = 0; var res = sound.getNumTags(ref numTags, ref numTagsUpdated); if (res == RESULT.OK && numTagsUpdated > 0) { for (int i=0; i < numTags; i++) { if (sound.getTag(null, i, ref tag) != RESULT.OK) { continue; } if (tag.type == TAGTYPE.FMOD && tag.name == "Sample Rate Change") { float newfreq = (float)Marshal.PtrToStructure(tag.data, typeof(float)); Logger.DebugLog("New stream frequency: " + newfreq.ToString("F" + 0)); channel.setFrequency(newfreq); } if (tag.datatype != TAGDATATYPE.STRING) continue; // Tell listeners about the Stream tag. This can be // displayed to the user. if (OnStreamInfo != null) OnStreamInfo(this, new StreamInfoArgs(tag.name.ToLower(), Marshal.PtrToStringAnsi(tag.data))); } } } catch (Exception ex) { Logger.DebugLog("Error getting stream tags: " + ex.Message); } })); } } }