本章节为您介绍了iOS的输入外部视频流和音频流的接口示例。

输入外部视频流

注意 增加自定义视频输入时,建议您提前进行采集,RTC入会之前开始送入数据,避免看到摄像头数据。
  1. 打开外部视频输入开关。

    接口说明如下所示。

    /**
     * @brief 启用外部视频输入源
     * @param enable YES:开启,NO:关闭
     * @param useTexture 是否使用texture模式
     * @param type 流类型
     */
    - (int)setExternalVideoSource:(BOOL)enable useTexture:(BOOL)useTexture sourceType:(AliRtcVideoSource)type;
    说明 目前userTexture暂不支持,type仅支持AliRtcVideosourceCameraLargeType(视频流)。

    示例方法如下所示。

    int ret = [self.engine setExternalVideoSource:YES useTexture:NO sourceType:AliRtcVideosourceCameraLargeType];
  2. 输入视频数据。

    接口说明如下所示。

    /**
     * @brief 输入视频数据
     * @param frame 帧数据
     * @param type 流类型
     * @return 返回>=0表示成功,<0表示失败
     */
    - (int)pushExternalVideoFrame:(AliRtcVideoDataSample *)frame sourceType:(AliRtcVideoSource)type;
    						

    参数说明,AliRtcVideoDataSample必填项如下所示。

    参数 说明
    dataPtr 数据句柄
    format 数据类型,目前仅支持AliRtcVideoFormat_I420
    width 视频流宽
    height 视频流高
    datalength 数据buffer length
    说明 需要APP开启线程进行push;type仅支持AliRtcVideosourceCameraLargeType(视频流)。

    示例方法如下所示。

    float pcmHzFloat;
    int yuvDataWidth;
    int yuvDataHeight;
    NSThread * yuvInputThread;
    FILE * yuvInputFile;
    
    - (void)inputYUVRun {
    
        int width = yuvDataWidth;
        int height = yuvDataHeight;
        int dataSize = width*height*3/2;
    
        char *yuv_read_data = (char *)malloc(dataSize);
    
        while (true) {
    
            if ([yuvInputThread isCancelled]) {
                break;
            }
    
            size_t read = fread(yuv_read_data,dataSize, 1, yuvInputFile);
    
            if (read > dataSize) {
                break;
            }
            if (read == 0) {
    
                fseek(yuvInputFile, 0,SEEK_SET);
                NSLog(@"input yuv reset head!");
                if (yuvInputThread) {
                    continue;
                } else {
                    break;
                }
            }
    
            bool push_error = false;
    
            while (true) {
    
                if (![yuvInputThread isExecuting]) {
                    push_error = YES;
                    break;
                }
    
                AliRtcVideoDataSample *dataSample = [[AliRtcVideoDataSample alloc] init];
                dataSample.dataPtr = (long)yuv_read_data;
                dataSample.format = AliRtcVideoFormat_I420;
                dataSample.width = width;
                dataSample.height = height;
                dataSample.strideY = width;
                dataSample.strideU = width/2;
                dataSample.strideV = width/2;
                dataSample.dataLength = dataSample.strideY * dataSample.height * 3/2;
    
                //加判断是否开启输入屏幕共享
                int ret = 0;
                if (yuvShareState != YES) {
                } else {
                    ret = [self.engine pushExternalVideoFrame:dataSample sourceType:AliRtcVideosourceScreenShareType];
                }
    
                if (ret == AliRtcErrAudioBufferFull &&
                    [yuvInputThread isCancelled] == NO) {
    
                } else {
                    if (ret < 0) {
                        push_error = true ;
                    }
                }
    
                //加判断频率, 默认为60hz(30毫秒)
                if (pcmHzFloat > 0) {
                    float hz = 1.0/pcmHzFloat;
                    [NSThread sleepForTimeInterval:hz];   // 指定频率
                } else {
                    [NSThread sleepForTimeInterval:0.03];   // 默认30毫秒 (加延迟操作播放出流畅的画面)
                }
    
                break;
            }
    
            if (push_error) {
                break ;
            }
        }
    
        free(yuv_read_data);
    
        fclose(yuvInputFile);
        yuvInputFile = NULL ;
    }

输入外部音频流

  1. 打开外部音频输入开关。

    接口如下所示。

    /**
     * @brief 设置是否启用外部音频输入源
     * @param enable YES 开启,NO 关闭
     * @param sampleRate 采样率 16k, 48k等
     * @param channelsPerFrame 声道数 1, 2
     * @return 返回>=0表示成功, <0表示失败
     */
    - (int)setExternalAudioSource:(BOOL)enable withSampleRate:(NSUInteger)sampleRate channelsPerFrame:(NSUInteger)channelsPerFrame;
    
    /**
     * @brief 设置是否与麦克风采集音频混合
     * @param mixed YES:混音,NO:完全替换麦克风采集数据
     */
    - (int)setMixedWithMic:(BOOL)mixed;
    说明 目前仅支持PCM数据。

    示例方法如下:

    int ret = [self.engine setExternalAudioSource:YES withSampleRate:pcmSampleRate channelsPerFrame:pcmChannels];
    
    // 完全替代麦克风采集
    [self.engine setMixedWithMic:NO];
  2. 输入音频数据。

    接口方法如下所示。

    /**
     * @brief 输入音频数据
     * @param data 音频数据 不建议超过40ms数据
     * @param samples 采样率
     * @param timestamp 时间戳
     * @return 返回>=0表示成功,<0表示失败
     * @note 如果返回值为errorCode中的AliRtcErrAudioBufferFull,代表当前buffer队列塞满,需要等待后再继续输送数据,,建议等待20ms
     */
    - (int)pushExternalAudioFrameRawData:(void *_Nonnull)data samples:(NSUInteger)samples timestamp:(NSTimeInterval)timestamp;
    说明 如果返回值为errorCode中的AliRtcErrAudioBufferFull,代表当前buffer队列塞满,需要等待后再继续输送数据,建议您等待20ms。

    示例方法如下所示。

    int pcmSampleRate;
    int pcmChannels;
    NSThread * pcmInputThread;
    FILE * pcmInputFile;
    
    - (void)inputPCMRun {
    
        // 40ms
        int readbufSize = (pcmSampleRate/100)*4*sizeof(int16_t)*pcmChannels ;
    
        while (true) {
    
            if ([pcmInputThread isCancelled]) {
                break;
            }
    
            size_t read = fread(pcmData, 1, readbufSize, pcmInputFile) ;
    
            if (read > readbufSize) {
                break;
            }
            if (read == 0) {
                fseek(pcmInputFile, 0, SEEK_SET) ;
                NSLog(@"input pcm reset head!");
                if (pcmInputThread) {
                    continue;
                } else {
                    break;
                }
            }
    
            bool push_error = false;
    
            while (true) {
                if (![pcmInputThread isExecuting]) {
                    push_error = YES;
                    break;
                }
    
                int rc = [self.engine pushExternalAudioFrameRawData:pcmData samples:read timestamp:0];
    
                if ( rc == AliRtcErrAudioBufferFull && [pcmInputThread isCancelled ] == NO ) {
                    [NSThread sleepForTimeInterval:0.08] ;
                } else {
                    if (rc < 0) {
                        push_error = true ;
                    }
    
                    break;
                }
    
            }
    
            if (push_error) {
                break;
            }
        }
    
        fclose(pcmInputFile);
        pcmInputFile = NULL ;
    }