From 40c1dcf1dc14926c18ce3ff834a03ee944d7122d Mon Sep 17 00:00:00 2001 From: "Kasiewicz, Marek" Date: Fri, 28 Feb 2025 09:57:53 +0000 Subject: [PATCH] Add: New API draft Signed-off-by: Kasiewicz, Marek --- doc/new_API/List-of-changes.md | 16 + doc/new_API/buffers-api.h | 58 ++++ doc/new_API/samples/diagrams.md | 160 +++++++++ doc/new_API/samples/sample-rx-app-owned.c | 108 ++++++ doc/new_API/samples/sample-rx-lib-owned.c | 51 +++ doc/new_API/samples/sample-tx-app-owned.c | 199 +++++++++++ doc/new_API/samples/sample-tx-lib-owned.c | 51 +++ doc/new_API/session-internal.h | 47 +++ doc/new_API/session.h | 394 ++++++++++++++++++++++ 9 files changed, 1084 insertions(+) create mode 100644 doc/new_API/List-of-changes.md create mode 100644 doc/new_API/buffers-api.h create mode 100644 doc/new_API/samples/diagrams.md create mode 100644 doc/new_API/samples/sample-rx-app-owned.c create mode 100644 doc/new_API/samples/sample-rx-lib-owned.c create mode 100644 doc/new_API/samples/sample-tx-app-owned.c create mode 100644 doc/new_API/samples/sample-tx-lib-owned.c create mode 100644 doc/new_API/session-internal.h create mode 100644 doc/new_API/session.h diff --git a/doc/new_API/List-of-changes.md b/doc/new_API/List-of-changes.md new file mode 100644 index 000000000..e62bd86a1 --- /dev/null +++ b/doc/new_API/List-of-changes.md @@ -0,0 +1,16 @@ +# List of changes in API this draft is trying to present + +- Removal of "frame" mode and rtp "mode", modified pipeline mode stays as only API for MTL sessions + +- Polymorphic session classes used to reduce code repetition + +- Replacing callback with event polling function to notify app about events in lib + +- Change of usage pattern for zero copy/external frame mode. A clear separation of two types of +buffer ownership; buffers owned by the library and buffers owned by the application. + +- Added stop() start() and shutdown() + +> **Note** +> Fields in all structures are dummy, they need to be correctly ported from current API. Also a few functions need to ported. +> This is not a complete API, just a presentation of a few ideas. \ No newline at end of file diff --git a/doc/new_API/buffers-api.h b/doc/new_API/buffers-api.h new file mode 100644 index 000000000..b77b3bee5 --- /dev/null +++ b/doc/new_API/buffers-api.h @@ -0,0 +1,58 @@ +#include +#include +#include + +// Forward declarations +typedef struct media_lib_session_base media_lib_session_t; +typedef struct media_lib_buffer_base media_lib_buffer_t; + +// Base buffer structure +typedef struct media_lib_buffer_base { + void* data; + mtl_iova_t iova; + size_t size; + uint64_t timestamp; + uint32_t flags; + uint32_t buffer_id; + void* _internal; + void* user_data; +} media_lib_buffer_base_t; + +// Video buffer structure +typedef struct media_lib_video_buffer { + // Base buffer must be the first member + media_lib_buffer_base_t base; + + // Video-specific fields + uint32_t width; + uint32_t height; + uint32_t format; + uint32_t stride; + // Additional video buffer fields +} media_lib_video_buffer_t; + +// Audio buffer structure +typedef struct media_lib_audio_buffer { + // Base buffer must be the first member + media_lib_buffer_base_t base; + + // Audio-specific fields + uint32_t sample_rate; + uint32_t channels; + uint32_t format; + uint32_t samples_per_frame; + // Additional audio buffer fields +} media_lib_audio_buffer_t; + +// Type casting macros for safe type conversion +#define MEDIA_LIB_SESSION_TO_VIDEO(session) \ + ((media_lib_video_session_t*)(session)) + +#define MEDIA_LIB_SESSION_TO_AUDIO(session) \ + ((media_lib_audio_session_t*)(session)) + +#define MEDIA_LIB_BUFFER_TO_VIDEO(buffer) \ + ((media_lib_video_buffer_t*)(buffer)) + +#define MEDIA_LIB_BUFFER_TO_AUDIO(buffer) \ + ((media_lib_audio_buffer_t*)(buffer)) \ No newline at end of file diff --git a/doc/new_API/samples/diagrams.md b/doc/new_API/samples/diagrams.md new file mode 100644 index 000000000..87179eae4 --- /dev/null +++ b/doc/new_API/samples/diagrams.md @@ -0,0 +1,160 @@ +```mermaid +sequenceDiagram + participant App as Application + participant Session as Media Library Session + + participant Network as Network I/O + + Note over App,Network: Library-Owned Receiver Flow (sample-rx-lib-owned.c) + + App->>Session: media_lib_video_session_create(instance, &rx_config, &session) + Session->>Session: Allocate memory (for NUM_BUFFERS) + Session->>Network: Setup receiver + Session->>Network: Add buffers to receive queue + Session-->>App: Return session handle + + loop Receive and process loop + App->>Session: media_lib_buffer_get(session, &buffer, TIMEOUT_MS) + Session->>Network: Wait for data + Network-->>Session: Data received + + Session-->>App: Return buffer pointer + + Note over App: Process buffer data + + App->>Session: media_lib_buffer_put(session, buffer) + + Session->>Network: Add buffer to receive queue + Session-->>App: MEDIA_LIB_SUCCESS + + end + App->>Session: media_lib_session_shutdown(session) + + App->>Session: media_lib_session_destroy(session) + Session->>Session: Deallocate memory + +``` + +```mermaid +sequenceDiagram + participant App as Application + participant Session as Media Library Session + participant Network as Network I/O + + Note over App,Network: Library-Owned Transmitter Flow (sample-tx-lib-owned.c) + + App->>Session: media_lib_video_session_create(instance, &tx_config, &session) + Session->>Session: Allocate memory (for NUM_BUFFERS) + Session->>Network: Setup transmitter + Session-->>App: Return session handle + + + loop Acquire, fill, and transmit loop + App->>Session: media_lib_buffer_get(session, &buffer, TIMEOUT_MS) + Session->>Session: Wait for available buffer + Session-->>App: Return available buffer + + Note over App: Fill buffer with media data + + App->>Session: media_lib_buffer_put(session, buffer) + Session->>Network: Start transmission + Session-->>App: MEDIA_LIB_SUCCESS + Network-->>Session: Transmission complete + Session->>Session: Mark buffer as available + + end + + App->>Session:media_lib_buffers_flush(session) + App->>Session: media_lib_session_shutdown(session) + App->>Session: media_lib_session_destroy(session) + Session->>Session: Deallocate memory + +``` + +```mermaid +sequenceDiagram + participant App as Application + participant Session as Media Library Session + participant DMA as DMA Memory Manager + participant Events as Event Queue + participant Network as Network I/O + + Note over App,Events: App-Owned Receiver Flow (sample-rx-app-owned.c) + + App->>Session: media_lib_video_session_create(instance, &rx_config, &session) + Session->>Network: Setup receiver + Session-->>App: Return session handle + + App->>App: Allocate memory (for NUM_BUFFERS) + App->>Session: media_lib_mem_register(session, memory, size, &dma_mem) + Session->>DMA: Register memory for DMA + DMA-->>Session: DMA handle + Session-->>App: Return DMA handle + + loop Buffer setup loop + App->>App: Create app_buffer_t for each buffer segment + App->>Session: media_lib_buffer_post(session, data, size, app_buffer) + Session->>Network: Add buffer to receive queue + end + + loop Poll and process loop + App->>Session: media_lib_event_poll(session, &event, TIMEOUT_MS) + Session->>Events: Check for events + + alt Data received + Network->>Session: Data received in posted buffer + Session->>Events: Add BUFFER_RECEIVED event + Events-->>Session: Return event + Session-->>App: Return event with app_buffer context + + Note over App: Process buffer data + + App->>Session: media_lib_buffer_post(session, buf->data, buf->size, buf) + Session->>Network: Repost buffer for next receive + end + end + + Note over App: Cleanup (not shown in sample) + App->>Session: media_lib_mem_unregister(session, dma_mem) + App->>Session: media_lib_session_shutdown(session) + App->>Session: media_lib_session_destroy(session) + +``` + +```mermaid +sequenceDiagram + participant ProducerThread as Producer Thread + participant PollerThread as Poller Thread + participant BufferQueue as Buffer Queue + participant Session as Media Library Session + participant DMA as DMA Memory Manager + participant Events as Event Queue + participant Network as Network I/O + + Note over ProducerThread,Events: App-Owned Transmitter Flow (sample-tx-app-owned.c) + + Note over ProducerThread,PollerThread: Main thread setup (not shown) + + Note over Session,DMA: Memory registration occurs in main thread + + loop Producer Thread Loop + ProducerThread->>BufferQueue: dequeue() - Get free buffer + BufferQueue-->>ProducerThread: Return app_buffer_t + Note over ProducerThread: Fill buffer with data + ProducerThread->>Session: media_lib_buffer_post(session, buf->data, buf->size, buf) + Session->>Network: Queue buffer for transmission + end + + loop Poller Thread Loop + PollerThread->>Session: media_lib_event_poll(session, &event, TIMEOUT_MS) + Session->>Events: Check for events + alt Transmission complete + Events-->>Session: Return BUFFER_TRANSMITTED event + Session-->>PollerThread: Return event with app_buffer context + PollerThread->>BufferQueue: enqueue(buffer) - Return to free queue + end + end + + Note over ProducerThread,PollerThread: Cleanup (not reached in sample) + +``` \ No newline at end of file diff --git a/doc/new_API/samples/sample-rx-app-owned.c b/doc/new_API/samples/sample-rx-app-owned.c new file mode 100644 index 000000000..0b34a1919 --- /dev/null +++ b/doc/new_API/samples/sample-rx-app-owned.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "media-lib-api.h" + +#define TIMEOUT_MS 1000 +#define NUM_BUFFERS 4 +#define BUFFER_SIZE 1024 + +// Application-defined simple buffer structure. +typedef struct { + uint8_t* data; // Pointer to the buffer data. + size_t size; // Size of the buffer. + int id; // Buffer identifier. +} app_buffer_t; + +int main(void) { + // Assume instance is created by the library initialization routine. + mtl_handle* instance = /* ... */ NULL; + media_lib_video_session_config_t rx_config = {0}; + media_lib_session_t* session = NULL; + uint8_t* registered_memory = NULL; + mtl_dma_mem_handle* dma_mem = NULL; + app_buffer_t* buffers[NUM_BUFFERS]; + media_lib_event_t event; + int err; + + // Configure a receiver session in user-owned (zero-copy) mode. + rx_config.base.type = MEDIA_LIB_SESSION_RECEIVER; + rx_config.base.ownership = MEDIA_LIB_BUFFER_USER_OWNED; + rx_config.base.buffer_size = BUFFER_SIZE; + rx_config.base.num_buffers = NUM_BUFFERS; + rx_config.base.address = "192.168.1.100"; + rx_config.base.port = 1234; + rx_config.base.timeout_ms = TIMEOUT_MS; + rx_config.width = 640; + rx_config.height = 480; + rx_config.framerate = 30; + rx_config.format = 0; // e.g., V_FMT_YUV420P + + err = media_lib_video_session_create(instance, &rx_config, &session); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to create receiver session\n"); + return -1; + } + + // Allocate a contiguous block of memory for all buffers. + registered_memory = malloc(NUM_BUFFERS * BUFFER_SIZE); + if (!registered_memory) { + printf("Failed to allocate memory\n"); + return -1; + } + err = media_lib_mem_register(session, registered_memory, NUM_BUFFERS * BUFFER_SIZE, &dma_mem); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to register memory\n"); + free(registered_memory); + return -1; + } + + // Create an array of application-defined buffers. + for (int i = 0; i < NUM_BUFFERS; i++) { + buffers[i] = malloc(sizeof(app_buffer_t)); + if (!buffers[i]) { + printf("Failed to allocate app_buffer_t for buffer %d\n", i); + // Cleanup omitted for brevity. + return -1; + } + buffers[i]->data = registered_memory + i * BUFFER_SIZE; + buffers[i]->size = BUFFER_SIZE; + buffers[i]->id = i; + // Post the buffer to the library. + // The app_buffer_t pointer is passed as the context. + err = media_lib_buffer_post(session, buffers[i]->data, buffers[i]->size, (void*)buffers[i]); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to post rx buffer %d\n", i); + } + } + + // Polling loop: process received buffers and repost them. + while (1) { + err = media_lib_event_poll(session, &event, TIMEOUT_MS); + if (err == MEDIA_LIB_SUCCESS) { + if (event.type == MEDIA_LIB_EVENT_BUFFER_RECEIVED) { + // event.ctx is the application context. + app_buffer_t* buf = (app_buffer_t*)event.ctx; + printf("Received buffer id %d, size %ld\n", buf->id, buf->size); + // Process the data in buf->data as needed... + + // After processing, repost the buffer back to the library. + err = media_lib_buffer_post(session, buf->data, buf->size, (void*)buf); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to repost rx buffer for id %d\n", buf->id); + } + } + } + } + + // Cleanup (never reached in this sample). + media_lib_mem_unregister(session, dma_mem); + media_lib_session_shutdown(session); + media_lib_session_destroy(session); + free(registered_memory); + for (int i = 0; i < NUM_BUFFERS; i++) { + free(buffers[i]); + } + return 0; +} diff --git a/doc/new_API/samples/sample-rx-lib-owned.c b/doc/new_API/samples/sample-rx-lib-owned.c new file mode 100644 index 000000000..fafa6ebed --- /dev/null +++ b/doc/new_API/samples/sample-rx-lib-owned.c @@ -0,0 +1,51 @@ +#include +#include "media-lib-api.h" + +#define TIMEOUT_MS 1000 + +int main(void) { + // Assume instance is created by the library initialization routine. + mtl_handle* instance = /* ... */ NULL; + media_lib_video_session_config_t rx_config = {0}; + media_lib_session_t* session = NULL; + media_lib_buffer_t* buffer = NULL; + int err; + + /* Configure a receiver session in library-owned mode */ + rx_config.base.type = MEDIA_LIB_SESSION_RECEIVER; + rx_config.base.ownership = MEDIA_LIB_BUFFER_LIBRARY_OWNED; + rx_config.base.buffer_size = 1024; + rx_config.base.num_buffers = 4; + rx_config.base.address = "192.168.1.102"; + rx_config.base.port = 1236; + rx_config.base.timeout_ms = TIMEOUT_MS; + rx_config.width = 640; + rx_config.height = 480; + rx_config.framerate = 30; + rx_config.format = /* e.g., V_FMT_YUV420P */ 0; + + err = media_lib_video_session_create(instance, &rx_config, &session); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to create receiver session\n"); + return -1; + } + + /* Loop to receive and process buffers */ + while (1) { + err = media_lib_buffer_get(session, &buffer, TIMEOUT_MS); + if (err == MEDIA_LIB_SUCCESS) { + printf("Received lib-owned buffer (size: %zu)\n", buffer->size); + /* Process the received data here... */ + + /* Return the buffer back to the library */ + err = media_lib_buffer_put(session, buffer); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to release buffer\n"); + } + } + } + + media_lib_session_shutdown(session); + media_lib_session_destroy(session); + return 0; +} diff --git a/doc/new_API/samples/sample-tx-app-owned.c b/doc/new_API/samples/sample-tx-app-owned.c new file mode 100644 index 000000000..d6d64bd5c --- /dev/null +++ b/doc/new_API/samples/sample-tx-app-owned.c @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include // For usleep() +#include +#include "media-lib-api.h" + +#define TIMEOUT_MS 1000 +#define NUM_BUFFERS 4 +#define BUFFER_SIZE 1024 // Size of each buffer in bytes + +// Application-defined simple buffer structure +typedef struct { + uint8_t* data; // Pointer to the buffer data (slice of registered memory) + size_t size; // Size of the buffer in bytes + int id; // Simple identifier (for logging or debugging) +} app_buffer_t; + +// A simple circular queue to hold free app buffers +typedef struct { + app_buffer_t* buffers[NUM_BUFFERS]; + int head; + int tail; + int count; + pthread_mutex_t mutex; + pthread_cond_t cond; +} buffer_queue_t; + +buffer_queue_t free_queue; + +void init_queue(buffer_queue_t* q) { + q->head = 0; + q->tail = 0; + q->count = 0; + pthread_mutex_init(&q->mutex, NULL); + pthread_cond_init(&q->cond, NULL); +} + +void enqueue(buffer_queue_t* q, app_buffer_t* buffer) { + pthread_mutex_lock(&q->mutex); + while (q->count == NUM_BUFFERS) { + pthread_cond_wait(&q->cond, &q->mutex); + } + q->buffers[q->tail] = buffer; + q->tail = (q->tail + 1) % NUM_BUFFERS; + q->count++; + pthread_cond_signal(&q->cond); + pthread_mutex_unlock(&q->mutex); +} + +app_buffer_t* dequeue(buffer_queue_t* q) { + app_buffer_t* buffer = NULL; + pthread_mutex_lock(&q->mutex); + while (q->count == 0) { + pthread_cond_wait(&q->cond, &q->mutex); + } + buffer = q->buffers[q->head]; + q->head = (q->head + 1) % NUM_BUFFERS; + q->count--; + pthread_cond_signal(&q->cond); + pthread_mutex_unlock(&q->mutex); + return buffer; +} + +// Global session pointer (assumed to be created successfully) +media_lib_session_t* session = NULL; +// Pointer to the registered memory block +uint8_t* registered_memory = NULL; +mtl_dma_mem_handle* dma_mem = NULL; + +// Producer thread: simulates video frame generation and posts frames for transmission. +void* frame_generator_thread(void* arg) { + app_buffer_t* buf; + int err; + + while (1) { + // Get a free buffer from the queue + buf = dequeue(&free_queue); + if (!buf) + continue; + + // Simulate frame generation: fill the buffer with dummy data. + memset(buf->data, 0xAB, buf->size); + // (Set additional fields if needed, e.g., frame timestamp) + + // Post the buffer for transmission. + // Note: We pass buf->data and buf->size, and use the app buffer as the context. + err = media_lib_buffer_post(session, buf->data, buf->size, (void*)buf); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to post tx buffer (id: %d)\n", buf->id); + // If posting fails, return the buffer back to the free queue. + enqueue(&free_queue, buf); + } else { + printf("Frame generated and posted for transmission (id: %d)\n", buf->id); + } + + // Simulate frame rate (e.g., 30fps ~33ms per frame) + usleep(33000); + } + return NULL; +} + +// Poller thread: waits for transmitted events and recycles buffers. +void* event_handler_thread(void* arg) { + media_lib_event_t event; + int err; + app_buffer_t* buf; + + while (1) { + err = media_lib_event_poll(session, &event, TIMEOUT_MS); + if (err == MEDIA_LIB_SUCCESS) { + if (event.type == MEDIA_LIB_EVENT_BUFFER_TRANSMITTED) { + // The library returns the transmitted buffer's app context in event.buffer. + // Cast it back to our app_buffer_t pointer. + buf = (app_buffer_t*)event.ctx; + if (buf) { + printf("Buffer transmitted successfully (id: %d)\n", buf->id); + // Return the buffer to the free queue for reuse. + enqueue(&free_queue, buf); + } + } + } else { + // Poll timeout or error; can log or handle as needed. + } + } + return NULL; +} + +int main(void) { + // Assume instance is obtained from your library initialization. + mtl_handle* instance = /* e.g., media_lib_instance_create() */ NULL; + media_lib_video_session_config_t tx_config = {0}; + pthread_t producer_thread, poller_thread; + app_buffer_t* buf; + int err; + + // Configure a transmitter session in app-owned (zero-copy) mode. + tx_config.base.type = MEDIA_LIB_SESSION_TRANSMITTER; + tx_config.base.ownership = MEDIA_LIB_BUFFER_USER_OWNED; + tx_config.base.buffer_size = BUFFER_SIZE; + tx_config.base.num_buffers = NUM_BUFFERS; + tx_config.base.address = "192.168.1.101"; + tx_config.base.port = 1235; + tx_config.base.timeout_ms = TIMEOUT_MS; + tx_config.width = 640; + tx_config.height = 480; + tx_config.framerate = 30; + tx_config.format = 0; // e.g., V_FMT_YUV420P + + err = media_lib_video_session_create(instance, &tx_config, &session); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to create transmitter session\n"); + return -1; + } + + // Allocate and register a contiguous memory block for all buffers. + registered_memory = malloc(NUM_BUFFERS * BUFFER_SIZE); + if (!registered_memory) { + printf("Failed to allocate registered memory\n"); + return -1; + } + err = media_lib_mem_register(session, registered_memory, NUM_BUFFERS * BUFFER_SIZE, &dma_mem); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to register memory\n"); + return -1; + } + + // Initialize the free buffer queue. + init_queue(&free_queue); + + // Create app-defined buffer structures and enqueue them. + for (int i = 0; i < NUM_BUFFERS; i++) { + buf = malloc(sizeof(app_buffer_t)); + if (!buf) { + printf("Failed to allocate app buffer structure\n"); + return -1; + } + buf->data = registered_memory + i * BUFFER_SIZE; + buf->size = BUFFER_SIZE; + buf->id = i; + enqueue(&free_queue, buf); + } + + // Create threads: one for frame generation, one for event polling. + pthread_create(&producer_thread, NULL, frame_generator_thread, NULL); + pthread_create(&poller_thread, NULL, event_handler_thread, NULL); + + // In a real application, you would add proper termination handling. + pthread_join(producer_thread, NULL); + pthread_join(poller_thread, NULL); + + // Cleanup (not reached in this sample). + media_lib_mem_unregister(session, dma_mem); + media_lib_session_shutdown(session); + media_lib_session_destroy(session); + free(registered_memory); + return 0; +} diff --git a/doc/new_API/samples/sample-tx-lib-owned.c b/doc/new_API/samples/sample-tx-lib-owned.c new file mode 100644 index 000000000..7c0fcd69e --- /dev/null +++ b/doc/new_API/samples/sample-tx-lib-owned.c @@ -0,0 +1,51 @@ +#include +#include "media-lib-api.h" + +#define TIMEOUT_MS 1000 + +int main(void) { + // Assume instance is created by the library initialization routine. + mtl_handle* instance = /* ... */ NULL; + media_lib_video_session_config_t tx_config = {0}; + media_lib_session_t* session = NULL; + media_lib_buffer_t* buffer = NULL; + int err; + + /* Configure a transmitter session in library-owned mode */ + tx_config.base.type = MEDIA_LIB_SESSION_TRANSMITTER; + tx_config.base.ownership = MEDIA_LIB_BUFFER_LIBRARY_OWNED; + tx_config.base.buffer_size = 1024; + tx_config.base.num_buffers = 4; + tx_config.base.address = "192.168.1.103"; + tx_config.base.port = 1237; + tx_config.base.timeout_ms = TIMEOUT_MS; + tx_config.width = 640; + tx_config.height = 480; + tx_config.framerate = 30; + tx_config.format = /* e.g., V_FMT_YUV420P */ 0; + + err = media_lib_video_session_create(instance, &tx_config, &session); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to create transmitter session\n"); + return -1; + } + + /* Loop to acquire a buffer, fill it with data, and transmit it */ + while (1) { + err = media_lib_buffer_get(session, &buffer, TIMEOUT_MS); + if (err == MEDIA_LIB_SUCCESS) { + printf("Acquired lib-owned buffer for transmission (size: %zu)\n", buffer->size); + /* Fill buffer->data with the media data to transmit */ + + err = media_lib_buffer_put(session, buffer); + if (err != MEDIA_LIB_SUCCESS) { + printf("Failed to transmit buffer\n"); + } + /* After transmission the buffer will be returned to the library, usually via an event */ + } + } + + media_lib_session_shutdown(session); + media_lib_session_destroy(session); + return 0; +} diff --git a/doc/new_API/session-internal.h b/doc/new_API/session-internal.h new file mode 100644 index 000000000..45c4e4dd2 --- /dev/null +++ b/doc/new_API/session-internal.h @@ -0,0 +1,47 @@ +// This is an internal definition, not exposed in the public header. +struct media_lib_session_base_t { + // Must be the first field for polymorphism. + media_lib_session_vtable_t* vtable; + + // Pointer to the parent library instance. + media_lib_instance_t* instance; + + // Session configuration (common) + media_lib_type_t media_type; // MEDIA_LIB_TYPE_VIDEO or MEDIA_LIB_TYPE_AUDIO + media_lib_session_type_t session_role; // Receiver or transmitter + media_lib_buffer_ownership_t ownership; // Buffer ownership mode + + // Common session parameters (from base config) + size_t buffer_size; + uint32_t num_buffers; + // etc. + + // Statistics for monitoring performance. + media_lib_session_stats_t stats; +}; + +// Video session structure +typedef struct media_lib_video_session { + // Base session must be the first member + media_lib_session_base_t base; + + // Video-specific fields + uint32_t width; + uint32_t height; + uint32_t framerate; + uint32_t format; + // Additional video-specific fields can be added here +} media_lib_video_session_t; + +// Audio session structure +typedef struct media_lib_audio_session { + // Base session must be the first member + media_lib_session_base_t base; + + // Audio-specific fields + uint32_t sample_rate; + uint32_t channels; + uint32_t bits_per_sample; + uint32_t format; + // Additional audio-specific fields can be added here +} media_lib_audio_session_t; \ No newline at end of file diff --git a/doc/new_API/session.h b/doc/new_API/session.h new file mode 100644 index 000000000..56b2f0cee --- /dev/null +++ b/doc/new_API/session.h @@ -0,0 +1,394 @@ +#ifndef MEDIA_LIB_API_H +#define MEDIA_LIB_API_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include "buffers-api.h" + +/*** Library Instance, the API for instance stays without changes ***/ +typedef struct mtl_handle mtl_handle; + +/*** Some Example Error Codes.. to be defined***/ +typedef enum { + MEDIA_LIB_SUCCESS = 0, + MEDIA_LIB_ERROR_INVALID_PARAMETER = -1, + // MEDIA_LIB_ERROR_NOT_INITIALIZED = -2, + // MEDIA_LIB_ERROR_OUT_OF_MEMORY = -3, + // MEDIA_LIB_ERROR_TIMEOUT = -4, + // MEDIA_LIB_ERROR_CONNECTION_FAILED = -5, + // MEDIA_LIB_ERROR_DISCONNECTED = -6, + // MEDIA_LIB_ERROR_BUFFER_FULL = -7, + // MEDIA_LIB_ERROR_BUFFER_EMPTY = -8, + // MEDIA_LIB_ERROR_INVALID_STATE = -9, + // MEDIA_LIB_ERROR_UNSUPPORTED = -10, + // MEDIA_LIB_ERROR_UNKNOWN = -100 +} media_lib_error_t; + +/*** Media Type Enumeration ***/ +typedef enum { + MEDIA_LIB_TYPE_VIDEO = 0, + MEDIA_LIB_TYPE_AUDIO = 1, + MEDIA_LIB_TYPE_ANCILLARY = 2, + MEDIA_LIB_TYPE_FAST_METADATA = 3, +} media_lib_type_t; + +/*** Session Type Enumeration ***/ +typedef enum { + MEDIA_LIB_SESSION_RECEIVER = 0, + MEDIA_LIB_SESSION_TRANSMITTER = 1 +} media_lib_session_type_t; + +/*** Buffer Ownership ***/ +typedef enum { + MEDIA_LIB_BUFFER_USER_OWNED = 0, + MEDIA_LIB_BUFFER_LIBRARY_OWNED = 1 +} media_lib_buffer_ownership_t; + +/*** Event Types ***/ +typedef enum { + MEDIA_LIB_EVENT_NONE = 0, + MEDIA_LIB_EVENT_BUFFER_RECEIVED = 1, // A buffer was received + MEDIA_LIB_EVENT_BUFFER_TRANSMITTED = 2, // A buffer was transmitted + MEDIA_LIB_EVENT_BUFFER_AVAILABLE = 3, // A buffer is available for use + MEDIA_LIB_EVENT_ERROR = 5 // An error occurred +} media_lib_event_type_t; + +/*** Event Structure ***/ +// In library-owned mode, it is a pointer to a media_lib_buffer_t. +// In app-owned mode, it is the application context passed in post_rx/post_tx. +typedef struct { + media_lib_event_type_t type; // Type of event + media_lib_error_t status; // Status/error code + uint64_t timestamp; // Event timestamp + void* ctx; // Associated buffer or context pointer (if applicable) +} media_lib_event_t; + + +/*** Session ***/ +typedef struct media_lib_session media_lib_session_t; + +/*** Base Session Configuration ***/ +typedef struct { + media_lib_session_type_t type; // Receiver or transmitter + media_lib_buffer_ownership_t ownership; // Buffer ownership mode + + /* Buffer configuration */ + size_t buffer_size; // Size of each buffer (in bytes) + uint32_t num_buffers; // Total number of buffers in the pool + + /* Network configuration */ + //address port etc. this will be copied from current API + +} media_lib_session_base_config_t; + +/*** Video-specific Session Configuration ***/ +typedef struct { + media_lib_session_base_config_t base; // Base configuration + + /* Video configuration */ + // uint32_t width; // Video frame width (pixels) + // uint32_t height; // Video frame height (pixels) + // uint32_t framerate; // Frames per second + // v_fmt_t format; // Video format (e.g., "YUV420P") + // etc. + +} media_lib_video_session_config_t; + +/*** Audio-specific Session Configuration ***/ +typedef struct { + media_lib_session_base_config_t base; // Base configuration + + /* Audio configuration */ + // uint32_t sample_rate; // Samples per second + // uint32_t channels; // Number of audio channels + // uint32_t bits_per_sample; // Bits per sample + // a_fmt_t format; // Audio format string (e.g., "PCM", "AAC") + // etc. +} media_lib_audio_session_config_t; + +/*** Session Interface (Function Table) ***/ +typedef struct { + /* + * media_lib_session_t operations + * + * These function pointers define the basic operations on a media session. + * The session is automatically activated upon creation, so the start() call + * is intended to restart it if it has been stopped. All operations return a + * media_lib_error_t code to indicate success or failure. + */ + + /* + * start - Activate or resume the media session. + * @session: Pointer to the media session instance. + * + * If the session has been stopped, this call will re-enable processing. + * The session is auto-activated at creation, so start() is used primarily + * for explicit reactivation after a stop(). + */ + media_lib_error_t (*start)(media_lib_session_t *session); + + /* + * stop - Temporarily halt media session processing. + * @session: Pointer to the media session instance. + * + * This function stops the session without deallocating resources, allowing + * for a later restart via start(). It is a clean, temporary shutdown of active + * operations. + */ + media_lib_error_t (*stop)(media_lib_session_t *session); + + /* + * shutdown - Gracefully terminate the session's asynchronous operations. + * @session: Pointer to the media session instance. + * + * This call is intended for an orderly shutdown of background tasks, ensuring + * that no further processing occurs before the session is destroyed. It should + * be invoked prior to destroy() to guarantee that all activities have ceased. + */ + media_lib_error_t (*shutdown)(media_lib_session_t *session); + + /* + * destroy - Free all resources associated with the media session. + * @session: Pointer to the media session instance. + * + * This function deallocates the session's resources and should be called only + * after a proper shutdown. Once destroy() is executed, the session pointer + * becomes invalid. + */ + media_lib_error_t (*destroy)(media_lib_session_t *session); + + /* + * Buffer management - Library-owned mode. + * get a buffer with a timeout. 'buffer_get' should block until a buffer is + * available or the timeout expires. + */ + media_lib_error_t (*buffer_get)(media_lib_session_t *session, + media_lib_buffer_t **buffer, + uint32_t timeout_ms); + + /* + * Buffer management - Library-owned mode. + * buffer_put - Return a previously acquired buffer back to the library. + * The caller relinquishes ownership of the buffer. + */ + media_lib_error_t (*buffer_put)(media_lib_session_t *session, + media_lib_buffer_t *buffer); + + /* + * Zero-copy buffer operation - App-owned mode. + * buffer_post - Post an app-owned buffer to the session for processing. + * This allows for zero-copy transfers from the application to the library. + */ + media_lib_error_t (*buffer_post)(media_lib_session_t *session, + void *data, + size_t size, + void *app_ctx); + + /* + * DMA memory management - App-owned mode. + * mem_register - Register an app-owned memory region for DMA operations. + * On success, a DMA memory handle is returned in dma_mem. + */ + media_lib_error_t (*mem_register)(media_lib_session_t *session, + void *data, + size_t size, + mtl_dma_mem_handle **dma_mem); + + /* + * mem_unregister - Unregister a previously registered DMA memory region. + * The provided DMA memory handle is invalidated after this call. + */ + media_lib_error_t (*mem_unregister)(media_lib_session_t *session, + mtl_dma_mem_handle *dma_mem); + + /* + * buffers_flush - Flush all buffers in the session. + * @session: Pointer to the media session instance. + * @timeout_ms: Timeout in milliseconds. + * + * This function waits till all buffers in the session are processed, + * ensuring that no pending data remains. + */ + media_lib_error_t (*buffers_flush)(media_lib_session_t *session, uint32_t timeout_ms); + + /* + * Polling interface. + * event_poll - Wait for an event on the media session with a timeout. + * Should return quickly if an event is pending, or block until timeout. + */ + media_lib_error_t (*event_poll)(media_lib_session_t *session, + media_lib_event_t *event, + uint32_t timeout_ms); + + /* + * Statistics and monitoring. + * stats_get - Retrieve current session statistics. + * The stats pointer should be filled with data about current session performance. + */ + media_lib_error_t (*stats_get)(media_lib_session_t *session, + void *stats); + +} media_lib_session_vtable_t; + + +/*** Session Statistics ***/ +typedef struct { + // uint64_t frames_processed; // Total frames/buffers sent or received + // uint64_t bytes_processed; // Total bytes transmitted or received + // uint64_t dropped_frames; // Frames/buffers dropped due to errors + // double current_rate; // Current effective frame/sample rate + // uint32_t total_buffers; // Total number of buffers + // uint32_t buffers_in_use; // Number of buffers currently in use + // uint64_t last_timestamp; // Timestamp of the last processed frame/sample + + // /* Queue statistics */ + // uint32_t free_queue_depth; // Number of buffers available for acquisition + // uint32_t transmit_queue_depth; // Number of buffers pending transmission + +} media_lib_session_stats_t; + +/************************************************************************* + * Session Creation Functions + *************************************************************************/ + +/* Create a video session */ +media_lib_error_t media_lib_video_session_create( + mtl_handle* instance, + const media_lib_video_session_config_t* config, + media_lib_session_t** session +); + +/* Create an audio session */ +media_lib_error_t media_lib_audio_session_create( + mtl_handle* instance, + const media_lib_audio_session_config_t* config, + media_lib_session_t** session +); + +/* Get the media type of a session */ +media_lib_type_t media_lib_session_get_type( + media_lib_session_t* session +); + +/************************************************************************* + * Polymorphic Interface Functions + *************************************************************************/ + +/* Session lifecycle */ +inline media_lib_error_t media_lib_session_start(media_lib_session_t* session) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->start(session); +} + +inline media_lib_error_t media_lib_session_stop(media_lib_session_t* session) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->stop(session); +} + +inline media_lib_error_t media_lib_session_shutdown(media_lib_session_t* session) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->shutdown(session); +} + +inline media_lib_error_t media_lib_session_destroy(media_lib_session_t* session) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->destroy(session); +} + +/* Buffer management - Library-owned mode */ +inline media_lib_error_t media_lib_buffer_get( + media_lib_session_t* session, + media_lib_buffer_t** buffer, + uint32_t timeout_ms +) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->buffer_get(session, buffer, timeout_ms); +} + +inline media_lib_error_t media_lib_buffer_put( + media_lib_session_t* session, + media_lib_buffer_t* buffer +) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->buffer_put(session, buffer); +} + +/* DMA memory management - User-owned mode */ +inline media_lib_error_t media_lib_mem_register( + media_lib_session_t* session, + void* data, + size_t size, + mtl_dma_mem_handle** dma_mem +) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->mem_register(session, data, size, dma_mem); +} + +inline media_lib_error_t media_lib_mem_unregister( + media_lib_session_t* session, + mtl_dma_mem_handle* dma_mem +) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->mem_unregister(session, dma_mem); +} + +/* Zero-copy buffer operations - App-owned mode */ +inline media_lib_error_t media_lib_buffer_post( + media_lib_session_t* session, + void* data, + size_t size, + void* app_ctx +) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->buffer_post(session, data, size, app_ctx); +} + +inline media_lib_error_t media_lib_buffers_flush( + media_lib_session_t* session, + uint32_t timeout_ms +) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->buffers_flush(session, timeout_ms); +} + +/* Polling interface */ +inline media_lib_error_t media_lib_event_poll( + media_lib_session_t* session, + media_lib_event_t* event, + uint32_t timeout_ms +) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->event_poll(session, event, timeout_ms); +} + +/* Statistics and monitoring */ +inline media_lib_error_t media_lib_stats_get( + media_lib_session_t* session, + media_lib_session_stats_t* stats +) { + if (!session) return MEDIA_LIB_ERROR_INVALID_PARAMETER; + media_lib_session_vtable_t* vtable = (media_lib_session_vtable_t*)session; + return vtable->stats_get(session, stats); +} + +#ifdef __cplusplus +} +#endif + +#endif /* MEDIA_LIB_API_H */