音频推流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{@Overridepublic 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也不是adifconfig->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;}//编码出的声音 都是 0x01packet->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

RTMP直播推流(二)音频推流相关推荐

  1. NDK RTMP直播客户端二

    在之前完成的实战项目[FFmpeg音视频播放器]属于拉流范畴,接下来将完成推流工作,通过RTMP实现推流,即直播客户端.简单的说,就是将手机采集的音频数据和视频数据,推到服务器端. 接下来的RTMP直 ...

  2. 用安卓RTMP直播推流进行音频侦听时,出现播放几秒后就无法播放问题的解决方法

    Real Time Messaging Protocol(RTMP)即实时消息传输协议,是 Adobe 公司开发的一个基于 TCP 的应用层协议,目前国内的视频云服务都是以 RTMP 为主要推流协议. ...

  3. Android流媒体开发之路二:NDK C++开发Android端RTMP直播推流程序

    经过一番折腾,成功把RTMP直播推流代码,通过NDK交叉编译的方式,移植到了Android下,从而实现了Android端采集摄像头和麦克缝数据,然后进行h264视频编码和aac音频编码,并发送到RTM ...

  4. 【Android RTMP】RTMP 直播推流阶段总结 ( 服务器端搭建 | Android 手机端编码推流 | 电脑端观看直播 | 服务器状态查看 )

    文章目录 安卓直播推流专栏博客总结 一. 服务器搭建 二. 手机端推流 三. 电脑端观看直播 四. RTMP 服务器端状态 安卓直播推流专栏博客总结 Android RTMP 直播推流技术专栏 : 0 ...

  5. 【Android RTMP】RTMP 直播推流服务器搭建 ( Ubuntu 18.04.4 虚拟机 )

    文章目录 安卓直播推流专栏博客总结 一. Android RTMP 直播推流简介 二. Nginx.RTMP Module 编译环境源码准备 三. pcre.OpenSSL.zlib 函数库安装 四. ...

  6. 【Android RTMP】RTMP 直播推流 ( 阿里云服务器购买 | 远程服务器控制 | 搭建 RTMP 服务器 | 服务器配置 | 推流软件配置 | 直播软件配置 | 推流直播效果展示 )

    文章目录 安卓直播推流专栏博客总结 一. 阿里云服务器购买 二. 远程服务器控制软件 三. 配置 Ubuntu 服务器 1 . 更新 apt 源 2 . 安装 pcre.OpenSSL.zlib 库 ...

  7. 利用FFmpeg实现录屏、直播推流、音频视频格式转换、剪裁等功能

    一.FFmpeg简介. 二.FFmpeg常用参数及命令. 三.FFmpeg在Unity 3D中的使用. 1.FFmpeg 录屏. 2.FFmpeg 推流. 3.FFmpeg 其他功能简述. 一.FFm ...

  8. php七牛云rtmp直播推流,GitHub - jangocheng/FlutterQiniucloudLivePlugin: Flutter 七牛云直播云 推流/播放 SDK集成...

    flutter_qiniucloud_live_plugin Flutter 七牛云直播云插件,支持IOS.Android客户端 Getting Started 集成七牛云直播云推流.观看等功能 功能 ...

  9. windows下ffmpeg+nginx-rtmp环境搭建及opencv+ffmpeg+python实现拉流和rtmp直播推流

    由于工作需要最近在研究rtsp拉流与直播推流的问题,目前先在我本机上进行了实验,本博客记录学习的内容,包含windows下ffmpeg.nginx-rtmp环境搭建及opencv+ffmpeg+pyt ...

最新文章

  1. 云时代服务器端工程师必备 CDN 技能包
  2. mysql8允许外网访问(转载+整理)
  3. nginx之worker进程个数
  4. Highcharts 显示图表
  5. Python实战从入门到精通第五讲——数据结构与算法3之序列中出现最多的元素
  6. 读书笔记--疯狂Android讲义 目录
  7. 修改了一个YUV/RGB播放器
  8. DeepFake技术--DeepFake克星来了,简单两步算法造假图像无处可逃
  9. 车载高精度GNSS定位天线
  10. 几款Android 应用自动化测试工具
  11. Ubuntu系统通用快捷键
  12. Mac Windows fliqlo 时钟屏保
  13. 反汇编工具ollydbg ida
  14. Promise then的嵌套
  15. GitHub 的 Pull Request 是指什么意思
  16. 网站建设SEO推广说明
  17. 5 款最棒的 Vue 移动端 UI 组件库 - 特别针对国内使用场景推荐
  18. Python中常用最神秘的函数! lambda 函数深度总结!
  19. Error Code: 1318. Incorrect number of arguments for PROCEDURE student.new_procedure; expected 0, got
  20. 海南省教育厅关于普通高中综合实践活动课程实施的指导意见

热门文章

  1. 干货 | 关于SwiftUI,看这一篇就够了
  2. 微信小程序实现手机屏幕左右旋转,页面元素左右移动,小程序加速计
  3. 徒留标点暧昧不明的微笑-转自www.97w.com
  4. centos7 lvm分区扩容(空间转移,将/home转至/根分区)
  5. 我的世界刷猪人塔java版_我的世界速攻猪人塔详解 史上最牛的经验塔
  6. @Required用法
  7. CDN: trunk URL couldn‘t be downloaded的解决办法
  8. mac外接显示器wifi无法正常使用的问题
  9. Pandas合并之Merge合并
  10. DataFrame上下或左右合并 pd.concat