me icon indicating copy to clipboard operation
me copied to clipboard

Swift & C (Part 1: RTMP Routine)

Open nonocast opened this issue 2 years ago • 0 comments

hello world

先起一个linux c的项目, foo.c

int biubiubiu() { return 666; }

Makefile

libfoo.a: foo.o
	libtool -static -o $@ $^

foo.o: foo.c
	clang -c -arch arm64 -arch x86_64 -o $@ $<

然后Xcode新建一个SwiftUI或Swift CommandLine都行,打开后在Target/General/Frameworks and Libraries中添加libfoo.a, 几点说明:

  • 在Target中添加等同于通过finder将libfoo.a拖动到左侧项目project navigator,这种方式添加的都是引用,如果删除的时候选择move to trash就会将引用的外部文件删掉
  • 根据需要选择是否将lib文件复制到项目中,比如要上传到git,那么就需要将libfoo.a放在项目中push到repo,如果另外一边libfoo.a需要同步开发,则ref到linux c的项目更好,同步更新
  • libfoo.a是静态库,ld在link时需要找到library,link后不需要library,因为已经嵌入到app中

第二步,在项目中添加一个C File, 此时Xcode会提示你添加一个Bridge文件,选同意,同意后保留Bridge删除刚才的C文件。Bridge就是用来告诉swiftc libfoo.a的definitions,所以可以选择3种方式:

  • 去tm的header,直接在bridge中定义int biubiubiu();
  • 在linux c项目中写一个make install将header复制到/usr/local/include, 然后在bridge中#include <foo/foo.h>
  • 将foo.h复制到项目中,然后在bridge中#include "foo.h"

最后,在swift中可以直接调用:

app.swift

func main() {
  print(biubiubiu()) // 666
}

main()

RTMP_LibVersion

  • 编译librtmp.a (gcc -arch arm64 -arch x86_64), make install
  • 为了共享给团队小伙伴,复制librtmp.a和header到项目中
  • 添加bridge, 在bridge中include librtmp header

func main() {
  let version = RTMP_LibVersion();
  let versionString = String(format:"0x%08x", version); // RTMP_LibVersion: 0x00020300
  print("RTMP_LibVersion: \(versionString)");
  RTMP_LogSetLevel(RTMP_LOGALL)
}

main()

RTMP main routine

import Foundation

func main() {
  RTMP_LogSetLevel(RTMP_LOGDEBUG)
  
  // Show librtmp version
  let version = RTMP_LibVersion();
  let versionString = String(format:"0x%08x", version); // RTMP_LibVersion: 0x00020300
  print("RTMP_LibVersion: \(versionString)");
  
  // C: RTMP rtmp
  var rtmp = RTMP()
  RTMP_Init(&rtmp)
  
  
  // C: char *url = "rtmp://shgbit.xyz/app/1"
  // C: RTMP_SetupURL(&rtmp, url)
  // RTMP_SetupURL(UnsafeMutablePointer<RTMP>! , _ url: UnsafeMutalbePointer<CChar>!)
  let url = "rtmp://shgbit.xyz/app/1"
  _ = url.withCString { ptr in
    RTMP_SetupURL(&rtmp, UnsafeMutablePointer<CChar>(mutating: ptr))
  }
  
  // C: RTMP_EnableWrite(&rtmp)
  RTMP_EnableWrite(&rtmp)
  
  // C: RTMP_Connect(&rtmp, NULL)
  RTMP_Connect(&rtmp, nil)
  
  // C: RTMP_ConnectStream(&rtmp, NULL)
  RTMP_ConnectStream(&rtmp, 0)
  
  
  // C: RTMP_Close(&rtmp)
  RTMP_Close(&rtmp)
}

main()

运行后输出:

RTMP_LibVersion: 0x00020300
DEBUG: Parsing...
DEBUG: Parsed protocol: 0
DEBUG: Parsed host    : shgbit.xyz
DEBUG: Parsed app     : app
DEBUG: RTMP_Connect1, ... connected, handshaking
DEBUG: HandShake: Type Answer   : 03
DEBUG: HandShake: Server Uptime : 1653333607
DEBUG: HandShake: FMS Version   : -14.92.-63.-82
DEBUG: RTMP_Connect1, handshaked
DEBUG: Invoking connect
DEBUG: HandleServerBW: server BW = 2500000
DEBUG: HandleClientBW: client BW = 2500000 2
DEBUG: HandleChangeChunkSize, received: chunk size change to 60000
DEBUG: RTMP_ClientPacket, received: invoke 510 bytes
DEBUG: (object begin)
DEBUG: (object begin)
DEBUG: Property: <Name:             fmsVer, STRING:	FMS/3,5,3,888>
DEBUG: Property: <Name:       capabilities, NUMBER:	127.00>
DEBUG: Property: <Name:               mode, NUMBER:	1.00>
DEBUG: (object end)
DEBUG: (object begin)
DEBUG: Property: <Name:              level, STRING:	status>
DEBUG: Property: <Name:               code, STRING:	NetConnection.Connect.Success>
DEBUG: Property: <Name:        description, STRING:	Connection succeeded>
DEBUG: Property: <Name:     objectEncoding, NUMBER:	0.00>
DEBUG: Property: <Name:               data, ECMA_ARRAY>
DEBUG: (object begin)
DEBUG: Property: <Name:            version, STRING:	3,5,3,888>
DEBUG: Property: <Name:            srs_sig, STRING:	SRS>
DEBUG: Property: <Name:         srs_server, STRING:	SRS/4.0.251(Leo)>
DEBUG: Property: <Name:        srs_license, STRING:	MIT>
DEBUG: Property: <Name:            srs_url, STRING:	https://github.com/ossrs/srs>
DEBUG: Property: <Name:        srs_version, STRING:	4.0.251>
DEBUG: Property: <Name:        srs_authors, STRING:	https://github.com/ossrs/srs/blob/4.0release/trunk/AUTHORS.txt>
DEBUG: Property: <Name:      srs_server_ip, STRING:	172.18.0.2>
DEBUG: Property: <Name:            srs_pid, NUMBER:	1.00>
DEBUG: Property: <Name:             srs_id, STRING:	c9615dg9>
DEBUG: (object end)
DEBUG: (object end)
DEBUG: (object end)
DEBUG: HandleInvoke, server invoking <_result>
DEBUG: HandleInvoke, received result for method call <connect>
DEBUG: Invoking releaseStream
DEBUG: Invoking FCPublish
DEBUG: Invoking createStream
DEBUG: RTMP_ClientPacket, received: invoke 21 bytes
DEBUG: (object begin)
DEBUG: Property: NULL
DEBUG: (object end)
DEBUG: HandleInvoke, server invoking <onBWDone>
DEBUG: Invoking _checkbw
DEBUG: RTMP_ClientPacket, received: invoke 21 bytes
DEBUG: (object begin)
DEBUG: Property: NULL
DEBUG: Property: NULL
DEBUG: (object end)
DEBUG: HandleInvoke, server invoking <_result>
DEBUG: HandleInvoke, received result id 2.000000 without matching request
DEBUG: RTMP_ClientPacket, received: invoke 21 bytes
DEBUG: (object begin)
DEBUG: Property: NULL
DEBUG: Property: NULL
DEBUG: (object end)
DEBUG: HandleInvoke, server invoking <_result>
DEBUG: HandleInvoke, received result id 3.000000 without matching request
DEBUG: RTMP_ClientPacket, received: invoke 29 bytes
DEBUG: (object begin)
DEBUG: Property: NULL
DEBUG: (object end)
DEBUG: HandleInvoke, server invoking <_result>
DEBUG: HandleInvoke, received result for method call <createStream>
DEBUG: Invoking publish
DEBUG: RTMP_ClientPacket, received: invoke 102 bytes
DEBUG: (object begin)
DEBUG: Property: NULL
DEBUG: (object begin)
DEBUG: Property: <Name:               code, STRING:	NetStream.Publish.Start>
DEBUG: Property: <Name:        description, STRING:	Started publishing stream.>
DEBUG: (object end)
DEBUG: (object end)
DEBUG: HandleInvoke, server invoking <onFCPublish>
DEBUG: RTMP_ClientPacket, received: invoke 136 bytes
DEBUG: (object begin)
DEBUG: Property: NULL
DEBUG: (object begin)
DEBUG: Property: <Name:              level, STRING:	status>
DEBUG: Property: <Name:               code, STRING:	NetStream.Publish.Start>
DEBUG: Property: <Name:        description, STRING:	Started publishing stream.>
DEBUG: Property: <Name:           clientid, STRING:	ASAICiss>
DEBUG: (object end)
DEBUG: (object end)
DEBUG: HandleInvoke, server invoking <onStatus>
DEBUG: HandleInvoke, onStatus: NetStream.Publish.Start
DEBUG: Invoking FCUnpublish
DEBUG: Invoking deleteStream

AMF

func amf() {
  var data: Array<CChar> = Array(repeating: 0x00, count: 256)
  let _ = data.withUnsafeMutableBufferPointer { ptr in
    var enc: UnsafeMutablePointer<CChar>
    let end = ptr.baseAddress?.advanced(by: ptr.count)
    enc = AMF_EncodeBoolean(ptr.baseAddress, end, 1)
    enc = AMF_EncodeInt32(enc, end, 7)
    
    "nonocast".withCString { cstr in
      var val = AVal(av_val: UnsafeMutablePointer<CChar>(mutating: cstr), av_len: Int32(strlen(cstr)))
      enc = AMF_EncodeString(enc, end, &val)
    }
    
    let offset = enc - ptr.baseAddress!
    RTMP_LogHexString(Int32(RTMP_LOGDEBUG.rawValue), ptr.baseAddress, UInt(offset))
  }
}

输出结果如下:

DEBUG:   0000:  01 01 00 00 00 07 02 00  08 6e 6f 6e 6f 63 61 73   .........nonocas  
DEBUG:   0010:  74 

参考阅读

nonocast avatar May 22 '22 23:05 nonocast