1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Paulo Rogério Panhoto <paulo@voicetechnology.com.br>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * mod_mp4 -- MP4 File Format support for video apps.
27  *
28  */
29 
30 #include <switch.h>
31 #include "mp4_helper.hpp"
32 #include "exception.hpp"
33 
34 
35 #ifndef min
36 #define min(x, y) ((x) < (y) ? (x) : (y))
37 #endif
38 
39 SWITCH_MODULE_LOAD_FUNCTION(mod_mp4_load);
40 SWITCH_MODULE_DEFINITION(mod_mp4, mod_mp4_load, NULL, NULL);
41 
42 #define VID_BIT (1 << 31)
43 #define VERSION 4201
44 
45 #ifdef MP4_RECORD
46 struct file_header {
47 	int32_t version;
48 	char video_codec_name[32];
49 	char video_fmtp[128];
50 	uint32_t audio_rate;
51 	uint32_t audio_ptime;
52 	switch_time_t created;
53 };
54 
55 struct record_helper {
56 	switch_core_session_t *session;
57 	switch_mutex_t *mutex;
58 	int fd;
59 	int up;
60 };
61 #endif
62 
63 struct AVParams {
64 	switch_core_session_t * session;
65 	switch_channel_t * channel;
66 	switch_timer_t * timer;
67 	switch_frame_t * frame;
68 	switch_mutex_t * mutex;
69 	bool video;
70 	switch_payload_t pt;
71 	MP4::Context * vc;
72 	bool done;
73 	bool * quit;
74 };
75 
record_video_thread(switch_thread_t * thread,void * obj)76 static void *SWITCH_THREAD_FUNC record_video_thread(switch_thread_t *thread, void *obj)
77 {
78 #ifdef MP4_RECORD
79 	record_helper *eh = reinterpret_cast<record_helper *>(obj);
80 	switch_core_session_t *session = eh->session;
81 	switch_channel_t *channel = switch_core_session_get_channel(session);
82 	switch_status_t status;
83 	switch_frame_t *read_frame;
84 	int bytes;
85 
86 	eh->up = 1;
87 	while (switch_channel_ready(channel)) {
88 		status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
89 
90 		if (!SWITCH_READ_ACCEPTABLE(status)) {
91 			break;
92 		}
93 
94 		if (switch_test_flag(read_frame, SFF_CNG)) {
95 			continue;
96 		}
97 
98 		bytes = read_frame->packetlen | VID_BIT;
99 
100 		switch_mutex_lock(eh->mutex);
101 
102 		if (write(eh->fd, &bytes, sizeof(bytes)) != (int) sizeof(bytes)) {
103 			switch_mutex_unlock(eh->mutex);
104 			break;
105 		}
106 
107 		if (write(eh->fd, read_frame->packet, read_frame->packetlen) != (int) read_frame->packetlen) {
108 			switch_mutex_unlock(eh->mutex);
109 			break;
110 		}
111 
112 		switch_mutex_unlock(eh->mutex);
113 
114 		switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
115 	}
116 	eh->up = 0;
117 #endif
118 	return NULL;
119 }
120 
SWITCH_STANDARD_APP(record_mp4_function)121 SWITCH_STANDARD_APP(record_mp4_function)
122 {
123 #ifdef MP4_RECORD
124 	switch_status_t status;
125 	switch_frame_t *read_frame;
126 	switch_channel_t *channel = switch_core_session_get_channel(session);
127 	struct record_helper eh = { 0 };
128 	switch_thread_t *thread;
129 	switch_threadattr_t *thd_attr = NULL;
130 	int fd;
131 	switch_mutex_t *mutex = NULL;
132 	switch_codec_t codec, *vid_codec;
133 	switch_codec_implementation_t read_impl = { };
134 	int count = 0, sanity = 30;
135 
136 	switch_core_session_get_read_impl(session, &read_impl);
137 	switch_channel_answer(channel);
138 
139 
140 	while (switch_channel_up(channel) && !switch_channel_test_flag(channel, CF_VIDEO)) {
141 		switch_yield(10000);
142 
143 		if (count) count--;
144 
145 		if (count == 0) {
146 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "%s waiting for video.\n", switch_channel_get_name(channel));
147 			count = 100;
148 			if (!--sanity) {
149 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s timeout waiting for video.\n",
150 								  switch_channel_get_name(channel));
151 				return;
152 			}
153 		}
154 	}
155 
156 	if (!switch_channel_ready(channel)) {
157 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "%s not ready.\n", switch_channel_get_name(channel));
158 		return;
159 	}
160 
161 /*
162 	if ((fd = open((char *) data, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR)) < 0) {
163 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error opening file %s\n", (char *) data);
164 		return;
165 	}
166 */
167 
168 	MP4::Context ctx(reinterpret_cast<char*>(data), true);
169 
170 	if (switch_core_codec_init(&codec,
171 							   "L16",
172 							   NULL,
173 							   NULL,
174 							   read_impl.samples_per_second,
175 							   read_impl.microseconds_per_packet / 1000,
176 							   1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
177 							   NULL, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS)
178 	{
179 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Activation Success\n");
180 	} else {
181 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Audio Codec Activation Fail\n");
182 		goto end;
183 	}
184 
185 	switch_core_session_set_read_codec(session, &codec);
186 
187 	if (switch_channel_test_flag(channel, CF_VIDEO)) {
188 		struct file_header h;
189 		memset(&h, 0, sizeof(h));
190 		vid_codec = switch_core_session_get_video_read_codec(session);
191 
192 		h.version = VERSION;
193 		h.created = switch_micro_time_now();
194 		switch_set_string(h.video_codec_name, vid_codec->implementation->iananame);
195 		if (vid_codec->fmtp_in) {
196 			switch_set_string(h.video_fmtp, vid_codec->fmtp_in);
197 		}
198 		h.audio_rate = read_impl.samples_per_second;
199 		h.audio_ptime = read_impl.microseconds_per_packet / 1000;
200 
201 		if (write(fd, &h, sizeof(h)) != sizeof(h)) {
202 			goto end;
203 		}
204 
205 		switch_mutex_init(&mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
206 		eh.mutex = mutex;
207 		eh.fd = fd;
208 		eh.session = session;
209 		switch_threadattr_create(&thd_attr, switch_core_session_get_pool(session));
210 		switch_threadattr_detach_set(thd_attr, 1);
211 		switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
212 		switch_thread_create(&thread, thd_attr, record_video_thread, &eh, switch_core_session_get_pool(session));
213 	}
214 
215 
216 	while (switch_channel_ready(channel)) {
217 
218 		status = switch_core_session_read_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
219 
220 		if (!SWITCH_READ_ACCEPTABLE(status)) {
221 			break;
222 		}
223 
224 		if (switch_test_flag(read_frame, SFF_CNG)) {
225 			continue;
226 		}
227 
228 		if (mutex) {
229 			switch_mutex_lock(mutex);
230 		}
231 
232 		if (write(fd, &read_frame->datalen, sizeof(read_frame->datalen)) != sizeof(read_frame->datalen)) {
233 			if (mutex) {
234 				switch_mutex_unlock(mutex);
235 			}
236 			break;
237 		}
238 
239 		if (write(fd, read_frame->data, read_frame->datalen) != (int) read_frame->datalen) {
240 			if (mutex) {
241 				switch_mutex_unlock(mutex);
242 			}
243 			break;
244 		}
245 
246 		if (mutex) {
247 			switch_mutex_unlock(mutex);
248 		}
249 	}
250 
251 
252   end:
253 
254 	if (eh.up) {
255 		while (eh.up) {
256 			switch_cond_next();
257 		}
258 	}
259 
260 	switch_core_session_set_read_codec(session, NULL);
261 	switch_core_codec_destroy(&codec);
262 #endif
263 }
264 
play_video_function(switch_thread_t * thread,void * obj)265 static void *SWITCH_THREAD_FUNC play_video_function(switch_thread_t *thread, void *obj)
266 {
267 	AVParams * pt = reinterpret_cast<AVParams*>(obj);
268 	u_int next = 0, first = 0xffffffff;
269 	uint64_t ts = 0, control = 0;
270 
271 	bool ok;
272 	bool sent = true;
273 	pt->done = false;
274 	switch_time_t start = switch_time_now();
275 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pt->session), SWITCH_LOG_DEBUG, "Video thread Started\n");
276 	while (!*pt->quit && switch_channel_ready(pt->channel)) {
277 		if (pt->video) {
278 			if (sent) {
279 				switch_mutex_lock(pt->mutex);
280 				pt->frame->packetlen = pt->frame->buflen;
281 				ok = pt->vc->getVideoPacket(pt->frame->packet, pt->frame->packetlen, next);
282 				switch_mutex_unlock(pt->mutex);
283 				sent = false;
284 				if (ok) {
285 					switch_rtp_hdr_t *hdr = reinterpret_cast<switch_rtp_hdr_t *>(pt->frame->packet);
286 					if(first == 0xffffffff) first = next;
287 					next -= first;
288 					control = next * 90000LL / pt->vc->videoTrack().track.clock;
289 					control -= first;
290 					hdr->ts = htonl(control);
291 					control = control * 1000 / 90;
292 					if (pt->pt)
293 						hdr->pt = pt->pt;
294 				} else break;
295 			}
296 
297 			ts = switch_time_now() - start;
298 			int64_t wait = control > ts ? (control - ts) : 0;
299 
300 			if (wait > 0) {
301 				switch_cond_next();
302 				// wait the time for the next Video frame
303 				switch_sleep(wait);
304 			}
305 
306 			if (switch_channel_test_flag(pt->channel, CF_VIDEO)) {
307 				switch_byte_t *data = (switch_byte_t *) pt->frame->packet;
308 
309 				pt->frame->data = data + 12;
310 				pt->frame->datalen = pt->frame->packetlen - 12;
311 				switch_core_session_write_video_frame(pt->session, pt->frame, SWITCH_IO_FLAG_NONE, 0);
312 				sent = true;
313 			}
314 
315 		}
316 	}
317 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pt->session), SWITCH_LOG_DEBUG, "Video thread ended\n");
318 	pt->done = true;
319 	return NULL;
320 }
321 
play_audio_function(switch_thread_t * thread,void * obj)322 static void *SWITCH_THREAD_FUNC play_audio_function(switch_thread_t *thread, void *obj)
323 {
324 	AVParams * pt = reinterpret_cast<AVParams*>(obj);
325 	u_int next = 0, first = 0xffffffff;
326 	uint64_t ts = 0, control = 0;
327 
328 	bool ok;
329 	bool sent = true;
330 	switch_dtmf_t dtmf = {0};
331 	pt->done = false;
332 	switch_frame_t * read_frame;
333 
334 	while (!*pt->quit && switch_channel_ready(pt->channel)) {
335 		// event processing.
336 		// -- SEE switch_ivr_play_say.c:1231 && mod_dptools.c:1428 && mod_dptools.c:1919
337 		switch_core_session_read_frame(pt->session, &read_frame, SWITCH_IO_FLAG_SINGLE_READ, 0);
338 
339 		if (switch_channel_test_flag(pt->channel, CF_BREAK)) {
340 			switch_channel_clear_flag(pt->channel, CF_BREAK);
341 			break;
342 		}
343 
344 		switch_ivr_parse_all_events(pt->session);
345 
346 		if (switch_channel_has_dtmf(pt->channel)) {
347 			switch_channel_dequeue_dtmf(pt->channel, &dtmf);
348 			const char * terminators = switch_channel_get_variable(pt->channel, SWITCH_PLAYBACK_TERMINATORS_VARIABLE);
349 			if (terminators && !strcasecmp(terminators, "none")) terminators = NULL;
350 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pt->session), SWITCH_LOG_DEBUG, "Digit %c\n", dtmf.digit);
351 			if (terminators && strchr(terminators, dtmf.digit)) {
352 				std::string digit(&dtmf.digit, 0, 1);
353 				switch_channel_set_variable(pt->channel, SWITCH_PLAYBACK_TERMINATOR_USED, digit.c_str());
354 				break;
355 			}
356 		}
357 
358 		switch_mutex_lock(pt->mutex);
359 		pt->frame->datalen = pt->frame->buflen;
360 		ok = pt->vc->getAudioPacket(pt->frame->data, pt->frame->datalen, next);
361 		switch_mutex_unlock(pt->mutex);
362 
363 		if (ok) {
364 		  if (pt->frame->datalen > (int) pt->frame->buflen)
365 				pt->frame->datalen = pt->frame->buflen;
366 
367 			switch_core_session_write_frame(pt->session, pt->frame, SWITCH_IO_FLAG_NONE, 0);
368 			switch_core_timer_next(pt->timer);
369 		}
370 		else break;
371 	}
372 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pt->session), SWITCH_LOG_DEBUG, "Audio done\n");
373 	*pt->quit = pt->done = true;
374 	return NULL;
375 }
376 
SWITCH_STANDARD_APP(play_mp4_function)377 SWITCH_STANDARD_APP(play_mp4_function)
378 {
379 	switch_channel_t *channel = switch_core_session_get_channel(session);
380 	switch_frame_t write_frame = { 0 }, vid_frame = {0};
381 	switch_codec_t codec = { 0 }, vid_codec = {0}, *read_vid_codec;
382 	unsigned char *aud_buffer;
383 	unsigned char *vid_buffer;
384 	switch_timer_t timer = { 0 };
385 	switch_codec_implementation_t read_impl = {};
386 	bool done = false;
387 
388 	try {
389 		MP4::Context vc((char *) data);
390 
391 		switch_payload_t pt = 0;
392 
393 		switch_core_session_get_read_impl(session, &read_impl);
394 
395 		aud_buffer = (unsigned char *) switch_core_session_alloc(session, SWITCH_RECOMMENDED_BUFFER_SIZE);
396 		vid_buffer = (unsigned char *) switch_core_session_alloc(session, SWITCH_RECOMMENDED_BUFFER_SIZE);
397 
398 		/*
399 		if (!vc.isOpen())
400 		{
401 			char msgbuf[1024];
402 			sprintf(msgbuf, "PLAYBACK ERROR (%s): FILE NOT FOUND.", (char*) data);
403 			switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, msgbuf);
404 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error opening file %s\n", (char *) data);
405 			return;
406 		}
407 
408 		if(!vc.isSupported())
409 		{
410 			char msgbuf[1024];
411 			sprintf(msgbuf, "PLAYBACK ERROR (%s): UNSUPPORTED FORMAT OR FILE NOT HINTED.", (char*) data);
412 			switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, msgbuf);
413 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT,
414 				"Error reading track info. Maybe this file is not hinted.\n");
415 			throw 1;
416 		}
417 		*/
418 
419 		switch_channel_set_variable(channel, "rtp_force_video_fmtp", vc.videoTrack().fmtp.c_str());
420 		switch_channel_answer(channel);
421 
422 		if ((read_vid_codec = switch_core_session_get_video_read_codec(session))) {
423 			pt = read_vid_codec->agreed_pt;
424 		}
425 
426 		write_frame.codec = &codec;
427 		write_frame.data = aud_buffer;
428 		write_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE;
429 
430 		vid_frame.codec = &vid_codec;
431 		vid_frame.packet = vid_buffer;
432 		vid_frame.data = vid_buffer + 12;
433 		vid_frame.buflen = SWITCH_RECOMMENDED_BUFFER_SIZE - 12;
434 		switch_set_flag((&vid_frame), SFF_RAW_RTP);
435 		switch_set_flag((&vid_frame), SFF_PROXY_PACKET);
436 
437 		if (switch_core_timer_init(&timer, "soft", read_impl.microseconds_per_packet / 1000,
438 			read_impl.samples_per_packet, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
439 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Timer Activation Fail\n");
440 			throw 2;
441 		}
442 
443 		if (switch_core_codec_init(&codec,
444 								   vc.audioTrack().codecName,
445 								   NULL,
446 								   NULL,
447 								   vc.audioTrack().clock,
448 								   vc.audioTrack().packetLength,
449 								   1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
450 								   NULL, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
451 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Activation Success\n");
452 		} else {
453 			throw Exception("Audio Codec Activation Fail");
454 		}
455 
456 		if (switch_core_codec_init(&vid_codec,
457 								   vc.videoTrack().track.codecName,
458 								   NULL,
459 								   NULL,
460 								   0,
461 								   0,
462 								   1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
463 								   NULL, switch_core_session_get_pool(session)) == SWITCH_STATUS_SUCCESS) {
464 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Video Codec Activation Success\n");
465 		} else
466 		{
467 			throw Exception("Video Codec Activation Fail");
468 		}
469 		switch_core_session_set_read_codec(session, &codec);
470 
471 		AVParams vpt;
472 		vpt.session = session;
473 		vpt.channel = channel;
474 		vpt.frame = &vid_frame;
475 		vpt.timer = &timer;
476 		vpt.video = true;
477 		vpt.pt = pt;
478 		vpt.vc = &vc;
479 		switch_mutex_init(&vpt.mutex, SWITCH_MUTEX_DEFAULT, switch_core_session_get_pool(session));
480 		vpt.quit = &done;
481 
482 		switch_threadattr_t * thd_attr;
483 		switch_threadattr_create(&thd_attr, switch_core_session_get_pool(session));
484 		switch_threadattr_detach_set(thd_attr, 1);
485 		switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
486 		switch_thread_t *thread;
487 		switch_thread_create(&thread, thd_attr, play_video_function, (void*)&vpt, switch_core_session_get_pool(session));
488 
489 		AVParams apt;
490 		apt.session = session;
491 		apt.channel = channel;
492 		apt.frame = &write_frame;
493 		apt.timer = &timer;
494 		apt.video = false;
495 		apt.vc = &vc;
496 		apt.mutex = vpt.mutex;
497 		apt.quit = &done;
498 		play_audio_function(NULL, &apt);
499 
500 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Waiting for video thread to join.\n");
501 		while (!vpt.done) {
502 			switch_cond_next();
503 		}
504 
505 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE PLAYED");
506 	} catch(const std::exception & e)
507 	{
508 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s\n", e.what());
509 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE,
510 			(std::string("PLAYBACK_FAILED - ") + e.what()).c_str());
511 	}catch(...)
512 	{
513 		switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "PLAYBACK_FAILED - See FS logs for detail.");
514 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Exception caught.\n");
515 	}
516 
517 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "All done.\n");
518 	if (timer.interval)  switch_core_timer_destroy(&timer);
519 
520 	switch_core_session_set_read_codec(session, NULL);
521 
522 	if (switch_core_codec_ready(&codec)) switch_core_codec_destroy(&codec);
523 
524 	if (switch_core_codec_ready(&vid_codec)) switch_core_codec_destroy(&vid_codec);
525 }
526 
SWITCH_MODULE_LOAD_FUNCTION(mod_mp4_load)527 SWITCH_MODULE_LOAD_FUNCTION(mod_mp4_load)
528 {
529 	switch_application_interface_t *app_interface;
530 
531 	/* connect my internal structure to the blank pointer passed to me */
532 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
533 
534 	SWITCH_ADD_APP(app_interface, "play_mp4", "play an MP4 file", "play an MP4 file", play_mp4_function, "<file>", SAF_NONE);
535 	//SWITCH_ADD_APP(app_interface, "record_mp4", "record an MP4 file", "record an MP4 file", record_mp4_function, "<file>", SAF_NONE);
536 
537 	/* indicate that the module should continue to be loaded */
538 	return SWITCH_STATUS_SUCCESS;
539 }
540 
541 /* For Emacs:
542  * Local Variables:
543  * mode:c
544  * indent-tabs-mode:t
545  * tab-width:4
546  * c-basic-offset:4
547  * End:
548  * For VIM:
549  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
550  */
551