im client iOS端将android端录制的格式为amr的语音转码为wav格式

用到一个开源的库:opencore-amr for ios

https://github.com/feuvan/opencore-amr-iOS

1.下载后运行xcode脚本,

2.脚本运行完成后,看到目录下test里面有例子,即解压和压缩的例子

  我试了下,用amrn-dec.c

+(DDMessageEntity *)makeMessageFromStream:(DDDataInputStream *)bodyData
{
    int32_t seqNo = [bodyData readInt];
    NSString *fromUserId = [bodyData readUTF];
    NSString *toUserId = [bodyData readUTF];
    int32_t msgTime = [bodyData readInt];
    int8_t msgType = [bodyData readChar];
    //int8_t msgRenderType = [bodyData readChar];
    DDMessageEntity *msg = [[DDMessageEntity alloc ] init];
    msg.msgType = msgType;
    msg.msgContentType = msgType;
    NSString* messageContent = nil;
    NSMutableDictionary* info = [[NSMutableDictionary alloc] init];
    if (msgType == DDMessageTypeVoice || msgType == DDGroup_MessageTypeVoice) {
        if (msgType ==DDMessageTypeVoice) {
            msg.msgType = MESSAGE_TYPE_SINGLE;
            msg.msgContentType =DDMessageTypeVoice;
        }else{
            msg.msgType = MESSAGE_TYPE_TEMP_GROUP;
            msg.msgContentType =DDGroup_MessageTypeVoice;
        }
        int32_t dataLength = [bodyData readInt];
        NSData* data = [bodyData readDataWithLength:dataLength];
        NSData* voiceData = [data subdataWithRange:NSMakeRange(4, [data length] - 4)];
        NSString* filename = [NSString stringWithString:[Encapsulator defaultFileName]];
        //....---------------------*********
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *voiceDirectory = [documentsDirectory stringByAppendingPathComponent:@"voice"];
        if ( ! [[NSFileManager defaultManager] fileExistsAtPath:voiceDirectory]) {
            [[NSFileManager defaultManager] createDirectoryAtPath:voiceDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
        }
        NSString* fileAmrName = [voiceDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%.0f.amr", [[NSDate date] timeIntervalSince1970]]];

        NSString* fileWavName = [voiceDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%.0f.wav", [[NSDate date] timeIntervalSince1970]]];

        if ([voiceData writeToFile:fileAmrName atomically:YES])
        {
            int decode = [MKServerHelper amrwbDec:2 sourcefile:fileAmrName AndTargetFile:fileWavName];

            if (decode == 0) {
                NSLog(@"格式转换成功");

            }
        }
        else
        {
            NSLog(@"语音存储出错");
        }

        //....---------------------*********
        if ([voiceData writeToFile:filename atomically:YES])
        {
            messageContent = filename;
        }
        else
        {
            messageContent = @"语音存储出错";
        }
        NSData* voiceLengthData = [data subdataWithRange:NSMakeRange(0, 4)];

        int8_t ch1;
        [voiceLengthData getBytes:&ch1 range:NSMakeRange(0,1)];
        ch1 = ch1 & 0x0ff;

        int8_t ch2;
        [voiceLengthData getBytes:&ch2 range:NSMakeRange(1,1)];
        ch2 = ch2 & 0x0ff;

        int32_t ch3;
        [voiceLengthData getBytes:&ch3 range:NSMakeRange(2,1)];
        ch3 = ch3 & 0x0ff;

        int32_t ch4;
        [voiceLengthData getBytes:&ch4 range:NSMakeRange(3,1)];
        ch4 = ch4 & 0x0ff;

        if ((ch1 | ch2 | ch3 | ch4) < 0){
            @throw [NSException exceptionWithName:@"Exception" reason:@"EOFException" userInfo:nil];
        }
        int voiceLength = ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
        [info setObject:@(voiceLength) forKey:VOICE_LENGTH];
        [info setObject:@(0) forKey:DDVOICE_PLAYED];
    }else
    {
        messageContent = (NSString *)[bodyData readUTF];
        if ([messageContent hasPrefix:DD_MESSAGE_IMAGE_PREFIX])
        {
            msg.msgContentType = DDMessageTypeImage;
        }
    }
    NSString *attach = [bodyData readUTF];
    msg.msgID = [DDMessageModule getMessageID];
    msg.seqNo = seqNo;
    msg.msgTime = msgTime;
    msg.toUserID=toUserId;
    msg.msgContent = [msg getNewMessageContentFromContent:messageContent];
    msg.attach = attach;
    if([msg isGroupMessage])
    {
        msg.sessionId = toUserId;       //群聊时,toUserId表示会话ID
        msg.senderId = fromUserId;      //群聊时,fromUserId表示发送者I
    }
    else
    {
        msg.sessionId = fromUserId; //单人时,fromUserId表示发送者ID,作为会话id
        msg.senderId = fromUserId;  //单人时,fromUserId表示发送者ID

    }
    if ([msg.sessionId isEqualToString:TheRuntime.userID]) {
        msg.sessionId = toUserId;
    }
      msg.info=info;
    return msg;
}

Helper:

+(int )amrwbDec :(int ) argc sourcefile:(NSString*)sourceFile AndTargetFile:(NSString*) targetFile
{
//    char *argv[10];

    const int sizes[] = { 12, 13, 15, 17, 19, 20, 26, 31, 5, 6, 5, 5, 0, 0, 0, 0 };

    FILE* in;
    char header[6];
    int n;
    void *wav, *amr;

    in = fopen([sourceFile UTF8String] , "rb");
    if (!in) {
        perror([sourceFile UTF8String]);
        return 1;
    }
    n = fread(header, 1, 6, in);
    if (n != 6 || memcmp(header, "#!AMR\n", 6)) {
        fprintf(stderr, "Bad header\n");
        return 1;
    }

    wav = wav_write_open([targetFile UTF8String], 8000, 16, 1);
    if (!wav) {
        fprintf(stderr, "Unable to open %s\n", [targetFile UTF8String]);
        return 1;
    }

    amr = Decoder_Interface_init();
    while (1) {
        uint8_t buffer[500], littleendian[320], *ptr;
        int size, i;
        int16_t outbuffer[160];
        /* Read the mode byte */
        n = fread(buffer, 1, 1, in);
        if (n <= 0)
            break;
        /* Find the packet size */
        size = sizes[(buffer[0] >> 3) & 0x0f];
        n = fread(buffer + 1, 1, size, in);
        if (n != size)
            break;

        /* Decode the packet */
        Decoder_Interface_Decode(amr, buffer, outbuffer, 0);

        /* Convert to little endian and write to wav */
        ptr = littleendian;
        for (i = 0; i < 160; i++) {
            *ptr++ = (outbuffer[i] >> 0) & 0xff;
            *ptr++ = (outbuffer[i] >> 8) & 0xff;
        }
        wav_write_data(wav, littleendian, 320);
    }
    fclose(in);
    Decoder_Interface_exit(amr);
    wav_write_close(wav);
    return 0;
}

生成的.wav文件用itools打开该应用,到voice目录下就可以找到,

时间: 2024-11-07 10:24:45

im client iOS端将android端录制的格式为amr的语音转码为wav格式的相关文章

Ionic3学习笔记(八)使iOS端、Android端 Navbar 透明化

本文为原创文章,转载请标明出处 若要使iOS端 Navbar 透明,只需要给 ion-navbar 添加 transparent 属性,但是Android端依旧会有一条border在,所以再给 ion-header 添加 no-border 属性 <ion-header no-border> <ion-navbar transparent> </ion-navbar> </ion-header> 如有不当之处,请予指正,谢谢-

Android端与Android端利用WIFI进行FTP通信

一.客户端通信工具类: import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.SocketException; import org.apache.commons.net.ftp.FTP; import org.apache.commo

安天移动安全联合猎豹移动首次揭露“Operation Manul”疑似在Android端的间谍软件行为

前言 去年8月份,美国黑帽大会曾公开发表了一篇报告,揭露了名为"Operation Manul"的组织针对该国相关人士进行的大面积网络攻击和窃听行为,并分析了其在PC端使用的窃听技术及域名. 通过对报告中披露的多个用做指令控制和文件上传的C2 Server域名进行内部检索对比,安天移动安全联合猎豹移动发现了一批相关恶意样本,分析发现该间谍软件通过伪装成海外知名应用潜入目标用户手机,在获取权限后会展开一系列窃听行为:私自拍照.录音,并窃取用户短信.通讯录.地理位置等隐私信息,而后将相关数

windows 代理服务器的搭建,提供Android 端访问外网.

这段时间遇到一个情况,移动的网络收费.但是可以访问学校内部的网络,比如说学校官网图书馆之类了.所以我这里便想到一个方法,用学校内部一个可以访问互联网的主机充当代理服务器(我这里使用自己的电脑,非服务器). 一,需要的软件: PC端,CCProxy Android端,proxydroid  如果想设置全局代理 (global proxy ) 手机需要  root   该软件的源码地址  :https://github.com/madeye/proxydroid 二,搭建必要条件: 充当服务器的PC

flutter android端 原理解析

首先看MainActivity, 继承FlutterActivity 再看FlutterActivity代码,继承Activity,实现Provider.PluginRegistry.ViewFactory 12345678910111213141516 private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);private final FlutterActivityEven

关于Web端即JS端编程

主要的技术是 HTML/JS/CSS/XML Web就是JS/DOM编程. 页面的数据来源: XML, JSON, HTML, Text, 第三方页面或者数据. 不一定都要跟服务器进行交互. JS端 vs Android端 vs IOS端 JS端可以从任何服务器Request数据. JS Request----------->Server1, Server2, Server3获取数据. Android Request------->Server1, Server2, Server3 IOS R

JS判断客户端是否是iOS或者Android端

通过判断浏览器的userAgent,用正则来判断手机是否是 IOS 和 Android 客户端. 代码如下: (function(){ var u = navigator.userAgent; var isAndroid =u.indexOf("Android") > -1 || u.indexOf("Adr") > -1; //Android终端 var isIOS =!!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)

支持视频流识别的移动端(Android、iOS)车牌识别

文章摘要:移动端(Android.iOS)车牌识别只需手机或pad扫一扫,即可快速识别车牌号码:支持超大角度识别车牌号:支持Android.iOS平台.手机ARM平台和PDA的X86架构:支持蓝牌.黄牌.挂车号牌.新军牌.警牌.新武警车牌.教练车牌.大使馆车牌.农用车牌.个性化车牌.港澳出入境车牌.澳台车牌.民航车牌.领馆车牌.新能源车牌等最全车牌,支持视频流识别和拍照识别两种识别模式...... 移动端(Android.iOS)车牌识别应用背景 随着汽车的爆炸式增长,停车位越来越紧缺,好多车主

用.Net打造一个移动客户端(Android/IOS)的服务端框架NHM——Android端消息处理机制

NhmFramework Android端的消息处理机制原理 1.概要表述:在我们的框架中,Android客户端通过继承Application来控制整个应用程序的生命周期,在Application onCreate()方法中,我们将启动一个MainService,这个Service将负责Activity的异步消息处理(包括异步Http请求).任务调度.数据共享等大部分持久化操作.那么这样做的目的何在呢? 1)异步消息处理:在Service中实现异步消息处理是为了将Activity的界面显示的操作