diff --git a/lib/native/linux-64/libjnawtrenderer.so b/lib/native/linux-64/libjnawtrenderer.so index 45cf80b7b3e5013ac938613d236c181bfb25b4cb..f6c61a4ff2d534e7e6350fa43e6b85abb5b712a3 100755 Binary files a/lib/native/linux-64/libjnawtrenderer.so and b/lib/native/linux-64/libjnawtrenderer.so differ diff --git a/lib/native/linux/libjnawtrenderer.so b/lib/native/linux/libjnawtrenderer.so index 1d164d2746e0b7a9897c068dec2b5e539009f1f0..9285b223974048497bed4d0165d400110eeb8099 100755 Binary files a/lib/native/linux/libjnawtrenderer.so and b/lib/native/linux/libjnawtrenderer.so differ diff --git a/lib/native/mac/libjnawtrenderer.jnilib b/lib/native/mac/libjnawtrenderer.jnilib index 1f7e95feda0cbd6d913ad74b2d58579d42a93fc8..6ed7922fa292f68bc364bece78af059dc1e34f40 100755 Binary files a/lib/native/mac/libjnawtrenderer.jnilib and b/lib/native/mac/libjnawtrenderer.jnilib differ diff --git a/lib/native/windows-64/jnawtrenderer.dll b/lib/native/windows-64/jnawtrenderer.dll index 9fa486a4ce8724895c4745ccfb1fdf1b4ba5a1cc..57548dbe3e98e949cb93807b9a68d7b37f393735 100755 Binary files a/lib/native/windows-64/jnawtrenderer.dll and b/lib/native/windows-64/jnawtrenderer.dll differ diff --git a/lib/native/windows/jnawtrenderer.dll b/lib/native/windows/jnawtrenderer.dll index 6163f058f9fc10b9c5a94eb526117012ccf53f36..e5465904230447c901d1ea3540cfa256b538b16d 100644 Binary files a/lib/native/windows/jnawtrenderer.dll and b/lib/native/windows/jnawtrenderer.dll differ diff --git a/src/native/build.xml b/src/native/build.xml index 69960938907559f975cd5141ec584642eb30308e..45102fa614676bce29a9ba00cc2f1c2524842aaf 100644 --- a/src/native/build.xml +++ b/src/native/build.xml @@ -174,79 +174,72 @@ </target> <!-- compile jnawtrenderer library --> - <target name="jawtrenderer" description="Build jnawtrenderer shared library" depends="init-native,jawtrenderer-windows" - unless="is.running.windows"> + <target name="jawtrenderer" description="Build jnawtrenderer shared library" depends="init-native"> <cc outtype="shared" name="gcc" outfile="${native_install_dir}/jnawtrenderer" objdir="${obj}"> <!-- common compiler flags --> + <compilerarg value="-D_JNI_IMPLEMENTATION_" /> + <compilerarg value="-m32" if="cross_32" unless="is.running.macos" /> + <compilerarg value="-m64" if="cross_64" unless="is.running.macos" /> + <compilerarg value="-O2" /> <compilerarg value="-std=c99" /> <compilerarg value="-Wall" /> - <compilerarg value="-O2" /> - <linkerarg value="-L${system.JAVA_HOME}/jre/lib/amd64" /> - <linkerarg value="-L${system.JAVA_HOME}/jre/lib/x86" /> + <compilerarg value="-I${system.JAVA_HOME}/include" unless="is.running.macos" /> + + <linkerarg value="-m32" if="cross_32" unless="is.running.macos" /> + <linkerarg value="-m64" if="cross_64" unless="is.running.macos" /> <linkerarg value="-ljawt" location="end" /> - <!-- Linux specific flags --> - <compilerarg value="-m32" if="cross_32" unless="is.running.macos" /> - <compilerarg value="-m64" if="cross_64" unless="is.running.macos" /> - <compilerarg value="-I${system.JAVA_HOME}/include" if="is.running.linux" /> + <!-- Linux-specific flags --> <compilerarg value="-I${system.JAVA_HOME}/include/linux" if="is.running.linux" /> - <linkerarg value="-m32" if="cross_32" unless="is.running.macos" /> - <linkerarg value="-m64" if="cross_64" unless="is.running.macos" /> + <linkerarg value="-L${system.JAVA_HOME}/jre/lib/i386" if="is.running.linux" /> + <linkerarg value="-L${system.JAVA_HOME}/jre/lib/amd64" if="is.running.linux" /> <linkerarg value="-lXv" location="end" if="is.running.linux" /> <linkerarg value="-lX11" location="end" if="is.running.linux" /> - <fileset dir="${src}/native/jawtrenderer" includes="net*.c JAWTRenderer_Linux.c" if="is.running.linux"/> + <fileset dir="${src}/native/jawtrenderer" includes="org*.c JAWTRenderer_Linux.c" if="is.running.linux"/> - <!-- Mac OS X specific flags --> + <!-- Mac OS X-specific flags --> <compilerarg value="-mmacosx-version-min=10.5" if="is.running.macos"/> <compilerarg value="-arch" if="is.running.macos" /> - <compilerarg value="x86_64" if="is.running.macos" /> - <compilerarg value="-arch" if="is.running.macos" /> <compilerarg value="i386" if="is.running.macos" /> + <compilerarg value="-arch" if="is.running.macos" /> + <compilerarg value="x86_64" if="is.running.macos" /> <compilerarg value="-I/System/Library/Frameworks/JavaVM.framework/Headers" if="is.running.macos" /> <linkerarg value="-o" location="end" if="is.running.macos" /> <linkerarg value="libjnawtrenderer.jnilib" location="end" if="is.running.macos" /> - <linkerarg value="-arch" if="is.running.macos" /> - <linkerarg value="x86_64" if="is.running.macos" /> + <linkerarg value="-dynamiclib" if="is.running.macos" /> <linkerarg value="-arch" if="is.running.macos" /> <linkerarg value="i386" if="is.running.macos" /> + <linkerarg value="-arch" if="is.running.macos" /> + <linkerarg value="x86_64" if="is.running.macos" /> <linkerarg value="-framework" if="is.running.macos" /> <linkerarg value="OpenGL" if="is.running.macos" /> <linkerarg value="-framework" if="is.running.macos" /> <linkerarg value="Foundation" if="is.running.macos" /> <linkerarg value="-framework" if="is.running.macos" /> <linkerarg value="AppKit" if="is.running.macos" /> + <linkerarg value="-framework" if="is.running.macos" /> + <linkerarg value="QuartzCore" if="is.running.macos" /> <linkerarg value="-L/System/Library/Frameworks/JavaVM.framework/Libraries/" if="is.running.macos" /> - <fileset dir="${src}/native/jawtrenderer" includes="net*.c JAWTRenderer_MacOSX.m" if="is.running.macos" /> - - </cc> - </target> + <fileset dir="${src}/native/jawtrenderer" includes="org*.c JAWTRenderer_MacOSX.m" if="is.running.macos" /> - <!-- compile jnawtrenderer library for Windows --> - <target name="jawtrenderer-windows" description="Build jnawtrenderer shared library for Windows" depends="init-native" - if="is.running.windows"> - <cc outtype="shared" name="msvc" outfile="${native_install_dir}/jnawtrenderer" objdir="${obj}"> - <compilerarg value="/O2" /> - <compilerarg value="/MT" location="end" /> - <compilerarg value="/IC:\Program Files\Microsoft DirectX SDK (February 2010)\Include" /> - <compilerarg value="/IC:\Program Files (x86)\Microsoft DirectX SDK (February 2010)\Include" /> - <compilerarg value="-I${system.JAVA_HOME}/include" /> - <compilerarg value="-I${system.JAVA_HOME}/include/win32" /> + <!-- Windows-specific flags --> + <compilerarg value="-D_WIN32_WINNT=0x0502" if="is.running.windows" /> + <compilerarg value="-DWINVER=0x0502" if="is.running.windows" /> + <compilerarg value="-I${system.JAVA_HOME}/include/win32" if="is.running.windows" /> - <!-- <linkerarg value="/LD" /> --> - <linkerarg value="/LIBPATH:C:\Program Files\Microsoft DirectX SDK (February 2010)\lib\x86" /> - <linkerarg value="/LIBPATH:C:\Program Files (x86)\Microsoft DirectX SDK (February 2010)\lib\x64" /> - <linkerarg value="/LIBPATH:${system.JAVA_HOME}\\lib" /> - <linkerarg value="d3d9.lib" location="end" /> - <linkerarg value="user32.lib" location="end" /> - <linkerarg value="jawt.lib" location="end" /> + <linkerarg value="-ojnawtrenderer.dll" if="is.running.windows" /> + <linkerarg value="-Wl,--kill-at" if="is.running.windows" /> + <linkerarg value="-L${system.JAVA_HOME}/lib" if="is.running.windows" /> + <linkerarg value="-ld3d9" location="end" if="is.running.windows" /> + <linkerarg value="-ld3dx9" location="end" if="is.running.windows" /> - <fileset dir="${src}/native/jawtrenderer" includes="net*.c JAWTRenderer_Windows.cpp windows/*.cpp windows/*.c"/> + <fileset dir="${src}/native/jawtrenderer" includes="org*.c JAWTRenderer_Windows.c" if="is.running.windows"/> </cc> </target> diff --git a/src/native/jawtrenderer/JAWTRenderer.h b/src/native/jawtrenderer/JAWTRenderer.h index a493c29350cc6321f57bbde540639fea8a6aa631..a5105e9e84da0966d8b9515f202cf830dd969156 100644 --- a/src/native/jawtrenderer/JAWTRenderer.h +++ b/src/native/jawtrenderer/JAWTRenderer.h @@ -16,26 +16,17 @@ extern "C" { #endif void JAWTRenderer_close - (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component); -jlong JAWTRenderer_open(JNIEnv *jniEnv, jclass clazz, jobject component); + (JNIEnv *env, jclass clazz, jlong handle, jobject component); +jlong JAWTRenderer_open(JNIEnv *env, jclass clazz, jobject component); jboolean JAWTRenderer_paint - (JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, jobject g); + (jint version, JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, + jobject g, jint zOrder); jboolean JAWTRenderer_process - (JNIEnv *jniEnv, jclass clazz, - jlong handle, jobject component, - jint *data, jint length, - jint width, jint height); + (JNIEnv *env, jclass clazz,jlong handle, jobject component, jint *data, + jint length, jint width, jint height); #ifdef __APPLE__ -void JAWTRenderer_addNotifyLightweightComponent - (jlong handle, jobject component, jlong parentHandle); -jboolean JAWTRenderer_paintLightweightComponent - (jlong handle, jobject component, jobject g); -void JAWTRenderer_processLightweightComponentEvent - (jlong handle, jint x, jint y, jint width, jint height); -void JAWTRenderer_removeNotifyLightweightComponent - (jlong handle, jobject component); -jstring JAWTRenderer_sysctlbyname(JNIEnv *jniEnv, jstring name); +jstring JAWTRenderer_sysctlbyname(JNIEnv *env, jstring name); #endif /* #ifdef __APPLE__ */ #ifdef __cplusplus diff --git a/src/native/jawtrenderer/JAWTRenderer_Linux.c b/src/native/jawtrenderer/JAWTRenderer_Linux.c index dde3bc29ea4a1c5d63d9e5e21fe6f91e4d44df37..e2d8554c0fce808fcef508cc767e6591eac73370 100644 --- a/src/native/jawtrenderer/JAWTRenderer_Linux.c +++ b/src/native/jawtrenderer/JAWTRenderer_Linux.c @@ -91,7 +91,8 @@ JAWTRenderer_open(JNIEnv *jniEnv, jclass clazz, jobject component) jboolean JAWTRenderer_paint - (JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, jobject g) + (jint version, JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, + jobject g, jint zOrder) { JAWT_X11DrawingSurfaceInfo *x11dsi; JAWTRenderer *renderer; diff --git a/src/native/jawtrenderer/JAWTRenderer_MacOSX.m b/src/native/jawtrenderer/JAWTRenderer_MacOSX.m index 81e3a545d34c955609163614bf94601a89893749..51d4e50a02c0a4e1aa2516736bc7b38dd06e2d83 100644 --- a/src/native/jawtrenderer/JAWTRenderer_MacOSX.m +++ b/src/native/jawtrenderer/JAWTRenderer_MacOSX.m @@ -16,324 +16,247 @@ #include <sys/types.h> #include <sys/sysctl.h> -#import <AppKit/NSOpenGL.h> #import <AppKit/NSView.h> -#import <Foundation/NSArray.h> #import <Foundation/NSAutoreleasePool.h> -#import <Foundation/NSNotification.h> #import <Foundation/NSObject.h> #import <OpenGL/gl.h> #import <OpenGL/OpenGL.h> +#import <QuartzCore/CALayer.h> +#import <QuartzCore/CAOpenGLLayer.h> #define JAWT_RENDERER_TEXTURE GL_TEXTURE_RECTANGLE_EXT #define JAWT_RENDERER_TEXTURE_FORMAT GL_BGRA #define JAWT_RENDERER_TEXTURE_TYPE GL_UNSIGNED_BYTE -@interface JAWTRenderer : NSObject +@interface JAWTRendererLayer : CAOpenGLLayer { +/* + * XXX The fields of JAWTRendererLayer are declared public for the sake of + * performance so that the function JAWTRenderer_process may effectively be + * implemented as a member of the class. + */ @public - /** - * The OpenGL context of this <tt>JAWTRenderer</tt> which shares - * <tt>texture</tt> with the OpenGL contexts of <tt>subrenderers</tt> and - * enables this <tt>JAWTRederer</tt> to not directly access the OpenGL - * contexts of <tt>subrenderers</tt> because it cannot guarantee - * synchronized access to them anyway. - */ - NSOpenGLContext *glContext; - - jint height; - GLuint texture; - jint width; - - CGFloat frameHeight; - CGFloat frameWidth; - CGFloat frameX; - CGFloat frameY; - - CGFloat boundsHeight; - CGFloat boundsWidth; - CGFloat boundsX; - CGFloat boundsY; - - NSView *view; - - /** - * The <tt>JAWTRenderer</tt>s which are to have their <tt>layer</tt>s - * contained in the <tt>layer</tt> of this <tt>JAWTRenderer</tt>. - */ - NSMutableArray *subrenderers; - /** - * The <tt>JAWTRenderer</tt> which has this <tt>JAWTRenderer</tt> in its - * <tt>subrenderers</tt>. - */ - JAWTRenderer *superrenderer; + CGLContextObj _glContext; + jint _height; + CGLPixelFormatObj _pixelFormat; + GLuint _texture; + jint _width; } -- (void)addSubrenderer:(JAWTRenderer *)subrenderer; -- (void)boundsDidChange:(NSNotification *)notification; -- (void)copyCGLContext:(NSOpenGLContext *)glContext - forPixelFormat:(CGLPixelFormatObj)pixelFormat; +- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat; +- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask; - (void)dealloc; -- (void)frameDidChange:(NSNotification *)notification; +- (void)drawInCGLContext:(CGLContextObj)glContext + pixelFormat:(CGLPixelFormatObj)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval + displayTime:(const CVTimeStamp *)timeStamp; - (id)init; -- (void)paint; -- (void)removeFromSuperrenderer; -- (void)removeSubrenderer:(JAWTRenderer *)subrenderer; -- (void)removeSubrendererAtIndex:(NSUInteger)index; -- (void)reshape; -- (void)setSuperrenderer:(JAWTRenderer *)aSuperrenderer; -- (void)setView:(NSView *)aView; -- (void)update; -@end /* JAWTRenderer */ - -void -JAWTRenderer_addNotifyLightweightComponent - (jlong handle, jobject component, jlong parentHandle) -{ - JAWTRenderer *renderer; - JAWTRenderer *parentRenderer; - NSAutoreleasePool *autoreleasePool; - - renderer = (JAWTRenderer *) (intptr_t) handle; - parentRenderer = (JAWTRenderer *) (intptr_t) parentHandle; - autoreleasePool = [[NSAutoreleasePool alloc] init]; - - if (parentRenderer) - [parentRenderer addSubrenderer:renderer]; - [renderer copyCGLContext:nil forPixelFormat:0]; - - [autoreleasePool release]; -} +@end /* JAWTRendererLayer */ void -JAWTRenderer_close - (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component) +JAWTRenderer_close(JNIEnv *env, jclass clazz, jlong handle, jobject component) { - JAWTRenderer *renderer; + JAWTRendererLayer **thiz; NSAutoreleasePool *autoreleasePool; - renderer = (JAWTRenderer *) (intptr_t) handle; + thiz = (JAWTRendererLayer **) (intptr_t) handle; autoreleasePool = [[NSAutoreleasePool alloc] init]; - JAWTRenderer_removeNotifyLightweightComponent(handle, component); - [renderer release]; + if (*thiz) + [*thiz release]; + free(thiz); [autoreleasePool release]; } jlong -JAWTRenderer_open(JNIEnv *jniEnv, jclass clazz, jobject component) +JAWTRenderer_open(JNIEnv *env, jclass clazz, jobject component) { - NSAutoreleasePool *autoreleasePool; - JAWTRenderer *renderer; - - autoreleasePool = [[NSAutoreleasePool alloc] init]; - - renderer = [[JAWTRenderer alloc] init]; - - [autoreleasePool release]; - return (jlong) (intptr_t) renderer; + return (jlong) (intptr_t) calloc(1, sizeof(JAWTRendererLayer *)); } jboolean JAWTRenderer_paint - (JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, jobject g) + (jint version, JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, + jobject g, jint zOrder) { - NSView *component; + NSAutoreleasePool *autoreleasePool; + JAWTRendererLayer *thizLayer; + jboolean wantsPaint = JNI_TRUE; + JAWTRendererLayer **thiz; - component - = ((JAWT_MacOSXDrawingSurfaceInfo *) (dsi->platformInfo))->cocoaViewRef; - if (component) - { - JAWTRenderer *renderer; - NSAutoreleasePool *autoreleasePool; + autoreleasePool = [[NSAutoreleasePool alloc] init]; - renderer = (JAWTRenderer *) (intptr_t) handle; - autoreleasePool = [[NSAutoreleasePool alloc] init]; + /* + * The native peer of the AWT Canvas that is the component of this + * JAWTRenderer should be a JAWTRendererLayer. + */ + if (JAWT_MACOSX_USE_CALAYER == (version & JAWT_MACOSX_USE_CALAYER)) + { + id<JAWT_SurfaceLayers> surfaceLayers + = (id<JAWT_SurfaceLayers>) (dsi->platformInfo); + CALayer *layer = surfaceLayers.layer; - if (renderer->view != component) - [renderer setView:component]; + if (layer && [layer isKindOfClass:[JAWTRendererLayer class]]) + thizLayer = (JAWTRendererLayer *) layer; else { - // update - NSRect frame; - - frame = [component frame]; - if ((renderer->frameX != frame.origin.x) - || (renderer->frameY != frame.origin.y) - || (renderer->frameWidth != frame.size.width) - || (renderer->frameHeight != frame.size.height)) - [renderer update]; + thizLayer = [JAWTRendererLayer layer]; + if (thizLayer) + surfaceLayers.layer = thizLayer; else + wantsPaint = JNI_FALSE; + } + } + else + { + NSView *view + = ((JAWT_MacOSXDrawingSurfaceInfo *) (dsi->platformInfo)) + ->cocoaViewRef; + CALayer *layer = [view layer]; + + if (layer && [layer isKindOfClass:[JAWTRendererLayer class]]) + thizLayer = (JAWTRendererLayer *) layer; + else + { + thizLayer = [JAWTRendererLayer layer]; + if (thizLayer) { - // reshape - NSRect bounds; - - bounds = [component bounds]; - if ((renderer->boundsX != bounds.origin.x) - || (renderer->boundsY != bounds.origin.y) - || (renderer->boundsWidth != bounds.size.width) - || (renderer->boundsHeight != bounds.size.height)) - [renderer reshape]; + [view setLayer:thizLayer]; + [view setWantsLayer:YES]; } + else + wantsPaint = JNI_FALSE; } - - [renderer paint]; - - [autoreleasePool release]; } - return JNI_TRUE; -} -jboolean -JAWTRenderer_paintLightweightComponent - (jlong handle, jobject component, jobject g) -{ - JAWTRenderer *renderer; - NSAutoreleasePool *autoreleasePool; - - renderer = (JAWTRenderer *) (intptr_t) handle; - autoreleasePool = [[NSAutoreleasePool alloc] init]; + /* + * This JAWTRenderer should paint into the JAWTRendererLayer which is the + * native peer of the AWT Canvas that is the component of this JAWTRenderer. + */ + thiz = (JAWTRendererLayer **) (intptr_t) handle; + if (*thiz != thizLayer) + { + if (*thiz) + [*thiz release]; + *thiz = thizLayer; + if (thizLayer) + [thizLayer retain]; + } - // TODO Auto-generated method stub + /* + * Forward the paint request from the AWT Canvas to the JAWTRendererLayer + * that is the former's native peer. + */ + if (thizLayer) + { + if (zOrder > -1) + thizLayer.zPosition = zOrder; + [thizLayer setNeedsDisplay]; + } [autoreleasePool release]; - return JNI_TRUE; + return wantsPaint; } jboolean JAWTRenderer_process - (JNIEnv *jniEnv, jclass clazz, - jlong handle, jobject component, - jint *data, jint length, - jint width, jint height) + (JNIEnv *env, jclass clazz, jlong handle, jobject component, jint *data, + jint length, jint width, jint height) { - JAWTRenderer *renderer; - NSAutoreleasePool *autoreleasePool; + JAWTRendererLayer *thiz = *((JAWTRendererLayer **) (intptr_t) handle); - renderer = (JAWTRenderer *) (intptr_t) handle; - autoreleasePool = [[NSAutoreleasePool alloc] init]; - - if (data && length) + if (thiz && data && length) { - @synchronized (renderer) - { - if (renderer->glContext) - { - [renderer->glContext makeCurrentContext]; + NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init]; + CGLContextObj glContext = thiz->_glContext; - if (renderer->texture - && ((width != renderer->width) - || (height != renderer->height))) - { - glDeleteTextures(1, &(renderer->texture)); - renderer->texture = 0; - } - if (renderer->texture) - { - glBindTexture(JAWT_RENDERER_TEXTURE, renderer->texture); - glTexSubImage2D( - JAWT_RENDERER_TEXTURE, - 0, - 0, 0, width, height, - JAWT_RENDERER_TEXTURE_FORMAT, - JAWT_RENDERER_TEXTURE_TYPE, - data); - } - else - { - glGenTextures(1, &(renderer->texture)); - glBindTexture(JAWT_RENDERER_TEXTURE, renderer->texture); - glTexParameterf( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_PRIORITY, - 1.0); - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_WRAP_S, - GL_CLAMP_TO_EDGE); - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_WRAP_T, - GL_CLAMP_TO_EDGE); - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_MAG_FILTER, - GL_LINEAR); - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_MIN_FILTER, - GL_LINEAR); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - glTexParameteri( - JAWT_RENDERER_TEXTURE, - GL_TEXTURE_STORAGE_HINT_APPLE, - GL_STORAGE_SHARED_APPLE); - - glTexImage2D( - JAWT_RENDERER_TEXTURE, - 0, - 4, - width, height, - 0, - JAWT_RENDERER_TEXTURE_FORMAT, - JAWT_RENDERER_TEXTURE_TYPE, - data); - } - renderer->width = width; - renderer->height = height; - } - } - } + if (glContext && (kCGLNoError == CGLLockContext(glContext))) + { + GLuint texture = thiz->_texture; - [autoreleasePool release]; - return JNI_TRUE; -} + CGLSetCurrentContext(glContext); -void -JAWTRenderer_processLightweightComponentEvent - (jlong handle, jint x, jint y, jint width, jint height) -{ - JAWTRenderer *renderer; - NSAutoreleasePool *autoreleasePool; + if (texture + && ((width != thiz->_width) || (height != thiz->_height))) + { + glDeleteTextures(1, &texture); + thiz->_texture = texture = 0; + } + if (texture) + { + glBindTexture(JAWT_RENDERER_TEXTURE, texture); + glTexSubImage2D( + JAWT_RENDERER_TEXTURE, + 0, + 0, 0, width, height, + JAWT_RENDERER_TEXTURE_FORMAT, + JAWT_RENDERER_TEXTURE_TYPE, + data); + } + else + { + glGenTextures(1, &texture); + thiz->_texture = texture; + + glBindTexture(JAWT_RENDERER_TEXTURE, texture); + glTexParameterf( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_PRIORITY, + 1.0); + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glTexParameteri( + JAWT_RENDERER_TEXTURE, + GL_TEXTURE_STORAGE_HINT_APPLE, + GL_STORAGE_SHARED_APPLE); + + glTexImage2D( + JAWT_RENDERER_TEXTURE, + 0, + 4, + width, height, + 0, + JAWT_RENDERER_TEXTURE_FORMAT, + JAWT_RENDERER_TEXTURE_TYPE, + data); + } + thiz->_width = width; + thiz->_height = height; - renderer = (JAWTRenderer *) (intptr_t) handle; - autoreleasePool = [[NSAutoreleasePool alloc] init]; + CGLUnlockContext(glContext); + } - @synchronized (renderer) - { - renderer->boundsX = x; - renderer->boundsY = y; - renderer->boundsWidth = width; - renderer->boundsHeight = height; + [autoreleasePool release]; } - [autoreleasePool release]; -} - -void -JAWTRenderer_removeNotifyLightweightComponent(jlong handle, jobject component) -{ - JAWTRenderer *renderer; - NSAutoreleasePool *autoreleasePool; - - renderer = (JAWTRenderer *) (intptr_t) handle; - autoreleasePool = [[NSAutoreleasePool alloc] init]; - - [renderer removeFromSuperrenderer]; - - [autoreleasePool release]; + return JNI_TRUE; } jstring -JAWTRenderer_sysctlbyname(JNIEnv *jniEnv, jstring name) +JAWTRenderer_sysctlbyname(JNIEnv *env, jstring name) { const char *_name; jstring value = NULL; - _name = (*jniEnv)->GetStringUTFChars(jniEnv, name, NULL); + _name = (*env)->GetStringUTFChars(env, name, NULL); if (_name) { size_t valueLength; @@ -357,443 +280,144 @@ JAWTRenderer_sysctlbyname(JNIEnv *jniEnv, jstring name) } else _value = NULL; - (*jniEnv)->ReleaseStringUTFChars(jniEnv, name, _name); + (*env)->ReleaseStringUTFChars(env, name, _name); if (_value) { - value = (*jniEnv)->NewStringUTF(jniEnv, _value); + value = (*env)->NewStringUTF(env, _value); free(_value); } } return value; } -@implementation JAWTRenderer -- (void)addSubrenderer:(JAWTRenderer *)subrenderer +@implementation JAWTRendererLayer +- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { - @synchronized (self) + CGLContextObj glContext = CGLRetainContext(_glContext); + + /* + * Perform any one-time configuration/preparation of the newly-initialized + * OpenGL context which this CAOpenGLLayer will be drawing into + * (in the future). + */ + if (glContext && (kCGLNoError == CGLLockContext(glContext))) { - if (!subrenderers) - subrenderers = [[NSMutableArray arrayWithCapacity:1] retain]; - if (NSNotFound == [subrenderers indexOfObject:subrenderer]) - { - [subrenderers addObject:subrenderer]; - [subrenderer retain]; - [subrenderer setSuperrenderer:self]; - } + GLint param; + + CGLSetCurrentContext(glContext); + + param = 1; + CGLSetParameter(glContext, kCGLCPSurfaceOpacity, ¶m); + param = 0; + CGLSetParameter(glContext, kCGLCPSwapInterval, ¶m); + + glDisable(GL_ALPHA_TEST); + glDisable(GL_BLEND); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_DITHER); + glDisable(GL_LIGHTING); + glDisable(GL_SCISSOR_TEST); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthMask(GL_FALSE); + glStencilMask(0); + glHint(GL_TRANSFORM_HINT_APPLE, GL_FASTEST); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + CGLUnlockContext(glContext); } -} -- (void)boundsDidChange:(NSNotification *)notification -{ - if ([notification object] == view) - [self reshape]; + return glContext; } -- (void)copyCGLContext:(NSOpenGLContext *)glContext - forPixelFormat:(CGLPixelFormatObj)pixelFormat +- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { - @synchronized (self) - { - if (self->glContext) - { - [self->glContext makeCurrentContext]; - if (texture) - { - glDeleteTextures(1, &texture); - texture = 0; - } - [NSOpenGLContext clearCurrentContext]; - - [self->glContext release]; - self->glContext = nil; - } - - if (glContext) - { - NSOpenGLPixelFormat *format = [NSOpenGLPixelFormat alloc]; - - /* - * Unfortunately, initWithCGLPixelFormatObj: is available starting - * with Mac OS X 10.6. - */ - if ([format - respondsToSelector:@selector(initWithCGLPixelFormatObj:)]) - { - format = [format initWithCGLPixelFormatObj:pixelFormat]; - } - else - { - NSOpenGLPixelFormatAttribute pixelFormatAttribs[] - = { NSOpenGLPFAWindow, 0 }; - - format = [format initWithAttributes:pixelFormatAttribs]; - } - - self->glContext - = [[NSOpenGLContext alloc] - initWithFormat:format - shareContext:glContext]; - [format release]; - } - } + return CGLRetainPixelFormat(_pixelFormat); } - (void)dealloc { - /* subrenderers */ - @synchronized (self) - { - if (subrenderers) - { - NSUInteger subrendererCount = [subrenderers count]; - - while (subrendererCount > 0) - { - --subrendererCount; - [self removeSubrendererAtIndex:subrendererCount]; - } - [subrenderers release]; - subrenderers = nil; - } - } - - [self setView:nil]; + if (_glContext) + CGLReleaseContext(_glContext); + if (_pixelFormat) + CGLReleasePixelFormat(_pixelFormat); [super dealloc]; } -- (void)frameDidChange:(NSNotification *)notification -{ - if ([notification object] == view) - [self update]; -} - -- (id)init +- (void)drawInCGLContext:(CGLContextObj)glContext + pixelFormat:(CGLPixelFormatObj)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval + displayTime:(const CVTimeStamp *)timeStamp { - if ((self = [super init])) + if (kCGLNoError == CGLLockContext(glContext)) { + glClear(GL_COLOR_BUFFER_BIT); - glContext = nil; - - height = 0; - texture = 0; - width = 0; - - frameHeight = 0; - frameWidth = 0; - frameX = 0; - frameY = 0; - - boundsHeight = 0; - boundsWidth = 0; - boundsX = 0; - boundsY = 0; - - view = nil; - - subrenderers = nil; - superrenderer = nil; - } - return self; -} - -- (void)paint -{ - if (!glContext) - return; - - [glContext makeCurrentContext]; - - // drawRect: - glClear(GL_COLOR_BUFFER_BIT); - - @synchronized (self) - { - if (texture) + if (_texture) { /* * It may be a misunderstanding of OpenGL context sharing but * JAWT_RENDERER_TEXTURE does not seem to work in glContext unless * it is explicitly bound to texture while glContext is current. */ - glBindTexture(JAWT_RENDERER_TEXTURE, texture); + glBindTexture(JAWT_RENDERER_TEXTURE, _texture); glEnable(JAWT_RENDERER_TEXTURE); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(-1.0, 1.0); - glTexCoord2f(width, 0); + glTexCoord2f(_width, 0); glVertex2f(1.0, 1.0); - glTexCoord2f(width, height); + glTexCoord2f(_width, _height); glVertex2f(1.0, -1.0); - glTexCoord2f(0, height); + glTexCoord2f(0, _height); glVertex2f(-1.0, -1.0); glEnd(); glDisable(JAWT_RENDERER_TEXTURE); } - - /* Draw the subrenderers of this JAWTRenderer. */ - if (subrenderers) - { - NSUInteger subrendererIndex = 0; - NSUInteger subrendererCount = [subrenderers count]; - CGLPixelFormatObj pixelFormat = 0; - for (; - subrendererIndex < subrendererCount; - subrendererIndex++) - { - JAWTRenderer *subrenderer - = [subrenderers objectAtIndex:subrendererIndex]; - - @synchronized (subrenderer) - { - GLfloat subrendererBoundsHeight; - GLfloat subrendererBoundsWidth; - - /* - * Make sure the subrenderer has an NSOpenGLContext - * which is compatible with glContext and shares its - * object state. - */ - if (!(subrenderer->glContext)) - { - if (!pixelFormat) - pixelFormat - = CGLGetPixelFormat([glContext CGLContextObj]); - [subrenderer copyCGLContext:glContext - forPixelFormat:pixelFormat]; - } - - subrendererBoundsHeight = subrenderer->boundsHeight; - subrendererBoundsWidth = subrenderer->boundsWidth; - if (subrenderer->texture - && (subrendererBoundsHeight > 0) - && (subrendererBoundsWidth > 0)) - { - GLfloat x_1 - = -1.0 + 2 * subrenderer->boundsX / boundsWidth; - GLfloat y1 - = 1 - 2 * subrenderer->boundsY / boundsHeight; - GLfloat x1 - = x_1 + 2 * subrendererBoundsWidth / boundsWidth; - GLfloat y_1 - = y1 - 2 * subrendererBoundsHeight / boundsHeight; - - glBindTexture( - JAWT_RENDERER_TEXTURE, - subrenderer->texture); - glEnable(JAWT_RENDERER_TEXTURE); - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex2f(x_1, y1); - glTexCoord2f(subrenderer->width, 0); - glVertex2f(x1, y1); - glTexCoord2f(subrenderer->width, subrenderer->height); - glVertex2f(x1, y_1); - glTexCoord2f(0, subrenderer->height); - glVertex2f(x_1, y_1); - glEnd(); - glDisable(JAWT_RENDERER_TEXTURE); - } - } - } - } + CGLUnlockContext(glContext); } - glFlush(); + [super drawInCGLContext:glContext + pixelFormat:pixelFormat + forLayerTime:timeInterval + displayTime:timeStamp]; } -- (void)removeFromSuperrenderer -{ - if (superrenderer) - [superrenderer removeSubrenderer:self]; - [self copyCGLContext:nil forPixelFormat:nil]; -} - -- (void)removeSubrenderer:(JAWTRenderer *)subrenderer -{ - @synchronized (self) - { - if (subrenderers) - { - NSUInteger index = [subrenderers indexOfObject:subrenderer]; - - if (NSNotFound != index) - [self removeSubrendererAtIndex:index]; - } - } -} - -- (void)removeSubrendererAtIndex:(NSUInteger)index -{ - @synchronized (self) - { - if (subrenderers) - { - JAWTRenderer *subrenderer = [subrenderers objectAtIndex:index]; - - [subrenderers removeObjectAtIndex:index]; - [subrenderer setSuperrenderer:nil]; - [subrenderer release]; - } - } -} - -- (void)reshape -{ - NSRect bounds; - - bounds = [view bounds]; - boundsHeight = bounds.size.height; - boundsWidth = bounds.size.width; - boundsX = bounds.origin.x; - boundsY = bounds.origin.y; - if ((bounds.size.width > 0) && (bounds.size.height > 0) && glContext) - { - [glContext makeCurrentContext]; - - glViewport( - bounds.origin.x, bounds.origin.y, - bounds.size.width, bounds.size.height); - } -} - -- (void)setSuperrenderer:(JAWTRenderer *)aSuperrenderer -{ - if (superrenderer != aSuperrenderer) - { - if (superrenderer) - [superrenderer release]; - - superrenderer = aSuperrenderer; - - if (superrenderer) - [superrenderer retain]; - } -} - -- (void)setView:(NSView *)aView +- (id)init { - if (view != aView) + if ((self = [super init])) { - if (view) + CGLPixelFormatAttribute attribs[] + = { kCGLPFAAccelerated, kCGLPFAWindow, 0 }; + GLint npix; + + _glContext = NULL; + _height = 0; + _pixelFormat = NULL; + _texture = 0; + _width = 0; + + if ((kCGLNoError == CGLChoosePixelFormat(attribs, &_pixelFormat, &npix)) + && (kCGLNoError + == CGLCreateContext(_pixelFormat, NULL, &_glContext))) { -#ifdef JAWT_RENDERER_USE_NSNOTIFICATIONCENTER - NSNotificationCenter *notificationCenter; - - notificationCenter = [NSNotificationCenter defaultCenter]; - if (notificationCenter) - { - [notificationCenter - removeObserver:self - name:NSViewBoundsDidChangeNotification - object:view]; - [notificationCenter - removeObserver:self - name:NSViewFrameDidChangeNotification - object:view]; - } -#endif /* JAWT_RENDERER_USE_NSNOTIFICATIONCENTER */ - - [self copyCGLContext:nil forPixelFormat:0]; - - [view release]; + self.asynchronous = YES; + /* + * The AWT Canvas that corresponds to this CAOpenGLLayer will ensure + * that the latter will be displayed on bounds changes. + */ + self.needsDisplayOnBoundsChange = NO; } - - view = aView; - - if (view) + else { - NSOpenGLPixelFormatAttribute pixelFormatAttribs[] - = { NSOpenGLPFAWindow, 0 }; - NSOpenGLPixelFormat *pixelFormat; - -#ifdef JAWT_RENDERER_USE_NSNOTIFICATIONCENTER - NSNotificationCenter *notificationCenter; -#endif /* JAWT_RENDERER_USE_NSNOTIFICATIONCENTER */ - - [view retain]; - - pixelFormat - = [[NSOpenGLPixelFormat alloc] - initWithAttributes:pixelFormatAttribs]; - if (pixelFormat) - { - glContext - = [[NSOpenGLContext alloc] initWithFormat:pixelFormat - shareContext:nil]; - if (glContext) - { - GLint surfaceOpacity; - GLint swapInterval; - - // prepareOpenGL - [glContext makeCurrentContext]; - - surfaceOpacity = 1; - [glContext setValues:&surfaceOpacity - forParameter:NSOpenGLCPSurfaceOpacity]; - swapInterval = 0; - [glContext setValues:&swapInterval - forParameter:NSOpenGLCPSwapInterval]; - - glDisable(GL_ALPHA_TEST); - glDisable(GL_BLEND); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_DITHER); - glDisable(GL_LIGHTING); - glDisable(GL_SCISSOR_TEST); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glDepthMask(GL_FALSE); - glStencilMask(0); - glHint(GL_TRANSFORM_HINT_APPLE, GL_FASTEST); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - } - [pixelFormat release]; - } - - if (glContext && ([glContext view] != view)) - [glContext setView:view]; - -#ifdef JAWT_RENDERER_USE_NSNOTIFICATIONCENTER - notificationCenter = [NSNotificationCenter defaultCenter]; - if (notificationCenter) - { - [view setPostsBoundsChangedNotifications:YES]; - [notificationCenter - addObserver:self - selector:@selector(boundsDidChange:) - name:NSViewBoundsDidChangeNotification - object:view]; - [view setPostsFrameChangedNotifications:YES]; - [notificationCenter - addObserver:self - selector:@selector(frameDidChange:) - name:NSViewFrameDidChangeNotification - object:view]; - } -#endif /* JAWT_RENDERER_USE_NSNOTIFICATIONCENTER */ - - [self update]; + [self release]; + self = nil; } } + return self; } - -- (void)update -{ - NSRect frame; - - frame = [view frame]; - frameHeight = frame.size.height; - frameWidth = frame.size.width; - frameX = frame.origin.x; - frameY = frame.origin.y; - if (glContext) - [glContext update]; - - [self reshape]; -} -@end /* JAWTRenderer */ +@end /* JAWTRendererLayer */ diff --git a/src/native/jawtrenderer/JAWTRenderer_Windows.c b/src/native/jawtrenderer/JAWTRenderer_Windows.c new file mode 100644 index 0000000000000000000000000000000000000000..bf161c0dedf6088a46e641dda53bbe45e0054c59 --- /dev/null +++ b/src/native/jawtrenderer/JAWTRenderer_Windows.c @@ -0,0 +1,279 @@ +/* + * Jitsi, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +#include "JAWTRenderer.h" + +#include <d3d9.h> +#include <d3dx9tex.h> +#include <jawt_md.h> +#include <stdint.h> +#include <stdlib.h> + +typedef struct _JAWTRenderer +{ + LPDIRECT3D9 d3d; + LPDIRECT3DDEVICE9 device; + jint height; + HWND hwnd; + BOOL lost; + LPDIRECT3DSURFACE9 surface; + jint width; +} +JAWTRenderer; + +HRESULT _JAWTRenderer_createDevice(JAWTRenderer *thiz, jint width, jint height); + +void +JAWTRenderer_close(JNIEnv *env, jclass clazz, jlong handle, jobject component) +{ + JAWTRenderer *thiz = (JAWTRenderer *) (intptr_t) handle; + + if (thiz->surface) + IDirect3DSurface9_Release(thiz->surface); + if (thiz->device) + IDirect3DDevice9_Release(thiz->device); + IDirect3D9_Release(thiz->d3d); + free(thiz); +} + +jlong +JAWTRenderer_open(JNIEnv *env, jclass clazz, jobject component) +{ + LPDIRECT3D9 d3d = Direct3DCreate9(D3D_SDK_VERSION); + JAWTRenderer *thiz; + + if (d3d) + { + thiz = calloc(1, sizeof(JAWTRenderer)); + if (thiz) + thiz->d3d = d3d; + else + IDirect3D9_Release(d3d); + } + else + thiz = NULL; + return (jlong) (intptr_t) thiz; +} + +jboolean +JAWTRenderer_paint + (jint version, JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, + jobject g, jint zOrder) +{ + HDC hdc = ((JAWT_Win32DrawingSurfaceInfo *) (dsi->platformInfo))->hdc; + JAWTRenderer *thiz = (JAWTRenderer *) (intptr_t) handle; + + LPDIRECT3DDEVICE9 device = thiz->device; + HWND hwnd = WindowFromDC(hdc); + + if (device && (thiz->hwnd == hwnd)) + { + HRESULT hr; + + /* + * Check whether Direct3D considers the device of this JAWTRenderer + * functional/valid. + */ + hr = IDirect3DDevice9_TestCooperativeLevel(device); + if (SUCCEEDED(hr)) + { + /* + * If we do not have a Direct3D surface to present, we will make + * sure that the display is cleared. Otherwise, we do not have to + * clear it because we render complete frames in the whole viewport + * with transparency. + */ + BOOL clear = TRUE; + + /* Copy the Direct3D surface into the back buffer. */ + if (thiz->surface) + { + LPDIRECT3DSURFACE9 backBuffer; + + hr + = IDirect3DDevice9_GetBackBuffer( + device, + 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer); + if (SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_BeginScene(device); + if (SUCCEEDED(hr)) + { + IDirect3DDevice9_UpdateSurface( + device, + thiz->surface, NULL, backBuffer, NULL); + IDirect3DDevice9_EndScene(device); + clear = FALSE; + } + IDirect3DSurface9_Release(backBuffer); + } + } + if (clear) + { + /* Clear the Direct3D back buffer. */ + IDirect3DDevice9_Clear( + device, + 0, + 0, + D3DCLEAR_TARGET, + D3DCOLOR_XRGB(0xff, 0xff, 0xff), + 0.0f, + 0); + } + + /* Present the Direct3D back buffer. */ + IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL); + } + else + thiz->lost = TRUE; + } + else + { + thiz->hwnd = hwnd; + thiz->lost = TRUE; + } + + return JNI_TRUE; +} + +jboolean +JAWTRenderer_process + (JNIEnv *env, jclass clazz, jlong handle, jobject component, jint *data, + jint length, jint width, jint height) +{ + JAWTRenderer *thiz = (JAWTRenderer *) (intptr_t) handle; + + if (!(thiz->device) + || (thiz->width != width) + || (thiz->height != height) + || thiz->lost) + { + /* + * Release the device and the surface if any because it appears we have + * to re-create them. + */ + thiz->lost = FALSE; + if (thiz->surface) + { + IDirect3DSurface9_Release(thiz->surface); + thiz->surface = NULL; + } + if (thiz->device) + { + IDirect3DDevice9_Release(thiz->device); + thiz->device = NULL; + } + + if (thiz->hwnd) + { + HRESULT hr; + + hr = _JAWTRenderer_createDevice(thiz, width, height); + if (SUCCEEDED(hr)) + { + hr + = IDirect3DDevice9_CreateOffscreenPlainSurface( + thiz->device, + width, + height, + D3DFMT_X8R8G8B8, + D3DPOOL_SYSTEMMEM, + &(thiz->surface), + NULL); + if (SUCCEEDED(hr)) + { + thiz->width = width; + thiz->height = height; + } + else + { + thiz->surface = NULL; + /* + * Well, we do not know why we would fail to create the + * surface but such a scenario seems grave enough to us to + * give up this JAWTRenderer. + */ + return JNI_FALSE; + } + } + /* + * If we failed to create the Direct3D device, we will try again + * next time in the hope that we will succeed eventually. + */ + } + } + + if (thiz->surface) + { + RECT rect; + + rect.bottom = height; + rect.left = 0; + rect.right = width; + rect.top = 0; + D3DXLoadSurfaceFromMemory( + thiz->surface, + NULL, + NULL, + data, + D3DFMT_A8R8G8B8, + width * 4, + NULL, + &rect, + D3DX_FILTER_NONE, + 0); + } + + return JNI_TRUE; +} + +HRESULT +_JAWTRenderer_createDevice(JAWTRenderer *thiz, jint width, jint height) +{ + D3DPRESENT_PARAMETERS params; + HRESULT hr; + + ZeroMemory(¶ms, sizeof(D3DPRESENT_PARAMETERS)); + + params.AutoDepthStencilFormat = D3DFMT_D16; + params.BackBufferCount = 1; + params.BackBufferFormat = D3DFMT_UNKNOWN; + params.BackBufferHeight = height; + params.BackBufferWidth = width; + params.EnableAutoDepthStencil = FALSE; + params.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; + params.FullScreen_RefreshRateInHz = 0; + params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + params.SwapEffect = D3DSWAPEFFECT_DISCARD; + params.Windowed = TRUE; + + hr + = IDirect3D9_CheckDeviceMultiSampleType( + thiz->d3d, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + params.BackBufferFormat, + params.Windowed, + D3DMULTISAMPLE_2_SAMPLES, + NULL); + params.MultiSampleQuality + = SUCCEEDED(hr) ? D3DMULTISAMPLE_2_SAMPLES : D3DMULTISAMPLE_NONE; + + hr + = IDirect3D9_CreateDevice( + thiz->d3d, + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + thiz->hwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + ¶ms, + &(thiz->device)); + if (FAILED(hr)) + thiz->device = NULL; + + return hr; +} diff --git a/src/native/jawtrenderer/JAWTRenderer_Windows.cpp b/src/native/jawtrenderer/JAWTRenderer_Windows.cpp deleted file mode 100644 index e150d571f922bbf2aad4182a8737103f6bc7cd04..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/JAWTRenderer_Windows.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -#include "jawt_md.h" -#include "JAWTRenderer.h" - -#include "windows/d3d_context.h" -#include "windows/d3d_device.h" -#include "windows/d3d_surface.h" - -struct D3DBlitter -{ - D3DContext* d3d; - D3DDevice* device; - D3DSurface* surface; - HWND hwnd; - size_t width; - size_t height; - bool lost; -}; - -void JAWTRenderer_close - (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component) -{ - D3DBlitter* blitter = reinterpret_cast<D3DBlitter*>(handle); - - if(!blitter) - { - return; - } - - if(blitter->surface) - { - delete blitter->surface; - blitter->surface = NULL; - } - - if(blitter->device) - { - delete blitter->device; - blitter->device = NULL; - } - - if(blitter->d3d) - { - delete blitter->d3d; - blitter->d3d = NULL; - } - - delete blitter; -} - -jlong JAWTRenderer_open(JNIEnv *jniEnv, jclass clazz, jobject component) -{ - D3DBlitter* ret = new D3DBlitter(); - - ret->d3d = D3DContext::createD3DContext(); - ret->surface = NULL; - ret->device = NULL; - ret->width = 0; - ret->height = 0; - ret->lost = false; - - /* failed to initialize Direct3D */ - if(!ret->d3d) - { - delete ret; - ret = NULL; - } - - return (jlong)ret; -} - -jboolean JAWTRenderer_paint - (JAWT_DrawingSurfaceInfo *dsi, jclass clazz, jlong handle, jobject g) -{ - JAWT_Win32DrawingSurfaceInfo* dsi_win = - reinterpret_cast<JAWT_Win32DrawingSurfaceInfo*>(dsi->platformInfo); - D3DBlitter* blitter = reinterpret_cast<D3DBlitter*>(handle); - HWND hwnd = WindowFromDC(dsi_win->hdc); - - if(!blitter) - return JNI_FALSE; - - if(blitter->device == NULL || blitter->hwnd != hwnd) - { - blitter->hwnd = hwnd; - blitter->lost = true; - return JNI_TRUE; - } - - if(!blitter->device->validate()) - { - blitter->lost = true; - return JNI_TRUE; - } - - blitter->device->render(blitter->surface); - return JNI_TRUE; -} - -jboolean JAWTRenderer_process - (JNIEnv *jniEnv, jclass clazz, - jlong handle, jobject component, - jint *data, jint length, - jint width, jint height) -{ - D3DBlitter* blitter = reinterpret_cast<D3DBlitter*>(handle); - - if(!blitter) - { - return JNI_FALSE; - } - - if(!blitter->device || blitter->width != width || blitter->height != height - || blitter->lost) - { - D3DSurface* oldSurface = NULL; - D3DDevice* oldDevice = NULL; - - blitter->lost = false; - - /* size has changed, recreate our device and surface */ - if(blitter->surface) - { - delete blitter->surface; - blitter->surface = NULL; - } - - if(blitter->device) - { - delete blitter->device; - blitter->device = NULL; - } - - if(blitter->hwnd == NULL) - { - return JNI_TRUE; - } - - blitter->device = blitter->d3d->createDevice(blitter->hwnd, width, - height); - - if(!blitter->device) - { - /* device creation failed */ - - blitter->surface = NULL; - /* maybe we go fullscreen and/or hwnd of the window has changed - * so we return true to force native method to be called and so - * update blitter->hwnd for the next call - */ - return JNI_TRUE; - } - - blitter->surface = blitter->device->createSurface(width, height); - - if(!blitter->surface) - { - return JNI_FALSE; - } - - blitter->width = width; - blitter->height = height; - } - - if(blitter->surface) - { - blitter->surface->loadData(reinterpret_cast<char*>(data), - width, height); - } - return JNI_TRUE; -} - diff --git a/src/native/jawtrenderer/org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.c b/src/native/jawtrenderer/org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.c index 465923003de1c8433e28c91b4b27c4a958f42abb..236350e28ebc05ba279f7492b5598fe4ea77ec29 100644 --- a/src/native/jawtrenderer/org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.c +++ b/src/native/jawtrenderer/org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.c @@ -8,45 +8,57 @@ #include "org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h" #include "JAWTRenderer.h" -JNIEXPORT void JNICALL -Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_addNotifyLightweightComponent - (JNIEnv *jniEnv, jclass clazz, - jlong handle, jobject component, - jlong parentHandle) -{ -#ifdef __APPLE__ - JAWTRenderer_addNotifyLightweightComponent(handle, component, parentHandle); -#endif /* #ifdef __APPLE__ */ -} - JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_close - (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component) + (JNIEnv *env, jclass clazz, jlong handle, jobject component) { - JAWTRenderer_close(jniEnv, clazz, handle, component); + JAWTRenderer_close(env, clazz, handle, component); } JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_open - (JNIEnv *jniEnv, jclass clazz, jobject component) + (JNIEnv *env, jclass clazz, jobject component) { - return JAWTRenderer_open(jniEnv, clazz, component); + return JAWTRenderer_open(env, clazz, component); } JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paint - (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component, jobject g) + (JNIEnv *env, jclass clazz, jlong handle, jobject component, jobject g, + jint zOrder) { JAWT awt; + jboolean awtIsAvailable; jboolean wantsPaint; - awt.version = JAWT_VERSION_1_3; + awt.version = JAWT_VERSION_1_4; +#ifdef __APPLE__ +#ifndef JAWT_MACOSX_USE_CALAYER +#define JAWT_MACOSX_USE_CALAYER 0x80000000 +#endif /* #ifndef JAWT_MACOSX_USE_CALAYER */ + + awt.version |= JAWT_MACOSX_USE_CALAYER; + awtIsAvailable = JAWT_GetAWT(env, &awt); + /* + * We do not know whether JAWT_GetAWT will fail when JAWT_MACOSX_USE_CALAYER + * is specified and not supported or it will rather remove the flag from the + * version field of JAWT. That's why we will call the function in question + * again in case of failure with the flag removed. + */ + if (JNI_FALSE == awtIsAvailable) + { + awt.version &= ~JAWT_MACOSX_USE_CALAYER; + awtIsAvailable = JAWT_GetAWT(env, &awt); + } +#else /* #ifdef __APPLE__ */ + awtIsAvailable = JAWT_GetAWT(env, &awt); +#endif /* #ifdef __APPLE__ */ wantsPaint = JNI_TRUE; - if (JAWT_GetAWT(jniEnv, &awt) != JNI_FALSE) + if (JNI_TRUE == awtIsAvailable) { JAWT_DrawingSurface *ds; - ds = awt.GetDrawingSurface(jniEnv, component); + ds = awt.GetDrawingSurface(env, component); if (ds) { jint dsLock; @@ -60,12 +72,19 @@ Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paint if (dsi && dsi->platformInfo) { /* - * The function arguments jniEnv and component are now + * The function arguments env and component are now * available as the fields env and target, respectively, of * the JAWT_DrawingSurface which is itself the value of the * field ds of the JAWT_DrawingSurfaceInfo. */ - wantsPaint = JAWTRenderer_paint(dsi, clazz, handle, g); + wantsPaint + = JAWTRenderer_paint( + awt.version, + dsi, + clazz, + handle, + g, + zOrder); ds->FreeDrawingSurfaceInfo(dsi); } ds->Unlock(ds); @@ -76,45 +95,25 @@ Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paint return wantsPaint; } -JNIEXPORT jboolean JNICALL -Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paintLightweightComponent - (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component, jobject g) -{ - jboolean wantsPaint; - -#ifdef __APPLE__ - wantsPaint = JAWTRenderer_paintLightweightComponent(handle, component, g); -#else /* #ifdef __APPLE__ */ - /* - * There is really no point in delivering any paint events/notifications - * because there is no implementation. - */ - wantsPaint = JNI_FALSE; -#endif /* #ifdef __APPLE__ */ - return wantsPaint; -} - JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_process - (JNIEnv *jniEnv, jclass clazz, - jlong handle, jobject component, - jintArray data, jint offset, jint length, - jint width, jint height) + (JNIEnv *env, jclass clazz, jlong handle, jobject component, jintArray data, + jint offset, jint length, jint width, jint height) { jint *dataPtr; jboolean processed; - dataPtr = (*jniEnv)->GetPrimitiveArrayCritical(jniEnv, data, NULL); + dataPtr = (*env)->GetPrimitiveArrayCritical(env, data, NULL); if (dataPtr) { processed = JAWTRenderer_process( - jniEnv, clazz, + env, clazz, handle, component, dataPtr + offset, length, width, height); - (*jniEnv)->ReleasePrimitiveArrayCritical( - jniEnv, + (*env)->ReleasePrimitiveArrayCritical( + env, data, dataPtr, JNI_ABORT); } @@ -123,32 +122,12 @@ Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_process return processed; } -JNIEXPORT void JNICALL -Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_processLightweightComponentEvent - (JNIEnv *jniEnv, jclass clazz, - jlong handle, - jint x, jint y, jint width, jint height) -{ -#ifdef __APPLE__ - JAWTRenderer_processLightweightComponentEvent(handle, x, y, width, height); -#endif /* #ifdef __APPLE__ */ -} - -JNIEXPORT void JNICALL -Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_removeNotifyLightweightComponent - (JNIEnv *jniEnv, jclass clazz, jlong handle, jobject component) -{ -#ifdef __APPLE__ - JAWTRenderer_removeNotifyLightweightComponent(handle, component); -#endif /* #ifdef __APPLE__ */ -} - JNIEXPORT jstring JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_sysctlbyname - (JNIEnv *jniEnv, jclass clazz, jstring name) + (JNIEnv *env, jclass clazz, jstring name) { #ifdef __APPLE__ - return JAWTRenderer_sysctlbyname(jniEnv, name); + return JAWTRenderer_sysctlbyname(env, name); #else /* #ifdef __APPLE__ */ return NULL; #endif /* #ifdef __APPLE__ */ diff --git a/src/native/jawtrenderer/org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h b/src/native/jawtrenderer/org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h index a2508d2da44d2d7b8cd5a438f224e1569285160e..29d983bb95635042069b52671615be8e15249a38 100644 --- a/src/native/jawtrenderer/org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h +++ b/src/native/jawtrenderer/org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer.h @@ -7,14 +7,6 @@ #ifdef __cplusplus extern "C" { #endif -/* - * Class: org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer - * Method: addNotifyLightweightComponent - * Signature: (JLjava/awt/Component;J)V - */ -JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_addNotifyLightweightComponent - (JNIEnv *, jclass, jlong, jobject, jlong); - /* * Class: org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer * Method: close @@ -34,18 +26,10 @@ JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video /* * Class: org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer * Method: paint - * Signature: (JLjava/awt/Component;Ljava/awt/Graphics;)Z + * Signature: (JLjava/awt/Component;Ljava/awt/Graphics;I)Z */ JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paint - (JNIEnv *, jclass, jlong, jobject, jobject); - -/* - * Class: org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer - * Method: paintLightweightComponent - * Signature: (JLjava/awt/Component;Ljava/awt/Graphics;)Z - */ -JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_paintLightweightComponent - (JNIEnv *, jclass, jlong, jobject, jobject); + (JNIEnv *, jclass, jlong, jobject, jobject, jint); /* * Class: org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer @@ -55,22 +39,6 @@ JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_vi JNIEXPORT jboolean JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_process (JNIEnv *, jclass, jlong, jobject, jintArray, jint, jint, jint, jint); -/* - * Class: org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer - * Method: processLightweightComponentEvent - * Signature: (JIIII)V - */ -JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_processLightweightComponentEvent - (JNIEnv *, jclass, jlong, jint, jint, jint, jint); - -/* - * Class: org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer - * Method: removeNotifyLightweightComponent - * Signature: (JLjava/awt/Component;)V - */ -JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer_removeNotifyLightweightComponent - (JNIEnv *, jclass, jlong, jobject); - /* * Class: org_jitsi_impl_neomedia_jmfext_media_renderer_video_JAWTRenderer * Method: sysctlbyname diff --git a/src/native/jawtrenderer/windows/d3d_context.cpp b/src/native/jawtrenderer/windows/d3d_context.cpp deleted file mode 100644 index 218d9e912b7a980e97ea6226d17f3761527198ae..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/windows/d3d_context.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -/** - * \file d3d_context.cpp - * \brief Direct3D context. - * \author Sebastien Vincent - * \date 2010 - */ - -#include "d3d_context.h" - -D3DContext* D3DContext::createD3DContext() -{ - D3DContext* ret = new D3DContext(); - - if(ret->getDirect3D()) - { - return ret; - } - else - { - /* fail to initialize Direct3D */ - delete ret; - return NULL; - } -} - -D3DContext::D3DContext() -{ - m_d3d = Direct3DCreate9(D3D_SDK_VERSION); -} - -D3DContext::~D3DContext() -{ - if(m_d3d) - { - m_d3d->Release(); - m_d3d = NULL; - } -} - -LPDIRECT3D9 D3DContext::getDirect3D() const -{ - return m_d3d; -} - -D3DDevice* D3DContext::createDevice(HWND hwnd, size_t width, size_t height) -{ - D3DDevice* ret = NULL; - - ret = new D3DDevice(hwnd, getDirect3D(), width, height, false); - if(ret->getDevice()) - { - return ret; - } - else - { - /* problem to create Direct3D device */ - delete ret; - return NULL; - } -} - diff --git a/src/native/jawtrenderer/windows/d3d_context.h b/src/native/jawtrenderer/windows/d3d_context.h deleted file mode 100644 index 36a044bb203cd60256c3a307c32b1e814d941eb9..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/windows/d3d_context.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -/** - * \file d3d_context.h - * \brief Direct3D context. - * \author Sebastien Vincent - * \date 2010 - */ - -#ifndef D3D_CONTEXT_H -#define D3D_CONTEXT_H - -#include <cstdlib> - -#include <d3d9.h> -#include <d3dx9.h> - -#include "d3d_device.h" - -/** - * \class D3DContext - * \brief Direct3D context. - */ -class D3DContext -{ - public: - /** - * \briefCreate a Direct3D context. - * \return Direct3D context pointer or NULL if failed - */ - static D3DContext* createD3DContext(); - - /** - * \brief Constructor. - */ - D3DContext(); - - /** - * \brief Destructor. - */ - ~D3DContext(); - - /** - * \brief Get raw Direct3D context pointer. - * \return Direct3D - */ - LPDIRECT3D9 getDirect3D() const; - - /** - * \brief Create Direct3D device. - * \param hwnd handle of a window - * \param width width of the device - * \param height height of the device - * \return Direct3D device - */ - D3DDevice* createDevice(HWND hwnd, size_t width, size_t height); - - private: - /** - * \brief Direct3D context pointer. - */ - LPDIRECT3D9 m_d3d; -}; - -#endif /* D3D_CONTEXT_H */ - diff --git a/src/native/jawtrenderer/windows/d3d_device.cpp b/src/native/jawtrenderer/windows/d3d_device.cpp deleted file mode 100644 index 45b981c270e8764d9ec31a61e70616b8af0505da..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/windows/d3d_device.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -/** - * \file d3d_device.cpp - * \brief Direct3D device. - * \author Sebastien Vincent - * \date 2010 - */ - -#include "d3d_device.h" - -D3DDevice::D3DDevice(HWND hwnd, LPDIRECT3D9 d3d, size_t width, size_t height, - bool fullscreen) -{ - HRESULT ret = 0; - D3DPRESENT_PARAMETERS settings; - D3DDISPLAYMODE dmode; - - ZeroMemory(&settings, sizeof(D3DPRESENT_PARAMETERS)); - - ret = d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dmode); - if(FAILED(ret)) - { - return; - } - - settings.BackBufferWidth = width; - settings.BackBufferHeight = height; - settings.BackBufferFormat = fullscreen ? dmode.Format : D3DFMT_UNKNOWN; - settings.BackBufferCount = 1; - //settings.hDeviceWindow = hwnd; - settings.Windowed = !fullscreen; - settings.SwapEffect = D3DSWAPEFFECT_DISCARD; - - if(SUCCEEDED(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, settings.BackBufferFormat, !fullscreen, - D3DMULTISAMPLE_2_SAMPLES, NULL))) - { - settings.MultiSampleQuality = D3DMULTISAMPLE_2_SAMPLES; - } - else - { - settings.MultiSampleQuality = D3DMULTISAMPLE_NONE; - } - - settings.EnableAutoDepthStencil = false; - settings.AutoDepthStencilFormat = D3DFMT_D16; - settings.FullScreen_RefreshRateInHz = 0; - settings.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //0; - settings.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER; - - ret = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING, &settings, &m_device); - - if(FAILED(ret)) - { - m_device = NULL; - /* TODO */ - return; - } - - /* copy settings */ - memcpy(&m_settings, &settings, sizeof(settings)); -} - -D3DDevice::~D3DDevice() -{ - if(m_backSurface) - { - //m_backSurface->Release(); - } - - if(m_device) - { - m_device->Release(); - m_device = NULL; - } -} - -LPDIRECT3DDEVICE9 D3DDevice::getDevice() const -{ - return m_device; -} - -bool D3DDevice::validate() -{ - HRESULT ret = 0; - - ret = m_device->TestCooperativeLevel(); - - if(FAILED(ret)) - { - /* device is lost (window not shown) */ - if(ret == D3DERR_DEVICELOST) - { - return false; - } - - /* ready to reset */ - if(ret == D3DERR_DEVICENOTRESET) - { - /* XXX in this case we simply delete and recreate device since - * it always failed to Reset in JAWT but not in pure Windows - * binary - */ - -#if 0 - if(m_backSurface) - { - m_backSurface->Release(); - m_backSurface = NULL; - } - - ret = m_device->Reset(&m_settings); - - if(FAILED(ret)) - { - return false; - } - - ret = m_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, - &m_backSurface); - - if(FAILED(ret)) - { - return false; - } -#endif - } - } - return true; -} - -D3DSurface* D3DDevice::createSurface(size_t width, size_t height) -{ - D3DSurface* ret = NULL; - - ret = new D3DSurface(getDevice(), width, height); - - if(ret->getSurface()) - { - return ret; - } - else - { - /* problem allocating surface */ - delete ret; - return NULL; - } -} - -void D3DDevice::render(D3DSurface* surface) -{ - HRESULT ret = 0; - LPDIRECT3DSURFACE9 surfacePointer = surface->getSurface(); - - if(!surfacePointer) - { - return; - } - - /* clear the back buffer */ - m_device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0xff, 0xff, 0xff), - 0.0f, 0); - - /* Get the back buffer */ - ret = m_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, - &m_backSurface); - if(FAILED(ret)) - { - return; - } - - ret = m_device->BeginScene(); - if(FAILED(ret)) - { - return; - } - - /* copy content on surface */ - m_device->UpdateSurface(surfacePointer, NULL, m_backSurface, NULL); - - /* finish scene and cleanup */ - m_device->EndScene(); - m_backSurface->Release(); - m_backSurface = NULL; - - /* present the back buffer to the display adapter to be drawn */ - m_device->Present(NULL, NULL, NULL, NULL); -} - diff --git a/src/native/jawtrenderer/windows/d3d_device.h b/src/native/jawtrenderer/windows/d3d_device.h deleted file mode 100644 index 61a191cf32689fde255b5876432effe52d49ca63..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/windows/d3d_device.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -/** - * \file d3d_device.h - * \brief Direct3D device. - * \author Sebastien Vincent - * \date 2010 - */ - -#ifndef D3D_DEVICE_H -#define D3D_DEVICE_H - -#include <cstdlib> - -#include <d3d9.h> -#include <d3dx9.h> - -#include "d3d_surface.h" - -/** - * \class D3DDevice - * \brief Direct3D device. - * - * It is used to render contents on screen. - */ -class D3DDevice -{ - public: - /** - * \brief Constructor. - * \param hwnd Handle of the Window - * \param d3d raw Direct3D context - * \param width width of the future device - * \param height height of the future device - * \param fullscreen create device for fullscreen mode - */ - D3DDevice(HWND hwnd, LPDIRECT3D9 d3d, size_t width, size_t height, bool fullscreen); - - /** - * \brief Destructor. - */ - ~D3DDevice(); - - /** - * \brief Get raw Direct3D device pointer. - * \return Direct3D device pointer - */ - LPDIRECT3DDEVICE9 getDevice() const; - - /** - * \brief Validate the device. - * \return true if validation succeed, false otherwise - */ - bool validate(); - - /** - * \brief Create a surface. - * \param width width of the surface - * \param height height of the surface - * \return surface or NULL if problem - */ - D3DSurface* createSurface(size_t width, size_t height); - - /** - * \brief Render a surface on the screen. - * \param surface surface to render on the screen - */ - void render(D3DSurface* surface); - - private: - /** - * \brief Raw Direct3D device. - */ - LPDIRECT3DDEVICE9 m_device; - - /** - * \brief Settings of the device. - */ - D3DPRESENT_PARAMETERS m_settings; - - /** - * \brief Back surface. - */ - LPDIRECT3DSURFACE9 m_backSurface; - - /** - * \brief Width of the device. - */ - size_t m_width; - - /** - * \brief Height of the device. - */ - size_t m_height; -}; - -#endif /* D3D_DEVICE_H */ - diff --git a/src/native/jawtrenderer/windows/d3d_surface.cpp b/src/native/jawtrenderer/windows/d3d_surface.cpp deleted file mode 100644 index c892e02e4cb905ef31c4569bed60590f3056f6b2..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/windows/d3d_surface.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -/** - * \file d3d_surface.cpp - * \brief Direct3D surface. - * \author Sebastien Vincent - * \date 2010 - */ - -#include "d3d_surface.h" -#include "d3dx9_utils.h" - -D3DSurface::D3DSurface(LPDIRECT3DDEVICE9 device, size_t width, size_t height) -{ - HRESULT ret = device->CreateOffscreenPlainSurface(width, height, - D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &m_surface, NULL); - - if(FAILED(ret)) - { - m_surface = NULL; - return; - } - - m_width = width; - m_height = height; -} - -D3DSurface::~D3DSurface() -{ - if(m_surface) - { - m_surface->Release(); - m_surface = NULL; - } -} - -LPDIRECT3DSURFACE9 D3DSurface::getSurface() const -{ - return m_surface; -} - -size_t D3DSurface::getWidth() -{ - return m_width; -} - -size_t D3DSurface::getHeight() -{ - return m_height; -} - -bool D3DSurface::loadData(char *data, size_t width, size_t height) -{ - HRESULT ret = 0; - RECT rect; - - rect.left = 0; - rect.top = 0; - rect.right = width; - rect.bottom = height; - - if(!m_surface) - { - return false; - } - - /* load image from memory */ - ret = D3DXLoadSurfaceFromMemory(m_surface, NULL, NULL, data, - D3DFMT_A8R8G8B8, width * 4, NULL, &rect, D3DX_FILTER_NONE, NULL); - return !FAILED(ret); -} - diff --git a/src/native/jawtrenderer/windows/d3d_surface.h b/src/native/jawtrenderer/windows/d3d_surface.h deleted file mode 100644 index b9074f782ecc5fb4fee54ae9742f78cffc982d1c..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/windows/d3d_surface.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -/** - * \file d3d_surface.h - * \brief Direct3D surface. - * \author Sebastien Vincent - * \date 2010 - */ - -#ifndef D3D_SURFACE_H -#define D3D_SURFACE_H - -#include <cstdlib> - -#include <d3d9.h> -#include <d3dx9.h> - -class D3DDevice; - -/** - * \class D3DSurface - * \brief Direct3D surface. - */ -class D3DSurface -{ - public: - /** - * \brief Constructor. - * \param device device that will create surface - * \param width width of the surface - * \param height height of the surface - */ - D3DSurface(LPDIRECT3DDEVICE9 device, size_t width, size_t height); - - /** - * \brief Destructor. - */ - ~D3DSurface(); - - /** - * \brief Get raw pointer of Direct3D surface. - * \return Direct3D surface. - */ - LPDIRECT3DSURFACE9 getSurface() const; - - /** - * \brief Load data into surface. - * \param data array of bytes - * \param width width of image - * \param height height of image - * \return true if data is loaded, false otherwise - */ - bool loadData(char* data, size_t width, size_t height); - - /** - * \brief Get surface width. - * \return surface width - */ - size_t getWidth(); - - /** - * \brief Get surface height. - * \return surface height - */ - size_t getHeight(); - - private: - /** - * \brief Raw Direct3D surface. - */ - LPDIRECT3DSURFACE9 m_surface; - - /** - * \brief Width of surface. - */ - size_t m_width; - - /** - * \brief Height of surface. - */ - size_t m_height; -}; - -#endif /* D3D_SURFACE_H */ - diff --git a/src/native/jawtrenderer/windows/d3dx9_utils.c b/src/native/jawtrenderer/windows/d3dx9_utils.c deleted file mode 100644 index d974f5eee6ed7da93ac33f1874d77d5b3a29856c..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/windows/d3dx9_utils.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -/* - * Copyright (C) 2009 Tony Wasserka - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - */ - -/** - * \file d3dx9_utils.c - * \brief DirectX functions implementation coming from Wine project. - * \author Wine project - */ - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <d3d9.h> -#include <d3dx9.h> - -#ifdef __cplusplus -extern "C" { /* } */ -#endif - -/* Following structures and functions functions comes from the Wine project. - * There are used to avoid linking to d3dx9_xx.dll since this DLL cannot be - * redistributed directly (it must be installed using DirectXSetup). - */ - -typedef enum _FormatType -{ - FORMAT_ARGB, /* unsigned */ - FORMAT_UNKNOWN - -} FormatType; - -typedef struct _PixelFormatDesc -{ - D3DFORMAT format; - BYTE bits[4]; - BYTE shift[4]; - UINT bytes_per_pixel; - FormatType type; -} PixelFormatDesc; - -/************************************************************ - * pixel format table providing info about number of bytes per pixel, - * number of bits per channel and format type. - * - * Call get_format_info to request information about a specific format. - */ -static const PixelFormatDesc formats[] = -{ - /* format bits per channel shifts per channel bpp type */ - { D3DFMT_R8G8B8, { 0, 8, 8, 8 }, { 0, 16, 8, 0 }, 3, FORMAT_ARGB }, - { D3DFMT_A8R8G8B8, { 8, 8, 8, 8 }, { 24, 16, 8, 0 }, 4, FORMAT_ARGB }, - { D3DFMT_X8R8G8B8, { 0, 8, 8, 8 }, { 0, 16, 8, 0 }, 4, FORMAT_ARGB }, - { D3DFMT_A8B8G8R8, { 8, 8, 8, 8 }, { 24, 0, 8, 16 }, 4, FORMAT_ARGB }, - { D3DFMT_X8B8G8R8, { 0, 8, 8, 8 }, { 0, 0, 8, 16 }, 4, FORMAT_ARGB }, - { D3DFMT_R5G6B5, { 0, 5, 6, 5 }, { 0, 11, 5, 0 }, 2, FORMAT_ARGB }, - { D3DFMT_X1R5G5B5, { 0, 5, 5, 5 }, { 0, 10, 5, 0 }, 2, FORMAT_ARGB }, - { D3DFMT_A1R5G5B5, { 1, 5, 5, 5 }, { 15, 10, 5, 0 }, 2, FORMAT_ARGB }, - { D3DFMT_R3G3B2, { 0, 3, 3, 2 }, { 0, 5, 2, 0 }, 1, FORMAT_ARGB }, - { D3DFMT_A8R3G3B2, { 8, 3, 3, 2 }, { 8, 5, 2, 0 }, 2, FORMAT_ARGB }, - { D3DFMT_A4R4G4B4, { 4, 4, 4, 4 }, { 12, 8, 4, 0 }, 2, FORMAT_ARGB }, - { D3DFMT_X4R4G4B4, { 0, 4, 4, 4 }, { 0, 8, 4, 0 }, 2, FORMAT_ARGB }, - { D3DFMT_A2R10G10B10, { 2, 10, 10, 10 }, { 30, 20, 10, 0 }, 4, FORMAT_ARGB }, - { D3DFMT_A2B10G10R10, { 2, 10, 10, 10 }, { 30, 0, 10, 20 }, 4, FORMAT_ARGB }, - { D3DFMT_G16R16, { 0, 16, 16, 0 }, { 0, 0, 16, 0 }, 4, FORMAT_ARGB }, - { D3DFMT_A8, { 8, 0, 0, 0 }, { 0, 0, 0, 0 }, 1, FORMAT_ARGB }, - { D3DFMT_UNKNOWN, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, FORMAT_UNKNOWN }, /* marks last element */ -}; - -/************************************************************ - * get_format_info - * - * Returns information about the specified format. - * If the format is unsupported, it's filled with the D3DFMT_UNKNOWN desc. - * - * PARAMS - * format [I] format whose description is queried - * desc [O] pointer to a StaticPixelFormatDesc structure - * - */ -const PixelFormatDesc *get_format_info(D3DFORMAT format) -{ - unsigned int i = 0; - while(formats[i].format != format && formats[i].format != D3DFMT_UNKNOWN) i++; - return &formats[i]; -} - -/************************************************************ - * copy_simple_data - * - * Copies the source buffer to the destination buffer, performing - * any necessary format conversion and color keying. - * Works only for ARGB formats with 1 - 4 bytes per pixel. - */ -static void copy_simple_data(CONST BYTE *src, UINT srcpitch, POINT srcsize, CONST PixelFormatDesc *srcformat, - CONST BYTE *dest, UINT destpitch, POINT destsize, CONST PixelFormatDesc *destformat, - DWORD dwFilter) -{ - DWORD srcshift[4], destshift[4]; - DWORD srcmask[4], destmask[4]; - BOOL process_channel[4]; - DWORD channels[4]; - DWORD channelmask = 0; - - UINT minwidth, minheight; - BYTE *srcptr, *destptr; - UINT i, x, y; - - ZeroMemory(channels, sizeof(channels)); - ZeroMemory(process_channel, sizeof(process_channel)); - - for(i = 0;i < 4;i++) { - /* srcshift is used to extract the _relevant_ components */ - srcshift[i] = srcformat->shift[i] + max( srcformat->bits[i] - destformat->bits[i], 0); - - /* destshift is used to move the components to the correct position */ - destshift[i] = destformat->shift[i] + max(destformat->bits[i] - srcformat->bits[i], 0); - - srcmask[i] = ((1 << srcformat->bits[i]) - 1) << srcformat->shift[i]; - destmask[i] = ((1 << destformat->bits[i]) - 1) << destformat->shift[i]; - - /* channelmask specifies bits which aren't used in the source format but in the destination one */ - if(destformat->bits[i]) { - if(srcformat->bits[i]) process_channel[i] = TRUE; - else channelmask |= destmask[i]; - } - } - - minwidth = (srcsize.x < destsize.x) ? srcsize.x : destsize.x; - minheight = (srcsize.y < destsize.y) ? srcsize.y : destsize.y; - - for(y = 0;y < minheight;y++) { - srcptr = (BYTE*)( src + y * srcpitch); - destptr = (BYTE*)(dest + y * destpitch); - for(x = 0;x < minwidth;x++) { - /* extract source color components */ - if(srcformat->type == FORMAT_ARGB) { - const DWORD col = *(DWORD*)srcptr; - for(i = 0;i < 4;i++) - if(process_channel[i]) - channels[i] = (col & srcmask[i]) >> srcshift[i]; - } - - /* recombine the components */ - if(destformat->type == FORMAT_ARGB) { - DWORD* const pixel = (DWORD*)destptr; - *pixel = 0; - - for(i = 0;i < 4;i++) { - if(process_channel[i]) { - /* necessary to make sure that e.g. an X4R4G4B4 white maps to an R8G8B8 white instead of 0xf0f0f0 */ - signed int shift; - for(shift = destshift[i]; shift > destformat->shift[i]; shift -= srcformat->bits[i]) *pixel |= channels[i] << shift; - *pixel |= (channels[i] >> (destformat->shift[i] - shift)) << destformat->shift[i]; - } - } - *pixel |= channelmask; /* new channels are set to their maximal value */ - } - srcptr += srcformat->bytes_per_pixel; - destptr += destformat->bytes_per_pixel; - } - } -} - -/************************************************************ - * D3DXLoadSurfaceFromMemory - * - * Loads data from a given memory chunk into a surface, - * applying any of the specified filters. - * - * PARAMS - * pDestSurface [I] pointer to the surface - * pDestPalette [I] palette to use - * pDestRect [I] to be filled area of the surface - * pSrcMemory [I] pointer to the source data - * SrcFormat [I] format of the source pixel data - * SrcPitch [I] number of bytes in a row - * pSrcPalette [I] palette used in the source image - * pSrcRect [I] area of the source data to load - * dwFilter [I] filter to apply on stretching - * Colorkey [I] colorkey - * - * RETURNS - * Success: D3D_OK, if we successfully load the pixel data into our surface or - * if pSrcMemory is NULL but the other parameters are valid - * Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect are NULL or - * if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) - * D3DXERR_INVALIDDATA, if we fail to lock pDestSurface - * E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid - * - * NOTES - * pSrcRect specifies the dimensions of the source data; - * negative values for pSrcRect are allowed as we're only looking at the width and height anyway. - * - */ -HRESULT WINAPI D3DXLoadSurfaceFromMemory(LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY *pDestPalette, - CONST RECT *pDestRect, - LPCVOID pSrcMemory, - D3DFORMAT SrcFormat, - UINT SrcPitch, - CONST PALETTEENTRY *pSrcPalette, - CONST RECT *pSrcRect, - DWORD dwFilter, - D3DCOLOR Colorkey) -{ - CONST PixelFormatDesc *srcformatdesc, *destformatdesc; - D3DSURFACE_DESC surfdesc; - D3DLOCKED_RECT lockrect; - POINT srcsize, destsize; - HRESULT hr; - - //TRACE("(%p, %p, %p, %p, %x, %u, %p, %p %u, %#x)\n", pDestSurface, pDestPalette, pDestRect, pSrcMemory, - // SrcFormat, SrcPitch, pSrcPalette, pSrcRect, dwFilter, Colorkey); - - if( !pDestSurface || !pSrcMemory || !pSrcRect ) return D3DERR_INVALIDCALL; - if(SrcFormat == D3DFMT_UNKNOWN || pSrcRect->left >= pSrcRect->right || pSrcRect->top >= pSrcRect->bottom) return E_FAIL; - - if(dwFilter != D3DX_FILTER_NONE) return E_NOTIMPL; - - IDirect3DSurface9_GetDesc(pDestSurface, &surfdesc); - - srcformatdesc = get_format_info(SrcFormat); - destformatdesc = get_format_info(surfdesc.Format); - if( srcformatdesc->type == FORMAT_UNKNOWN || srcformatdesc->bytes_per_pixel > 4) return E_NOTIMPL; - if(destformatdesc->type == FORMAT_UNKNOWN || destformatdesc->bytes_per_pixel > 4) return E_NOTIMPL; - - srcsize.x = pSrcRect->right - pSrcRect->left; - srcsize.y = pSrcRect->bottom - pSrcRect->top; - if( !pDestRect ) { - destsize.x = surfdesc.Width; - destsize.y = surfdesc.Height; - } else { - destsize.x = pDestRect->right - pDestRect->left; - destsize.y = pDestRect->bottom - pDestRect->top; - } - - hr = IDirect3DSurface9_LockRect(pDestSurface, &lockrect, pDestRect, 0); - if(FAILED(hr)) return D3DXERR_INVALIDDATA; - - copy_simple_data((CONST BYTE*)pSrcMemory, SrcPitch, srcsize, srcformatdesc, - (CONST BYTE*)lockrect.pBits, lockrect.Pitch, destsize, destformatdesc, - dwFilter); - - IDirect3DSurface9_UnlockRect(pDestSurface); - return D3D_OK; -} - -#ifdef __cplusplus -} -#endif - diff --git a/src/native/jawtrenderer/windows/d3dx9_utils.h b/src/native/jawtrenderer/windows/d3dx9_utils.h deleted file mode 100644 index d49457daf1272d2dd334196d7e0fcd645ac564ec..0000000000000000000000000000000000000000 --- a/src/native/jawtrenderer/windows/d3dx9_utils.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ - -/* - * Copyright (C) 2009 Tony Wasserka - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - */ - -/** - * \file d3dx9_utils.h - * \brief DirectX functions implementation coming from Wine project. - * \author Wine project - */ - -#ifdef __cplusplus -extern "C" { /* } */ -#endif - -/************************************************************ - * D3DXLoadSurfaceFromMemory - * - * Loads data from a given memory chunk into a surface, - * applying any of the specified filters. - * - * PARAMS - * pDestSurface [I] pointer to the surface - * pDestPalette [I] palette to use - * pDestRect [I] to be filled area of the surface - * pSrcMemory [I] pointer to the source data - * SrcFormat [I] format of the source pixel data - * SrcPitch [I] number of bytes in a row - * pSrcPalette [I] palette used in the source image - * pSrcRect [I] area of the source data to load - * dwFilter [I] filter to apply on stretching - * Colorkey [I] colorkey - * - * RETURNS - * Success: D3D_OK, if we successfully load the pixel data into our surface or - * if pSrcMemory is NULL but the other parameters are valid - * Failure: D3DERR_INVALIDCALL, if pDestSurface, SrcPitch or pSrcRect are NULL or - * if SrcFormat is an invalid format (other than D3DFMT_UNKNOWN) - * D3DXERR_INVALIDDATA, if we fail to lock pDestSurface - * E_FAIL, if SrcFormat is D3DFMT_UNKNOWN or the dimensions of pSrcRect are invalid - * - * NOTES - * pSrcRect specifies the dimensions of the source data; - * negative values for pSrcRect are allowed as we're only looking at the width and height anyway. - * - */ -HRESULT WINAPI D3DXLoadSurfaceFromMemory(LPDIRECT3DSURFACE9 pDestSurface, - CONST PALETTEENTRY *pDestPalette, - CONST RECT *pDestRect, - LPCVOID pSrcMemory, - D3DFORMAT SrcFormat, - UINT SrcPitch, - CONST PALETTEENTRY *pSrcPalette, - CONST RECT *pSrcRect, - DWORD dwFilter, - D3DCOLOR Colorkey); - -#ifdef __cplusplus -} -#endif - diff --git a/src/org/jitsi/impl/neomedia/AudioMediaStreamImpl.java b/src/org/jitsi/impl/neomedia/AudioMediaStreamImpl.java index 26f6d1792904ccdc84728a52dacaa10d182158af..dafadd8be2ba045313cec640e7f9df546cc971ea 100644 --- a/src/org/jitsi/impl/neomedia/AudioMediaStreamImpl.java +++ b/src/org/jitsi/impl/neomedia/AudioMediaStreamImpl.java @@ -35,7 +35,7 @@ public class AudioMediaStreamImpl extends MediaStreamImpl implements AudioMediaStream, - PropertyChangeListener + PropertyChangeListener { /** @@ -73,21 +73,22 @@ public class AudioMediaStreamImpl = Logger.getLogger(AudioMediaStreamImpl.class); /** - * A property change notifier which will inform this stream if a selected - * audio device (capture, playback or notification device) has changed. We - * want to listen to these events, especially for those generated after the - * audio system has changed. + * A <tt>PropertyChangeNotifier<tt> which will inform this + * <tt>AudioStream</tt> if a selected audio device (capture, playback or + * notification device) has changed. We want to listen to these events, + * especially for those generated after the <tt>AudioSystem</tt> has + * changed. */ - private PropertyChangeNotifier audioSystemChangeNotifier; + private final PropertyChangeNotifier audioSystemChangeNotifier; /** * The listener that gets notified of changes in the audio level of * remote conference participants. */ - private CsrcAudioLevelListener csrcAudioLevelListener = null; + private CsrcAudioLevelListener csrcAudioLevelListener; /** - * The list of DTMF listeners; + * The list of DTMF listeners. */ private final List<DTMFListener> dtmfListeners = new ArrayList<DTMFListener>(); @@ -95,7 +96,21 @@ public class AudioMediaStreamImpl /** * The transformer that we use for sending and receiving DTMF packets. */ - private DtmfTransformEngine dtmfTransfrmEngine ; + private DtmfTransformEngine dtmfTransfrmEngine; + + /** + * The listener which has been set on this instance to get notified of + * changes in the levels of the audio that the local peer/user is sending to + * the remote peer(s). + */ + private SimpleAudioLevelListener localUserAudioLevelListener; + + /** + * The listener which has been set on this instance to get notified of + * changes in the levels of the audios that the local peer/user is receiving + * from the remote peer(s). + */ + private SimpleAudioLevelListener streamAudioLevelListener; /** * Initializes a new <tt>AudioMediaStreamImpl</tt> instance which will use @@ -109,20 +124,23 @@ public class AudioMediaStreamImpl * <tt>StreamConnector</tt> * @param srtpControl a control which is already created, used to control * the srtp operations. - * @param audioSystemChangeNotifier A property change notifier which will - * inform this stream if a selected audio device (capture, playback or - * notification device) has changed. We want to listen to these events, - * especially for those generated after the audio system has changed. */ - public AudioMediaStreamImpl(StreamConnector connector, - MediaDevice device, - SrtpControl srtpControl, - PropertyChangeNotifier audioSystemChangeNotifier - ) + public AudioMediaStreamImpl( + StreamConnector connector, + MediaDevice device, + SrtpControl srtpControl) { super(connector, device, srtpControl); - this.audioSystemChangeNotifier = audioSystemChangeNotifier; - this.audioSystemChangeNotifier.addPropertyChangeListener(this); + + MediaService mediaService = LibJitsi.getMediaService(); + + if (mediaService instanceof PropertyChangeNotifier) + { + audioSystemChangeNotifier = (PropertyChangeNotifier) mediaService; + audioSystemChangeNotifier.addPropertyChangeListener(this); + } + else + audioSystemChangeNotifier = null; } /** @@ -167,6 +185,23 @@ public void addRTPExtension(byte extensionID, RTPExtension rtpExtension) } } + /** + * Delivers the <tt>audioLevels</tt> map to whoever's interested. This + * method is meant for use primarily by the transform engine handling + * incoming RTP packets (currently <tt>CsrcTransformEngine</tt>). + * + * @param audioLevels a array mapping CSRC IDs to audio levels in + * consecutive elements. + */ + public void audioLevelsReceived(long[] audioLevels) + { + CsrcAudioLevelListener csrcAudioLevelListener + = this.csrcAudioLevelListener; + + if (csrcAudioLevelListener != null) + csrcAudioLevelListener.audioLevelsReceived(audioLevels); + } + /** * Releases the resources allocated by this instance in the course of its * execution and prepares it to be garbage collected. @@ -180,10 +215,12 @@ public void close() if(dtmfTransfrmEngine != null) { - dtmfTransfrmEngine = null; + dtmfTransfrmEngine.close(); + dtmfTransfrmEngine = null; } - this.audioSystemChangeNotifier.removePropertyChangeListener(this); + if (audioSystemChangeNotifier != null) + audioSystemChangeNotifier.removePropertyChangeListener(this); } /** @@ -264,20 +301,44 @@ protected DtmfTransformEngine createDtmfTransformEngine() } /** - * Delivers the <tt>audioLevels</tt> map to whoever's interested. This - * method is meant for use primarily by the transform engine handling - * incoming RTP packets (currently <tt>CsrcTransformEngine</tt>). + * {@inheritDoc} * - * @param audioLevels a array mapping CSRC IDs to audio levels in - * consecutive elements. + * Makes sure that {@link #localUserAudioLevelListener} and + * {@link #streamAudioLevelListener} which have been set on this + * <tt>AudioMediaStream</tt> will be automatically updated when a new + * <tt>MediaDevice</tt> is set on this instance. */ - public void fireConferenceAudioLevelEvent(long[] audioLevels) + @Override + protected void deviceSessionChanged( + MediaDeviceSession oldValue, + MediaDeviceSession newValue) { - CsrcAudioLevelListener csrcAudioLevelListener - = this.csrcAudioLevelListener; + if (oldValue != null) + { + AudioMediaDeviceSession deviceSession + = (AudioMediaDeviceSession) oldValue; - if (csrcAudioLevelListener != null) - csrcAudioLevelListener.audioLevelsReceived(audioLevels); + if (localUserAudioLevelListener != null) + deviceSession.setLocalUserAudioLevelListener(null); + if (streamAudioLevelListener != null) + deviceSession.setStreamAudioLevelListener(null); + } + if (newValue != null) + { + AudioMediaDeviceSession deviceSession + = (AudioMediaDeviceSession) newValue; + + if (localUserAudioLevelListener != null) + { + deviceSession.setLocalUserAudioLevelListener( + localUserAudioLevelListener); + } + if (streamAudioLevelListener != null) + { + deviceSession.setStreamAudioLevelListener( + streamAudioLevelListener); + } + } } /** @@ -352,14 +413,20 @@ protected int getPriority() /** * Receives and reacts to property change events: if the selected device * (for capture, playback or notifications) has changed, then create or - * recreate the streams in order to use it. - * We want to listen to these events, especially for those generated after - * the audio system has changed. + * recreate the streams in order to use it. We want to listen to these + * events, especially for those generated after the audio system has + * changed. * - * @param evt The event which may contain a audio system change event. + * @param ev The event which may contain a audio system change event. */ - public void propertyChange(PropertyChangeEvent evt) + public void propertyChange(PropertyChangeEvent ev) { + /* + * FIXME It is very wrong to do the following upon every + * PropertyChangeEvent fired by MediaServiceImpl. Moreover, it does not + * seem right that we'd want to start this MediaStream upon a + * PropertyChangeEvent (regardless of its specifics). + */ if (sendStreamsAreCreated) recreateSendStreams(); else @@ -421,7 +488,7 @@ public void removeDTMFListener(DTMFListener listener) */ public void setCsrcAudioLevelListener(CsrcAudioLevelListener listener) { - this.csrcAudioLevelListener = listener; + csrcAudioLevelListener = listener; } /** @@ -434,9 +501,20 @@ public void setCsrcAudioLevelListener(CsrcAudioLevelListener listener) * measurements. */ public void setLocalUserAudioLevelListener( - SimpleAudioLevelListener listener) + SimpleAudioLevelListener listener) { - getDeviceSession().setLocalUserAudioLevelListener(listener); + if (localUserAudioLevelListener != listener) + { + localUserAudioLevelListener = listener; + + AudioMediaDeviceSession deviceSession = getDeviceSession(); + + if (deviceSession != null) + { + deviceSession.setLocalUserAudioLevelListener( + localUserAudioLevelListener); + } + } } /** @@ -450,7 +528,18 @@ public void setLocalUserAudioLevelListener( */ public void setStreamAudioLevelListener(SimpleAudioLevelListener listener) { - getDeviceSession().setStreamAudioLevelListener(listener); + if (streamAudioLevelListener != listener) + { + streamAudioLevelListener = listener; + + AudioMediaDeviceSession deviceSession = getDeviceSession(); + + if (deviceSession != null) + { + deviceSession.setStreamAudioLevelListener( + streamAudioLevelListener); + } + } } /** @@ -518,8 +607,8 @@ public void stopSendingDTMF(DTMFMethod dtmfMethod) switch (dtmfMethod) { case INBAND_DTMF: - // The INBAND DTMF is send by impluse of constant duration and - // does not need to be stopped explecitely. + // The INBAND DTMF is sent by impluse of constant duration and does + // not need to be stopped explicitly. break; case RTP_DTMF: @@ -528,7 +617,7 @@ public void stopSendingDTMF(DTMFMethod dtmfMethod) break; case SIP_INFO_DTMF: - // The SIP-INFO DTMF is not managed directly by the + // The SIP-INFO DTMF is managed directly by the // OperationSetDTMFSipImpl. break; diff --git a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java index 438f844e6ad84a0e9c9538af88b156e6400fd972..861ca1a2337a735f43d718c9c3e5ffca7a0f1ecc 100644 --- a/src/org/jitsi/impl/neomedia/MediaServiceImpl.java +++ b/src/org/jitsi/impl/neomedia/MediaServiceImpl.java @@ -359,8 +359,7 @@ else if ((device != null) && !mediaType.equals(device.getMediaType())) switch (mediaType) { case AUDIO: - return - new AudioMediaStreamImpl(connector, device, srtpControl, this); + return new AudioMediaStreamImpl(connector, device, srtpControl); case VIDEO: return new VideoMediaStreamImpl(connector, device, srtpControl); default: @@ -1006,8 +1005,10 @@ public Object getVideoPreviewComponent( final JComponent videoContainer = new VideoContainer(noPreview, false); if ((preferredWidth > 0) && (preferredHeight > 0)) + { videoContainer.setPreferredSize( new Dimension(preferredWidth, preferredHeight)); + } try { @@ -1015,7 +1016,7 @@ public Object getVideoPreviewComponent( if ((device != null) && ((captureDeviceInfo - = ((MediaDeviceImpl)device) + = ((MediaDeviceImpl) device) .getCaptureDeviceInfo()) != null)) { @@ -1059,7 +1060,8 @@ public void controllerUpdate(ControllerEvent event) { if (t instanceof ThreadDeath) throw (ThreadDeath) t; - logger.error("Failed to create video preview", t); + else + logger.error("Failed to create video preview", t); } return videoContainer; @@ -1231,8 +1233,13 @@ public void windowClosing(WindowEvent event) previewContainer.add(preview); - previewContainer.revalidate(); - previewContainer.repaint(); + if (previewContainer.isDisplayable()) + { + previewContainer.revalidate(); + previewContainer.repaint(); + } + else + previewContainer.doLayout(); } else disposePlayer(player); diff --git a/src/org/jitsi/impl/neomedia/device/AudioMediaDeviceSession.java b/src/org/jitsi/impl/neomedia/device/AudioMediaDeviceSession.java index df731e0c4bd130ab1c0acbb9eda672c321d8a450..3548ebfd3b3cfef4fa1260bf0fae2281e250d44c 100644 --- a/src/org/jitsi/impl/neomedia/device/AudioMediaDeviceSession.java +++ b/src/org/jitsi/impl/neomedia/device/AudioMediaDeviceSession.java @@ -243,7 +243,7 @@ private void registerStreamAudioLevelJMFEffect(TrackControl trackControl) public void setLocalUserAudioLevelListener( SimpleAudioLevelListener listener) { - this.localUserAudioLevelEffect.setAudioLevelListener(listener); + localUserAudioLevelEffect.setAudioLevelListener(listener); } /** @@ -261,6 +261,6 @@ public void setLocalUserAudioLevelListener( */ public void setStreamAudioLevelListener(SimpleAudioLevelListener listener) { - this.streamAudioLevelEffect.setAudioLevelListener(listener); + streamAudioLevelEffect.setAudioLevelListener(listener); } } diff --git a/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java b/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java index 697e800003b6c92835448458909dd0c6ec3ea36a..ccd5a5ec7dc61331b01bb000315c6e5bdc7452aa 100644 --- a/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java +++ b/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java @@ -1149,7 +1149,7 @@ public void setLocalUserAudioLevelListener(SimpleAudioLevelListener l) if (l != null) { - this.localUserAudioLevelListener = l; + localUserAudioLevelListener = l; // add the listener only if we are not muted // this happens when holding a conversation, stream is muted diff --git a/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java b/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java index 85a67b23c3898c22a25202c7db7097a91f5bef29..92df100f899b782657f947e7a8c633ae35a153e7 100644 --- a/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java +++ b/src/org/jitsi/impl/neomedia/device/DeviceConfiguration.java @@ -67,11 +67,11 @@ public class DeviceConfiguration private static final String[] CUSTOM_RENDERERS = new String[] { - OSUtils.IS_ANDROID ? "org.jitsi.impl.neomedia.jmfext.media.renderer.audio.AudioTrackRenderer" : null, - OSUtils.IS_ANDROID ? "org.jitsi.impl.neomedia.jmfext.media.renderer.audio.OpenSLESRenderer" : null, + OSUtils.IS_ANDROID ? ".audio.AudioTrackRenderer" : null, + OSUtils.IS_ANDROID ? ".audio.OpenSLESRenderer" : null, OSUtils.IS_LINUX ? ".audio.PulseAudioRenderer" : null, OSUtils.IS_ANDROID ? null : ".audio.PortAudioRenderer", - "net.java.sip.communicator.impl.neomedia.jmfext.media.renderer.video.JAWTRenderer" + ".video.JAWTRenderer" }; /** diff --git a/src/org/jitsi/impl/neomedia/format/MediaFormatImpl.java b/src/org/jitsi/impl/neomedia/format/MediaFormatImpl.java index 29dc9cee58efb9bd2ade1d94f58a1f84ebba5518..8aa72515fd365a64f3379544d6d74e14ea86bbb0 100644 --- a/src/org/jitsi/impl/neomedia/format/MediaFormatImpl.java +++ b/src/org/jitsi/impl/neomedia/format/MediaFormatImpl.java @@ -39,14 +39,6 @@ public abstract class MediaFormatImpl<T extends Format> static final Map<String, String> EMPTY_FORMAT_PARAMETERS = Collections.emptyMap(); - /** - * The value of the <tt>codecSettings</tt> property of - * <tt>MediaFormatImpl</tt> when no codec-specific settings. - * Explicitly defined in order to reduce unnecessary allocations. - */ - static final Map<String, String> EMPTY_CODEC_SETTINGS - = Collections.emptyMap(); - /** * The name of the <tt>encoding</tt> property of <tt>MediaFormatImpl</tt>. */ @@ -58,11 +50,6 @@ public abstract class MediaFormatImpl<T extends Format> */ public static final String FORMAT_PARAMETERS_PNAME = "fmtps"; - /** - * The additional codec settings. - */ - private Map<String, String> codecSettings = EMPTY_CODEC_SETTINGS; - /** * Creates a new <tt>MediaFormat</tt> instance for a specific JMF * <tt>Format</tt>. @@ -96,7 +83,7 @@ else if (format instanceof VideoFormat) * @param clockRate the clock rate of the new instance * @param formatParameters the set of format-specific parameters of the new * instance - * @param advancedAttrs advanced attributes of the new instance + * @param advancedAttributess advanced attributes of the new instance * @return a new <tt>MediaFormat</tt> instance for the specified JMF * <tt>Format</tt> and with the specified clock rate and set of * format-specific parameters @@ -105,7 +92,7 @@ public static MediaFormatImpl<? extends Format> createInstance( Format format, double clockRate, Map<String, String> formatParameters, - Map<String, String> advancedAttrs) + Map<String, String> advancedAttributess) { if (format instanceof AudioFormat) { @@ -122,88 +109,22 @@ public static MediaFormatImpl<? extends Format> createInstance( (AudioFormat) clockRateAudioFormat.intersects(audioFormat), formatParameters, - advancedAttrs); + advancedAttributess); } else if (format instanceof VideoFormat) + { return new VideoMediaFormatImpl( (VideoFormat) format, clockRate, -1, formatParameters, - advancedAttrs); + advancedAttributess); + } else return null; } - /** - * Determines whether a specific set of advanced attributes is equal to - * another set of advanced attributes in the sense that they define an equal - * number of parameters and assign them equal values. Since the values are - * <tt>String</tt>s, presumes that a value of <tt>null</tt> is equal to the - * empty <tt>String</tt>. - * <p> - * - * @param adv the first set of advanced attributes to be tested for - * equality - * @param adv2 the second set of advanced attributes to be tested for - * equality - * @return <tt>true</tt> if the specified sets of advanced attributes - * equal; <tt>false</tt>, otherwise - */ - public boolean advancedAttributesAreEqual(Map<String, String> adv, - Map<String, String> adv2) - { - if(adv == null && adv2 != null || adv != null && adv2 == null) - return false; - - if(adv == null && adv2 == null) - return true; - - if(adv.size() != adv2.size()) - return false; - - for(Map.Entry<String, String> a : adv.entrySet()) - { - String value = adv2.get(a.getKey()); - if(value == null) - return false; - else - if(!value.equals(a.getValue())) - return false; - } - return true; - } - - /** - * Determines whether a specific set of format parameters is equal to - * another set of format parameters in the sense that they define an equal - * number of parameters and assign them equal values. Since the values are - * <tt>String</tt>s, presumes that a value of <tt>null</tt> is equal to the - * empty <tt>String</tt>. - * <p> - * The two <tt>Map</tt> instances of format parameters to be checked for - * equality are presumed to be modifiable in the sense that if the lack of a - * format parameter in a given <tt>Map</tt> is equivalent to it having a - * specific value, an association of the format parameter to the value in - * question may be added to or removed from the respective <tt>Map</tt> - * instance for the purposes of determining equality. - * </p> - * - * @param fmtps1 the first set of format parameters to be tested for - * equality - * @param fmtps2 the second set of format parameters to be tested for - * equality - * @return <tt>true</tt> if the specified sets of format parameters are - * equal; <tt>false</tt>, otherwise - */ - protected boolean formatParametersAreEqual( - Map<String, String> fmtps1, - Map<String, String> fmtps2) - { - return formatParametersAreEqual(getEncoding(), fmtps1, fmtps2); - } - /** * Determines whether a specific set of format parameters is equal to * another set of format parameters in the sense that they define an equal @@ -267,17 +188,15 @@ else if (!value1.equals(value2)) } /** - * {@inheritDoc} - * <p> - * The default implementation of <tt>MediaFormatImpl</tt> always returns - * <tt>true</tt> because format parameters in general do not cause the - * distinction of payload types. - * </p> + * The advanced parameters of this instance which have been received + * via SIP/SDP or XMPP/Jingle. */ - public boolean formatParametersMatch(Map<String, String> fmtps) - { - return true; - } + private final Map<String, String> advancedAttributes; + + /** + * The additional codec settings. + */ + private Map<String, String> codecSettings = EMPTY_FORMAT_PARAMETERS; /** * The JMF <tt>Format</tt> this instance wraps and provides an @@ -291,12 +210,6 @@ public boolean formatParametersMatch(Map<String, String> fmtps) */ private final Map<String, String> formatParameters; - /** - * The advanced parameters of this instance which have been received - * via SIP/SDP or XMPP/Jingle. - */ - private final Map<String, String> advancedParameters; - /** * Initializes a new <tt>MediaFormatImpl</tt> instance which is to provide * an implementation of <tt>MediaFormat</tt> for a specific <tt>Format</tt>. @@ -318,13 +231,13 @@ protected MediaFormatImpl(T format) * implementation of <tt>MediaFormat</tt> for * @param formatParameters any codec-specific parameters that have been * received via SIP/SDP or XMPP/Jingle - * @param advancedParameters any parameters that have been + * @param advancedAttributes any parameters that have been * received via SIP/SDP or XMPP/Jingle */ protected MediaFormatImpl( T format, Map<String, String> formatParameters, - Map<String, String> advancedParameters) + Map<String, String> advancedAttributes) { if (format == null) throw new NullPointerException("format"); @@ -334,10 +247,49 @@ protected MediaFormatImpl( = ((formatParameters == null) || formatParameters.isEmpty()) ? EMPTY_FORMAT_PARAMETERS : new HashMap<String, String>(formatParameters); - this.advancedParameters - = ((advancedParameters == null) || advancedParameters.isEmpty()) + this.advancedAttributes + = ((advancedAttributes == null) || advancedAttributes.isEmpty()) ? EMPTY_FORMAT_PARAMETERS - : new HashMap<String, String>(advancedParameters); + : new HashMap<String, String>(advancedAttributes); + } + + /** + * Determines whether a specific set of advanced attributes is equal to + * another set of advanced attributes in the sense that they define an equal + * number of parameters and assign them equal values. Since the values are + * <tt>String</tt>s, presumes that a value of <tt>null</tt> is equal to the + * empty <tt>String</tt>. + * <p> + * + * @param adv the first set of advanced attributes to be tested for + * equality + * @param adv2 the second set of advanced attributes to be tested for + * equality + * @return <tt>true</tt> if the specified sets of advanced attributes + * equal; <tt>false</tt>, otherwise + */ + public boolean advancedAttributesAreEqual(Map<String, String> adv, + Map<String, String> adv2) + { + if(adv == null && adv2 != null || adv != null && adv2 == null) + return false; + + if(adv == null && adv2 == null) + return true; + + if(adv.size() != adv2.size()) + return false; + + for(Map.Entry<String, String> a : adv.entrySet()) + { + String value = adv2.get(a.getKey()); + if(value == null) + return false; + else + if(!value.equals(a.getValue())) + return false; + } + return true; } /** @@ -368,6 +320,94 @@ && formatParametersAreEqual( mediaFormatImpl.getFormatParameters()); } + /** + * Determines whether a specific set of format parameters is equal to + * another set of format parameters in the sense that they define an equal + * number of parameters and assign them equal values. Since the values are + * <tt>String</tt>s, presumes that a value of <tt>null</tt> is equal to the + * empty <tt>String</tt>. + * <p> + * The two <tt>Map</tt> instances of format parameters to be checked for + * equality are presumed to be modifiable in the sense that if the lack of a + * format parameter in a given <tt>Map</tt> is equivalent to it having a + * specific value, an association of the format parameter to the value in + * question may be added to or removed from the respective <tt>Map</tt> + * instance for the purposes of determining equality. + * </p> + * + * @param fmtps1 the first set of format parameters to be tested for + * equality + * @param fmtps2 the second set of format parameters to be tested for + * equality + * @return <tt>true</tt> if the specified sets of format parameters are + * equal; <tt>false</tt>, otherwise + */ + protected boolean formatParametersAreEqual( + Map<String, String> fmtps1, + Map<String, String> fmtps2) + { + return formatParametersAreEqual(getEncoding(), fmtps1, fmtps2); + } + + /** + * {@inheritDoc} + * <p> + * The default implementation of <tt>MediaFormatImpl</tt> always returns + * <tt>true</tt> because format parameters in general do not cause the + * distinction of payload types. + * </p> + */ + public boolean formatParametersMatch(Map<String, String> fmtps) + { + return true; + } + + /** + * Returns additional codec settings. + * + * @return additional settings represented by a map. + */ + public Map<String, String> getAdditionalCodecSettings() + { + return codecSettings; + } + + /** + * Implements MediaFormat#getAdvancedAttributes(). Returns a copy of the + * attribute properties of this instance. Modifications to the returned Map + * do no affect the format properties of this instance. + * + * @return a copy of the attribute properties of this instance. + * Modifications to the returned Map do no affect the format properties of + * this instance. + */ + public Map<String, String> getAdvancedAttributes() + { + return (advancedAttributes == EMPTY_FORMAT_PARAMETERS) + ? EMPTY_FORMAT_PARAMETERS + : new HashMap<String, String>(advancedAttributes); + } + + /** + * Returns a <tt>String</tt> representation of the clock rate associated + * with this <tt>MediaFormat</tt> making sure that the value appears as + * an integer (i.e. its long-casted value is equal to its original one) + * unless it is actually a non integer. + * + * @return a <tt>String</tt> representation of the clock rate associated + * with this <tt>MediaFormat</tt>. + */ + public String getClockRateString() + { + double clockRate = getClockRate(); + long clockRateL = (long) clockRate; + + if (clockRateL == clockRate) + return Long.toString(clockRateL); + else + return Double.toString(clockRate); + } + /** * Implements MediaFormat#getEncoding() and returns the encoding of the JMF * <tt>Format</tt> that we are encapsulating here but it is the RFC-known @@ -424,22 +464,6 @@ public Map<String, String> getFormatParameters() : new HashMap<String, String>(formatParameters); } - /** - * Implements MediaFormat#getAdvancedParameters(). Returns a copy of the - * attribute properties of this instance. Modifications to the returned Map - * do no affect the format properties of this instance. - * - * @return a copy of the attribute properties of this instance. - * Modifications to the returned Map do no affect the format properties of - * this instance. - */ - public Map<String, String> getAdvancedAttributes() - { - return (advancedParameters == EMPTY_FORMAT_PARAMETERS) - ? EMPTY_FORMAT_PARAMETERS - : new HashMap<String, String>(advancedParameters); - } - /** * Gets the encoding of the JMF <tt>Format</tt> represented by this * instance as it is known to JMF (in contrast to its RFC name). @@ -452,61 +476,6 @@ public String getJMFEncoding() return format.getEncoding(); } - /** - * Gets the RTP payload type (number) of this <tt>MediaFormat</tt> as it is - * known in RFC 3551 "RTP Profile for Audio and Video Conferences with - * Minimal Control". - * - * @return the RTP payload type of this <tt>MediaFormat</tt> if it is known - * in RFC 3551 "RTP Profile for Audio and Video Conferences with Minimal - * Control"; otherwise, {@link #RTP_PAYLOAD_TYPE_UNKNOWN} - * @see MediaFormat#getRTPPayloadType() - */ - public byte getRTPPayloadType() - { - return MediaUtils.getRTPPayloadType(getJMFEncoding(), getClockRate()); - } - - /** - * Overrides Object#hashCode() because Object#equals(Object) is overridden. - * - * @return a hash code value for this <tt>MediaFormat</tt>. - */ - @Override - public int hashCode() - { - /* - * XXX We've experienced a case of JMF's VideoFormat#hashCode() - * returning different values for instances which are reported equal by - * VideoFormat#equals(Object) which is inconsistent with the protocol - * covering the two methods in question and causes problems, - * for example, with Map. While jmfEncoding is more generic than format, - * it still provides a relatively good distribution given that we do not - * have a lot of instances with one and the same jmfEncoding. - */ - return getJMFEncoding().hashCode() | getFormatParameters().hashCode(); - } - - /** - * Returns a <tt>String</tt> representation of the clock rate associated - * with this <tt>MediaFormat</tt> making sure that the value appears as - * an integer (i.e. its long-casted value is equal to its original one) - * unless it is actually a non integer. - * - * @return a <tt>String</tt> representation of the clock rate associated - * with this <tt>MediaFormat</tt>. - */ - public String getClockRateString() - { - double clockRate = getClockRate(); - long clockRateL = (long) clockRate; - - if (clockRateL == clockRate) - return Long.toString(clockRateL); - else - return Double.toString(clockRate); - } - /** * Returns a <tt>String</tt> representation of the real used clock rate * associated with this <tt>MediaFormat</tt> making sure that the value @@ -533,80 +502,38 @@ public String getRealUsedClockRateString() } /** - * Sets additional codec settings. - * - * @param settings additional settings represented by a map. - */ - public void setAdditionalCodecSettings(Map<String, String> settings) - { - codecSettings = settings; - } - - /** - * Returns additional codec settings. + * Gets the RTP payload type (number) of this <tt>MediaFormat</tt> as it is + * known in RFC 3551 "RTP Profile for Audio and Video Conferences with + * Minimal Control". * - * @return additional settings represented by a map. + * @return the RTP payload type of this <tt>MediaFormat</tt> if it is known + * in RFC 3551 "RTP Profile for Audio and Video Conferences with Minimal + * Control"; otherwise, {@link #RTP_PAYLOAD_TYPE_UNKNOWN} + * @see MediaFormat#getRTPPayloadType() */ - public Map<String, String> getAdditionalCodecSettings() + public byte getRTPPayloadType() { - return codecSettings; + return MediaUtils.getRTPPayloadType(getJMFEncoding(), getClockRate()); } /** - * Returns a <tt>String</tt> representation of this <tt>MediaFormat</tt> - * containing, among other things, its encoding and clockrate values. + * Overrides Object#hashCode() because Object#equals(Object) is overridden. * - * @return a <tt>String</tt> representation of this <tt>MediaFormat</tt>. + * @return a hash code value for this <tt>MediaFormat</tt>. */ @Override - public String toString() + public int hashCode() { - StringBuffer str = new StringBuffer(); - - str.append("rtpmap:"); - str.append(getRTPPayloadType()); - str.append(' '); - str.append(getEncoding()); - str.append('/'); - str.append(getClockRateString()); - /* - * If the number of channels is 1, it does not have to be mentioned - * because it is the default. + * XXX We've experienced a case of JMF's VideoFormat#hashCode() + * returning different values for instances which are reported equal by + * VideoFormat#equals(Object) which is inconsistent with the protocol + * covering the two methods in question and causes problems, + * for example, with Map. While jmfEncoding is more generic than format, + * it still provides a relatively good distribution given that we do not + * have a lot of instances with one and the same jmfEncoding. */ - if (MediaType.AUDIO.equals(getMediaType())) - { - int channels = ((AudioFormat) getFormat()).getChannels(); - - if (channels != 1) - { - str.append('/'); - str.append(channels); - } - } - - Map<String, String> formatParameters = getFormatParameters(); - - if (!formatParameters.isEmpty()) - { - str.append(" fmtp:"); - - boolean prependSeparator = false; - - for (Map.Entry<String, String> formatParameter - : formatParameters.entrySet()) - { - if (prependSeparator) - str.append(';'); - else - prependSeparator = true; - str.append(formatParameter.getKey()); - str.append('='); - str.append(formatParameter.getValue()); - } - } - - return str.toString(); + return getJMFEncoding().hashCode() | getFormatParameters().hashCode(); } /** @@ -691,4 +618,74 @@ public boolean matches(MediaType mediaType, // formatParameters return formatParametersMatch(formatParameters); } + + /** + * Sets additional codec settings. + * + * @param settings additional settings represented by a map. + */ + public void setAdditionalCodecSettings(Map<String, String> settings) + { + codecSettings + = ((settings == null) || settings.isEmpty()) + ? EMPTY_FORMAT_PARAMETERS + : settings; + } + + /** + * Returns a <tt>String</tt> representation of this <tt>MediaFormat</tt> + * containing, among other things, its encoding and clockrate values. + * + * @return a <tt>String</tt> representation of this <tt>MediaFormat</tt>. + */ + @Override + public String toString() + { + StringBuffer str = new StringBuffer(); + + str.append("rtpmap:"); + str.append(getRTPPayloadType()); + str.append(' '); + str.append(getEncoding()); + str.append('/'); + str.append(getClockRateString()); + + /* + * If the number of channels is 1, it does not have to be mentioned + * because it is the default. + */ + if (MediaType.AUDIO.equals(getMediaType())) + { + int channels = ((AudioFormat) getFormat()).getChannels(); + + if (channels != 1) + { + str.append('/'); + str.append(channels); + } + } + + Map<String, String> formatParameters = getFormatParameters(); + + if (!formatParameters.isEmpty()) + { + str.append(" fmtp:"); + + boolean prependSeparator = false; + + for (Map.Entry<String, String> formatParameter + : formatParameters.entrySet()) + { + if (prependSeparator) + str.append(';'); + else + prependSeparator = true; + str.append(formatParameter.getKey()); + str.append('='); + str.append(formatParameter.getValue()); + } + } + + return str.toString(); + } } diff --git a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/video/JAWTRenderer.java b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRenderer.java similarity index 88% rename from src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/video/JAWTRenderer.java rename to src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRenderer.java index f156866626e95a2e40049744b3333d67f004c382..fac7bf20ee294f9cf66cfc8a29c2425b61e0457b 100644 --- a/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/video/JAWTRenderer.java +++ b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRenderer.java @@ -4,7 +4,7 @@ * Distributable under LGPL license. * See terms of license at gnu.org. */ -package net.java.sip.communicator.impl.neomedia.jmfext.media.renderer.video; +package org.jitsi.impl.neomedia.jmfext.media.renderer.video; import java.awt.*; import java.lang.reflect.*; @@ -15,8 +15,6 @@ import javax.swing.*; import org.jitsi.impl.neomedia.jmfext.media.renderer.*; -import org.jitsi.service.configuration.*; -import org.jitsi.service.libjitsi.*; import org.jitsi.util.*; import org.jitsi.util.swing.*; @@ -69,49 +67,9 @@ public class JAWTRenderer 0x00FF0000, 0x0000FF00, 0x000000FF) }; - /** - * The indicator which determines whether <tt>CALayer</tt>-based painting is - * to be performed by <tt>JAWTRenderer</tt> on Mac OS X. - */ - private static final boolean USE_MACOSX_CALAYERS; - static { System.loadLibrary("jnawtrenderer"); - - /* - * XXX The native JAWTRenderer implementation on Mac OS X which paints - * in a CALayer-like fashion has been determined through testing to not - * work as expected on MacBookPro8. Unfortunately, the cause of the - * problem has not been determined. As a workaround, fall back to the - * alternative implementation (currently used on the other supported - * operating systems) on the problematic model. - */ - if (OSUtils.IS_MAC) - { - ConfigurationService cfg = LibJitsi.getConfigurationService(); - - if ((cfg == null) - || cfg.getBoolean( - JAWTRenderer.class.getName() - + ".USE_MACOSX_CALAYERS", - false)) - { - String hwModel = sysctlbyname("hw.model"); - - USE_MACOSX_CALAYERS - = (hwModel == null) - || !(hwModel.startsWith("MacBookPro8") - || hwModel.startsWith("MacBookAir4")); - } - else - USE_MACOSX_CALAYERS = false; - } - else - { - // CALayer-like painting is currently only supported on Mac OS X. - USE_MACOSX_CALAYERS = false; - } } /** @@ -143,10 +101,6 @@ public JAWTRenderer() { } - public static native void addNotifyLightweightComponent( - long handle, Component component, - long parentHandle); - /** * Closes this <tt>PlugIn</tt> and releases the resources it has retained * during its execution. No more data will be accepted by this @@ -199,7 +153,7 @@ public synchronized void close() * platform-specific info of <tt>component</tt> is not guaranteed to be * valid. */ - public static native void close(long handle, Component component); + private static native void close(long handle, Component component); /** * Gets the region in the component of this <tt>VideoRenderer</tt> where the @@ -231,9 +185,7 @@ public synchronized Component getComponent() "org.jitsi" + ".impl.neomedia.jmfext.media.renderer.video" + ".JAWTRenderer"); - if (USE_MACOSX_CALAYERS && OSUtils.IS_MAC) - componentClassName.append("Swing"); - else if (OSUtils.IS_ANDROID) + if (OSUtils.IS_ANDROID) componentClassName.append("Android"); componentClassName.append("VideoComponent"); @@ -395,7 +347,7 @@ public void run() * is to draw into the specified AWT <tt>Component</tt> * @throws ResourceUnavailableException if there is a problem during opening */ - public static native long open(Component component) + private static native long open(Component component) throws ResourceUnavailableException; /** @@ -413,6 +365,7 @@ public static native long open(Component component) * <tt>paint</tt>. * @param g the <tt>Graphics</tt> context into which the drawing is to be * performed + * @param zOrder * @return <tt>true</tt> if the native counterpart of a * <tt>JAWTRenderer</tt> wants to continue receiving the <tt>paint</tt> * calls on the AWT <tt>Component</tt>; otherwise, false. For example, after @@ -423,11 +376,10 @@ public static native long open(Component component) * indicate with <tt>false</tt> that it does not need further <tt>paint</tt> * deliveries. */ - public static native boolean paint( - long handle, Component component, Graphics g); - - public static native boolean paintLightweightComponent( - long handle, Component component, Graphics g); + static native boolean paint( + long handle, + Component component, Graphics g, + int zOrder); /** * Processes the data provided in a specific <tt>Buffer</tt> and renders it @@ -510,19 +462,12 @@ public synchronized int process(Buffer buffer) * @param height the height of the video frame in <tt>data</tt> * @return <tt>true</tt> if data has been successfully processed */ - public static native boolean process( + static native boolean process( long handle, Component component, int[] data, int offset, int length, int width, int height); - public static native void processLightweightComponentEvent( - long handle, - int x, int y, int width, int height); - - public static native void removeNotifyLightweightComponent( - long handle, Component component); - /** * Sets the region in the component of this <tt>VideoRenderer</tt> where the * video is to be rendered. diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRendererSwingVideoComponent.java b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRendererSwingVideoComponent.java deleted file mode 100644 index 9071d1de2e9e969e53b22442f30598d35e3be43e..0000000000000000000000000000000000000000 --- a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRendererSwingVideoComponent.java +++ /dev/null @@ -1,910 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Distributable under LGPL license. - * See terms of license at gnu.org. - */ -package org.jitsi.impl.neomedia.jmfext.media.renderer.video; - -import java.awt.*; -import java.awt.event.*; -import java.awt.image.*; -import java.util.*; -import java.util.List; - -import javax.media.*; -import javax.swing.*; - -import net.java.sip.communicator.impl.neomedia.jmfext.media.renderer.video.*; - -import org.jitsi.util.*; -import org.jitsi.util.swing.*; - -/** - * Implements a Swing <tt>Component</tt> in which <tt>JAWTRenderer</tt> paints. - * - * @author Lyubomir Marinov - */ -public class JAWTRendererSwingVideoComponent - extends JPanel -{ - /** - * Serial version UID. - */ - private static final long serialVersionUID = 0L; - - /** - * The <tt>Logger</tt> used by the <tt>JAWTRendererSwingVideoComponent</tt> - * class and its instances for logging output. - */ - private static final Logger logger - = Logger.getLogger(JAWTRendererSwingVideoComponent.class); - - /** - * The <tt>SwingVideoComponentCanvas</tt> in which this - * <tt>SwingVideoComponent</tt> is painted according to the last call to - * {@link #addNotify()}. - */ - private SwingVideoComponentCanvas canvas; - - /** - * The <tt>Container</tt> which is the last-known parent of this - * <tt>SwingVideoComponent</tt>. - */ - private Container parent; - - /** - * The <tt>ComponentListener</tt> which is to be or is listening to - * <tt>ComponentEvent</tt>s fired by {@link #parent}. - */ - private final ComponentListener parentComponentListener - = new ComponentAdapter() - { - @Override - public void componentResized(ComponentEvent e) - { - /* - * It is necessary to call - * #procesLightweightComponentEvent() when the parent gets - * resized only if the native counterpart of this - * SwingVideoComponent expects bounds in a coordinate system - * which changes with respect to the bounds of this - * SwingVideoComponent when the parent gets resized. - */ - //processLightweightComponentEvent(); - } - }; - - /** - * The <tt>JAWTRenderer</tt> which paints in this - * <tt>JAWTRendererSwingVideoComponent</tt>. - */ - private final JAWTRenderer renderer; - - /** - * The indicator which determines whether the native counterpart of this - * <tt>JAWTRenderer</tt> wants <tt>paint</tt> calls on its Swing - * <tt>Component</tt> to be delivered. - * - * @see JAWTRendererVideoComponent#wantsPaint - */ - private boolean wantsPaint = true; - - /** - * Constructor. - * - * @param renderer <tt>JAWTRenderer</tt> instance - */ - public JAWTRendererSwingVideoComponent(JAWTRenderer renderer) - { - if (VideoContainer.DEFAULT_BACKGROUND_COLOR != null) - setBackground(VideoContainer.DEFAULT_BACKGROUND_COLOR); - - this.renderer = renderer; - } - - @Override - public void addNotify() - { - /* - * Since JAWTRenderer#open() may be performing the call, it may be - * wrong about this SwingVideoComponent having a parent. - */ - Container parent = getParent(); - - if (parent == null) - return; - - super.addNotify(); - - wantsPaint = true; - - synchronized (renderer.getHandleLock()) - { - long handle = renderer.getHandle(); - - if (handle != 0) - { - SwingVideoComponentCanvas canvas = findCanvas(); - - if (canvas == null) - { - JAWTRenderer.addNotifyLightweightComponent( - handle, this, - 0); - } - else - { - long canvasHandle; - - synchronized (canvas.getHandleLock()) - { - canvasHandle = canvas.getHandle(); - JAWTRenderer.addNotifyLightweightComponent( - handle, this, - canvasHandle); - } - if ((canvasHandle != 0) && (this.canvas != canvas)) - { - this.canvas = canvas; - } - } - - /* - * Emulate a ComponentEvent so that, for example, the native - * counterpart of this Component gets its bounds up to date. - */ - processLightweightComponentEvent(); - } - } - - if (this.parent != parent) - { - this.parent = parent; - this.parent.addComponentListener(parentComponentListener); - } - } - - /** - * Creates a new AWT <tt>Component</tt> in which - * <tt>SwingVideoComponent</tt>s can be rendered. - * @return new AWT <tt>Component</tt> in which <tt>SwingVideoComponent</tt>s - * can be rendered - */ - public Component createCanvas() - { - return new SwingVideoComponentCanvas(renderer); - } - - /** - * Finds a <tt>SwingVideoComponentCanvas</tt> in which this - * <tt>SwingVideoComponent</tt> can be painted. - * - * @return a <tt>SwingVideoComponentCanvas</tt> in which this - * <tt>SwingVideoComponent</tt> can be painted if any; otherwise, - * <tt>null</tt> - */ - private SwingVideoComponentCanvas findCanvas() - { - Container parent = getParent(); - - if (parent != null) - for (Component component : parent.getComponents()) - if (component instanceof SwingVideoComponentCanvas) - return (SwingVideoComponentCanvas) component; - return null; - } - - /** - * Gets the <tt>SwingVideoComponentCanvas</tt> in which this - * <tt>SwingVideoComponent</tt> is being painted. - * - * @return the <tt>SwingVideoComponentCanvas</tt> in which this - * <tt>SwingVideoComponent</tt> is being painted if any; otherwise, - * <tt>null</tt> - */ - SwingVideoComponentCanvas getCanvas() - { - return canvas; - } - - @Override - public void paint(Graphics g) - { - synchronized (renderer.getHandleLock()) - { - long handle = renderer.getHandle(); - - if (wantsPaint && (handle != 0)) - { - wantsPaint - = JAWTRenderer.paintLightweightComponent( - handle, - this, - g); - } - } - } - - @Override - protected void processComponentEvent(ComponentEvent e) - { - super.processComponentEvent(e); - - if (equals(e.getComponent())) - { - switch(e.getID()) - { - case ComponentEvent.COMPONENT_MOVED: - case ComponentEvent.COMPONENT_RESIZED: - processLightweightComponentEvent(); - break; - } - } - } - - /** - * Notifies this <tt>SwingVideoComponent</tt> that a - * <tt>ComponentEvent</tt> related to it has occurred. - */ - private void processLightweightComponentEvent() - { - Rectangle bounds = getBounds(); - - if (bounds != null) - { - synchronized (renderer.getHandleLock()) - { - long handle = renderer.getHandle(); - - if (handle != 0) - { - JAWTRenderer.processLightweightComponentEvent( - handle, - bounds.x, - bounds.y, - bounds.width, - bounds.height); - } - } - } - } - - @Override - public void removeNotify() - { - if (parent != null) - { - parent.removeComponentListener(parentComponentListener); - parent = null; - } - - synchronized (renderer.getHandleLock()) - { - long handle = renderer.getHandle(); - - if (handle != 0) - { - if (canvas != null) - { - synchronized (canvas.getHandleLock()) - { - JAWTRenderer.removeNotifyLightweightComponent( - handle, this); - } - canvas = null; - } - else - { - JAWTRenderer.removeNotifyLightweightComponent( - handle, this); - } - } - } - - /* - * In case the associated JAWTRenderer has said that it does not - * want paint events/notifications, ask it again next time because - * the native handle of this Canvas may be recreated. - */ - wantsPaint = true; - - super.removeNotify(); - } - - @Override - public void repaint() - { - super.repaint(); - - /* - * Since SwingVideoComponent is to be painted in a - * SwingVideoComponentCanvas, the latter should repaint when the - * former does. - */ - Component canvas = getCanvas(); - - if (canvas != null) - canvas.repaint(); - } - - @Override - public void setBounds(int x, int y, int width, int height) - { - super.setBounds(x, y, width, height); - - /* - * Calling #setBounds(int, int, int, int) does not seem to cause - * this SwingVideoComponent to process a ComponentEvent so force it - * because it is really necessary to deliver the up-to-date bounds - * to the native counterpart. - */ - processLightweightComponentEvent(); - } - - @Override - public void setLocation(int x, int y) - { - super.setLocation(x, y); - - processLightweightComponentEvent(); - } - - /** - * Represents a <tt>Component</tt> which is neither a - * <tt>AWTVideoComponent</tt> nor a <tt>SwingVideoComponent</tt> but which - * is to be painted by a <tt>SwingVideoComponentCanvas</tt> anyway. - */ - private static class NonVideoComponent - { - /** - * The <tt>BufferedImage</tt> into which {@link #component} is to be - * painted so that it can be processed and then rendered by - * {@link #handle}. - */ - private BufferedImage bufferedImage; - - /** - * The <tt>Component</tt> represented by this <tt>NonVideoComponent</tt> - * instance. - */ - public final Component component; - - /** - * The handle of the native <tt>JAWTRenderer</tt> which paints this - * <tt>NonVideoComponent</tt>. - */ - private long handle; - - /** - * The height in pixels of {@link #bufferedImage} and {@link #rgb}. - */ - private int height; - - /** - * The pixels of {@link #bufferedImage} to be processed by - * {@link #handle}. - */ - private int[] rgb; - - /** - * The width in pixels of {@link #bufferedImage} and {@link #rgb}. - */ - private int width; - - /** - * Initializes a new <tt>NonVideoComponent</tt> instance which is to - * paint a specific <tt>Component</tt> in the context of a parent - * <tt>JAWTRenderer</tt>. - * - * @param component the <tt>Component</tt> to be painted - * @param parentHandle the handle of the native <tt>JAWTRenderer</tt> in - * the context of which <tt>component</tt> is to be painted - */ - public NonVideoComponent(Component component, long parentHandle) - { - this.component = component; - - try - { - handle = JAWTRenderer.open(this.component); - if (handle != 0) - { - JAWTRenderer.addNotifyLightweightComponent( - handle, this.component, - parentHandle); - } - } - catch (ResourceUnavailableException rue) - { - logger.error( - "Failed to JAWTRenderer.open for NonVideoComponent", - rue); - } - } - - /** - * Releases the resources of this <tt>NonVideoComponent</tt> and - * prepares it to be garbage collected. - */ - public void dispose() - { - if (handle != 0) - { - JAWTRenderer.removeNotifyLightweightComponent( - handle, component); - JAWTRenderer.close(handle, component); - handle = 0; - } - } - - /** - * Paints the <tt>Component</tt> associated with this - * <tt>NonVideoComponent</tt> instance. - */ - public void paint() - { - if (handle != 0) - { - /* - * Make sure the location, the size and the visibility known to - * the associated native JAWTRenderer are in sync with these of - * the component. - */ - Rectangle bounds = component.getBounds(); - - if (!component.isVisible()) - { - bounds.height = 0; - bounds.width = 0; - } - JAWTRenderer.processLightweightComponentEvent( - handle, - bounds.x, bounds.y, bounds.width, bounds.height); - - /* - * If the component is not visible, the native JAWTRenderer - * already knows that it is not to be rendered. - */ - if ((bounds.height < 1) || (bounds.width < 1)) - return; - - /* - * Paint the component and tell the native JAWTRenderer about - * the latest painting. - */ - if ((height != bounds.height) || (width != bounds.width)) - { - rgb = new int[bounds.width * bounds.height]; - bufferedImage - = new BufferedImage( - bounds.width, bounds.height, - BufferedImage.TYPE_INT_ARGB); - height = bounds.height; - width = bounds.width; - } - if ((bufferedImage != null) && (rgb != null)) - { - Graphics g = bufferedImage.createGraphics(); - boolean process = false; - - try - { - component.paint(g); - process = true; - } - finally - { - g.dispose(); - } - if (process) - { - bufferedImage.getRGB( - 0, 0, width, height, - rgb, 0, width); - JAWTRenderer.process( - handle, component, - rgb, 0, rgb.length, - width, height); - } - } - } - } - } - - /** - * Implements an AWT <tt>Component</tt> in which - * <tt>SwingVideoComponent</tt>s can be rendered. - */ - private static class SwingVideoComponentCanvas - extends JAWTRendererVideoComponent - { - /** - * Serial version UID. - */ - private static final long serialVersionUID = 0L; - - /** - * The handle to the native <tt>JAWTRenderer</tt> which does the actual - * painting of this <tt>SwingVideoComponentCanvas</tt>. - */ - private long handle; - - /** - * The <tt>Component</tt> to which this - * <tt>SwingVideoComponentCanvas</tt> has dispatched a - * {@link MouseEvent#MOUSE_PRESSED}. - */ - private Component mousePressedComponent; - - /** - * The <tt>NoVideoComponent</tt>s painted by this - * <tt>SwingVideoComponentCanvas</tt>. - */ - private final List<NonVideoComponent> nonVideoComponents - = new LinkedList<NonVideoComponent>(); - - /** - * The <tt>Container</tt> which is the last-known parent of this - * <tt>SwingVideoComponentCanvas</tt>. - */ - private Container parent; - - /** - * The <tt>ContainerListener</tt> which listens to {@link #parent}. - */ - private final ContainerListener parentContainerListener - = new ContainerListener() - { - public void componentAdded(ContainerEvent e) - { - Component c = e.getChild(); - - if (!(c instanceof JAWTRendererVideoComponent) - && !(c instanceof JAWTRendererSwingVideoComponent)) - { - nonVideoComponentAdded(c); - } - } - - public void componentRemoved(ContainerEvent e) - { - Component c = e.getChild(); - - if (mousePressedComponent == c) - mousePressedComponent = null; - - if (!(c instanceof JAWTRendererVideoComponent) - && !(c instanceof JAWTRendererSwingVideoComponent)) - { - nonVideoComponentRemoved(c); - } - else if (SwingVideoComponentCanvas.this.equals(c)) - removeAllNonVideoComponents(); - } - }; - - /** - * Initializes a new <tt>SwingVideoComponentCanvas</tt> instance. - * - * @param renderer - */ - public SwingVideoComponentCanvas(JAWTRenderer renderer) - { - super(renderer); - - enableEvents( - AWTEvent.MOUSE_EVENT_MASK - | AWTEvent.MOUSE_MOTION_EVENT_MASK); - } - - @Override - public void addNotify() - { - super.addNotify(); - - synchronized (getHandleLock()) - { - if (getHandle() == 0) - { - try - { - this.handle = JAWTRenderer.open(this); - } - catch (ResourceUnavailableException rue) - { - throw new RuntimeException(rue); - } - if (getHandle() == 0) - { - throw new RuntimeException( - "JAWTRenderer#open(Component)"); - } - } - } - - Container parent = getParent(); - - if ((parent != null) && (this.parent != parent)) - { - this.parent = parent; - this.parent.addContainerListener(parentContainerListener); - } - } - - @Override - public boolean contains(int x, int y) - { - /* - * Act as a "glass pane" i.e. be transparent with respect to points - * and pretend they are in whatever is underneath. - */ - return false; - } - - /** - * Dispatches <tt>MouseEvent</tt>s to whatever is underneath this - * <tt>SwingVideoComponentCanvas</tt> because it only renders - * <tt>Component</tt>s i.e. it is like a "glass pane". - */ - private boolean dispatchMouseEvent(MouseEvent e) - { - Component srcc = e.getComponent(); - - if (srcc != null) - { - int id = e.getID(); - Component dstc = null; - - /* - * After a MOUSE_PRESSED, this SwingVideoComponentCanvas will - * continue to receive, for example, MouseMotionEvents even - * when the point has moved out of it. Emulate the same behavior - * for the Components this SwingVideoComponentCanvas dispatches - * events to since it is transparent in this respect. - */ - if (MouseEvent.MOUSE_PRESSED == id) - mousePressedComponent = null; - else if (mousePressedComponent != null) - { - dstc = mousePressedComponent; - if ((MouseEvent.MOUSE_CLICKED == id) - || (MouseEvent.MOUSE_RELEASED == id)) - mousePressedComponent = null; - } - - if (dstc == null) - { - Container parent = getParent(); - - if (parent != null) - { - Point parentPoint - = SwingUtilities.convertPoint( - srcc, - e.getPoint(), - parent); - - dstc = getComponentAt(parent, parentPoint); - } - } - - if (dstc != null) - { - if (MouseEvent.MOUSE_PRESSED == id) - mousePressedComponent = dstc; - dstc.dispatchEvent( - SwingUtilities.convertMouseEvent( - srcc, - e, - dstc)); - return true; - } - } - return false; - } - - /** - * Determines the <tt>Component</tt> which is a child of a specific - * <tt>Container</tt> which contains a specific <tt>Point</tt>. Since - * <tt>SwingVideoComponentCanvas</tt> is like a "glass pane", it never - * contains the specified <tt>point</tt>. - * - * @param parent the <tt>Container</tt> which contains the - * <tt>Component</tt>s which may contain the specified <tt>point</tt> - * @param point the point in the coordinate system of <tt>parent</tt> - * which is to be determined which <tt>Component</tt> contains it - * @return the <tt>Component</tt> which is a child of the specified - * <tt>Container</tt> and contains the specified <tt>Point</tt> or - * <tt>null</tt> if there is no such <tt>Component</tt> - */ - private Component getComponentAt(Container parent, Point point) - { - Component[] components = parent.getComponents(); - - for (int componentIndex = components.length - 1; - componentIndex >= 0; - componentIndex--) - { - Component component = components[componentIndex]; - - if (!equals(component) - && component.isVisible() - && component.contains( - SwingUtilities.convertPoint( - parent, - point, - component))) - { - return component; - } - } - return null; - } - - /* Overrides JAWTRendererVideoComponent#getHandle(). */ - @Override - protected long getHandle() - { - return handle; - } - - /* Overrides JAWTRendererVideoComponent#getHandleLock(). */ - @Override - protected Object getHandleLock() - { - return this; - } - - /** - * Notifies this <tt>SwingVideoComponentCanvas</tt> that a - * <tt>Component</tt> which is neither an <tt>AWTVideoComponent</tt> nor - * a <tt>SwingVideoComponent</tt> has been added to {@link #parent}. - * - * @param c the component which has been added - */ - private void nonVideoComponentAdded(Component c) - { - synchronized (getHandleLock()) - { - synchronized (nonVideoComponents) - { - for (NonVideoComponent nonVideoComponent - : nonVideoComponents) - { - if (nonVideoComponent.component.equals(c)) - return; - } - - nonVideoComponents.add( - new NonVideoComponent(c, getHandle())); - } - } - } - - /** - * Notifies this <tt>SwingVideoComponentCanvas</tt> that a - * <tt>Component</tt> which is neither an <tt>AWTVideoComponent</tt> nor - * a <tt>SwingVideoComponent</tt> has been removed from {@link #parent}. - * - * @param c the component which has been removed - */ - private void nonVideoComponentRemoved(Component c) - { - synchronized (nonVideoComponents) - { - Iterator<NonVideoComponent> nonVideoComponentIter - = nonVideoComponents.iterator(); - - while (nonVideoComponentIter.hasNext()) - { - NonVideoComponent nonVideoComponent - = nonVideoComponentIter.next(); - - if (nonVideoComponent.component.equals(c)) - { - nonVideoComponentIter.remove(); - nonVideoComponent.dispose(); - break; - } - } - } - } - - @Override - public void paint(Graphics g) - { - try - { - synchronized (nonVideoComponents) - { - for (NonVideoComponent nonVideoComponent - : nonVideoComponents) - nonVideoComponent.paint(); - } - } - finally - { - super.paint(g); - } - } - - @Override - protected void processMouseEvent(MouseEvent e) - { - /* - * Act as a "glass pane" i.e. be transparent with respect to - * MouseEvents and dispatch them to whatever is underneath. - */ - if (!dispatchMouseEvent(e)) - super.processMouseEvent(e); - } - - @Override - protected void processMouseMotionEvent(MouseEvent e) - { - /* - * Act as a "glass pane" i.e. be transparent with respect to - * MouseEvents and dispatch them to whatever is underneath. - */ - if (!dispatchMouseEvent(e)) - super.processMouseMotionEvent(e); - } - - /** - * Removes all <tt>NonVideoComponent</tt>s from this - * <tt>SwingVideoComponentCanvas</tt> so that their associated - * <tt>Component</tt>s are no longer painted by the represented native - * <tt>JAWTRenderer</tt>. - */ - private void removeAllNonVideoComponents() - { - synchronized (nonVideoComponents) - { - Iterator<NonVideoComponent> nonVideoComponentIter - = nonVideoComponents.iterator(); - - while (nonVideoComponentIter.hasNext()) - { - NonVideoComponent nonVideoComponent - = nonVideoComponentIter.next(); - - nonVideoComponentIter.remove(); - nonVideoComponent.dispose(); - } - } - } - - @Override - public void removeNotify() - { - mousePressedComponent = null; - - if (parent != null) - { - parent.removeContainerListener(parentContainerListener); - removeAllNonVideoComponents(); - parent = null; - } - - synchronized (getHandleLock()) - { - long handle = getHandle(); - - if (handle != 0) - { - try - { - JAWTRenderer.close(handle, this); - } - finally - { - this.handle = 0; - } - } - } - - super.removeNotify(); - } - } -} diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRendererVideoComponent.java b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRendererVideoComponent.java index 26f05e62dbe3bb58fec8da240fd91c1ddfc4ddac..de8e03a8bc8e342bc3af208e0132ea0f0188397a 100644 --- a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRendererVideoComponent.java +++ b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/video/JAWTRendererVideoComponent.java @@ -8,10 +8,6 @@ import java.awt.*; -import net.java.sip.communicator.impl.neomedia.jmfext.media.renderer.video.*; - -import org.jitsi.util.swing.*; - /** * Implements an AWT <tt>Component</tt> in which <tt>JAWTRenderer</tt> paints. * @@ -52,9 +48,6 @@ public class JAWTRendererVideoComponent */ public JAWTRendererVideoComponent(JAWTRenderer renderer) { - if (VideoContainer.DEFAULT_BACKGROUND_COLOR != null) - setBackground(VideoContainer.DEFAULT_BACKGROUND_COLOR); - this.renderer = renderer; } @@ -110,7 +103,15 @@ public void paint(Graphics g) long handle; if ((handle = getHandle()) != 0) - wantsPaint = JAWTRenderer.paint(handle, this, g); + { + Container parent = getParent(); + int zOrder + = (parent == null) + ? -1 + : parent.getComponentZOrder(this); + + wantsPaint = JAWTRenderer.paint(handle, this, g, zOrder); + } } } } diff --git a/src/org/jitsi/impl/neomedia/transform/csrc/CsrcTransformEngine.java b/src/org/jitsi/impl/neomedia/transform/csrc/CsrcTransformEngine.java index 1d0122226e5324127dce3973df067b8a20ed0974..b310a8db84d1351e396cc41a8220552a36efcb06 100644 --- a/src/org/jitsi/impl/neomedia/transform/csrc/CsrcTransformEngine.java +++ b/src/org/jitsi/impl/neomedia/transform/csrc/CsrcTransformEngine.java @@ -280,40 +280,33 @@ public void run() { isRunning = true; - //no point in listening if our stream is not an audio one. + // Audio levels are received in RTP audio streams only. if(!(mediaStream instanceof AudioMediaStreamImpl)) return; - long[] temp = null; + AudioMediaStreamImpl audioStream + = (AudioMediaStreamImpl) mediaStream; while(isRunning) { + long[] audioLevels; + synchronized(this) { if(lastReportedLevels == null) { - try - { - wait(); - } - catch (InterruptedException ie) {} + try { wait(); } catch (InterruptedException ie) {} + continue; } - - temp = lastReportedLevels; - // make lastReportedLevels to null - // so we will wait for the next level on next iteration - lastReportedLevels = null; - } - - if(temp != null) - { - //now notify our listener - if (mediaStream != null) + else { - ((AudioMediaStreamImpl)mediaStream) - .fireConferenceAudioLevelEvent(temp); + audioLevels = lastReportedLevels; + lastReportedLevels = null; } } + + if(audioLevels != null) + audioStream.audioLevelsReceived(audioLevels); } } @@ -328,7 +321,6 @@ public void addLevels(long[] levels) synchronized(this) { this.lastReportedLevels = levels; - notifyAll(); } } @@ -343,7 +335,6 @@ public void stop() { this.lastReportedLevels = null; isRunning = false; - notifyAll(); } } diff --git a/src/org/jitsi/util/swing/FitLayout.java b/src/org/jitsi/util/swing/FitLayout.java index 6af174e3efc46fa18b3d1751936dd02af2afa644..e61c6cd2f6ebe648c2d7432443c0a641633ee245 100644 --- a/src/org/jitsi/util/swing/FitLayout.java +++ b/src/org/jitsi/util/swing/FitLayout.java @@ -62,12 +62,13 @@ protected void layoutComponent( /* * XXX The following is a quick and dirty hack for the purposes of video * conferencing which adds transparent JPanels to VideoContainer and - * does not want them fitted because they contains VideoContainers + * does not want them fitted because they contain VideoContainers * themselves and the videos get fitted in them. */ - if ((component instanceof JPanel) - && !component.isOpaque() - && (((Container) component).getComponentCount() > 1)) + if (((component instanceof JPanel) + && !component.isOpaque() + && (((Container) component).getComponentCount() > 1)) + || (component instanceof VideoContainer)) { componentSize = bounds.getSize(); } diff --git a/src/org/jitsi/util/swing/VideoContainer.java b/src/org/jitsi/util/swing/VideoContainer.java index 7a1267926e37df1802a31c0fea4afc0f46153926..41194e97ec18a950adcdf87bf404d13816791cdb 100644 --- a/src/org/jitsi/util/swing/VideoContainer.java +++ b/src/org/jitsi/util/swing/VideoContainer.java @@ -8,7 +8,6 @@ import java.awt.*; import java.awt.event.*; -import java.lang.reflect.*; import org.jitsi.util.*; @@ -29,34 +28,12 @@ public class VideoContainer */ private static final long serialVersionUID = 0L; - /** - * The <tt>Logger</tt> used by the <tt>VideoContainer</tt> class and its - * instances for logging output. - */ - private static final Logger logger = Logger.getLogger(VideoContainer.class); - /** * The default background color. */ public static final Color DEFAULT_BACKGROUND_COLOR = OSUtils.IS_MAC ? Color.BLACK : null; - /** - * The name of the instance method of <tt>Component</tt>s added to - * <tt>VideoContainer</tt> which creates a new <tt>Component</tt> acting as - * a canvas in which the other <tt>Component</tt>s contained in the - * <tt>VideoContainer</tt> are painted. - */ - private static final String VIDEO_CANVAS_FACTORY_METHOD_NAME - = "createCanvas"; - - /** - * The <tt>Component</tt> which is the canvas, if any, in which the other - * <tt>Component</tt>s contained in this <tt>VideoContainer</tt> are - * painted. - */ - private Component canvas; - private int inAddOrRemove; /** @@ -87,16 +64,6 @@ public VideoContainer(Component noVideoComponent, boolean conference) this.noVideoComponent = noVideoComponent; - /* - * JAWTRenderer on Mac OS X will by default occupy the whole video - * container and will, consequently, draw a black background. In certain - * problematic cases which it will try to provide a workaround, it will - * not occupy the whole video container. To make the experience - * relatively the same, always use a black background. - */ - if (DEFAULT_BACKGROUND_COLOR != null) - setBackground(DEFAULT_BACKGROUND_COLOR); - addContainerListener( new ContainerListener() { @@ -165,94 +132,6 @@ public void add(Component comp, Object constraints, int index) remove(noVideoComponent); } - if ((canvas == null) || (canvas.getParent() != this)) - { - if (OSUtils.IS_MAC && (comp != canvas)) - { - /* - * Unless the comp has a createCanvas() method, it makes no - * sense to consider any exception a problem. - */ - boolean ignoreException; - Throwable exception; - - ignoreException = true; - exception = null; - canvas = null; - - try - { - Method m - = comp.getClass().getMethod( - VIDEO_CANVAS_FACTORY_METHOD_NAME); - - if (m != null) - { - ignoreException = false; - - Object c = m.invoke(comp); - - if (c instanceof Component) - canvas = (Component) c; - } - } - catch (ClassCastException cce) - { - exception = cce; - } - catch (ExceptionInInitializerError eiie) - { - exception = eiie; - } - catch (IllegalAccessException illegalAccessException) - { - exception = illegalAccessException; - } - catch (IllegalArgumentException illegalArgumentException) - { - exception = illegalArgumentException; - } - catch (InvocationTargetException ita) - { - exception = ita; - } - catch (NoSuchMethodException nsme) - { - exception = nsme; - } - catch (NullPointerException npe) - { - exception = npe; - } - catch (SecurityException se) - { - exception = se; - } - if (canvas != null) - add(canvas, VideoLayout.CANVAS, 0); - else if ((exception != null) && !ignoreException) - logger.error("Failed to create video canvas.", exception); - } - } - if ((canvas != null) - && (canvas.getParent() == this) - && OSUtils.IS_MAC - && (comp != canvas)) - { - /* - * The canvas in which the other components are to be painted - * should always be at index 0. And the order of adding is - * important so no index should be specified. - */ - index = -1; - } - - /* - * XXX Do not call #remove(Component) beyond this point and before - * #add(Component, Object, int) because #removeCanvasIfNecessary() - * will remove the canvas. - */ - super.add(comp, constraints, index); } finally @@ -297,29 +176,10 @@ private void exitAddOrRemove() private void onContainerEvent(ContainerEvent ev) { - try - { - if (DEFAULT_BACKGROUND_COLOR != null) - { - int componentCount = getComponentCount(); - - if ((componentCount == 1) - && (getComponent(0) - == VideoContainer.this.noVideoComponent)) - { - componentCount = 0; - } - - setOpaque(componentCount > 0); - } - } - finally + synchronized (syncRoot) { - synchronized (syncRoot) - { - if (inAddOrRemove != 0) - validateAndRepaint = true; - } + if (inAddOrRemove != 0) + validateAndRepaint = true; } } @@ -337,13 +197,6 @@ public void remove(Component comp) { super.remove(comp); - if ((comp == canvas) - && (canvas != null) - && (canvas.getParent() != this)) - { - canvas = null; - } - Component[] components = getComponents(); VideoLayout videoLayout = (VideoLayout) getLayout(); boolean hasComponentsAtCenterRemote = false; @@ -365,8 +218,6 @@ public void remove(Component comp) { add(noVideoComponent, VideoLayout.CENTER_REMOTE); } - - removeCanvasIfNecessary(); } finally { @@ -391,9 +242,6 @@ public void removeAll() { super.removeAll(); - if ((canvas != null) && (canvas.getParent() != this)) - canvas = null; - if (noVideoComponent != null) add(noVideoComponent, VideoLayout.CENTER_REMOTE); } @@ -402,38 +250,4 @@ public void removeAll() exitAddOrRemove(); } } - - /** - * Removes {@link #canvas} from this <tt>VideoContainer</tt> if no sibling - * <tt>Component</tt> needs it. - */ - private void removeCanvasIfNecessary() - { - if ((canvas == null) || !OSUtils.IS_MAC) - return; - - boolean removeCanvas = true; - - for (Component component : getComponents()) - { - if (component == canvas) - continue; - try - { - component.getClass().getMethod( - VIDEO_CANVAS_FACTORY_METHOD_NAME); - removeCanvas = false; - break; - } - catch (NoSuchMethodException nsme) - { - /* - * Ignore it because we already presume that component does not - * need the canvas. - */ - } - } - if (removeCanvas) - remove(canvas); - } } diff --git a/src/org/jitsi/util/swing/VideoLayout.java b/src/org/jitsi/util/swing/VideoLayout.java index d3a94827df16f84cbc7e3db9433c9688dd7bb5c2..2e34da871666e048d13087b6181a0e2077b89485 100644 --- a/src/org/jitsi/util/swing/VideoLayout.java +++ b/src/org/jitsi/util/swing/VideoLayout.java @@ -301,6 +301,7 @@ else if (remoteCount > 0) int columns = calculateColumnCount(remotes); int columnsMinus1 = columns - 1; int rows = (remoteCount + columnsMinus1) / columns; + int rowsMinus1 = rows - 1; Rectangle bounds = new Rectangle( 0, @@ -314,31 +315,47 @@ else if (remoteCount > 0) */ (parentSize.width - (columnsMinus1 * HGAP)) / columns, parentSize.height / rows); - int i = 0; - for (Component remote : remotes) + for (int i = 0; i < remoteCount; i++) { + int column = i % columns; + int row = i / columns; + /* - * We want the remote videos ordered from right to left so that - * the local video does not cover a remote video when possible. - */ - /* - * We account for the HGAP between the Components being laid out - * by this VideoLayout. + * On the x axis, the first column starts at zero and each + * subsequent column starts relative to the end of its preceding + * column. */ - bounds.x - = (columnsMinus1 - (i % columns)) * (bounds.width + HGAP); - bounds.y = (i / columns) * bounds.height; + if (column == 0) + { + bounds.x = 0; + /* + * Eventually, there may be empty cells in the last row. + * Center the non-empty cells horizontally. + */ + if (row == rowsMinus1) + { + int available = remoteCount - i; + + if (available < columns) + { + bounds.x + = (parentSize.width + - available * bounds.width + - (available - 1) * HGAP) + / 2; + } + } + } + else + bounds.x += (bounds.width + HGAP); + bounds.y = row * bounds.height; super.layoutComponent( - remote, + remotes.get(i), bounds, Component.CENTER_ALIGNMENT, Component.CENTER_ALIGNMENT); - - i++; - if (i >= remoteCount) - break; } }