audio ios 只播放一次
2017-11-23 01:52:03 weixin_34162228 阅读数 38

ios中audio不能直接通过audio.play()播放,需要用户在click事件或者touch事件中执行audio.play()才能播放。

ajax回调中audio.play()音乐不能正常播放。

用户点击按钮,等服务器返回数据后再播放相应的成功或失败的音乐,测试在ios中不能正常播放。猜测ios中的audio不能再ajax回调函数中play()

下面记录一下ios中ajax回调中播放音乐的问题解决过程

  • 解决方案一 --降低音量

在用户点击时间后将audio的音量设置为0,等success后将音量设置为1; volume可以控制audio的音量大小,取值范围为 0~1

audio.volume=number

发现在chrome的手机模式可以将音乐静音,ios中竟然不能控制音量,好吧这个被ios屏蔽了。放弃了。。。

  • 解决方案二 --播放后立即暂停

用户点击按钮后立即播放音乐,等ajax返回数据后再继续播放。测试能够正常播放。部分代码如下:

// 用户click事件
if (this.isIOS()) {          // ios单独处理 安卓不需要
  this.$refs.audio.play()
  this.$refs.audio.pause()
}

// ajax成功后的事件
  this.$refs.audio.pause()
  this.$refs.audio.currentTime = 0
  this.$refs.audio.play()

由于是vue项目,所以代码中有this.$refs小伙伴们别介意;

总结

  1. 在ios中,如果需要播放音乐或者视频,需要用户手动触发事件在调用.play()才能播放(autoplay或者直接.play()是不能直接触发的);

  2. 如果需要在ajax回调函数中播放音乐,需要在用户触发事件后播放音乐立即暂停然后才能在回调函数中.play(),不然ios中是播放不成功的。

2017-07-27 08:27:00 weixin_34220834 阅读数 15

最近做项目,碰到一个问题:就是音频播放,同样的设置,在安卓上面无比顺畅,但是在ios上面却始终没有任何效果,作为H5开发,我痛恨世界上的所有兼容,迫切出现一个大佬一桶天下,不过眼下拿人工资,总要先解决bug,话不多说,解决如下

原因:ios不支持audio自动播放

解决:

1、普通页面添加事件可以是onload,或者click,使其可以自动播放

`document.getElementById('audio').play()`

2、微信页面,我看到有大神铺贴,就直接摘抄下来,有帮助到地方就谢谢前仆后继的先驱者把

`//一般情况下,这样就可以自动播放了,但是一些奇葩iPhone机不可以

document.getElementById('audio').play();

//微信必须加入Weixin JSAPI的WeixinJSBridgeReady才能生效

document.addEventListener("WeixinJSBridgeReady", function () {

document.getElementById('audio').play();

// document.getElementById('video').play(); //视频自动播放

}, false);`

2012-10-23 10:28:41 iceleeb1234b 阅读数 417

原文  http://blog.csdn.net/onlyou930/article/details/7372791

要在iOS设备上播放和录制音频,苹果推荐我们使用AVFoundation框架中的AVAudioPlayer和AVAudioRecorder类。虽然用法比较简单,但是不支持流式;这就意味着:在播放音频前,必须等到整个音频加载完成后,才能开始播放音频;录音时,也必须等到录音结束后,才能获取到录音数据。这给应用造成了很大的局限性。为了解决这个问题,我们就需要使用Audio Queue Services来播放和录制音频为了简化音频文件的处理,这里还需要用到Audio File Services(以前以为C语言没有音频文件处理的函数库,现在找到了)。

 

         在使用之前,我们需要了解AudioQueue Service的基本工作原理。

 

图1一个录音音频队列(Recording Audio Queue)

         

 

         由上图可以得知,一个Recording Audio Queue,包括Buffer(缓冲器)组成的Buffer Queue(缓冲队列),以及一个Callback(回调)。他们之间是如何工作的呢?

 

图2 录音流程


         1. 将音频填入第一个缓冲器中

         2. 当队列中的第一个缓冲器填满时,会自动填充下一个缓冲器。此时,会触发回调。

         3. 在回调函数中需要将音频数据流写入磁盘

         4. 然后,需要在回调函数中将该缓冲器重新放入缓冲队列,以便重复使用该缓冲器。重复步骤2。


         在了解录音的流程之后,让我们来看看播放基本体系结构。

图3 一个播放音频队列(A playback audio queue)


         由上图可以得知,其结构和录音音频队列基本一致,只是回调触发的时机不同,工作流程略有差异。


图4 播放流程

 


         1. 将音频读入到缓存器中。一旦填充满一个缓存器,就会进入缓存队列,此时处于待命状态。

         2. 应用程序命令发出指令,要求音频队列开始播放。

         3. 音频会从第一个缓存器中取数据,并开始播放。

         4. 一旦播放完成,就会触发回调,并开始播放下一个缓存器中的内容。

         5. 回调中需要给该缓存器取后面的音频数据,然后重新放入缓存队列中。重复步骤3。

 

         至此,Audio QueueServices的基本原理就算介绍完了。在实际的应用中,还需要处理好各种状态,以及异常情况,例如播放中断、没有录音设备等。关于Audio File Services 的使用,我这里就不做介绍了,详细参考源码。


 与本文配套的源代码示例:http://download.csdn.net/detail/midfar/4044390

 

参考资料:

Audio Queue Services Programming Guide

https://developer.apple.com/library/ios/#documentation/MusicAudio/Conceptual/AudioQueueProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005343

Audio Queue Services Reference

https://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/uid/TP40005117

Audio File Services Reference

https://developer.apple.com/library/ios/#documentation/MusicAudio/Reference/AudioFileConvertRef/Reference/reference.html#//apple_ref/doc/uid/TP40006072


2019-05-13 11:09:00 weixin_33834679 阅读数 3

这是一篇干货,是直接应用的关于audio queue 播放

先看下面一张运行时的流程原理图:

1447246-0489b63350e5cab9.png
playback_callback_function_2x.png

上图中的步骤:
1、准备播放的音频队列,为每个音频队列缓冲区(Buffer)进行数据填充;
2、当启用AudioQueueStart时,即刻进行播放数据;
3、将队列里第一个缓冲的buffer发送到音频输出区
4、播放队列进入循环模式,音频队列可以进行下一个的音频缓冲区播放
5、回调告诉上层缓冲的buffer已被使用了,然后可以进行下一次的缓冲
6、待上一个已被播放了的音频buffer释放后再次填充buffer

1、设置宏定义

#define MIN_SIZE_PER_FRAME 2000
#define QUEUE_BUFFER_NUM 3

2、定义相关的属性

    AudioQueueRef audioQueue;
    AudioStreamBasicDescription _audioDescription;
    AudioQueueBufferRef audioQueueBuffers[QUEUE_BUFFER_NUM];
    BOOL audioqueueBufferUsed[QUEUE_BUFFER_NUM];
    NSLock *sysLock;
    NSMutableData *tempData;
    OSStatus osState;

3、初始化音频播放的参数

  _audioDescription.mSampleRate = 8000;//采样率
            _audioDescription.mFormatID = kAudioFormatLinearPCM;//音频格式
            _audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;//保存音频数据的方式的说明
            _audioDescription.mChannelsPerFrame = 1; //1单声道 2双声道
            _audioDescription.mFramesPerPacket = 1;//每一个packet指定只有一帧数据,每个数据包的帧数
            _audioDescription.mBitsPerChannel = 16;//采样点,语音每个采样点的占用位数
            _audioDescription.mBytesPerFrame = (_audioDescription.mBitsPerChannel/8) * _audioDescription.mChannelsPerFrame;
            _audioDescription.mBytesPerPacket = _audioDescription.mBytesPerFrame * _audioDescription.mFramesPerPacket;
 AudioQueueNewOutput(&_audioDescription, AudioPlayerAQInputCallback, (__bridge void*)self, NULL, kCFRunLoopCommonModes, 0, &audioQueue);
        //设置AudioSessionInitialize


        // 设置音量
        AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, 1.0);
        
        //初始化缓冲区
        for (int i = 0; i < QUEUE_BUFFER_NUM; i++) {
            audioqueueBufferUsed[i] = false;
            osState = AudioQueueAllocateBuffer(audioQueue, MIN_SIZE_PER_FRAME, &audioQueueBuffers[i]);
            printf("第 %d 个AudioQueueAllocateBuffer 初始化结果 %d (0表示成功)\n", i + 1, osState);
        }
        
        osState = AudioQueueStart(audioQueue, NULL);
        if (osState != noErr) {
            NSLog(@"Audio Queue Start Failed");
        }

4、设置相关的回调函数,用于设置数据的回调

// 回调回来把buffer状态设为未使用
static void AudioPlayerAQInputCallback(void* inUserData,AudioQueueRef audioQueueRef, AudioQueueBufferRef audioQueueBufferRef) {
    
    ECAudioQueuePlayer* player = (__bridge ECAudioQueuePlayer*)inUserData;
    
    [player resetBufferState:audioQueueRef and:audioQueueBufferRef];
}

- (void)resetBufferState:(AudioQueueRef)audioQueueRef and:(AudioQueueBufferRef)audioQueueBufferRef {
    
    for (int i = 0; i < QUEUE_BUFFER_NUM; i++) {
        // 将这个buffer设为未使用
        if (audioQueueBufferRef == audioQueueBuffers[i]) {
            audioqueueBufferUsed[i] = false;
        }
    }
}

6、输入播放数据

-(void)playWithData:(NSData *)data{
    [sysLock lock];
    tempData = nil;
    tempData = [NSMutableData new];
    [tempData appendData:data];
    NSUInteger len = tempData.length;
    Byte *bytes = (Byte *)malloc(len);
    [tempData getBytes:bytes length:len];
    int i = 0;
    while (true) {
        if (!audioqueueBufferUsed[i]) {
            audioqueueBufferUsed[i] = true;
            break;
        }else{
            i++;
            if (i>=QUEUE_BUFFER_NUM) {
                i = 0;
            }
        }
    }
    
    audioQueueBuffers[i]->mAudioDataByteSize = (unsigned int)len;
    memcpy(audioQueueBuffers[i]->mAudioData, bytes, len);
    
    free(bytes);
    AudioQueueEnqueueBuffer(audioQueue, audioQueueBuffers[i], 0, NULL);
    [sysLock unlock];

}

转载于:https://www.jianshu.com/p/f57747a07ca3

2018-07-05 10:19:00 weixin_34250434 阅读数 73


示例代码: XBVoiceTool


步骤:

1.设置AVAudioSession
2.初始化audioUnit
3.设置输出流格式
4.设置回调
5.在回调中提供数据

设置AVAudioSession
    //设置session
    NSError *error = nil;
    AVAudioSession* session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:&error];
    [session setActive:YES error:nil];
初始化audioUnit
    //初始化audioUnit
    AudioComponentDescription outputDesc;
    outputDesc.componentType = kAudioUnitType_Output;
    outputDesc.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
    outputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
    outputDesc.componentFlags = 0;
    outputDesc.componentFlagsMask = 0;
    AudioComponent outputComponent = AudioComponentFindNext(NULL, &outputDesc);
    AudioComponentInstanceNew(outputComponent, &audioUnit);
设置输出流格式
    //设置输出格式
    int mFramesPerPacket = 1;
    int mBytesPerFrame = channel * bit / 8;
    
    AudioStreamBasicDescription streamDesc;
    streamDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsNonInterleaved;
    streamDesc.mFormatID = kAudioFormatLinearPCM;
    streamDesc.mSampleRate = rate;
    streamDesc.mFramesPerPacket = mFramesPerPacket;
    streamDesc.mChannelsPerFrame = channel;
    streamDesc.mBitsPerChannel = bit;
    streamDesc.mBytesPerFrame = mBytesPerFrame;
    streamDesc.mBytesPerPacket = mBytesPerFrame * mFramesPerPacket;
    
    OSStatus status = AudioUnitSetProperty(audioUnit,
                                           kAudioUnitProperty_StreamFormat,
                                           kAudioUnitScope_Input,
                                           kOutputBus,
                                           &streamDesc,
                                           sizeof(streamDesc));
    CheckError(status, "SetProperty StreamFormat failure");
设置回调
    //设置回调
    AURenderCallbackStruct outputCallBackStruct;
    outputCallBackStruct.inputProc = outputCallBackFun;
    outputCallBackStruct.inputProcRefCon = (__bridge void * _Nullable)(self);
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_SetRenderCallback,
                                  kAudioUnitScope_Input,
                                  kOutputBus,
                                  &outputCallBackStruct,
                                  sizeof(outputCallBackStruct));
    CheckError(status, "SetProperty EnableIO failure");
在回调中提供数据

这里设置成在player 的 bl_input回调中提供数据

static OSStatus outputCallBackFun(    void *                            inRefCon,
                    AudioUnitRenderActionFlags *    ioActionFlags,
                    const AudioTimeStamp *            inTimeStamp,
                    UInt32                            inBusNumber,
                    UInt32                            inNumberFrames,
                    AudioBufferList * __nullable    ioData)
{
    memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize);
//    memset(ioData->mBuffers[1].mData, 0, ioData->mBuffers[1].mDataByteSize);
    
    XBAudioUnitPlayer *player = (__bridge XBAudioUnitPlayer *)(inRefCon);
    if (player.bl_input)
    {
        player.bl_input(ioData);
    }
    return noErr;
}
没有更多推荐了,返回首页