summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiong Sauw Ming <ming@teluu.com>2015-04-07 01:47:51 +0000
committerLiong Sauw Ming <ming@teluu.com>2015-04-07 01:47:51 +0000
commitac0421f0a215fa9533a72fde494f3fca4d48cd2f (patch)
tree2319d0336e7aac6c71f398b3db842b0fb00735ab
parent024b2ca5c92600456eac7ab2b7c735e025986545 (diff)
Fixed #1835: Fixed crash in iOS OpenGL renderer when in background and assertion during destruction
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5047 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/src/pjmedia-videodev/ios_opengl_dev.m119
1 files changed, 87 insertions, 32 deletions
diff --git a/pjmedia/src/pjmedia-videodev/ios_opengl_dev.m b/pjmedia/src/pjmedia-videodev/ios_opengl_dev.m
index 150fcad5..2826bf4b 100644
--- a/pjmedia/src/pjmedia-videodev/ios_opengl_dev.m
+++ b/pjmedia/src/pjmedia-videodev/ios_opengl_dev.m
@@ -31,6 +31,12 @@
#define THIS_FILE "ios_opengl_dev.c"
+/* If this is enabled, iOS OpenGL will not return error during creation when
+ * in the background. Instead, it will perform the initialization later
+ * during rendering.
+ */
+#define ALLOW_DELAYED_INITIALIZATION 0
+
typedef struct iosgl_fmt_info
{
pjmedia_format_id pjmedia_format;
@@ -60,15 +66,16 @@ struct iosgl_stream
pjmedia_vid_dev_cb vid_cb; /**< Stream callback */
void *user_data; /**< Application data */
+ pj_bool_t is_running;
pj_status_t status;
pj_timestamp frame_ts;
unsigned ts_inc;
pjmedia_rect_size vid_size;
const pjmedia_frame *frame;
- gl_buffers *gl_buf;
- GLView *gl_view;
- EAGLContext *ogl_context;
+ gl_buffers *gl_buf;
+ GLView *gl_view;
+ EAGLContext *ogl_context;
};
@@ -128,7 +135,7 @@ static iosgl_fmt_info* get_iosgl_format_info(pjmedia_format_id id)
return [CAEAGLLayer class];
}
-- (void) init_buffers
+- (void) init_gl
{
/* Initialize OpenGL ES 2 */
CAEAGLLayer *eagl_layer = (CAEAGLLayer *)[stream->gl_view layer];
@@ -139,11 +146,19 @@ static iosgl_fmt_info* get_iosgl_format_info(pjmedia_format_id id)
kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
nil];
+ /* EAGLContext initialization will crash if we are in background mode */
+ if ([UIApplication sharedApplication].applicationState ==
+ UIApplicationStateBackground) {
+ stream->status = PJMEDIA_EVID_INIT;
+ return;
+ }
+
stream->ogl_context = [[EAGLContext alloc] initWithAPI:
kEAGLRenderingAPIOpenGLES2];
if (!stream->ogl_context ||
![EAGLContext setCurrentContext:stream->ogl_context])
{
+ NSLog(@"Failed in initializing EAGLContext");
stream->status = PJMEDIA_EVID_SYSERR;
return;
}
@@ -159,13 +174,45 @@ static iosgl_fmt_info* get_iosgl_format_info(pjmedia_format_id id)
stream->status = pjmedia_vid_dev_opengl_init_buffers(stream->gl_buf);
}
+- (void)deinit_gl
+{
+ if ([EAGLContext currentContext] == stream->ogl_context)
+ [EAGLContext setCurrentContext:nil];
+
+ if (stream->ogl_context) {
+ [stream->ogl_context release];
+ stream->ogl_context = NULL;
+ }
+
+ if (stream->gl_buf) {
+ pjmedia_vid_dev_opengl_destroy_buffers(stream->gl_buf);
+ stream->gl_buf = NULL;
+ }
+
+ [self removeFromSuperview];
+}
+
- (void)render
{
/* Don't make OpenGLES calls while in the background */
if ([UIApplication sharedApplication].applicationState ==
UIApplicationStateBackground)
+ {
return;
-
+ }
+
+#if ALLOW_DELAYED_INITIALIZATION
+ if (stream->status != PJ_SUCCESS) {
+ if (stream->status == PJMEDIA_EVID_INIT) {
+ [self init_gl];
+ NSLog(@"Initializing OpenGL now %s", stream->status == PJ_SUCCESS?
+ "success": "failed");
+ }
+
+ return;
+ }
+#endif
+
if (![EAGLContext setCurrentContext:stream->ogl_context]) {
/* Failed to set context */
return;
@@ -175,6 +222,13 @@ static iosgl_fmt_info* get_iosgl_format_info(pjmedia_format_id id)
stream->frame->buf);
}
+- (void)finish_render
+{
+ /* Do nothing. This function is serialized in the main thread, so when
+ * it is called, we can be sure that render() has completed.
+ */
+}
+
@end
/* API: create stream */
@@ -218,11 +272,20 @@ pjmedia_vid_dev_opengl_imp_create_stream(pj_pool_t *pool,
/* Perform OpenGL buffer initializations in the main thread. */
strm->status = PJ_SUCCESS;
- [strm->gl_view performSelectorOnMainThread:@selector(init_buffers)
+ [strm->gl_view performSelectorOnMainThread:@selector(init_gl)
withObject:nil waitUntilDone:YES];
- if ((status = strm->status) != PJ_SUCCESS) {
- PJ_LOG(3, (THIS_FILE, "Unable to create and init OpenGL buffers"));
- goto on_error;
+ if ((status = strm->status) != PJ_SUCCESS)
+ {
+ if (status == PJMEDIA_EVID_INIT) {
+ PJ_LOG(3, (THIS_FILE, "Failed to initialize iOS OpenGL because "
+ "we are in background"));
+#if !ALLOW_DELAYED_INITIALIZATION
+ goto on_error;
+#endif
+ } else {
+ PJ_LOG(3, (THIS_FILE, "Unable to create and init OpenGL buffers"));
+ goto on_error;
+ }
}
/* Apply the remaining settings */
@@ -376,9 +439,8 @@ static pj_status_t iosgl_stream_start(pjmedia_vid_dev_stream *strm)
{
struct iosgl_stream *stream = (struct iosgl_stream*)strm;
- PJ_UNUSED_ARG(stream);
-
PJ_LOG(4, (THIS_FILE, "Starting ios opengl stream"));
+ stream->is_running = PJ_TRUE;
return PJ_SUCCESS;
}
@@ -389,12 +451,13 @@ static pj_status_t iosgl_stream_put_frame(pjmedia_vid_dev_stream *strm,
{
struct iosgl_stream *stream = (struct iosgl_stream*)strm;
+ if (!stream->is_running)
+ return PJ_EINVALIDOP;
+
stream->frame = frame;
/* Perform OpenGL drawing in the main thread. */
[stream->gl_view performSelectorOnMainThread:@selector(render)
withObject:nil waitUntilDone:YES];
- // dispatch_async(dispatch_get_main_queue(),
- // ^{[stream->gl_view render];});
[stream->ogl_context presentRenderbuffer:GL_RENDERBUFFER];
@@ -406,9 +469,12 @@ static pj_status_t iosgl_stream_stop(pjmedia_vid_dev_stream *strm)
{
struct iosgl_stream *stream = (struct iosgl_stream*)strm;
- PJ_UNUSED_ARG(stream);
-
PJ_LOG(4, (THIS_FILE, "Stopping ios opengl stream"));
+ stream->is_running = PJ_FALSE;
+
+ /* Wait until the rendering finishes */
+ [stream->gl_view performSelectorOnMainThread:@selector(finish_render)
+ withObject:nil waitUntilDone:YES];
return PJ_SUCCESS;
}
@@ -421,28 +487,17 @@ static pj_status_t iosgl_stream_destroy(pjmedia_vid_dev_stream *strm)
PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
- iosgl_stream_stop(strm);
-
- if ([EAGLContext currentContext] == stream->ogl_context)
- [EAGLContext setCurrentContext:nil];
-
- if (stream->ogl_context) {
- [stream->ogl_context release];
- stream->ogl_context = NULL;
- }
+ if (stream->is_running)
+ iosgl_stream_stop(strm);
if (stream->gl_view) {
- UIView *view = stream->gl_view;
- dispatch_async(dispatch_get_main_queue(),
- ^{
- [view removeFromSuperview];
- [view release];
- });
+ [stream->gl_view performSelectorOnMainThread:@selector(deinit_gl)
+ withObject:nil waitUntilDone:YES];
+
+ [stream->gl_view release];
stream->gl_view = NULL;
}
- pjmedia_vid_dev_opengl_destroy_buffers(stream->gl_buf);
-
pj_pool_release(stream->pool);
return PJ_SUCCESS;