• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag
 

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: ... not sure if this is a KVO or a Core Audio problem with my code
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: ... not sure if this is a KVO or a Core Audio problem with my code


  • Subject: Re: ... not sure if this is a KVO or a Core Audio problem with my code
  • From: Ken Thomases <email@hidden>
  • Date: Fri, 28 Nov 2008 13:59:14 -0600

On Nov 28, 2008, at 8:48 AM, John Zorko wrote:

I'm experiencing a hang in my app when I do things too quickly. When I pause the app and examine the callstack, I see this:

#0 0x31467b18 in semaphore_timedwait_signal_trap ()
#1 0x3145e984 in semaphore_timedwait_signal ()
#2 0x3145b104 in _pthread_cond_wait ()
#3 0x3145b260 in pthread_cond_timedwait_relative_np ()
#4 0x348cbd58 in CAGuard::WaitFor ()
#5 0x34909954 in ClientAudioQueue::ServicePendingCallbacks ()
#6 0x34909ab8 in AudioQueueStop ()
#7 0x00014334 in -[AudioStreamer stop] (self=0x895800, _cmd=0x3018cc44) at /Users/jmzorko/work/root/Magnatune/Classes/ AudioStreamer.m:529
#8 0x00003566 in -[MagnatuneAppDelegate stopStream] (self=0x11cc40, _cmd=0x18694) at /Users/jmzorko/work/root/Magnatune/Classes/ MagnatuneAppDelegate.m:237
#9 0x0000f8d2 in -[SongController tableView:didSelectRowAtIndexPath:] (self=0x12e4c0, _cmd=0x300f1a90, tableView=0x186080, indexPath=0x1491a0) at /Users/jmzorko/work/root/ Magnatune/Classes/SongController.m:212


This is happening inside my observeValueForKeyPath method ... basically the background thread that does the Core Audio stuff has been told to stop via AudioQueueStop(), and the IsRunning callback set the value of a boolean called isPlaying to false. I've registered as an observer to this boolean, and usually things work well. However, when I select a new song to play too soon after a previous song, observeValueForKeyPath seems to hang. Here is observeValueForKeyPath:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
						change:(NSDictionary *)change context:(void *)context
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSLog(@"observeValueForKeyPath -- current thread ID: %x, keypath: %s", [NSThread currentThread], [keyPath UTF8String]);

if ([keyPath isEqualToString:@"isPlaying"])
{
NSLog(@"calling handleIsPlaying");
[self performSelectorOnMainThread:@selector(handleIsPlaying:) withObject:keyPath waitUntilDone:YES];

The "waitUntilDone:YES" is part of the problem.


[pool release];
return;
}

.
.
.

[pool release];
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}


... and here is handleIsPlaying:

[...]

... I can't immediately see why handleIsPlaying() or observeValueForKeyPath() would hang, but according to the callstack, it's waiting for something. The last thing I see in my console log is:

2008-11-28 06:29:44.459 Magnatune[1357:20b] calling AudioQueueStop() from AudioStreamer stop method
2008-11-28 06:29:44.990 Magnatune[1357:ba0f] ---------------- audio queue callback called
2008-11-28 06:29:45.001 Magnatune[1357:ba0f] observeValueForKeyPath -- current thread ID: 1a3860, keypath: isPlaying
2008-11-28 06:29:45.007 Magnatune[1357:ba0f] calling handleIsPlaying


If anyone could illuminate me as to what the problem is (what is CAGuard supposed to guard against, and why am I running into this issue?), i'd be very appreciative.

What you're seeing is a classic deadlock. If, in the debugger, you would look at the other threads' stack traces, you would see another thread which is inside some Core Audio stuff but has done something which needs to wait on your first thread (the one whose stack trace you showed above).


CAGuard is guarding internal state of Core Audio. Exactly what isn't for you to know. The issue is that any callback that Core Audio makes to your code is likely to happen while such a guard is held (locked). So, anything you do in such a callback can't block waiting on another thread which might in turn be waiting for that same guard. Actually, since Core Audio calls your callbacks on real time threads, you really shouldn't do anything which might block if you can at all avoid it.

I would recommend that you reconsider your design. If you can avoid it, don't update your isPlaying property from a Core Audio callback. If you need to track that, you can set it in the thread which starts the audio queue. Alternatively, you can query AudioQueueGetProperty with kAudioQueueProperty_IsRunning.

If you do want to deal with properties, perhaps reconsider where (and how) you're shunting the update to the main thread. Instead of shunting the call of handleIsPlaying: to the main thread, try shunting the actual setting of the isPlaying property. Remember, you might not be the only one observing that property. And, of course, don't wait until done.

Lastly, your implementation of -observeValueForKeyPath:... isn't done correctly. It isn't sufficient to test the keyPath. You must provide a unique context when you register as an observer and check that. Search the archives for the reasons and the correct form, or type "observe" and then ask Xcode to do code completion so it inserts a template showing the correct form.

Cheers,
Ken

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


References: 
 >... not sure if this is a KVO or a Core Audio problem with my code (From: John Zorko <email@hidden>)

  • Prev by Date: Re: Using a string as filepath
  • Next by Date: Re: question re: mem leak analysis and RSIZE
  • Previous by thread: ... not sure if this is a KVO or a Core Audio problem with my code
  • Next by thread: Garbage collection and root objects
  • Index(es):
    • Date
    • Thread