Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

解决ijk第一次初始化时异步线程调用主线程造成的线程卡顿问题 #4683

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#import "IJKSDLAudioQueueController.h"
#import "IJKSDLAudioKit.h"
#import "ijksdl_log.h"
#import "ijksdl_thread_ios.h"

#import <AVFoundation/AVFoundation.h>

Expand All @@ -41,8 +42,7 @@ @implementation IJKSDLAudioQueueController {
NSLock *_lock;
}

- (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec
{
- (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec {
self = [super init];
if (self) {
if (aSpec == NULL) {
Expand All @@ -52,12 +52,12 @@ - (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec
_spec = *aSpec;

if (aSpec->format != AUDIO_S16SYS) {
NSLog(@"aout_open_audio: unsupported format %d\n", (int)aSpec->format);
NSLog(@"aout_open_audio: unsupported format %d\n", (int) aSpec->format);
return nil;
}

if (aSpec->channels > 2) {
NSLog(@"aout_open_audio: unsupported channels %d\n", (int)aSpec->channels);
NSLog(@"aout_open_audio: unsupported channels %d\n", (int) aSpec->channels);
return nil;
}

Expand All @@ -75,14 +75,14 @@ - (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec
/* Set the desired format */
AudioQueueRef audioQueueRef;
OSStatus status = AudioQueueNewOutput(&streamDescription,
IJKSDLAudioQueueOuptutCallback,
(__bridge void *) self,
NULL,
kCFRunLoopCommonModes,
0,
&audioQueueRef);
IJKSDLAudioQueueOuptutCallback,
(__bridge void *) self,
NULL,
kCFRunLoopCommonModes,
0,
&audioQueueRef);
if (status != noErr) {
NSLog(@"AudioQueue: AudioQueueNewOutput failed (%d)\n", (int)status);
NSLog(@"AudioQueue: AudioQueueNewOutput failed (%d)\n", (int) status);
self = nil;
return nil;
}
Expand All @@ -96,15 +96,14 @@ - (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec

status = AudioQueueStart(audioQueueRef, NULL);
if (status != noErr) {
NSLog(@"AudioQueue: AudioQueueStart failed (%d)\n", (int)status);
NSLog(@"AudioQueue: AudioQueueStart failed (%d)\n", (int) status);
self = nil;
return nil;
}

_audioQueueRef = audioQueueRef;

for (int i = 0;i < kIJKAudioQueueNumberBuffers; i++)
{
for (int i = 0; i < kIJKAudioQueueNumberBuffers; i++) {
AudioQueueAllocateBuffer(audioQueueRef, _spec.size, &_audioQueueBufferRefArray[i]);
_audioQueueBufferRefArray[i]->mAudioDataByteSize = _spec.size;
memset(_audioQueueBufferRefArray[i]->mAudioData, 0, _spec.size);
Expand All @@ -126,59 +125,56 @@ - (id)initWithAudioSpec:(const SDL_AudioSpec *)aSpec
return self;
}

- (void)dealloc
{
- (void)dealloc {
[self close];
}

- (void)play
{
- (void)play {
if (!_audioQueueRef)
return;

self.spec.callback(self.spec.userdata, NULL, 0);

@synchronized(_lock) {
@synchronized (_lock) {
_isPaused = NO;
NSError *error = nil;
if (NO == [[AVAudioSession sharedInstance] setActive:YES error:&error]) {
if (![[AVAudioSession sharedInstance] setActive:YES error:&error]) {
NSLog(@"AudioQueue: AVAudioSession.setActive(YES) failed: %@\n", error ? [error localizedDescription] : @"nil");
}

OSStatus status = AudioQueueStart(_audioQueueRef, NULL);
if (status != noErr)
NSLog(@"AudioQueue: AudioQueueStart failed (%d)\n", (int)status);
NSLog(@"AudioQueue: AudioQueueStart failed (%d)\n", (int) status);
}
}

- (void)pause
{
- (void)pause {
if (!_audioQueueRef)
return;

@synchronized(_lock) {
@synchronized (_lock) {
if (_isStopped)
return;

_isPaused = YES;
OSStatus status = AudioQueuePause(_audioQueueRef);
if (status != noErr)
NSLog(@"AudioQueue: AudioQueuePause failed (%d)\n", (int)status);
IJKMainThredExecute(^{
OSStatus status = AudioQueuePause(_audioQueueRef);
if (status != noErr)
NSLog(@"AudioQueue: AudioQueuePause failed (%d)\n", (int) status);
});
}
}

- (void)flush
{
- (void)flush {
if (!_audioQueueRef)
return;

@synchronized(_lock) {
@synchronized (_lock) {
if (_isStopped)
return;

if (_isPaused == YES) {
for (int i = 0; i < kIJKAudioQueueNumberBuffers; i++)
{
if (_isPaused) {
for (int i = 0; i < kIJKAudioQueueNumberBuffers; i++) {
if (_audioQueueBufferRefArray[i] && _audioQueueBufferRefArray[i]->mAudioData) {
_audioQueueBufferRefArray[i]->mAudioDataByteSize = _spec.size;
memset(_audioQueueBufferRefArray[i]->mAudioData, 0, _spec.size);
Expand All @@ -190,31 +186,29 @@ - (void)flush
}
}

- (void)stop
{
- (void)stop {
if (!_audioQueueRef)
return;

@synchronized(_lock) {
@synchronized (_lock) {
if (_isStopped)
return;

_isStopped = YES;
}

// do not lock AudioQueueStop, or may be run into deadlock
AudioQueueStop(_audioQueueRef, true);
AudioQueueDispose(_audioQueueRef, true);
IJKMainThredExecute(^{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里会导致野指针崩溃,因AudioQuueueDispose 在主队列的执行时间不确定,可能IJKSDLAudioQueueController的实例已经被释放,但AudioQueueDispose还没执行,导致IJKSDLAudioQueueOuptutCallback回调时访问已释放的IJKSDLAudioQueueController的实例,引起崩溃;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

测试场景:
播放资源切换,因为ijkffmoviecontroller的设计,实际上每次播放一个新的资源都是创建一个新的ijkffmoviecontroller的实例

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

试一试

    [self.player stop];
    [self.player shutdown];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我也遇到这个问题了,请问解决了么

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我今天遇到了这个问题,有解决的吗?

// do not lock AudioQueueStop, or may be run into deadlock
AudioQueueStop(_audioQueueRef, true);
AudioQueueDispose(_audioQueueRef, true);
});
}

- (void)close
{
- (void)close {
[self stop];
_audioQueueRef = nil;
}

- (void)setPlaybackRate:(float)playbackRate
{
- (void)setPlaybackRate:(float)playbackRate {
if (fabsf(playbackRate - 1.0f) <= 0.000001) {
UInt32 propValue = 1;
AudioQueueSetProperty(_audioQueueRef, kAudioQueueProperty_TimePitchBypass, &propValue, sizeof(propValue));
Expand All @@ -226,8 +220,7 @@ - (void)setPlaybackRate:(float)playbackRate
}
}

- (void)setPlaybackVolume:(float)playbackVolume
{
- (void)setPlaybackVolume:(float)playbackVolume {
float aq_volume = playbackVolume;
if (fabsf(aq_volume - 1.0f) <= 0.000001) {
AudioQueueSetParameter(_audioQueueRef, kAudioQueueParam_Volume, 1.f);
Expand All @@ -236,14 +229,13 @@ - (void)setPlaybackVolume:(float)playbackVolume
}
}

- (double)get_latency_seconds
{
return ((double)(kIJKAudioQueueNumberBuffers)) * _spec.samples / _spec.freq;
- (double)get_latency_seconds {
return ((double) (kIJKAudioQueueNumberBuffers)) * _spec.samples / _spec.freq;
}

static void IJKSDLAudioQueueOuptutCallback(void * inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
static void IJKSDLAudioQueueOuptutCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
@autoreleasepool {
IJKSDLAudioQueueController* aqController = (__bridge IJKSDLAudioQueueController *) inUserData;
IJKSDLAudioQueueController *aqController = (__bridge IJKSDLAudioQueueController *) inUserData;

if (!aqController) {
// do nothing;
Expand Down
Loading