40 |
40 |
41 #include "gstbaseaudiosrc.h" |
41 #include "gstbaseaudiosrc.h" |
42 |
42 |
43 #include "gst/gst-i18n-plugin.h" |
43 #include "gst/gst-i18n-plugin.h" |
44 |
44 |
45 #ifdef __SYMBIAN32__ |
|
46 #include <glib_global.h> |
|
47 #endif |
|
48 |
|
49 GST_DEBUG_CATEGORY_STATIC (gst_base_audio_src_debug); |
45 GST_DEBUG_CATEGORY_STATIC (gst_base_audio_src_debug); |
50 #define GST_CAT_DEFAULT gst_base_audio_src_debug |
46 #define GST_CAT_DEFAULT gst_base_audio_src_debug |
51 |
47 |
|
48 #ifdef __SYMBIAN32__ |
|
49 EXPORT_C |
|
50 #endif |
|
51 |
|
52 GType |
|
53 gst_base_audio_src_slave_method_get_type (void) |
|
54 { |
|
55 static GType slave_method_type = 0; |
|
56 static const GEnumValue slave_method[] = { |
|
57 {GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE, "Resampling slaving", "resample"}, |
|
58 {GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP, "Re-timestamp", "re-timestamp"}, |
|
59 {GST_BASE_AUDIO_SRC_SLAVE_SKEW, "Skew", "skew"}, |
|
60 {GST_BASE_AUDIO_SRC_SLAVE_NONE, "No slaving", "none"}, |
|
61 {0, NULL, NULL}, |
|
62 }; |
|
63 |
|
64 if (!slave_method_type) { |
|
65 slave_method_type = |
|
66 g_enum_register_static ("GstBaseAudioSrcSlaveMethod", slave_method); |
|
67 } |
|
68 return slave_method_type; |
|
69 } |
|
70 |
52 #define GST_BASE_AUDIO_SRC_GET_PRIVATE(obj) \ |
71 #define GST_BASE_AUDIO_SRC_GET_PRIVATE(obj) \ |
53 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_SRC, GstBaseAudioSrcPrivate)) |
72 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_SRC, GstBaseAudioSrcPrivate)) |
54 |
73 |
55 struct _GstBaseAudioSrcPrivate |
74 struct _GstBaseAudioSrcPrivate |
56 { |
75 { |
57 gboolean provide_clock; |
76 gboolean provide_clock; |
|
77 |
|
78 /* the clock slaving algorithm in use */ |
|
79 GstBaseAudioSrcSlaveMethod slave_method; |
58 }; |
80 }; |
59 |
81 |
60 /* BaseAudioSrc signals and args */ |
82 /* BaseAudioSrc signals and args */ |
61 enum |
83 enum |
62 { |
84 { |
145 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_src_dispose); |
175 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_src_dispose); |
146 |
176 |
147 g_object_class_install_property (gobject_class, PROP_BUFFER_TIME, |
177 g_object_class_install_property (gobject_class, PROP_BUFFER_TIME, |
148 g_param_spec_int64 ("buffer-time", "Buffer Time", |
178 g_param_spec_int64 ("buffer-time", "Buffer Time", |
149 "Size of audio buffer in microseconds", 1, |
179 "Size of audio buffer in microseconds", 1, |
150 G_MAXINT64, DEFAULT_BUFFER_TIME, G_PARAM_READWRITE)); |
180 G_MAXINT64, DEFAULT_BUFFER_TIME, |
|
181 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
151 |
182 |
152 g_object_class_install_property (gobject_class, PROP_LATENCY_TIME, |
183 g_object_class_install_property (gobject_class, PROP_LATENCY_TIME, |
153 g_param_spec_int64 ("latency-time", "Latency Time", |
184 g_param_spec_int64 ("latency-time", "Latency Time", |
154 "Audio latency in microseconds", 1, |
185 "Audio latency in microseconds", 1, |
155 G_MAXINT64, DEFAULT_LATENCY_TIME, G_PARAM_READWRITE)); |
186 G_MAXINT64, DEFAULT_LATENCY_TIME, |
|
187 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
188 |
|
189 /** |
|
190 * GstBaseAudioSrc:actual-buffer-time: |
|
191 * |
|
192 * Actual configured size of audio buffer in microseconds. |
|
193 * |
|
194 * Since: 0.10.20 |
|
195 **/ |
|
196 g_object_class_install_property (gobject_class, PROP_ACTUAL_BUFFER_TIME, |
|
197 g_param_spec_int64 ("actual-buffer-time", "Actual Buffer Time", |
|
198 "Actual configured size of audio buffer in microseconds", |
|
199 DEFAULT_ACTUAL_BUFFER_TIME, G_MAXINT64, DEFAULT_ACTUAL_BUFFER_TIME, |
|
200 G_PARAM_READABLE)); |
|
201 |
|
202 /** |
|
203 * GstBaseAudioSrc:actual-latency-time: |
|
204 * |
|
205 * Actual configured audio latency in microseconds. |
|
206 * |
|
207 * Since: 0.10.20 |
|
208 **/ |
|
209 g_object_class_install_property (gobject_class, PROP_ACTUAL_LATENCY_TIME, |
|
210 g_param_spec_int64 ("actual-latency-time", "Actual Latency Time", |
|
211 "Actual configured audio latency in microseconds", |
|
212 DEFAULT_ACTUAL_LATENCY_TIME, G_MAXINT64, DEFAULT_ACTUAL_LATENCY_TIME, |
|
213 G_PARAM_READABLE)); |
156 |
214 |
157 g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK, |
215 g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK, |
158 g_param_spec_boolean ("provide-clock", "Provide Clock", |
216 g_param_spec_boolean ("provide-clock", "Provide Clock", |
159 "Provide a clock to be used as the global pipeline clock", |
217 "Provide a clock to be used as the global pipeline clock", |
160 DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE)); |
218 DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
219 |
|
220 g_object_class_install_property (gobject_class, PROP_SLAVE_METHOD, |
|
221 g_param_spec_enum ("slave-method", "Slave Method", |
|
222 "Algorithm to use to match the rate of the masterclock", |
|
223 GST_TYPE_BASE_AUDIO_SRC_SLAVE_METHOD, DEFAULT_SLAVE_METHOD, |
|
224 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
161 |
225 |
162 gstelement_class->change_state = |
226 gstelement_class->change_state = |
163 GST_DEBUG_FUNCPTR (gst_base_audio_src_change_state); |
227 GST_DEBUG_FUNCPTR (gst_base_audio_src_change_state); |
164 gstelement_class->provide_clock = |
228 gstelement_class->provide_clock = |
165 GST_DEBUG_FUNCPTR (gst_base_audio_src_provide_clock); |
229 GST_DEBUG_FUNCPTR (gst_base_audio_src_provide_clock); |
536 |
681 |
537 static gboolean |
682 static gboolean |
538 gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event) |
683 gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event) |
539 { |
684 { |
540 GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc); |
685 GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc); |
|
686 gboolean res; |
|
687 |
|
688 res = TRUE; |
541 |
689 |
542 switch (GST_EVENT_TYPE (event)) { |
690 switch (GST_EVENT_TYPE (event)) { |
543 case GST_EVENT_FLUSH_START: |
691 case GST_EVENT_FLUSH_START: |
|
692 GST_DEBUG_OBJECT (bsrc, "flush-start"); |
544 gst_ring_buffer_pause (src->ringbuffer); |
693 gst_ring_buffer_pause (src->ringbuffer); |
545 gst_ring_buffer_clear_all (src->ringbuffer); |
694 gst_ring_buffer_clear_all (src->ringbuffer); |
546 break; |
695 break; |
547 case GST_EVENT_FLUSH_STOP: |
696 case GST_EVENT_FLUSH_STOP: |
|
697 GST_DEBUG_OBJECT (bsrc, "flush-stop"); |
548 /* always resync on sample after a flush */ |
698 /* always resync on sample after a flush */ |
549 src->next_sample = -1; |
699 src->next_sample = -1; |
550 gst_ring_buffer_clear_all (src->ringbuffer); |
700 gst_ring_buffer_clear_all (src->ringbuffer); |
551 break; |
701 break; |
|
702 case GST_EVENT_SEEK: |
|
703 GST_DEBUG_OBJECT (bsrc, "refuse to seek"); |
|
704 res = FALSE; |
|
705 break; |
552 default: |
706 default: |
553 break; |
707 GST_DEBUG_OBJECT (bsrc, "dropping event %p", event); |
554 } |
708 break; |
555 return TRUE; |
709 } |
|
710 return res; |
556 } |
711 } |
557 |
712 |
558 /* get the next offset in the ringbuffer for reading samples. |
713 /* get the next offset in the ringbuffer for reading samples. |
559 * If the next sample is too far away, this function will position itself to the |
714 * If the next sample is too far away, this function will position itself to the |
560 * next most recent sample, creating discontinuity */ |
715 * next most recent sample, creating discontinuity */ |
687 timestamp = gst_util_uint64_scale_int (sample, GST_SECOND, spec->rate); |
844 timestamp = gst_util_uint64_scale_int (sample, GST_SECOND, spec->rate); |
688 duration = gst_util_uint64_scale_int (src->next_sample, GST_SECOND, |
845 duration = gst_util_uint64_scale_int (src->next_sample, GST_SECOND, |
689 spec->rate) - timestamp; |
846 spec->rate) - timestamp; |
690 |
847 |
691 GST_OBJECT_LOCK (src); |
848 GST_OBJECT_LOCK (src); |
692 clock = GST_ELEMENT_CLOCK (src); |
849 if (!(clock = GST_ELEMENT_CLOCK (src))) |
693 if (clock != NULL && clock != src->clock) { |
850 goto no_sync; |
694 GstClockTime base_time, latency; |
851 |
695 |
852 if (clock != src->clock) { |
696 /* We are slaved to another clock, take running time of the clock and just |
853 /* we are slaved, check how to handle this */ |
697 * timestamp against it. Somebody else in the pipeline should figure out the |
854 switch (src->priv->slave_method) { |
698 * clock drift, for now. We keep the duration we calculated above. */ |
855 case GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE: |
699 timestamp = gst_clock_get_time (clock); |
856 /* not implemented, use skew algorithm. This algorithm should |
|
857 * work on the readout pointer and produces more or less samples based |
|
858 * on the clock drift */ |
|
859 case GST_BASE_AUDIO_SRC_SLAVE_SKEW: |
|
860 { |
|
861 GstClockTime running_time; |
|
862 GstClockTime base_time; |
|
863 GstClockTime current_time; |
|
864 guint64 running_time_sample; |
|
865 gint running_time_segment; |
|
866 gint current_segment; |
|
867 gint segment_skew; |
|
868 gint sps; |
|
869 |
|
870 /* samples per segment */ |
|
871 sps = ringbuffer->samples_per_seg; |
|
872 |
|
873 /* get the current time */ |
|
874 current_time = gst_clock_get_time (clock); |
|
875 |
|
876 /* get the basetime */ |
|
877 base_time = GST_ELEMENT_CAST (src)->base_time; |
|
878 |
|
879 /* get the running_time */ |
|
880 running_time = current_time - base_time; |
|
881 |
|
882 /* the running_time converted to a sample (relative to the ringbuffer) */ |
|
883 running_time_sample = |
|
884 gst_util_uint64_scale_int (running_time, spec->rate, GST_SECOND); |
|
885 |
|
886 /* the segmentnr corrensponding to running_time, round down */ |
|
887 running_time_segment = running_time_sample / sps; |
|
888 |
|
889 /* the segment currently read from the ringbuffer */ |
|
890 current_segment = sample / sps; |
|
891 |
|
892 /* the skew we have between running_time and the ringbuffertime */ |
|
893 segment_skew = running_time_segment - current_segment; |
|
894 |
|
895 GST_DEBUG_OBJECT (bsrc, "\n running_time = %" GST_TIME_FORMAT |
|
896 "\n timestamp = %" GST_TIME_FORMAT |
|
897 "\n running_time_segment = %d" |
|
898 "\n current_segment = %d" |
|
899 "\n segment_skew = %d", |
|
900 GST_TIME_ARGS (running_time), |
|
901 GST_TIME_ARGS (timestamp), |
|
902 running_time_segment, current_segment, segment_skew); |
|
903 |
|
904 /* Resync the ringbuffer if: |
|
905 * 1. We get one segment into the future. |
|
906 * This is clearly a lie, because we can't |
|
907 * possibly have a buffer with timestamp 1 at |
|
908 * time 0. (unless it has time-travelled...) |
|
909 * |
|
910 * 2. We are more than the length of the ringbuffer behind. |
|
911 * The length of the ringbuffer then gets to dictate |
|
912 * the threshold for what is concidered "too late" |
|
913 * |
|
914 * 3. If this is our first buffer. |
|
915 * We know that we should catch up to running_time |
|
916 * the first time we are ran. |
|
917 */ |
|
918 if ((segment_skew < 0) || |
|
919 (segment_skew >= ringbuffer->spec.segtotal) || |
|
920 (current_segment == 0)) { |
|
921 gint segments_written; |
|
922 gint first_segment; |
|
923 gint last_segment; |
|
924 gint new_last_segment; |
|
925 gint segment_diff; |
|
926 gint new_first_segment; |
|
927 guint64 new_sample; |
|
928 |
|
929 /* we are going to say that the last segment was captured at the current time |
|
930 (running_time), minus one segment of creation-latency in the ringbuffer. |
|
931 This can be thought of as: The segment arrived in the ringbuffer at time X, and |
|
932 that means it was created at time X - (one segment). */ |
|
933 new_last_segment = running_time_segment - 1; |
|
934 |
|
935 /* for better readablity */ |
|
936 first_segment = current_segment; |
|
937 |
|
938 /* get the amount of segments written from the device by now */ |
|
939 segments_written = g_atomic_int_get (&ringbuffer->segdone); |
|
940 |
|
941 /* subtract the base to segments_written to get the number of the |
|
942 last written segment in the ringbuffer (one segment written = segment 0) */ |
|
943 last_segment = segments_written - ringbuffer->segbase - 1; |
|
944 |
|
945 /* we see how many segments the ringbuffer was timeshifted */ |
|
946 segment_diff = new_last_segment - last_segment; |
|
947 |
|
948 /* we move the first segment an equal amount */ |
|
949 new_first_segment = first_segment + segment_diff; |
|
950 |
|
951 /* and we also move the segmentbase the same amount */ |
|
952 ringbuffer->segbase -= segment_diff; |
|
953 |
|
954 /* we calculate the new sample value */ |
|
955 new_sample = ((guint64) new_first_segment) * sps; |
|
956 |
|
957 /* and get the relative time to this -> our new timestamp */ |
|
958 timestamp = |
|
959 gst_util_uint64_scale_int (new_sample, GST_SECOND, spec->rate); |
|
960 |
|
961 /* we update the next sample accordingly */ |
|
962 src->next_sample = new_sample + samples; |
|
963 |
|
964 GST_DEBUG_OBJECT (bsrc, |
|
965 "Timeshifted the ringbuffer with %d segments: " |
|
966 "Updating the timestamp to %" GST_TIME_FORMAT ", " |
|
967 "and src->next_sample to %" G_GUINT64_FORMAT, segment_diff, |
|
968 GST_TIME_ARGS (timestamp), src->next_sample); |
|
969 } |
|
970 break; |
|
971 } |
|
972 case GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP: |
|
973 { |
|
974 GstClockTime base_time, latency; |
|
975 |
|
976 /* We are slaved to another clock, take running time of the pipeline clock and |
|
977 * timestamp against it. Somebody else in the pipeline should figure out the |
|
978 * clock drift. We keep the duration we calculated above. */ |
|
979 timestamp = gst_clock_get_time (clock); |
|
980 base_time = GST_ELEMENT_CAST (src)->base_time; |
|
981 |
|
982 if (timestamp > base_time) |
|
983 timestamp -= base_time; |
|
984 else |
|
985 timestamp = 0; |
|
986 |
|
987 /* subtract latency */ |
|
988 latency = |
|
989 gst_util_uint64_scale_int (total_samples, GST_SECOND, spec->rate); |
|
990 if (timestamp > latency) |
|
991 timestamp -= latency; |
|
992 else |
|
993 timestamp = 0; |
|
994 } |
|
995 case GST_BASE_AUDIO_SRC_SLAVE_NONE: |
|
996 break; |
|
997 } |
|
998 } else { |
|
999 GstClockTime base_time; |
|
1000 |
|
1001 /* to get the timestamp against the clock we also need to add our offset */ |
|
1002 timestamp = gst_audio_clock_adjust (clock, timestamp); |
|
1003 |
|
1004 /* we are not slaved, subtract base_time */ |
700 base_time = GST_ELEMENT_CAST (src)->base_time; |
1005 base_time = GST_ELEMENT_CAST (src)->base_time; |
701 |
1006 |
702 if (timestamp > base_time) |
1007 if (timestamp > base_time) { |
703 timestamp -= base_time; |
1008 timestamp -= base_time; |
704 else |
1009 GST_LOG_OBJECT (src, |
|
1010 "buffer timestamp %" GST_TIME_FORMAT " (base_time %" GST_TIME_FORMAT |
|
1011 ")", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (base_time)); |
|
1012 } else { |
|
1013 GST_LOG_OBJECT (src, |
|
1014 "buffer timestamp 0, ts %" GST_TIME_FORMAT " <= base_time %" |
|
1015 GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), |
|
1016 GST_TIME_ARGS (base_time)); |
705 timestamp = 0; |
1017 timestamp = 0; |
706 |
1018 } |
707 /* subtract latency */ |
1019 } |
708 latency = gst_util_uint64_scale_int (total_samples, GST_SECOND, spec->rate); |
1020 |
709 if (timestamp > latency) |
1021 no_sync: |
710 timestamp -= latency; |
|
711 else |
|
712 timestamp = 0; |
|
713 } |
|
714 GST_OBJECT_UNLOCK (src); |
1022 GST_OBJECT_UNLOCK (src); |
715 |
1023 |
716 GST_BUFFER_TIMESTAMP (buf) = timestamp; |
1024 GST_BUFFER_TIMESTAMP (buf) = timestamp; |
717 GST_BUFFER_DURATION (buf) = duration; |
1025 GST_BUFFER_DURATION (buf) = duration; |
718 GST_BUFFER_OFFSET (buf) = sample; |
1026 GST_BUFFER_OFFSET (buf) = sample; |
719 GST_BUFFER_OFFSET_END (buf) = sample + samples; |
1027 GST_BUFFER_OFFSET_END (buf) = sample + samples; |
720 |
|
721 gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (bsrc))); |
|
722 |
1028 |
723 *outbuf = buf; |
1029 *outbuf = buf; |
724 |
1030 |
725 return GST_FLOW_OK; |
1031 return GST_FLOW_OK; |
726 |
1032 |