iOS語音對(duì)講(二)RTSP+RTP協(xié)議實(shí)時(shí)傳輸

本文介紹iOS實(shí)時(shí)語音雙向?qū)χv(語音通話)功能:
(一)實(shí)時(shí)采集PCM并編碼AAC
(二)RTSP+RTP協(xié)議實(shí)時(shí)傳輸
(三)FFmpeg實(shí)時(shí)解碼AAC并播放PCM

第二篇介紹使用基于CocoaAsyncSocket的第三方開源庫GCDAsyncSocket進(jìn)行RTSP協(xié)議的Socket網(wǎng)絡(luò)通訊。
GitHub下載地址:https://github.com/robbiehanson/CocoaAsyncSocket


具體過程如下:
創(chuàng)建socket并建立一個(gè)連接

- (int)connectServer:(NSString *)hostIP port:(int)hostPort {
    if (_socket == nil) {
        _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        NSError *err = nil;
        int t = [_socket connectToHost:hostIP onPort:hostPort error:&err];
        if (!t) {
            return 0;
        }else{
            return 1;
        }
    }else {
        [_socket readDataWithTimeout:-1 tag:0];
        return 1;
    }
}

GCDAsyncSocketDelegate代理方法

//連接成功
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    BOOL state = [self.socket isConnected];
    if (state) {
        [self sendCmd];
    }
}
//斷開連接
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
    BOOL state = [_socket isConnected];
    NSLog(@"disconnect,state=%d",state);
    self.socket = nil;
}

發(fā)送RTSP命令

- (void)sendCmd
{
    [self doSetup:self.url];
}

- (void)doSetup:(NSString *)url {
    NSMutableString *dataString = [NSMutableString string];
    [dataString appendString:[NSString stringWithFormat:@"SETUP %@ RTSP/1.0\r\n", url]];
    [dataString appendString:@"Content-Length: 0\r\n"];
    [dataString appendFormat:@"CSeq: 0\r\n"];
    [dataString appendString:@"Transport: RTP/AVP/DHTP;unicast\r\n"];
    [dataString appendString:@"\r\n"];
    NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
    [self.socket writeData:data withTimeout:-1 tag:0];
    [self.socket readDataWithTimeout:-1 tag:0];
}

- (void)doPlay:(NSString *)url {
    NSMutableString *dataString = [NSMutableString string];
    [dataString appendString:[NSString stringWithFormat:@"PLAY %@ RTSP/1.0\r\n", url]];
    [dataString appendString:@"Content-Length: 0\r\n"];
    [dataString appendFormat:@"CSeq: 1\r\n"];
    [dataString appendString:@"\r\n"];
    NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
    [self.socket writeData:data withTimeout:-1 tag:1];
    [self.socket readDataWithTimeout:-1 tag:1];
}

- (void)doTeardown:(NSString *)url {
    NSMutableString *dataString = [NSMutableString string];
    [dataString appendString:[NSString stringWithFormat:@"TEARDOWN %@ RTSP/1.0\r\n", url]];
    [dataString appendString:@"Content-Length: 0\r\n"];
    [dataString appendString:@"CSeq: 2\r\n"];
    [dataString appendString:@"\r\n"];
    NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
    [self.socket writeData:data withTimeout:-1 tag:2];
}

讀取數(shù)據(jù)

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    switch (tag) {
        case 0:
            [self doPlay:self.url];
            break;
        case 1:
            [self startCapture];
            break;
        case 200:
            if (!dataString) {
                [self getPayload:data];
            }
            break;
        default:
            break;
    }
    [sock readDataWithTimeout:-1 tag:200];
}
PS:標(biāo)準(zhǔn)的RTSP協(xié)議DESCRIBE、OPTIONS、SETUP、PLAY、TEARDOWN等方法一般都需要發(fā)送,作者這里為非標(biāo)準(zhǔn)RTSP,只需發(fā)送SETUP、PLAY、TEARDOWN。可參考RTSP百科:RTSP

其中readDataWithTimeout表示需要讀取發(fā)送后返回的數(shù)據(jù),-1表示不會(huì)使用超時(shí)。

以上,則實(shí)現(xiàn)了RTSP的通訊,可將編碼后的AAC以RTP的形式進(jìn)行傳輸,且可以一邊發(fā)送一邊讀取。


Demo地址:https://github.com/XuningZhai/TalkDemo
支持G711的Demo地址:https://github.com/XuningZhai/TalkDemo_G711_AAC

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容