RTMP直播推流(二)音频推流

音频推流java层代码:

package com.example.push.channel;

import static android.media.AudioFormat.CHANNEL_IN_STEREO;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;

import com.example.push.LivePusher;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class AudioChannel {

    private  int inputSamples;
    private  ExecutorService executor;
    private  AudioRecord audioRecord;
    private LivePusher mLivePusher;
    private int channels=2;
    private boolean isLiving;

    public AudioChannel(LivePusher livePusher){
        mLivePusher=livePusher;
        //启动一个线程 线程池
         executor = Executors.newSingleThreadExecutor();
        //准备录音机 来采集pcm数据 传送到native层
        int channelConfig;
        if (channels==2){
           channelConfig= AudioFormat.CHANNEL_IN_STEREO;
        }else {
            channelConfig= AudioFormat.CHANNEL_IN_MONO;
        }

        mLivePusher.native_setAudioEncInfo( 44100, channels) ;
        //16位 两个字节
         inputSamples= mLivePusher.getInputSamples()*2;

        //最小需要的缓冲区
        int minBufferSize= AudioRecord.getMinBufferSize( 44100,channelConfig,AudioFormat.ENCODING_PCM_16BIT )*2;
        //1、麦克风 2、采样率 3、声道数
        audioRecord=new AudioRecord( MediaRecorder.AudioSource.MIC,44100,channelConfig,AudioFormat.ENCODING_PCM_16BIT ,minBufferSize>inputSamples?minBufferSize:inputSamples);
    }

    public void startLive() {
        isLiving=true;
        executor.submit( new AudioTeask() );
    }
    public void stopLive() {
        isLiving=false;
    }

    public void release(){
       audioRecord.release();
    }

    class AudioTeask implements Runnable{

        @Override
        public void run() {
           //启动录音机
            audioRecord.startRecording();
            byte[] bytes=new byte[inputSamples];
            while (isLiving){
                int len=audioRecord.read( bytes,0,bytes.length);
               if (len>0){
                   //送去编码
                   mLivePusher.native_pushAudio( bytes );
               }
            }
            //停止录音机
            audioRecord.stop();
        }
    }
}

和直播推流类似:

extern "C"
JNIEXPORT void JNICALL
Java_com_example_push_LivePusher_native_1setAudioEncInfo(JNIEnv *env, jobject instance, jint sampleRateInHz,
                                                           jint channels) {
    // TODO: implement native_setAudioEncInfo()
    if (audioChannel){
        audioChannel->setAudioEncInfo(sampleRateInHz,channels);
    }
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_push_LivePusher_getInputSamples(JNIEnv *env, jobject instance) {
    if (audioChannel){
        return audioChannel->getInputSamples();
    }
    return -1;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_push_LivePusher_native_1pushAudio(JNIEnv *env, jobject instance, jbyteArray data_) {


    if (!audioChannel || !readyPushing) {
        return;
    }
    jbyte *data = env->GetByteArrayElements(data_, NULL);
    audioChannel->encodeData(data);
    env->ReleaseByteArrayElements(data_, data, 0);

}

faac初始化

void AudioChannel::setAudioEncInfo(int samplesInHZ, int channels) {
    //打开编码器
    mChannels=channels;

    //3、一次最大能输入编码器的样本数量 要编码的数据个数
    //4、最大可能的输出数据  编码后的最大字节数
     audioCodec=faacEncOpen(samplesInHZ,channels,&inputSamples,&maxOutputBytes);

     //设置编码器参数
     faacEncConfigurationPtr config= faacEncGetCurrentConfiguration(audioCodec);
     //指定为 mpeg4标准
     config->mpegVersion=MPEG4;
     //lc标准
     config->aacObjectType=LOW;
     //16位
     config->inputFormat=FAAC_INPUT_16BIT;
     //编码出原始数据 既不是adts也不是adif
     config->outputFormat=0;
    faacEncSetConfiguration(audioCodec,config);

    //输出缓冲区 编码后的数据 用这个缓冲区来保存
    buffer=new u_char[maxOutputBytes];
}

发送faac编码的音频头

RTMPPacket *AudioChannel::getAudioTag() {
    u_char *buf;
    u_long len;
    faacEncGetDecoderSpecificInfo(audioCodec, &buf, &len);
    int bodySize = 2 + len;
    RTMPPacket *packet = new RTMPPacket;
    RTMPPacket_Alloc(packet, bodySize);
    //双声道
    packet->m_body[0] = 0xAF;
    if (mChannels == 1) {
        packet->m_body[0] = 0xAE;
    }
    packet->m_body[1] = 0x00;
    //图片数据
    memcpy(&packet->m_body[2], buf, len);

    packet->m_hasAbsTimestamp = 0;
    packet->m_nBodySize = bodySize;
    packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
    packet->m_nChannel = 0x11;
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
    return packet;
}

发送音频数据

void AudioChannel::encodeData(int8_t *data) {
    //音频编码  返回编码后数据字节的长度
    int bytelen=faacEncEncode(audioCodec, reinterpret_cast<int32_t *>(data), inputSamples, buffer, maxOutputBytes);
    if (bytelen > 0) {
        //看表
        int bodySize = 2 + bytelen;
        RTMPPacket *packet = new RTMPPacket;
        RTMPPacket_Alloc(packet, bodySize);
        //双声道
        packet->m_body[0] = 0xAF;
        if (mChannels == 1) {
            packet->m_body[0] = 0xAE;
        }
        //编码出的声音 都是 0x01
        packet->m_body[1] = 0x01;
        //图片数据
        memcpy(&packet->m_body[2], buffer, bytelen);

        packet->m_hasAbsTimestamp = 0;
        packet->m_nBodySize = bodySize;
        packet->m_packetType = RTMP_PACKET_TYPE_AUDIO;
        packet->m_nChannel = 0x11;
        packet->m_headerType = RTMP_PACKET_SIZE_LARGE;
        audioCallback(packet);
    }

效果图:

 链接:https://pan.baidu.com/s/1T6wqTbJweKEeanTz9gR1ow 
提取码:9jgr 
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RTMP(Real-Time Messaging Protocol)是一种流媒体协议,用于在互联网上实时传输音频、视频和数据。RTMP支持点播和直播两种模式,其中直播模式常用于视频直播和游戏直播等场景中。下面是RTMP直播推流的详细介绍: 1. 准备推流工具 推流工具可以将视频、音频等流媒体数据推送到RTMP服务器,常用的推流工具有 OBS、XSplit、FFmpeg 等。其中,OBS(Open Broadcaster Software)是一个开源的推流工具,易于使用且功能强大。 2. 获取RTMP推流地址 在推流之前,需要先获取RTMP服务器的推流地址,一般由直播平台提供。例如,在B站直播中,可以在直播间设置中获取推流地址。 3. 配置推流工具 将获取的RTMP推流地址填入推流工具的设置中,同时根据需要设置视频、音频等参数。例如,在OBS中,可以配置视频分辨率、视频码率、音频码率等参数。 4. 开始推流推流工具配置完成后,点击开始推流按钮,即可将流媒体数据推送到RTMP服务器。在推流过程中,可以通过推流工具的界面监控推流状态和推流质量等信息。 5. 直播播放 推流完成后,直播平台即可将推流的视频、音频等流媒体数据转发给观众,观众即可通过直播平台观看直播。在直播过程中,可以通过直播平台的管理后台监控直播状态和观众数据等信息。 需要注意的是,在推流过程中,需要保证网络稳定和带宽充足,否则会影响推流质量和观看体验。另外,推流过程中也需要注意保护个人隐私和知识产权等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值