FreeRDP
Loading...
Searching...
No Matches
tsmf_media.c
1
23#include <freerdp/config.h>
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <signal.h>
29
30#ifndef _WIN32
31#include <sys/time.h>
32#endif
33
34#include <winpr/crt.h>
35#include <winpr/synch.h>
36#include <winpr/string.h>
37#include <winpr/thread.h>
38#include <winpr/stream.h>
39#include <winpr/collections.h>
40
41#include <freerdp/freerdp.h>
42#include <freerdp/client/tsmf.h>
43
44#include "tsmf_constants.h"
45#include "tsmf_types.h"
46#include "tsmf_decoder.h"
47#include "tsmf_audio.h"
48#include "tsmf_main.h"
49#include "tsmf_codec.h"
50#include "tsmf_media.h"
51
52#define AUDIO_TOLERANCE 10000000LL
53
54/* 1 second = 10,000,000 100ns units*/
55#define VIDEO_ADJUST_MAX (10ULL * 1000ULL * 1000ULL)
56
57#define MAX_ACK_TIME 666667
58
59#define AUDIO_MIN_BUFFER_LEVEL 3
60#define AUDIO_MAX_BUFFER_LEVEL 6
61
62#define VIDEO_MIN_BUFFER_LEVEL 10
63#define VIDEO_MAX_BUFFER_LEVEL 30
64
65struct S_TSMF_PRESENTATION
66{
67 BYTE presentation_id[GUID_SIZE];
68
69 const char* audio_name;
70 const char* audio_device;
71
72 IWTSVirtualChannelCallback* channel_callback;
73
74 UINT64 audio_start_time;
75 UINT64 audio_end_time;
76
77 UINT32 volume;
78 UINT32 muted;
79
80 wArrayList* stream_list;
81
82 RECTANGLE_32 rect;
83
84 UINT32 nr_rects;
85 RECTANGLE_32* rects;
86};
87
88struct S_TSMF_STREAM
89{
90 UINT32 stream_id;
91
92 TSMF_PRESENTATION* presentation;
93
94 ITSMFDecoder* decoder;
95
96 int major_type;
97 int eos;
98 UINT32 eos_message_id;
99 IWTSVirtualChannelCallback* eos_channel_callback;
100 int delayed_stop;
101 UINT32 width;
102 UINT32 height;
103
104 ITSMFAudioDevice* audio;
105 UINT32 sample_rate;
106 UINT32 channels;
107 UINT32 bits_per_sample;
108
109 /* The start time of last played sample */
110 UINT64 last_start_time;
111 /* The end_time of last played sample */
112 UINT64 last_end_time;
113 /* Next sample should not start before this system time. */
114 UINT64 next_start_time;
115
116 UINT32 minBufferLevel;
117 UINT32 maxBufferLevel;
118 UINT32 currentBufferLevel;
119
120 HANDLE play_thread;
121 HANDLE ack_thread;
122 HANDLE stopEvent;
123 HANDLE ready;
124
125 wQueue* sample_list;
126 wQueue* sample_ack_list;
127 rdpContext* rdpcontext;
128
129 BOOL seeking;
130};
131
132struct S_TSMF_SAMPLE
133{
134 UINT32 sample_id;
135 UINT64 start_time;
136 UINT64 end_time;
137 UINT64 duration;
138 UINT32 extensions;
139 UINT32 data_size;
140 BYTE* data;
141 UINT32 decoded_size;
142 UINT32 pixfmt;
143
144 BOOL invalidTimestamps;
145
146 TSMF_STREAM* stream;
147 IWTSVirtualChannelCallback* channel_callback;
148 UINT64 ack_time;
149};
150
151static wArrayList* presentation_list = NULL;
152static int TERMINATING = 0;
153
154static void s_tsmf_presentation_free(void* obj);
155static void s_tsmf_stream_free(void* obj);
156
157static UINT64 get_current_time(void)
158{
159 struct timeval tp;
160 gettimeofday(&tp, 0);
161 return ((UINT64)tp.tv_sec) * 10000000LL + ((UINT64)tp.tv_usec) * 10LL;
162}
163
164static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
165{
166 TSMF_SAMPLE* sample = NULL;
167 BOOL pending = FALSE;
168
169 if (!stream)
170 return NULL;
171
172 TSMF_PRESENTATION* presentation = stream->presentation;
173
174 if (Queue_Count(stream->sample_list) < 1)
175 return NULL;
176
177 if (sync)
178 {
179 if (stream->decoder)
180 {
181 if (stream->decoder->GetDecodedData)
182 {
183 if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO)
184 {
185 /* Check if some other stream has earlier sample that needs to be played first
186 */
187 /* Start time is more reliable than end time as some stream types seem to have
188 * incorrect end times from the server
189 */
190 if (stream->last_start_time > AUDIO_TOLERANCE)
191 {
192 ArrayList_Lock(presentation->stream_list);
193 const size_t count = ArrayList_Count(presentation->stream_list);
194
195 for (size_t index = 0; index < count; index++)
196 {
197 TSMF_STREAM* s =
198 (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
199
200 /* Start time is more reliable than end time as some stream types seem
201 * to have incorrect end times from the server
202 */
203 if (s != stream && !s->eos && s->last_start_time &&
204 s->last_start_time < stream->last_start_time - AUDIO_TOLERANCE)
205 {
206 DEBUG_TSMF("Pending due to audio tolerance");
207 pending = TRUE;
208 break;
209 }
210 }
211
212 ArrayList_Unlock(presentation->stream_list);
213 }
214 }
215 else
216 {
217 /* Start time is more reliable than end time as some stream types seem to have
218 * incorrect end times from the server
219 */
220 if (stream->last_start_time > presentation->audio_start_time)
221 {
222 DEBUG_TSMF("Pending due to stream start time > audio start time");
223 pending = TRUE;
224 }
225 }
226 }
227 }
228 }
229
230 if (pending)
231 return NULL;
232
233 sample = (TSMF_SAMPLE*)Queue_Dequeue(stream->sample_list);
234
235 /* Only update stream last end time if the sample end time is valid and greater than the current
236 * stream end time */
237 if (sample && (sample->end_time > stream->last_end_time) && (!sample->invalidTimestamps))
238 stream->last_end_time = sample->end_time;
239
240 /* Only update stream last start time if the sample start time is valid and greater than the
241 * current stream start time */
242 if (sample && (sample->start_time > stream->last_start_time) && (!sample->invalidTimestamps))
243 stream->last_start_time = sample->start_time;
244
245 return sample;
246}
247
248static void tsmf_sample_free(void* arg)
249{
250 TSMF_SAMPLE* sample = arg;
251
252 if (!sample)
253 return;
254
255 free(sample->data);
256 free(sample);
257}
258
259static BOOL tsmf_sample_ack(TSMF_SAMPLE* sample)
260{
261 if (!sample)
262 return FALSE;
263
264 return tsmf_playback_ack(sample->channel_callback, sample->sample_id, sample->duration,
265 sample->data_size);
266}
267
268static BOOL tsmf_sample_queue_ack(TSMF_SAMPLE* sample)
269{
270 if (!sample)
271 return FALSE;
272
273 if (!sample->stream)
274 return FALSE;
275
276 return Queue_Enqueue(sample->stream->sample_ack_list, sample);
277}
278
279/* Returns TRUE if no more samples are currently available
280 * Returns FALSE otherwise
281 */
282static BOOL tsmf_stream_process_ack(void* arg, BOOL force)
283{
284 TSMF_STREAM* stream = arg;
285 TSMF_SAMPLE* sample = NULL;
286 UINT64 ack_time = 0;
287 BOOL rc = FALSE;
288
289 if (!stream)
290 return TRUE;
291
292 Queue_Lock(stream->sample_ack_list);
293 sample = (TSMF_SAMPLE*)Queue_Peek(stream->sample_ack_list);
294
295 if (!sample)
296 {
297 rc = TRUE;
298 goto finally;
299 }
300
301 if (!force)
302 {
303 /* Do some min/max ack limiting if we have access to Buffer level information */
304 if (stream->decoder && stream->decoder->BufferLevel)
305 {
306 /* Try to keep buffer level below max by withholding acks */
307 if (stream->currentBufferLevel > stream->maxBufferLevel)
308 goto finally;
309 /* Try to keep buffer level above min by pushing acks through quickly */
310 else if (stream->currentBufferLevel < stream->minBufferLevel)
311 goto dequeue;
312 }
313
314 /* Time based acks only */
315 ack_time = get_current_time();
316
317 if (sample->ack_time > ack_time)
318 goto finally;
319 }
320
321dequeue:
322 sample = Queue_Dequeue(stream->sample_ack_list);
323
324 if (sample)
325 {
326 tsmf_sample_ack(sample);
327 tsmf_sample_free(sample);
328 }
329
330finally:
331 Queue_Unlock(stream->sample_ack_list);
332 return rc;
333}
334
335TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid,
336 IWTSVirtualChannelCallback* pChannelCallback)
337{
338 wObject* obj = NULL;
339 TSMF_PRESENTATION* presentation = NULL;
340
341 if (!guid || !pChannelCallback)
342 return NULL;
343
344 presentation = (TSMF_PRESENTATION*)calloc(1, sizeof(TSMF_PRESENTATION));
345
346 if (!presentation)
347 {
348 WLog_ERR(TAG, "calloc failed");
349 return NULL;
350 }
351
352 CopyMemory(presentation->presentation_id, guid, GUID_SIZE);
353 presentation->channel_callback = pChannelCallback;
354 presentation->volume = 5000; /* 50% */
355 presentation->muted = 0;
356
357 if (!(presentation->stream_list = ArrayList_New(TRUE)))
358 goto error_stream_list;
359
360 obj = ArrayList_Object(presentation->stream_list);
361 if (!obj)
362 goto error_add;
363 obj->fnObjectFree = s_tsmf_stream_free;
364
365 if (!ArrayList_Append(presentation_list, presentation))
366 goto error_add;
367
368 return presentation;
369error_add:
370 ArrayList_Free(presentation->stream_list);
371error_stream_list:
372 free(presentation);
373 return NULL;
374}
375
376static char* guid_to_string(const BYTE* guid, char* str, size_t len)
377{
378 if (!guid || !str)
379 return NULL;
380
381 for (size_t i = 0; i < GUID_SIZE && (len > 2 * i); i++)
382 (void)sprintf_s(str + (2 * i), len - 2 * i, "%02" PRIX8 "", guid[i]);
383
384 return str;
385}
386
387TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid)
388{
389 BOOL found = FALSE;
390 char guid_str[GUID_SIZE * 2 + 1] = { 0 };
391 TSMF_PRESENTATION* presentation = NULL;
392 ArrayList_Lock(presentation_list);
393 const size_t count = ArrayList_Count(presentation_list);
394
395 for (size_t index = 0; index < count; index++)
396 {
397 presentation = (TSMF_PRESENTATION*)ArrayList_GetItem(presentation_list, index);
398
399 if (memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0)
400 {
401 found = TRUE;
402 break;
403 }
404 }
405
406 ArrayList_Unlock(presentation_list);
407
408 if (!found)
409 WLog_WARN(TAG, "presentation id %s not found",
410 guid_to_string(guid, guid_str, sizeof(guid_str)));
411
412 return (found) ? presentation : NULL;
413}
414
415static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample)
416{
417 WINPR_ASSERT(sample);
418
419 TSMF_STREAM* stream = sample->stream;
420 TSMF_PRESENTATION* presentation = stream->presentation;
421 TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)sample->channel_callback;
422 TsmfClientContext* tsmf = (TsmfClientContext*)callback->plugin->pInterface;
423 DEBUG_TSMF("MessageId %" PRIu32 " EndTime %" PRIu64 " data_size %" PRIu32 " consumed.",
424 sample->sample_id, sample->end_time, sample->data_size);
425
426 if (sample->data)
427 {
428 const UINT64 t = get_current_time();
429
430 /* Start time is more reliable than end time as some stream types seem to have incorrect
431 * end times from the server
432 */
433 if (stream->next_start_time > t &&
434 ((sample->start_time >= presentation->audio_start_time) ||
435 ((sample->start_time < stream->last_start_time) && (!sample->invalidTimestamps))))
436 {
437 size_t delay = (stream->next_start_time - t) / 10;
438 while (delay > 0)
439 {
440 const UINT32 d = (delay > UINT32_MAX) ? UINT32_MAX : (UINT32)delay;
441 USleep(d);
442 delay -= d;
443 }
444 }
445
446 if (sample->stream->width > INT16_MAX)
447 return FALSE;
448 if (sample->stream->height > INT16_MAX)
449 return FALSE;
450 if (presentation->rect.left > INT16_MAX)
451 return FALSE;
452 if (presentation->rect.top > INT16_MAX)
453 return FALSE;
454 if (presentation->rect.width > INT16_MAX)
455 return FALSE;
456 if (presentation->rect.height > INT16_MAX)
457 return FALSE;
458 if (presentation->nr_rects > UINT16_MAX)
459 return FALSE;
460
461 stream->next_start_time = t + sample->duration - 50000;
462
463 TSMF_VIDEO_FRAME_EVENT event = { 0 };
464 event.frameData = sample->data;
465 event.frameSize = sample->decoded_size;
466 event.framePixFmt = sample->pixfmt;
467 event.frameWidth = (INT16)sample->stream->width;
468 event.frameHeight = (INT16)sample->stream->height;
469 event.x = (INT16)presentation->rect.left;
470 event.y = (INT16)presentation->rect.top;
471 event.width = (INT16)presentation->rect.width;
472 event.height = (INT16)presentation->rect.height;
473
474 if (presentation->nr_rects > 0)
475 {
476 event.numVisibleRects = (UINT16)presentation->nr_rects;
477 event.visibleRects = (RECTANGLE_16*)calloc(event.numVisibleRects, sizeof(RECTANGLE_16));
478
479 if (!event.visibleRects)
480 {
481 WLog_ERR(TAG, "can't allocate memory for copy rectangles");
482 return FALSE;
483 }
484
485 for (size_t x = 0; x < presentation->nr_rects; x++)
486 {
487 const RECTANGLE_32* cur = &presentation->rects[x];
488 RECTANGLE_16* dst = &event.visibleRects[x];
489 if ((cur->left > UINT16_MAX) || (cur->top > UINT16_MAX) ||
490 (cur->width > UINT16_MAX) || (cur->height > UINT16_MAX))
491 {
492 free(event.visibleRects);
493 return FALSE;
494 }
495 dst->right = dst->left = (UINT16)cur->left;
496 dst->bottom = dst->top = (UINT16)cur->top;
497 dst->right += (UINT16)cur->width;
498 dst->bottom += (UINT16)cur->height;
499 }
500 memcpy(event.visibleRects, presentation->rects,
501 presentation->nr_rects * sizeof(RECTANGLE_16));
502 presentation->nr_rects = 0;
503 }
504
505 /* The frame data ownership is passed to the event object, and is freed after the event is
506 * processed. */
507 sample->data = NULL;
508 sample->decoded_size = 0;
509
510 if (tsmf->FrameEvent)
511 tsmf->FrameEvent(tsmf, &event);
512
513 free(event.frameData);
514 free(event.visibleRects);
515 }
516
517 return TRUE;
518}
519
520static BOOL tsmf_sample_playback_audio(TSMF_SAMPLE* sample)
521{
522 UINT64 latency = 0;
523 TSMF_STREAM* stream = sample->stream;
524 BOOL ret = 0;
525 DEBUG_TSMF("MessageId %" PRIu32 " EndTime %" PRIu64 " consumed.", sample->sample_id,
526 sample->end_time);
527
528 if (stream->audio && sample->data)
529 {
530 ret =
531 sample->stream->audio->Play(sample->stream->audio, sample->data, sample->decoded_size);
532 free(sample->data);
533 sample->data = NULL;
534 sample->decoded_size = 0;
535
536 if (stream->audio->GetLatency)
537 latency = stream->audio->GetLatency(stream->audio);
538 }
539 else
540 {
541 ret = TRUE;
542 latency = 0;
543 }
544
545 sample->ack_time = latency + get_current_time();
546
547 /* Only update stream times if the sample timestamps are valid */
548 if (!sample->invalidTimestamps)
549 {
550 stream->last_start_time = sample->start_time + latency;
551 stream->last_end_time = sample->end_time + latency;
552 stream->presentation->audio_start_time = sample->start_time + latency;
553 stream->presentation->audio_end_time = sample->end_time + latency;
554 }
555
556 return ret;
557}
558
559static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample)
560{
561 BOOL ret = FALSE;
562 UINT32 width = 0;
563 UINT32 height = 0;
564 UINT32 pixfmt = 0;
565 TSMF_STREAM* stream = sample->stream;
566
567 if (stream->decoder)
568 {
569 if (stream->decoder->DecodeEx)
570 {
571 /* Try to "sync" video buffers to audio buffers by looking at the running time for each
572 * stream The difference between the two running times causes an offset between audio
573 * and video actual render times. So, we try to adjust timestamps on the video buffer to
574 * match those on the audio buffer.
575 */
576 if (stream->major_type == TSMF_MAJOR_TYPE_VIDEO)
577 {
578 TSMF_STREAM* temp_stream = NULL;
579 TSMF_PRESENTATION* presentation = stream->presentation;
580 ArrayList_Lock(presentation->stream_list);
581 const size_t count = ArrayList_Count(presentation->stream_list);
582
583 for (size_t index = 0; index < count; index++)
584 {
585 UINT64 time_diff = 0;
586 temp_stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
587
588 if (temp_stream->major_type == TSMF_MAJOR_TYPE_AUDIO)
589 {
590 UINT64 video_time = stream->decoder->GetRunningTime(stream->decoder);
591 UINT64 audio_time =
592 temp_stream->decoder->GetRunningTime(temp_stream->decoder);
593 UINT64 max_adjust = VIDEO_ADJUST_MAX;
594
595 if (video_time < audio_time)
596 max_adjust = -VIDEO_ADJUST_MAX;
597
598 if (video_time > audio_time)
599 time_diff = video_time - audio_time;
600 else
601 time_diff = audio_time - video_time;
602
603 time_diff = time_diff < VIDEO_ADJUST_MAX ? time_diff : max_adjust;
604 sample->start_time += time_diff;
605 sample->end_time += time_diff;
606 break;
607 }
608 }
609
610 ArrayList_Unlock(presentation->stream_list);
611 }
612
613 ret = stream->decoder->DecodeEx(stream->decoder, sample->data, sample->data_size,
614 sample->extensions, sample->start_time,
615 sample->end_time, sample->duration);
616 }
617 else
618 {
619 ret = stream->decoder->Decode(stream->decoder, sample->data, sample->data_size,
620 sample->extensions);
621 }
622 }
623
624 if (!ret)
625 {
626 WLog_ERR(TAG, "decode error, queue ack anyways");
627
628 if (!tsmf_sample_queue_ack(sample))
629 {
630 WLog_ERR(TAG, "error queuing sample for ack");
631 return FALSE;
632 }
633
634 return TRUE;
635 }
636
637 free(sample->data);
638 sample->data = NULL;
639
640 if (stream->major_type == TSMF_MAJOR_TYPE_VIDEO)
641 {
642 if (stream->decoder->GetDecodedFormat)
643 {
644 pixfmt = stream->decoder->GetDecodedFormat(stream->decoder);
645
646 if (pixfmt == ((UINT32)-1))
647 {
648 WLog_ERR(TAG, "unable to decode video format");
649
650 if (!tsmf_sample_queue_ack(sample))
651 {
652 WLog_ERR(TAG, "error queuing sample for ack");
653 }
654
655 return FALSE;
656 }
657
658 sample->pixfmt = pixfmt;
659 }
660
661 if (stream->decoder->GetDecodedDimension)
662 {
663 ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height);
664
665 if (ret && (width != stream->width || height != stream->height))
666 {
667 DEBUG_TSMF("video dimension changed to %" PRIu32 " x %" PRIu32 "", width, height);
668 stream->width = width;
669 stream->height = height;
670 }
671 }
672 }
673
674 if (stream->decoder->GetDecodedData)
675 {
676 sample->data = stream->decoder->GetDecodedData(stream->decoder, &sample->decoded_size);
677
678 switch (sample->stream->major_type)
679 {
680 case TSMF_MAJOR_TYPE_VIDEO:
681 ret = tsmf_sample_playback_video(sample) && tsmf_sample_queue_ack(sample);
682 break;
683
684 case TSMF_MAJOR_TYPE_AUDIO:
685 ret = tsmf_sample_playback_audio(sample) && tsmf_sample_queue_ack(sample);
686 break;
687 default:
688 break;
689 }
690 }
691 else
692 {
693 UINT64 ack_anticipation_time = get_current_time();
694 BOOL buffer_filled = TRUE;
695
696 /* Classify the buffer as filled once it reaches minimum level */
697 if (stream->decoder->BufferLevel)
698 {
699 if (stream->currentBufferLevel < stream->minBufferLevel)
700 buffer_filled = FALSE;
701 }
702
703 ack_anticipation_time +=
704 (sample->duration / 2 < MAX_ACK_TIME) ? sample->duration / 2 : MAX_ACK_TIME;
705
706 switch (sample->stream->major_type)
707 {
708 case TSMF_MAJOR_TYPE_VIDEO:
709 {
710 break;
711 }
712
713 case TSMF_MAJOR_TYPE_AUDIO:
714 {
715 break;
716 }
717 default:
718 break;
719 }
720
721 sample->ack_time = ack_anticipation_time;
722
723 if (!tsmf_sample_queue_ack(sample))
724 {
725 WLog_ERR(TAG, "error queuing sample for ack");
726 ret = FALSE;
727 }
728 }
729
730 return ret;
731}
732
733static DWORD WINAPI tsmf_stream_ack_func(LPVOID arg)
734{
735 HANDLE hdl[2];
736 TSMF_STREAM* stream = (TSMF_STREAM*)arg;
737 UINT error = CHANNEL_RC_OK;
738 DEBUG_TSMF("in %" PRIu32 "", stream->stream_id);
739 hdl[0] = stream->stopEvent;
740 hdl[1] = Queue_Event(stream->sample_ack_list);
741
742 while (1)
743 {
744 DWORD ev = WaitForMultipleObjects(2, hdl, FALSE, 1000);
745
746 if (ev == WAIT_FAILED)
747 {
748 error = GetLastError();
749 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
750 break;
751 }
752
753 if (stream->decoder)
754 if (stream->decoder->BufferLevel)
755 stream->currentBufferLevel = stream->decoder->BufferLevel(stream->decoder);
756
757 if (stream->eos)
758 {
759 while ((stream->currentBufferLevel > 0) && !(tsmf_stream_process_ack(stream, TRUE)))
760 {
761 DEBUG_TSMF("END OF STREAM PROCESSING!");
762
763 if (stream->decoder && stream->decoder->BufferLevel)
764 stream->currentBufferLevel = stream->decoder->BufferLevel(stream->decoder);
765 else
766 stream->currentBufferLevel = 1;
767
768 USleep(1000);
769 }
770
771 tsmf_send_eos_response(stream->eos_channel_callback, stream->eos_message_id);
772 stream->eos = 0;
773
774 if (stream->delayed_stop)
775 {
776 DEBUG_TSMF("Finishing delayed stream stop, now that eos has processed.");
777 tsmf_stream_flush(stream);
778
779 if (stream->decoder && stream->decoder->Control)
780 stream->decoder->Control(stream->decoder, Control_Stop, NULL);
781 }
782 }
783
784 /* Stream stopped force all of the acks to happen */
785 if (ev == WAIT_OBJECT_0)
786 {
787 DEBUG_TSMF("ack: Stream stopped!");
788
789 while (1)
790 {
791 if (tsmf_stream_process_ack(stream, TRUE))
792 break;
793
794 USleep(1000);
795 }
796
797 break;
798 }
799
800 if (tsmf_stream_process_ack(stream, FALSE))
801 continue;
802
803 if (stream->currentBufferLevel > stream->minBufferLevel)
804 USleep(1000);
805 }
806
807 if (error && stream->rdpcontext)
808 setChannelError(stream->rdpcontext, error, "tsmf_stream_ack_func reported an error");
809
810 DEBUG_TSMF("out %" PRIu32 "", stream->stream_id);
811 ExitThread(error);
812 return error;
813}
814
815static DWORD WINAPI tsmf_stream_playback_func(LPVOID arg)
816{
817 HANDLE hdl[2];
818 TSMF_SAMPLE* sample = NULL;
819 TSMF_STREAM* stream = (TSMF_STREAM*)arg;
820 TSMF_PRESENTATION* presentation = stream->presentation;
821 UINT error = CHANNEL_RC_OK;
822 DWORD status = 0;
823 DEBUG_TSMF("in %" PRIu32 "", stream->stream_id);
824
825 if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO && stream->sample_rate && stream->channels &&
826 stream->bits_per_sample)
827 {
828 if (stream->decoder)
829 {
830 if (stream->decoder->GetDecodedData)
831 {
832 stream->audio = tsmf_load_audio_device(
833 presentation->audio_name && presentation->audio_name[0]
834 ? presentation->audio_name
835 : NULL,
836 presentation->audio_device && presentation->audio_device[0]
837 ? presentation->audio_device
838 : NULL);
839
840 if (stream->audio)
841 {
842 stream->audio->SetFormat(stream->audio, stream->sample_rate, stream->channels,
843 stream->bits_per_sample);
844 }
845 }
846 }
847 }
848
849 hdl[0] = stream->stopEvent;
850 hdl[1] = Queue_Event(stream->sample_list);
851
852 while (1)
853 {
854 status = WaitForMultipleObjects(2, hdl, FALSE, 1000);
855
856 if (status == WAIT_FAILED)
857 {
858 error = GetLastError();
859 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
860 break;
861 }
862
863 status = WaitForSingleObject(stream->stopEvent, 0);
864
865 if (status == WAIT_FAILED)
866 {
867 error = GetLastError();
868 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
869 break;
870 }
871
872 if (status == WAIT_OBJECT_0)
873 break;
874
875 if (stream->decoder)
876 if (stream->decoder->BufferLevel)
877 stream->currentBufferLevel = stream->decoder->BufferLevel(stream->decoder);
878
879 sample = tsmf_stream_pop_sample(stream, 0);
880
881 if (sample && !tsmf_sample_playback(sample))
882 {
883 WLog_ERR(TAG, "error playing sample");
884 error = ERROR_INTERNAL_ERROR;
885 break;
886 }
887
888 if (stream->currentBufferLevel > stream->minBufferLevel)
889 USleep(1000);
890 }
891
892 if (stream->audio)
893 {
894 stream->audio->Free(stream->audio);
895 stream->audio = NULL;
896 }
897
898 if (error && stream->rdpcontext)
899 setChannelError(stream->rdpcontext, error, "tsmf_stream_playback_func reported an error");
900
901 DEBUG_TSMF("out %" PRIu32 "", stream->stream_id);
902 ExitThread(error);
903 return error;
904}
905
906static BOOL tsmf_stream_start(TSMF_STREAM* stream)
907{
908 if (!stream || !stream->presentation || !stream->decoder || !stream->decoder->Control)
909 return TRUE;
910
911 stream->eos = 0;
912 return stream->decoder->Control(stream->decoder, Control_Restart, NULL);
913}
914
915static BOOL tsmf_stream_stop(TSMF_STREAM* stream)
916{
917 if (!stream || !stream->decoder || !stream->decoder->Control)
918 return TRUE;
919
920 /* If stopping after eos - we delay until the eos has been processed
921 * this allows us to process any buffers that have been acked even though
922 * they have not actually been completely processes by the decoder
923 */
924 if (stream->eos)
925 {
926 DEBUG_TSMF("Setting up a delayed stop for once the eos has been processed.");
927 stream->delayed_stop = 1;
928 return TRUE;
929 }
930 /* Otherwise force stop immediately */
931 else
932 {
933 DEBUG_TSMF("Stop with no pending eos response, so do it immediately.");
934 tsmf_stream_flush(stream);
935 return stream->decoder->Control(stream->decoder, Control_Stop, NULL);
936 }
937}
938
939static BOOL tsmf_stream_pause(TSMF_STREAM* stream)
940{
941 if (!stream || !stream->decoder || !stream->decoder->Control)
942 return TRUE;
943
944 return stream->decoder->Control(stream->decoder, Control_Pause, NULL);
945}
946
947static BOOL tsmf_stream_restart(TSMF_STREAM* stream)
948{
949 if (!stream || !stream->decoder || !stream->decoder->Control)
950 return TRUE;
951
952 stream->eos = 0;
953 return stream->decoder->Control(stream->decoder, Control_Restart, NULL);
954}
955
956static BOOL tsmf_stream_change_volume(TSMF_STREAM* stream, UINT32 newVolume, UINT32 muted)
957{
958 if (!stream || !stream->decoder)
959 return TRUE;
960
961 if (stream->decoder != NULL && stream->decoder->ChangeVolume)
962 {
963 return stream->decoder->ChangeVolume(stream->decoder, newVolume, muted);
964 }
965 else if (stream->audio != NULL && stream->audio->ChangeVolume)
966 {
967 return stream->audio->ChangeVolume(stream->audio, newVolume, muted);
968 }
969
970 return TRUE;
971}
972
973BOOL tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume,
974 UINT32 muted)
975{
976 TSMF_STREAM* stream = NULL;
977 BOOL ret = TRUE;
978 presentation->volume = newVolume;
979 presentation->muted = muted;
980 ArrayList_Lock(presentation->stream_list);
981 size_t count = ArrayList_Count(presentation->stream_list);
982
983 for (size_t index = 0; index < count; index++)
984 {
985 stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
986 ret &= tsmf_stream_change_volume(stream, newVolume, muted);
987 }
988
989 ArrayList_Unlock(presentation->stream_list);
990 return ret;
991}
992
993BOOL tsmf_presentation_paused(TSMF_PRESENTATION* presentation)
994{
995 TSMF_STREAM* stream = NULL;
996 BOOL ret = TRUE;
997 ArrayList_Lock(presentation->stream_list);
998 size_t count = ArrayList_Count(presentation->stream_list);
999
1000 for (size_t index = 0; index < count; index++)
1001 {
1002 stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
1003 ret &= tsmf_stream_pause(stream);
1004 }
1005
1006 ArrayList_Unlock(presentation->stream_list);
1007 return ret;
1008}
1009
1010BOOL tsmf_presentation_restarted(TSMF_PRESENTATION* presentation)
1011{
1012 TSMF_STREAM* stream = NULL;
1013 BOOL ret = TRUE;
1014 ArrayList_Lock(presentation->stream_list);
1015 size_t count = ArrayList_Count(presentation->stream_list);
1016
1017 for (size_t index = 0; index < count; index++)
1018 {
1019 stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
1020 ret &= tsmf_stream_restart(stream);
1021 }
1022
1023 ArrayList_Unlock(presentation->stream_list);
1024 return ret;
1025}
1026
1027BOOL tsmf_presentation_start(TSMF_PRESENTATION* presentation)
1028{
1029 TSMF_STREAM* stream = NULL;
1030 BOOL ret = TRUE;
1031 ArrayList_Lock(presentation->stream_list);
1032 size_t count = ArrayList_Count(presentation->stream_list);
1033
1034 for (size_t index = 0; index < count; index++)
1035 {
1036 stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
1037 ret &= tsmf_stream_start(stream);
1038 }
1039
1040 ArrayList_Unlock(presentation->stream_list);
1041 return ret;
1042}
1043
1049UINT tsmf_presentation_sync(TSMF_PRESENTATION* presentation)
1050{
1051 UINT error = 0;
1052 ArrayList_Lock(presentation->stream_list);
1053 size_t count = ArrayList_Count(presentation->stream_list);
1054
1055 for (size_t index = 0; index < count; index++)
1056 {
1057 TSMF_STREAM* stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
1058
1059 if (WaitForSingleObject(stream->ready, 500) == WAIT_FAILED)
1060 {
1061 error = GetLastError();
1062 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
1063 return error;
1064 }
1065 }
1066
1067 ArrayList_Unlock(presentation->stream_list);
1068 return CHANNEL_RC_OK;
1069}
1070
1071BOOL tsmf_presentation_stop(TSMF_PRESENTATION* presentation)
1072{
1073 TSMF_STREAM* stream = NULL;
1074 BOOL ret = TRUE;
1075 ArrayList_Lock(presentation->stream_list);
1076 size_t count = ArrayList_Count(presentation->stream_list);
1077
1078 for (size_t index = 0; index < count; index++)
1079 {
1080 stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
1081 ret &= tsmf_stream_stop(stream);
1082 }
1083
1084 ArrayList_Unlock(presentation->stream_list);
1085 presentation->audio_start_time = 0;
1086 presentation->audio_end_time = 0;
1087 return ret;
1088}
1089
1090BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, UINT32 x, UINT32 y,
1091 UINT32 width, UINT32 height, UINT32 num_rects,
1092 const RECTANGLE_32* rects)
1093{
1094 TSMF_STREAM* stream = NULL;
1095 BOOL ret = TRUE;
1096
1097 /* The server may send messages with invalid width / height.
1098 * Ignore those messages. */
1099 if (!width || !height)
1100 return TRUE;
1101
1102 /* Streams can be added/removed from the presentation and the server will resend geometry info
1103 * when a new stream is added to the presentation. Also, num_rects is used to indicate whether
1104 * or not the window is visible. So, always process a valid message with unchanged position/size
1105 * and/or no visibility rects.
1106 */
1107 presentation->rect.left = x;
1108 presentation->rect.top = y;
1109 presentation->rect.width = width;
1110 presentation->rect.height = height;
1111 void* tmp_rects = realloc(presentation->rects, sizeof(RECTANGLE_32) * num_rects);
1112
1113 if (!tmp_rects && num_rects)
1114 return FALSE;
1115
1116 presentation->nr_rects = num_rects;
1117 presentation->rects = (RECTANGLE_32*)tmp_rects;
1118 if (presentation->rects)
1119 CopyMemory(presentation->rects, rects, sizeof(RECTANGLE_32) * num_rects);
1120 ArrayList_Lock(presentation->stream_list);
1121 size_t count = ArrayList_Count(presentation->stream_list);
1122
1123 for (size_t index = 0; index < count; index++)
1124 {
1125 stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
1126
1127 if (!stream->decoder)
1128 continue;
1129
1130 if (stream->decoder->UpdateRenderingArea)
1131 {
1132 ret = stream->decoder->UpdateRenderingArea(stream->decoder, x, y, width, height,
1133 num_rects, rects);
1134 }
1135 }
1136
1137 ArrayList_Unlock(presentation->stream_list);
1138 return ret;
1139}
1140
1141void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, const char* name,
1142 const char* device)
1143{
1144 presentation->audio_name = name;
1145 presentation->audio_device = device;
1146}
1147
1148BOOL tsmf_stream_flush(TSMF_STREAM* stream)
1149{
1150 BOOL ret = TRUE;
1151
1152 // TSMF_SAMPLE* sample;
1153 /* TODO: free lists */
1154 if (stream->audio)
1155 ret = stream->audio->Flush(stream->audio);
1156
1157 stream->eos = 0;
1158 stream->eos_message_id = 0;
1159 stream->eos_channel_callback = NULL;
1160 stream->delayed_stop = 0;
1161 stream->last_end_time = 0;
1162 stream->next_start_time = 0;
1163
1164 if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO)
1165 {
1166 stream->presentation->audio_start_time = 0;
1167 stream->presentation->audio_end_time = 0;
1168 }
1169
1170 return ret;
1171}
1172
1173void s_tsmf_presentation_free(void* obj)
1174{
1175 TSMF_PRESENTATION* presentation = (TSMF_PRESENTATION*)obj;
1176
1177 if (presentation)
1178 {
1179 tsmf_presentation_stop(presentation);
1180 ArrayList_Clear(presentation->stream_list);
1181 ArrayList_Free(presentation->stream_list);
1182 free(presentation->rects);
1183 ZeroMemory(presentation, sizeof(TSMF_PRESENTATION));
1184 free(presentation);
1185 }
1186}
1187
1188void tsmf_presentation_free(TSMF_PRESENTATION* presentation)
1189{
1190 ArrayList_Remove(presentation_list, presentation);
1191}
1192
1193TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id,
1194 rdpContext* rdpcontext)
1195{
1196 wObject* obj = NULL;
1197 TSMF_STREAM* stream = NULL;
1198 stream = tsmf_stream_find_by_id(presentation, stream_id);
1199
1200 if (stream)
1201 {
1202 WLog_ERR(TAG, "duplicated stream id %" PRIu32 "!", stream_id);
1203 return NULL;
1204 }
1205
1206 stream = (TSMF_STREAM*)calloc(1, sizeof(TSMF_STREAM));
1207
1208 if (!stream)
1209 {
1210 WLog_ERR(TAG, "Calloc failed");
1211 return NULL;
1212 }
1213
1214 stream->minBufferLevel = VIDEO_MIN_BUFFER_LEVEL;
1215 stream->maxBufferLevel = VIDEO_MAX_BUFFER_LEVEL;
1216 stream->currentBufferLevel = 1;
1217 stream->seeking = FALSE;
1218 stream->eos = 0;
1219 stream->eos_message_id = 0;
1220 stream->eos_channel_callback = NULL;
1221 stream->stream_id = stream_id;
1222 stream->presentation = presentation;
1223 stream->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1224
1225 if (!stream->stopEvent)
1226 goto error_stopEvent;
1227
1228 stream->ready = CreateEvent(NULL, TRUE, TRUE, NULL);
1229
1230 if (!stream->ready)
1231 goto error_ready;
1232
1233 stream->sample_list = Queue_New(TRUE, -1, -1);
1234
1235 if (!stream->sample_list)
1236 goto error_sample_list;
1237
1238 obj = Queue_Object(stream->sample_list);
1239 if (!obj)
1240 goto error_sample_ack_list;
1241 obj->fnObjectFree = tsmf_sample_free;
1242
1243 stream->sample_ack_list = Queue_New(TRUE, -1, -1);
1244
1245 if (!stream->sample_ack_list)
1246 goto error_sample_ack_list;
1247
1248 obj = Queue_Object(stream->sample_ack_list);
1249 if (!obj)
1250 goto error_play_thread;
1251 obj->fnObjectFree = tsmf_sample_free;
1252
1253 stream->play_thread =
1254 CreateThread(NULL, 0, tsmf_stream_playback_func, stream, CREATE_SUSPENDED, NULL);
1255
1256 if (!stream->play_thread)
1257 goto error_play_thread;
1258
1259 stream->ack_thread =
1260 CreateThread(NULL, 0, tsmf_stream_ack_func, stream, CREATE_SUSPENDED, NULL);
1261
1262 if (!stream->ack_thread)
1263 goto error_ack_thread;
1264
1265 if (!ArrayList_Append(presentation->stream_list, stream))
1266 goto error_add;
1267
1268 stream->rdpcontext = rdpcontext;
1269 return stream;
1270error_add:
1271 (void)SetEvent(stream->stopEvent);
1272
1273 if (WaitForSingleObject(stream->ack_thread, INFINITE) == WAIT_FAILED)
1274 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
1275
1276error_ack_thread:
1277 (void)SetEvent(stream->stopEvent);
1278
1279 if (WaitForSingleObject(stream->play_thread, INFINITE) == WAIT_FAILED)
1280 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
1281
1282error_play_thread:
1283 Queue_Free(stream->sample_ack_list);
1284error_sample_ack_list:
1285 Queue_Free(stream->sample_list);
1286error_sample_list:
1287 (void)CloseHandle(stream->ready);
1288error_ready:
1289 (void)CloseHandle(stream->stopEvent);
1290error_stopEvent:
1291 free(stream);
1292 return NULL;
1293}
1294
1295void tsmf_stream_start_threads(TSMF_STREAM* stream)
1296{
1297 ResumeThread(stream->play_thread);
1298 ResumeThread(stream->ack_thread);
1299}
1300
1301TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id)
1302{
1303 BOOL found = FALSE;
1304 TSMF_STREAM* stream = NULL;
1305 ArrayList_Lock(presentation->stream_list);
1306 size_t count = ArrayList_Count(presentation->stream_list);
1307
1308 for (size_t index = 0; index < count; index++)
1309 {
1310 stream = (TSMF_STREAM*)ArrayList_GetItem(presentation->stream_list, index);
1311
1312 if (stream->stream_id == stream_id)
1313 {
1314 found = TRUE;
1315 break;
1316 }
1317 }
1318
1319 ArrayList_Unlock(presentation->stream_list);
1320 return (found) ? stream : NULL;
1321}
1322
1323static void tsmf_stream_resync(void* arg)
1324{
1325 TSMF_STREAM* stream = arg;
1326 (void)ResetEvent(stream->ready);
1327}
1328
1329BOOL tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s)
1330{
1331 TS_AM_MEDIA_TYPE mediatype;
1332 BOOL ret = TRUE;
1333
1334 if (stream->decoder)
1335 {
1336 WLog_ERR(TAG, "duplicated call");
1337 return FALSE;
1338 }
1339
1340 if (!tsmf_codec_parse_media_type(&mediatype, s))
1341 {
1342 WLog_ERR(TAG, "unable to parse media type");
1343 return FALSE;
1344 }
1345
1346 if (mediatype.MajorType == TSMF_MAJOR_TYPE_VIDEO)
1347 {
1348 DEBUG_TSMF("video width %" PRIu32 " height %" PRIu32 " bit_rate %" PRIu32
1349 " frame_rate %f codec_data %" PRIu32 "",
1350 mediatype.Width, mediatype.Height, mediatype.BitRate,
1351 (double)mediatype.SamplesPerSecond.Numerator /
1352 (double)mediatype.SamplesPerSecond.Denominator,
1353 mediatype.ExtraDataSize);
1354 stream->minBufferLevel = VIDEO_MIN_BUFFER_LEVEL;
1355 stream->maxBufferLevel = VIDEO_MAX_BUFFER_LEVEL;
1356 }
1357 else if (mediatype.MajorType == TSMF_MAJOR_TYPE_AUDIO)
1358 {
1359 DEBUG_TSMF("audio channel %" PRIu32 " sample_rate %" PRIu32 " bits_per_sample %" PRIu32
1360 " codec_data %" PRIu32 "",
1361 mediatype.Channels, mediatype.SamplesPerSecond.Numerator,
1362 mediatype.BitsPerSample, mediatype.ExtraDataSize);
1363 stream->sample_rate = mediatype.SamplesPerSecond.Numerator;
1364 stream->channels = mediatype.Channels;
1365 stream->bits_per_sample = mediatype.BitsPerSample;
1366
1367 if (stream->bits_per_sample == 0)
1368 stream->bits_per_sample = 16;
1369
1370 stream->minBufferLevel = AUDIO_MIN_BUFFER_LEVEL;
1371 stream->maxBufferLevel = AUDIO_MAX_BUFFER_LEVEL;
1372 }
1373
1374 stream->major_type = mediatype.MajorType;
1375 stream->width = mediatype.Width;
1376 stream->height = mediatype.Height;
1377 stream->decoder = tsmf_load_decoder(name, &mediatype);
1378 ret &= tsmf_stream_change_volume(stream, stream->presentation->volume,
1379 stream->presentation->muted);
1380
1381 if (!stream->decoder)
1382 return FALSE;
1383
1384 if (stream->decoder->SetAckFunc)
1385 ret &= stream->decoder->SetAckFunc(stream->decoder, tsmf_stream_process_ack, stream);
1386
1387 if (stream->decoder->SetSyncFunc)
1388 ret &= stream->decoder->SetSyncFunc(stream->decoder, tsmf_stream_resync, stream);
1389
1390 return ret;
1391}
1392
1393void tsmf_stream_end(TSMF_STREAM* stream, UINT32 message_id,
1394 IWTSVirtualChannelCallback* pChannelCallback)
1395{
1396 if (!stream)
1397 return;
1398
1399 stream->eos = 1;
1400 stream->eos_message_id = message_id;
1401 stream->eos_channel_callback = pChannelCallback;
1402}
1403
1404void s_tsmf_stream_free(void* obj)
1405{
1406 TSMF_STREAM* stream = (TSMF_STREAM*)obj;
1407
1408 if (!stream)
1409 return;
1410
1411 tsmf_stream_stop(stream);
1412 (void)SetEvent(stream->stopEvent);
1413
1414 if (stream->play_thread)
1415 {
1416 if (WaitForSingleObject(stream->play_thread, INFINITE) == WAIT_FAILED)
1417 {
1418 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
1419 return;
1420 }
1421
1422 (void)CloseHandle(stream->play_thread);
1423 stream->play_thread = NULL;
1424 }
1425
1426 if (stream->ack_thread)
1427 {
1428 if (WaitForSingleObject(stream->ack_thread, INFINITE) == WAIT_FAILED)
1429 {
1430 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
1431 return;
1432 }
1433
1434 (void)CloseHandle(stream->ack_thread);
1435 stream->ack_thread = NULL;
1436 }
1437
1438 Queue_Free(stream->sample_list);
1439 Queue_Free(stream->sample_ack_list);
1440
1441 if (stream->decoder && stream->decoder->Free)
1442 {
1443 stream->decoder->Free(stream->decoder);
1444 stream->decoder = NULL;
1445 }
1446
1447 (void)CloseHandle(stream->stopEvent);
1448 (void)CloseHandle(stream->ready);
1449 ZeroMemory(stream, sizeof(TSMF_STREAM));
1450 free(stream);
1451}
1452
1453void tsmf_stream_free(TSMF_STREAM* stream)
1454{
1455 TSMF_PRESENTATION* presentation = stream->presentation;
1456 ArrayList_Remove(presentation->stream_list, stream);
1457}
1458
1459BOOL tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pChannelCallback,
1460 UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration,
1461 UINT32 extensions, UINT32 data_size, BYTE* data)
1462{
1463 TSMF_SAMPLE* sample = NULL;
1464 (void)SetEvent(stream->ready);
1465
1466 if (TERMINATING)
1467 return TRUE;
1468
1469 sample = (TSMF_SAMPLE*)calloc(1, sizeof(TSMF_SAMPLE));
1470
1471 if (!sample)
1472 {
1473 WLog_ERR(TAG, "calloc sample failed!");
1474 return FALSE;
1475 }
1476
1477 sample->sample_id = sample_id;
1478 sample->start_time = start_time;
1479 sample->end_time = end_time;
1480 sample->duration = duration;
1481 sample->extensions = extensions;
1482
1483 if ((sample->extensions & 0x00000080) || (sample->extensions & 0x00000040))
1484 sample->invalidTimestamps = TRUE;
1485 else
1486 sample->invalidTimestamps = FALSE;
1487
1488 sample->stream = stream;
1489 sample->channel_callback = pChannelCallback;
1490 sample->data_size = data_size;
1491 sample->data = calloc(1, data_size + TSMF_BUFFER_PADDING_SIZE);
1492
1493 if (!sample->data)
1494 goto fail;
1495
1496 CopyMemory(sample->data, data, data_size);
1497 if (!Queue_Enqueue(stream->sample_list, sample))
1498 goto fail;
1499
1500 return TRUE;
1501
1502fail:
1503 if (sample)
1504 free(sample->data);
1505 free(sample);
1506 return FALSE;
1507}
1508
1509#ifndef _WIN32
1510
1511static void tsmf_signal_handler(int s)
1512{
1513 TERMINATING = 1;
1514 ArrayList_Free(presentation_list);
1515
1516 if (s == SIGINT)
1517 {
1518 (void)signal(s, SIG_DFL);
1519 kill(getpid(), s);
1520 }
1521 else if (s == SIGUSR1)
1522 {
1523 (void)signal(s, SIG_DFL);
1524 }
1525}
1526
1527#endif
1528
1529BOOL tsmf_media_init(void)
1530{
1531 wObject* obj = NULL;
1532#ifndef _WIN32
1533 struct sigaction sigtrap;
1534 sigtrap.sa_handler = tsmf_signal_handler;
1535 sigemptyset(&sigtrap.sa_mask);
1536 sigtrap.sa_flags = 0;
1537 sigaction(SIGINT, &sigtrap, 0);
1538 sigaction(SIGUSR1, &sigtrap, 0);
1539#endif
1540
1541 if (!presentation_list)
1542 {
1543 presentation_list = ArrayList_New(TRUE);
1544
1545 if (!presentation_list)
1546 return FALSE;
1547
1548 obj = ArrayList_Object(presentation_list);
1549 if (!obj)
1550 return FALSE;
1551 obj->fnObjectFree = s_tsmf_presentation_free;
1552 }
1553
1554 return TRUE;
1555}
This struct contains function pointer to initialize/free objects.
Definition collections.h:57