1 /** 2 * Copyright 2014 JogAmp Community. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, are 5 * permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * The views and conclusions contained in the software and documentation are those of the 25 * authors and should not be interpreted as representing official policies, either expressed 26 * or implied, of JogAmp Community. 27 */ 28 29 package com.jogamp.opengl.test.junit.jogl.demos.es2.av; 30 31 import com.jogamp.common.net.Uri; 32 import com.jogamp.common.util.InterruptSource; 33 import com.jogamp.opengl.util.av.AudioSink; 34 import com.jogamp.opengl.util.av.GLMediaPlayer; 35 import com.jogamp.opengl.util.av.GLMediaPlayer.GLMediaEventListener; 36 import com.jogamp.opengl.util.av.GLMediaPlayer.StreamException; 37 import com.jogamp.opengl.util.av.GLMediaPlayerFactory; 38 import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame; 39 40 import java.io.File; 41 42 /** 43 * Parallel media player that demonstrate CrossFade of audio volume during playback. 44 * This also demonstrate audio only playback of the GLMediaPlayer. 45 */ 46 public class CrossFadePlayer 47 { 48 static GLMediaPlayer[] player; 49 static volatile boolean stop = false; 50 main(final String[] args)51 public static void main(final String[] args) 52 { 53 54 if(args.length==0) { 55 System.out.println("No files! \n" + 56 "pass as many media files you want\n" + 57 "to the CrossFadePlayer arguments \n" + 58 "and i will try CrossFade-play them all in parallel!"); 59 } 60 61 final GLMediaEventListener mediaEventListener = new GLMediaEventListener() 62 { 63 @Override 64 public void newFrameAvailable(final GLMediaPlayer ts, final TextureFrame newFrame, final long when) { } 65 66 @Override 67 public void attributesChanged(final GLMediaPlayer mp, final int event_mask, final long when) 68 { 69 System.out.println("\n***\nEvent mask changed: " + event_mask); 70 System.out.println("Timestamp: "+ when); 71 System.out.println("State of player: " + mp.getState().toString() +"\n"); 72 73 if ((event_mask & GLMediaEventListener.EVENT_CHANGE_INIT) !=0) { 74 System.out.println("Duration: " + mp.getDuration() + "ms"); 75 System.out.println("Volume: " + mp.getAudioVolume()); 76 System.out.println("player.initGL()..."); 77 new InterruptSource.Thread() { 78 public void run() { 79 try { 80 mp.initGL(null); 81 if ( GLMediaPlayer.State.Paused == mp.getState() ) { // init OK 82 mp.play(); 83 } 84 } catch (final Exception e) { 85 e.printStackTrace(); 86 } 87 } 88 }.start(); 89 } else if ((event_mask & GLMediaEventListener.EVENT_CHANGE_PAUSE) !=0) { 90 System.out.println("player.paused()..."); 91 } else if ((event_mask & GLMediaEventListener.EVENT_CHANGE_PLAY) !=0) { 92 System.out.println("playing..."); 93 System.out.println(mp.toString()); 94 System.out.println(mp.getAudioSink().toString()); 95 } else if( 0 != ( GLMediaEventListener.EVENT_CHANGE_EOS & event_mask ) ) { 96 final StreamException se = mp.getStreamException(); 97 if( null != se ) { 98 System.err.println("Player State: EOS + Exception"); 99 stop = true; 100 } else { 101 System.err.println("Player State: EOS"); 102 new InterruptSource.Thread() { 103 public void run() { 104 System.out.println("mp.setPlaySpeed(1f) returned: " + mp.setPlaySpeed(1f)); 105 mp.seek(0); 106 mp.play(); 107 } 108 }.start(); 109 } 110 } 111 if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) { 112 final StreamException se = mp.getStreamException(); 113 if( null != se ) { 114 se.printStackTrace(); 115 } 116 new InterruptSource.Thread() { 117 public void run() { 118 System.out.println("terminating..."); 119 stop = true; 120 } 121 }.start(); 122 } 123 124 } 125 }; 126 127 // Initialize media players 128 player = new GLMediaPlayer[args.length]; 129 int i=0; 130 for( final String arg: args ) { 131 player[i] = GLMediaPlayerFactory.createDefault(); 132 if(player[i]!=null){ 133 System.out.println("Created CrossFade player: "+ i + " " + player[i].getClass().getName()); 134 player[i].addEventListener(mediaEventListener); 135 try { 136 final String filename = arg; 137 if(filename.equals("")){ 138 System.out.println("No file selected: arg " + i +" = "+ filename); 139 player[i]=null; 140 } else { 141 final File file = new File(filename); 142 if(!file.exists()){ 143 System.out.println("File do not exist"); 144 } else { 145 final Uri uri = Uri.valueOf(file); 146 System.out.println("State of player "+ i +": " + player[i].getState().toString()); 147 System.out.println("...initializing stream "+ i +"..."); 148 player[i].initStream(uri, GLMediaPlayer.STREAM_ID_NONE, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.TEXTURE_COUNT_DEFAULT); 149 150 } 151 } 152 } catch (final Exception e1) { 153 e1.printStackTrace(); 154 } 155 } else { 156 System.out.println("Failed to create player "+ i +"!"); 157 } 158 i++; 159 } 160 161 162 // Main thread CrossFade until playback is done 163 final long startTime = com.jogamp.common.os.Platform.currentTimeMillis(); 164 final double piPlayers = Math.PI*2.0f/args.length; 165 StreamException se = null; 166 while( null == se && stop == false ) { 167 try { 168 Thread.sleep(100); 169 } catch (final InterruptedException e) { } 170 171 // Find out the longest duration... 172 float maxDuration = 1000.0f ; 173 for(final GLMediaPlayer p: player) { 174 if(p!=null){ 175 if( p.getDuration() > maxDuration) { 176 maxDuration = p.getDuration(); 177 } 178 } 179 } 180 181 // tune the volume on players to crossfade! 182 final float progress = (com.jogamp.common.os.Platform.currentTimeMillis()-startTime)/maxDuration; 183 184 i = 0; 185 for(final GLMediaPlayer p: player){ 186 if(p!=null){ 187 final AudioSink sink = p.getAudioSink(); 188 if(sink != null){ 189 final float volume = (float) (0.5f+(0.5f*(Math.cos(40.0f*progress+(piPlayers*i))))); 190 final float playbacktime = com.jogamp.common.os.Platform.currentTimeMillis()-startTime; 191 // System.out.println("player: "+ i +" volume = " + volume +" progress = "+ progress +" time = "+ playbacktime + " / duration = " + maxDuration); 192 sink.setVolume(volume); 193 } 194 195 se = p.getStreamException(); 196 if( null != se) { 197 se.printStackTrace(); 198 throw new RuntimeException(se); 199 } 200 } 201 202 i++; 203 } 204 } 205 206 for(final GLMediaPlayer p: player) { 207 if(p!=null) 208 p.destroy(null); 209 } 210 System.out.println("...main exit..."); 211 } 212 } 213