diff --git a/Classes/RTMPStream.h b/Classes/RTMPStream.h index 0f40f74..edf5147 100644 --- a/Classes/RTMPStream.h +++ b/Classes/RTMPStream.h @@ -13,7 +13,7 @@ TCPSocket *socket; NSFileHandle *connection; NSMutableData *buffer; + NSURL *streamURL; } -- (void)connectToServer:(NSString *)server onPort:(unsigned short)port; -- (void)requestStream:(NSString *)file; +@property (nonatomic, copy) NSURL *streamURL; @end diff --git a/Classes/RTMPStream.m b/Classes/RTMPStream.m index a2aec5c..17a3aec 100644 --- a/Classes/RTMPStream.m +++ b/Classes/RTMPStream.m @@ -8,11 +8,29 @@ #import "RTMPStream.h" #import "NSData-BytePacking.h" - +const unsigned short RTMP_DEFAULT_PORT = 1935; /*Constants sourced from VLC's rtmp_amf_flv.c*/ const unsigned char RTMP_HANDSHAKE = 0x03; const unsigned short RTMP_HANDSHAKE_BODY_SIZE = 1536; +/* content types */ +const unsigned char RTMP_CONTENT_TYPE_CHUNK_SIZE = 0x01; +const unsigned char RTMP_CONTENT_TYPE_UNKNOWN_02 = 0x02; +const unsigned char RTMP_CONTENT_TYPE_BYTES_READ = 0x03; +const unsigned char RTMP_CONTENT_TYPE_PING = 0x04; +const unsigned char RTMP_CONTENT_TYPE_SERVER_BW = 0x05; +const unsigned char RTMP_CONTENT_TYPE_CLIENT_BW = 0x06; +const unsigned char RTMP_CONTENT_TYPE_UNKNOWN_07 = 0x07; +const unsigned char RTMP_CONTENT_TYPE_AUDIO_DATA = 0x08; +const unsigned char RTMP_CONTENT_TYPE_VIDEO_DATA = 0x09; +const unsigned char RTMP_CONTENT_TYPE_UNKNOWN_0A_0E = 0x0A; +const unsigned char RTMP_CONTENT_TYPE_FLEX_STREAM = 0x0F; +const unsigned char RTMP_CONTENT_TYPE_FLEX_SHARED_OBJECT = 0x10; +const unsigned char RTMP_CONTENT_TYPE_MESSAGE = 0x11; +const unsigned char RTMP_CONTENT_TYPE_NOTIFY = 0x12; +const unsigned char RTMP_CONTENT_TYPE_SHARED_OBJECT = 0x13; +const unsigned char RTMP_CONTENT_TYPE_INVOKE = 0x14; + const unsigned char AMF_BOOLEAN_FALSE = 0x00; const unsigned char AMF_BOOLEAN_TRUE = 0x01; @@ -58,19 +76,41 @@ /*Private calls not visible to the fellow classes*/ @interface RTMPStream (Private) +- (void)connectToServer:(NSString *)server onPort:(unsigned short)port; + - (void)sendHandshake; - (void)disconnect; - (void)sendConnectRequest; - (void)waitForHandshakeResponse; +- (void)sendPacket:(NSData *)packet type:(unsigned char)type; +- (NSData *)encodePacket:(NSData *)packet type:(unsigned char)type; + - (NSData *)encodeAMFString:(NSString *)str; - (NSData *)encodeAMFNumber:(unsigned long long)number; - (NSData *)encodeAMFBoolean:(BOOL)value; - (NSData *)encodeAMFObject:(NSData *)object; +- (NSData *)encodeAMFEndObject; + - (NSData *)encodeAMFStringVariable:(NSString *)value key:(NSString *)key; +- (NSData *)encodeAMFNumberVariable:(unsigned long long)value key:(NSString *)key; - (NSData *)encodeAMFBooleanVariable:(BOOL)value key:(NSString *)key; @end @implementation RTMPStream +- (NSURL *)streamURL +{ + return streamURL; +} +- (void)setStreamURL:(NSURL *)aStreamURL +{ + streamURL = [aStreamURL copy]; + unsigned short port = RTMP_DEFAULT_PORT; + if([streamURL port]) + { + port = [[streamURL port] unsignedShortValue]; + } + [self connectToServer:[streamURL host] onPort:port]; +} - (void)connectToServer:(NSString *)server onPort:(unsigned short)port { //if for some reason we are re-connecting to the server, the socket, buffer, and file handle need to be invalidated and re-created @@ -87,11 +127,7 @@ [connection waitForDataInBackgroundAndNotify]; } -- (void)requestStream:(NSString *)file -{ - NSMutableData *packet = [NSMutableData data]; - -} + - (void)sendHandshake { NSMutableData *packet = [NSMutableData data]; @@ -134,12 +170,28 @@ - (void)sendConnectRequest { NSMutableData *packet = [NSMutableData data]; - [data appendData:[self encodeAMFString:@"connect"]]; - [data appendData:[self encodeAMFNumber:AMF_CALL_NETCONNECTION_CONNECT]]; - [data appendData:[self encodeAMFObject:NULL]]; - [data appendData:[self encodeAMFStringVariable:@"TUvé" key:@"app"]]; - [data appendData:[self encodeAMFStringVariable:@"LNX 9,0,48,0" key:@"flashVer"]]; - [data appendData:[self encodeAMFStringVariable:@"file://iphone.flv" key:@"swfUrl"]]; + [packet appendData:[self encodeAMFString:@"connect"]]; + [packet appendData:[self encodeAMFNumber:AMF_CALL_NETCONNECTION_CONNECT]]; + [packet appendData:[self encodeAMFObject:NULL]]; + [packet appendData:[self encodeAMFStringVariable:@"TUvé" key:@"app"]]; + [packet appendData:[self encodeAMFStringVariable:@"LNX 9,0,48,0" key:@"flashVer"]]; + [packet appendData:[self encodeAMFStringVariable:@"file://iphone.flv" key:@"swfUrl"]]; + [packet appendData:[self encodeAMFStringVariable:[streamURL absoluteString] key:@"tcUrl"]]; + [packet appendData:[self encodeAMFBooleanVariable:FALSE key:@"fpad"]]; + [packet appendData:[self encodeAMFNumberVariable:AMF_CALL_NETCONNECTION_CONNECT_AUDIOCODECS key:@"audioCodecs"]]; + [packet appendData:[self encodeAMFNumberVariable:AMF_CALL_NETCONNECTION_CONNECT_VIDEOCODECS key:@"videoCodecs"]]; + [packet appendData:[self encodeAMFNumberVariable:AMF_CALL_NETCONNECTION_CONNECT_VIDEOFUNCTION key:@"videoFunction"]]; + [packet appendData:[self encodeAMFStringVariable:@"file://iphone.html" key:@"pageUrl"]]; + [packet appendData:[self encodeAMFNumberVariable:AMF_CALL_NETCONNECTION_CONNECT_OBJECTENCODING key:@"objectEncoding"]]; + [packet appendData:[self encodeAMFEndObject]]; + [self sendPacket:packet type:RTMP_CONTENT_TYPE_INVOKE]; +} +- (void)sendPacket:(NSData *)packet type:(unsigned char)type +{ + [connection writeData:[self encodePacket:connection type:type]]; +} +- (NSData *)encodePacket:(NSData *)packet type:(unsigned char)type +{ } - (NSData *)encodeAMFString:(NSString *)str { @@ -174,6 +226,13 @@ [encodedObject pad:[NSData dataWithByte:0x00] count:AMF_DATATYPE_SIZE_OBJECT-1]; return encodedObject; } +- (NSData *)encodeAMFEndObject +{ + NSMutableData *encodedObject = [NSMutableData data]; + [encodedObject pad:[NSData dataWithByte:0x00] count:AMF_DATATYPE_SIZE_END_OF_OBJECT - 1]; + [encodedObject appendByte:AMF_DATATYPE_END_OF_OBJECT]; + return encodedObject; +} - (NSData *)encodeAMFStringVariable:(NSString *)value key:(NSString *)key { NSMutableData *encodedVariable = [NSMutableData data]; @@ -182,12 +241,21 @@ [encodedVariable appendData:[self encodeAMFString:value]]; return encodedVariable; } +- (NSData *)encodeAMFNumberVariable:(unsigned long long)value key:(NSString *)key +{ + NSMutableData *encodedVariable = [NSMutableData data]; + [encodedVariable appendUShort:[key length] ordered:NSBigEndian]; + [encodedVariable appendString:key encoding:NSUTF8StringEncoding]; + [encodedVariable appendData:[self encodeAMFNumber:value]]; + return encodedVariable; +} - (NSData *)encodeAMFBooleanVariable:(BOOL)value key:(NSString *)key { NSMutableData *encodedVariable = [NSMutableData data]; [encodedVariable appendUShort:[key length] ordered:NSBigEndian]; [encodedVariable appendString:key encoding:NSUTF8StringEncoding]; - [encodedVariable appendData:[self encodedAMFBoolean:value]]; + [encodedVariable appendData:[self encodeAMFBoolean:value]]; return encodedVariable; } + @end