@ -1,5 +1,6 @@
/* Android actor: локальный preview, очередь, stop/FIN, отменённый open и detach concurrent producer. */
# include <pthread.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
@ -8,6 +9,7 @@
# include "../lib/sqlite3.h"
# include "../src/chat/chat_core.h"
# include "../src/chat/chat_event.h"
# include "../src/chat/chat_setting.h"
# include "../src/stream/stream.h"
# include "../src/stream/stream_member.h"
# include "../src/utun_instance.h"
@ -61,7 +63,7 @@ int main(void) {
debug_config_init ( ) ; debug_set_level ( DEBUG_LEVEL_WARN ) ; debug_set_category_level ( DEBUG_CATEGORY_STREAM , DEBUG_LEVEL_INFO ) ;
size_t before = u_get_allocated_count ( ) ; test_clock_init ( 100 ) ; ua = uasync_create ( ) ; CHECK ( ua ) ;
struct UTUN_INSTANCE * inst = utun_instance_create_from_str ( ua ,
" [global] \n auto_sockets=no \n [chatserver] \n group_autoconnect=0 \n storage_autoload=0 \n member_files_enabled=0 \n " ) ;
" [global] \n auto_sockets=no \n [chatserver] \n group_autoconnect=0 \n stream_subblocks=8 \n stream_rs_redundant=0 \n st orage_autoload=0 \n member_files_enabled=0 \n " ) ;
CHECK ( inst & & ! utun_core_start ( inst ) & & ! chat_service_start ( inst ) ) ;
chat_core_create_channel_auto ( inst , " Stream \" test \" 😀 " ) ;
sqlite3_stmt * statement = NULL ;
@ -80,11 +82,15 @@ int main(void) {
CHECK ( source_events = = 2 & & strstr ( source_snapshot , " epoch " ) ) ;
struct stream_member_state member ;
CHECK ( stream_member_load ( inst , group , inst - > node_id , & member , NULL ) = = STREAM_OK & & member . published ) ;
CHECK ( member . audio_enabled ) ;
CHECK ( member . audio_enabled & & member . source . n = = 8 & & member . source . r = = 0 ) ;
CHECK ( chat_setting_set ( inst , " stream_subblocks " , " 8 " ) = = 0 ) ;
CHECK ( chat_setting_set ( inst , " stream_rs_redundant " , " 2 " ) = = 0 ) ;
CHECK ( chat_setting_set ( inst , " stream_subblocks " , " 256 " ) = = - 2 ) ;
CHECK ( chat_setting_set ( inst , " stream_rs_redundant " , " -1 " ) = = - 2 ) ;
CHECK ( android_stream_set_audio_enabled ( 1 , 0 ) = = 0 ) ; test_clock_poll ( ua , 100 ) ;
struct stream_member_state muted ;
CHECK ( stream_member_load ( inst , group , inst - > node_id , & muted , NULL ) = = STREAM_OK & & ! muted . audio_enabled ) ;
CHECK ( muted . source . source_epoch = = member . source . source_epoch ) ;
CHECK ( muted . source . source_epoch = = member . source . source_epoch & & muted . source . n = = 8 & & muted . source . r = = 0 ) ;
CHECK ( android_stream_set_audio_enabled ( 2 , 1 ) < 0 ) ;
CHECK ( android_stream_set_audio_enabled ( 1 , 1 ) = = 0 ) ; test_clock_poll ( ua , 100 ) ;
CHECK ( stream_member_load ( inst , group , inst - > node_id , & muted , NULL ) = = STREAM_OK & & muted . audio_enabled ) ;
@ -178,6 +184,8 @@ int main(void) {
CHECK ( ! strcmp ( source_snapshot , " [] " ) ) ;
current_format . rotation = 0 ; current_format . audio_codec = 0 ;
CHECK ( android_stream_open ( 3 , group , 0 , 1280 , 720 , 0 , 0 , 0 , STREAM_MEDIA_H264 ) = = 0 ) ; u_free ( wait_event ( 3 , 4 , & size ) ) ;
CHECK ( stream_member_load ( inst , group , inst - > node_id , & member , NULL ) = = STREAM_OK ) ;
CHECK ( member . source . n = = 8 & & member . source . r = = 2 ) ;
CHECK ( android_stream_set_audio_enabled ( 3 , 1 ) < 0 ) ;
uint8_t * large = u_malloc ( 500000 ) ; CHECK ( large ) ; memset ( large , 1 , 500000 ) ;
CHECK ( feed ( 3 , 1 , 500000 , 1 , large , 500000 ) = = 1 ) ; u_free ( large ) ;
@ -195,6 +203,34 @@ int main(void) {
android_stream_attach ( inst ) ;
CHECK ( android_stream_open ( 4 , group , 0 , 1280 , 720 , 0 , 0 , 0 , STREAM_MEDIA_H264 ) = = 0 ) ; android_stream_stop ( 4 ) ;
u_free ( wait_event ( 4 , 5 , & size ) ) ;
/* Маленькая пачка и пачка сверх предела медиаблока: полный кадр проходит через локальный viewer. */
const unsigned totals [ ] = { 1 , 16 , 64 } ;
for ( unsigned test = 0 ; test < sizeof ( totals ) / sizeof ( totals [ 0 ] ) ; test + + ) {
unsigned total = totals [ test ] , parity = total = = 16 ? 4 : 0 ;
char setting [ 8 ] ; snprintf ( setting , sizeof ( setting ) , " %u " , total ) ;
CHECK ( chat_setting_set ( inst , " stream_subblocks " , setting ) = = 0 ) ;
snprintf ( setting , sizeof ( setting ) , " %u " , parity ) ;
CHECK ( chat_setting_set ( inst , " stream_rs_redundant " , setting ) = = 0 ) ;
CHECK ( android_stream_open ( 6 , group , 0 , 1280 , 720 , 0 , 0 , 0 , STREAM_MEDIA_H264 ) = = 0 ) ;
u_free ( wait_event ( 6 , 4 , & size ) ) ;
CHECK ( stream_member_load ( inst , group , inst - > node_id , & member , NULL ) = = STREAM_OK ) ;
CHECK ( member . source . n = = total & & member . source . r = = parity ) ;
struct STREAM_HANDLE * reader = NULL ;
CHECK ( stream_media_open ( inst , group , inst - > node_id , member . source . source_epoch , STREAM_MEDIA_TRACK_VIDEO , & reader ) = = STREAM_OK ) ;
size_t length = total = = 1 ? sizeof ( video ) : 100000 ;
uint8_t * frame = u_malloc ( length ) ; CHECK ( frame ) ; memset ( frame , 7 , length ) ;
CHECK ( feed ( 6 , 1 , 100000 , 1 , frame , length ) = = 1 ) ;
struct stream_media_packet packet ; int received = 0 ;
for ( unsigned i = 0 ; i < 1000 & & ! received ; i + + ) {
test_clock_poll ( ua , 100 ) ;
int result = stream_media_read ( reader , 100000 , 1 , - 1 , & packet ) ;
if ( result = = STREAM_OK ) {
CHECK ( packet . kind = = STREAM_MEDIA_READ_VIDEO & & packet . video . length = = length & & ! memcmp ( packet . video . data , frame , length ) ) ; received = 1 ;
} else CHECK ( result = = STREAM_WAIT | | result = = STREAM_MORE ) ;
}
CHECK ( received ) ; u_free ( frame ) ; stream_close ( reader ) ;
android_stream_stop ( 6 ) ; u_free ( wait_event ( 6 , 5 , & size ) ) ;
}
android_stream_detach ( inst ) ; uasync_mark_stopped ( ua ) ; utun_instance_destroy ( inst ) ; uasync_destroy ( ua , 0 ) ;
u_free ( source_snapshot ) ;
CHECK ( u_get_allocated_count ( ) = = before ) ;