AliSherKashif / codenameone

Automatically exported from code.google.com/p/codenameone
0 stars 0 forks source link

iOS crash with sounds playing #926

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
This is the code I use to repeat the crash on calling sequential createMedia 
and Media play calls on iOS.  I use the URI version of the call for loading the 
file.

I have built a simple test App with 2 forms, which recreate the crash issue I 
was seeing in my full app.
The first form, managed by a UITimer, does the following:
 
 
1.  calls create media to load the sound
2.  plays the sound (about 1 second or so of audio)
3.  and the Runnable calls 
                   if(media_.isPlaying())
                              media_.pause();
                  media_.cleanup();
                  media_ = null;
 
4. The timer waits for the Runnable to signal completion
5. Then the whole process repeats by calling create media again

 
On an Android build of this test, I have let it run for over an hour with no 
issues. On the iOS build, it usually does not last more than 4-5 minutes before 
the sound stops playing without any manual direction. No sounds are ever 
heard again. This does not cause the app to crash right away, but text 
manipulation in a label does! After the sound has stopped, I go to a second 
form which has a text field. When I focus the textfield for editing, and the 
app would immediately disappear (crash). I suspect if I changed the text of a 
label, it would crash as well.

So testing steps are:

Press Suicide Button on first form so sound is playing continuously.
Sound should stop playing on its own (within 5 minutes on my phone).
Press Second button to go to second form.
Click on text field to go boom.

code src directory from basic eclipse project attached.

Thanks so much.

Original issue reported on code.google.com by killerbe...@gmail.com on 22 Oct 2013 at 11:35

Attachments:

GoogleCodeExporter commented 9 years ago
Shai, I have been looking into this and have made some interesting discoveries.

I ran the attached test app through the debugger with instruments, and did not 
observe any memory leak associated with the sounds, however, it was clear there 
was a resource leak as the sound resources were not being let go.

The ultimate error when it crashes is caused by a "too many open files" 
message. Also, the allocations section shows numerous in memory sound objects 
that had been allocated but never released.

Looking at the dealloc code, the audio player is clearly getting released - but 
the allocations was still showing a reference count of 1. 

The problematic file is AudioPlayer.m, with the AudioPlayer interface.  Here 
are the two constructors:

(id)initWithURL:(NSString*)url callback:(void*)callback {
    self = [super init];
    if (self) {
        runnableCallback = callback;
        errorInfo = nil;
        playerInstance = nil;
        avPlayerInstance = nil;
        if(currentlyPlaying == nil) {
            currentlyPlaying = self;
        }
        if ([url hasPrefix:@"http"]) {
            avPlayerInstance = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:url]];
            avPlayerInstance.actionAtItemEnd = AVPlayerActionAtItemEndNone;

            [[NSNotificationCenter defaultCenter] addObserver:self
                                                     selector:@selector(playerItemDidReachEnd:)
                                                         name:AVPlayerItemDidPlayToEndTimeNotification
                                                       object:[avPlayerInstance currentItem]];
            [avPlayerInstance retain];
        } else {
            playerInstance = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:url] error:&errorInfo];
            playerInstance.delegate = self;
            if(volume > -1) {
                playerInstance.volume = volume;
            }
            [playerInstance retain];
        }
    }

    return self;    
}

- (id)initWithNSData:(NSData*)data callback:(void*)callback {
    self = [super init];
    if (self) {
        runnableCallback = callback;
        playerInstance = [[AVAudioPlayer alloc] initWithData:data error:&errorInfo];
        playerInstance.delegate = self;
        if(volume > -1) {
            playerInstance.volume = volume;
        }
        if(currentlyPlaying == nil) {
            currentlyPlaying = self;
        }
        [playerInstance retain];
    }

    return self;    
}

Objective C is new to me, but  after looking up some memory management 
questions I found this thread : 
http://stackoverflow.com/questions/6578/understanding-reference-counting-with-co
coa-and-objective-c and cross referencing apple's doc on memory management ( 
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgm
t/Articles/MemoryMgmt.html ) ,
it shows that using "retain" bumps up the reference count for an object. So in 
this case, the explicit retain  on “playerInstance”sets the memory 
reference count to initially to 2, so when It is released, it only decrements 
to 1 and is kept open by what ever is tracking reference counts in the app.

I do not understand why the retain is there in the first place, and I believe 
this is the source of the bug.

Do note that retain is called in both constructors of AudioPlayer  (url and 
data) so I assume it is a bug in both.

I have run with the retain line commented out in the constructor and it appears 
to not resource leak.

Please let me know whether or not you agree with this analysis and if so, let 
me know when it will be fixed.
  Thanks.

Original comment by killerbe...@gmail.com on 7 Nov 2013 at 7:08

GoogleCodeExporter commented 9 years ago
Also, though I am not using video, I would think the same applies for  
[avPlayerInstance retain];

Original comment by killerbe...@gmail.com on 7 Nov 2013 at 7:21

GoogleCodeExporter commented 9 years ago
Thanks, I've committed a fix for this. We had a crash in that class in the past 
and just added retains when trying to figure stuff out.

Original comment by shai.almog on 9 Nov 2013 at 8:34