diff options
Diffstat (limited to 'toxav/toxmedia.c')
-rw-r--r-- | toxav/toxmedia.c | 473 |
1 files changed, 24 insertions, 449 deletions
diff --git a/toxav/toxmedia.c b/toxav/toxmedia.c index aff3cf8c..359832d3 100644 --- a/toxav/toxmedia.c +++ b/toxav/toxmedia.c | |||
@@ -34,45 +34,13 @@ | |||
34 | #include <libswscale/swscale.h> | 34 | #include <libswscale/swscale.h> |
35 | #include <libavdevice/avdevice.h> | 35 | #include <libavdevice/avdevice.h> |
36 | #include <libavutil/opt.h> | 36 | #include <libavutil/opt.h> |
37 | #include <AL/al.h> | ||
38 | #include <AL/alc.h> | ||
39 | #include <SDL/SDL.h> | ||
40 | #include <SDL/SDL_thread.h> | ||
41 | #include <pthread.h> | ||
42 | #include <opus/opus.h> | 37 | #include <opus/opus.h> |
38 | #include <assert.h> | ||
43 | 39 | ||
44 | #include "toxmsi.h" | 40 | #include "toxmsi.h" |
45 | #include "toxrtp.h" | 41 | #include "toxrtp.h" |
46 | #include "toxmedia.h" | 42 | #include "toxmedia.h" |
47 | 43 | ||
48 | SDL_Surface *screen; | ||
49 | |||
50 | int display_received_frame(codec_state *cs, AVFrame *r_video_frame) | ||
51 | { | ||
52 | AVPicture pict; | ||
53 | SDL_LockYUVOverlay(cs->video_picture.bmp); | ||
54 | |||
55 | pict.data[0] = cs->video_picture.bmp->pixels[0]; | ||
56 | pict.data[1] = cs->video_picture.bmp->pixels[2]; | ||
57 | pict.data[2] = cs->video_picture.bmp->pixels[1]; | ||
58 | pict.linesize[0] = cs->video_picture.bmp->pitches[0]; | ||
59 | pict.linesize[1] = cs->video_picture.bmp->pitches[2]; | ||
60 | pict.linesize[2] = cs->video_picture.bmp->pitches[1]; | ||
61 | |||
62 | /* Convert the image into YUV format that SDL uses */ | ||
63 | sws_scale(cs->sws_SDL_r_ctx, (uint8_t const * const *)r_video_frame->data, r_video_frame->linesize, 0, | ||
64 | cs->video_decoder_ctx->height, pict.data, pict.linesize ); | ||
65 | |||
66 | SDL_UnlockYUVOverlay(cs->video_picture.bmp); | ||
67 | SDL_Rect rect; | ||
68 | rect.x = 0; | ||
69 | rect.y = 0; | ||
70 | rect.w = cs->video_decoder_ctx->width; | ||
71 | rect.h = cs->video_decoder_ctx->height; | ||
72 | SDL_DisplayYUVOverlay(cs->video_picture.bmp, &rect); | ||
73 | return 1; | ||
74 | } | ||
75 | |||
76 | struct jitter_buffer { | 44 | struct jitter_buffer { |
77 | RTPMessage **queue; | 45 | RTPMessage **queue; |
78 | uint16_t capacity; | 46 | uint16_t capacity; |
@@ -85,6 +53,7 @@ struct jitter_buffer { | |||
85 | uint8_t id_set; | 53 | uint8_t id_set; |
86 | }; | 54 | }; |
87 | 55 | ||
56 | |||
88 | struct jitter_buffer *create_queue(int capacity) | 57 | struct jitter_buffer *create_queue(int capacity) |
89 | { | 58 | { |
90 | struct jitter_buffer *q; | 59 | struct jitter_buffer *q; |
@@ -240,10 +209,23 @@ int queue(struct jitter_buffer *q, RTPMessage *pk) | |||
240 | 209 | ||
241 | int init_receive_audio(codec_state *cs) | 210 | int init_receive_audio(codec_state *cs) |
242 | { | 211 | { |
243 | int err = OPUS_OK; | 212 | int rc; |
244 | cs->audio_decoder = opus_decoder_create(48000, 1, &err); | 213 | cs->audio_decoder = opus_decoder_create(48000, 1, &rc ); |
245 | opus_decoder_init(cs->audio_decoder, 48000, 1); | 214 | |
246 | printf("init audio decoder successful\n"); | 215 | if ( rc != OPUS_OK ){ |
216 | printf("Error while starting audio decoder!\n"); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | rc = opus_decoder_init(cs->audio_decoder, 48000, 1); | ||
221 | |||
222 | if ( rc != OPUS_OK ){ | ||
223 | printf("Error while starting audio decoder!\n"); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | |||
228 | printf("Init audio decoder successful\n"); | ||
247 | return 1; | 229 | return 1; |
248 | } | 230 | } |
249 | 231 | ||
@@ -252,23 +234,23 @@ int init_receive_video(codec_state *cs) | |||
252 | cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); | 234 | cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC); |
253 | 235 | ||
254 | if (!cs->video_decoder) { | 236 | if (!cs->video_decoder) { |
255 | printf("init video_decoder failed\n"); | 237 | printf("Init video_decoder failed\n"); |
256 | return 0; | 238 | return 0; |
257 | } | 239 | } |
258 | 240 | ||
259 | cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder); | 241 | cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder); |
260 | 242 | ||
261 | if (!cs->video_decoder_ctx) { | 243 | if (!cs->video_decoder_ctx) { |
262 | printf("init video_decoder_ctx failed\n"); | 244 | printf("Init video_decoder_ctx failed\n"); |
263 | return 0; | 245 | return 0; |
264 | } | 246 | } |
265 | 247 | ||
266 | if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) { | 248 | if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) { |
267 | printf("opening video decoder failed\n"); | 249 | printf("Opening video decoder failed\n"); |
268 | return 0; | 250 | return 0; |
269 | } | 251 | } |
270 | 252 | ||
271 | printf("init video decoder successful\n"); | 253 | printf("Init video decoder successful\n"); |
272 | return 1; | 254 | return 1; |
273 | } | 255 | } |
274 | 256 | ||
@@ -356,32 +338,6 @@ int init_send_audio(codec_state *cs) | |||
356 | { | 338 | { |
357 | cs->support_send_audio = 0; | 339 | cs->support_send_audio = 0; |
358 | 340 | ||
359 | const ALchar *pDeviceList = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); | ||
360 | int i = 0; | ||
361 | const ALchar *device_names[20]; | ||
362 | |||
363 | if (pDeviceList) { | ||
364 | printf("\nAvailable Capture Devices are:\n"); | ||
365 | |||
366 | while (*pDeviceList) { | ||
367 | device_names[i] = pDeviceList; | ||
368 | printf("%d) %s\n", i, device_names[i]); | ||
369 | pDeviceList += strlen(pDeviceList) + 1; | ||
370 | ++i; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | printf("enter capture device number: \n"); | ||
375 | char dev[2]; | ||
376 | fgets(dev, sizeof(dev), stdin); | ||
377 | cs->audio_capture_device = alcCaptureOpenDevice(device_names[dev[0] - 48], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, | ||
378 | AUDIO_FRAME_SIZE * 4); | ||
379 | |||
380 | if (alcGetError(cs->audio_capture_device) != AL_NO_ERROR) { | ||
381 | printf("could not start capture device! %d\n", alcGetError(cs->audio_capture_device)); | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | int err = OPUS_OK; | 341 | int err = OPUS_OK; |
386 | cs->audio_bitrate = AUDIO_BITRATE; | 342 | cs->audio_bitrate = AUDIO_BITRATE; |
387 | cs->audio_encoder = opus_encoder_create(AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &err); | 343 | cs->audio_encoder = opus_encoder_create(AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &err); |
@@ -435,385 +391,4 @@ int init_decoder(codec_state *cs) | |||
435 | cs->receive_video = 1; | 391 | cs->receive_video = 1; |
436 | 392 | ||
437 | return 1; | 393 | return 1; |
438 | } | 394 | } \ No newline at end of file |
439 | |||
440 | int video_encoder_refresh(codec_state *cs, int bps) | ||
441 | { | ||
442 | if (cs->video_encoder_ctx) | ||
443 | avcodec_close(cs->video_encoder_ctx); | ||
444 | |||
445 | cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC); | ||
446 | |||
447 | if (!cs->video_encoder) { | ||
448 | printf("init video_encoder failed\n"); | ||
449 | return -1; | ||
450 | } | ||
451 | |||
452 | cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder); | ||
453 | |||
454 | if (!cs->video_encoder_ctx) { | ||
455 | printf("init video_encoder_ctx failed\n"); | ||
456 | return -1; | ||
457 | } | ||
458 | |||
459 | cs->video_encoder_ctx->bit_rate = bps; | ||
460 | cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate; | ||
461 | av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0); | ||
462 | av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0); | ||
463 | |||
464 | cs->video_encoder_ctx->thread_count = 4; | ||
465 | cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95; | ||
466 | cs->video_encoder_ctx->rc_buffer_size = bps * 6; | ||
467 | cs->video_encoder_ctx->profile = 0; | ||
468 | cs->video_encoder_ctx->qmax = 54; | ||
469 | cs->video_encoder_ctx->qmin = 4; | ||
470 | AVRational myrational = {1, 25}; | ||
471 | cs->video_encoder_ctx->time_base = myrational; | ||
472 | cs->video_encoder_ctx->gop_size = 99999; | ||
473 | cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P; | ||
474 | cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width; | ||
475 | cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height; | ||
476 | |||
477 | if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) { | ||
478 | printf("opening video encoder failed\n"); | ||
479 | return -1; | ||
480 | } | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | void *encode_video_thread(void *arg) | ||
485 | { | ||
486 | codec_state *cs = (codec_state *)arg; | ||
487 | AVPacket pkt1, *packet = &pkt1; | ||
488 | int p = 0; | ||
489 | int err; | ||
490 | int got_packet; | ||
491 | RTPMessage *s_video_msg; | ||
492 | int video_frame_finished; | ||
493 | AVFrame *s_video_frame; | ||
494 | AVFrame *webcam_frame; | ||
495 | s_video_frame = avcodec_alloc_frame(); | ||
496 | webcam_frame = avcodec_alloc_frame(); | ||
497 | AVPacket enc_video_packet; | ||
498 | |||
499 | uint8_t *buffer; | ||
500 | int numBytes; | ||
501 | /* Determine required buffer size and allocate buffer */ | ||
502 | numBytes = avpicture_get_size(PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height); | ||
503 | buffer = (uint8_t *)av_calloc(numBytes * sizeof(uint8_t),1); | ||
504 | avpicture_fill((AVPicture *)s_video_frame, buffer, PIX_FMT_YUV420P, cs->webcam_decoder_ctx->width, | ||
505 | cs->webcam_decoder_ctx->height); | ||
506 | cs->sws_ctx = sws_getContext(cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, | ||
507 | cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P, | ||
508 | SWS_BILINEAR, NULL, NULL, NULL); | ||
509 | |||
510 | while (!cs->quit && cs->send_video) { | ||
511 | |||
512 | if (av_read_frame(cs->video_format_ctx, packet) < 0) { | ||
513 | printf("error reading frame\n"); | ||
514 | |||
515 | if (cs->video_format_ctx->pb->error != 0) | ||
516 | break; | ||
517 | |||
518 | continue; | ||
519 | } | ||
520 | |||
521 | if (packet->stream_index == cs->video_stream) { | ||
522 | if (avcodec_decode_video2(cs->webcam_decoder_ctx, webcam_frame, &video_frame_finished, packet) < 0) { | ||
523 | printf("couldn't decode\n"); | ||
524 | continue; | ||
525 | } | ||
526 | |||
527 | av_free_packet(packet); | ||
528 | sws_scale(cs->sws_ctx, (uint8_t const * const *)webcam_frame->data, webcam_frame->linesize, 0, | ||
529 | cs->webcam_decoder_ctx->height, s_video_frame->data, s_video_frame->linesize); | ||
530 | /* create a new I-frame every 60 frames */ | ||
531 | ++p; | ||
532 | |||
533 | if (p == 60) { | ||
534 | |||
535 | s_video_frame->pict_type = AV_PICTURE_TYPE_BI ; | ||
536 | } else if (p == 61) { | ||
537 | s_video_frame->pict_type = AV_PICTURE_TYPE_I ; | ||
538 | p = 0; | ||
539 | } else { | ||
540 | s_video_frame->pict_type = AV_PICTURE_TYPE_P ; | ||
541 | } | ||
542 | |||
543 | if (video_frame_finished) { | ||
544 | err = avcodec_encode_video2(cs->video_encoder_ctx, &enc_video_packet, s_video_frame, &got_packet); | ||
545 | |||
546 | if (err < 0) { | ||
547 | printf("could not encode video frame\n"); | ||
548 | continue; | ||
549 | } | ||
550 | |||
551 | if (!got_packet) { | ||
552 | continue; | ||
553 | } | ||
554 | |||
555 | pthread_mutex_lock(&cs->rtp_msg_mutex_lock); | ||
556 | |||
557 | if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n"); | ||
558 | |||
559 | if ( 0 > rtp_send_msg ( cs->_rtp_video, cs->_messenger, enc_video_packet.data, enc_video_packet.size) ) { | ||
560 | printf("invalid message\n"); | ||
561 | } | ||
562 | |||
563 | pthread_mutex_unlock(&cs->rtp_msg_mutex_lock); | ||
564 | av_free_packet(&enc_video_packet); | ||
565 | } | ||
566 | } else { | ||
567 | av_free_packet(packet); | ||
568 | } | ||
569 | } | ||
570 | |||
571 | /* clean up codecs */ | ||
572 | pthread_mutex_lock(&cs->avcodec_mutex_lock); | ||
573 | av_free(buffer); | ||
574 | av_free(webcam_frame); | ||
575 | av_free(s_video_frame); | ||
576 | sws_freeContext(cs->sws_ctx); | ||
577 | avcodec_close(cs->webcam_decoder_ctx); | ||
578 | avcodec_close(cs->video_encoder_ctx); | ||
579 | pthread_mutex_unlock(&cs->avcodec_mutex_lock); | ||
580 | pthread_exit ( NULL ); | ||
581 | } | ||
582 | |||
583 | void *encode_audio_thread(void *arg) | ||
584 | { | ||
585 | codec_state *cs = (codec_state *)arg; | ||
586 | RTPMessage *s_audio_msg; | ||
587 | unsigned char encoded_data[4096]; | ||
588 | int encoded_size = 0; | ||
589 | int16_t frame[4096]; | ||
590 | int frame_size = AUDIO_FRAME_SIZE; | ||
591 | ALint sample = 0; | ||
592 | alcCaptureStart(cs->audio_capture_device); | ||
593 | |||
594 | while (!cs->quit && cs->send_audio) { | ||
595 | alcGetIntegerv(cs->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample); | ||
596 | |||
597 | if (sample >= frame_size) { | ||
598 | alcCaptureSamples(cs->audio_capture_device, frame, frame_size); | ||
599 | encoded_size = opus_encode(cs->audio_encoder, frame, frame_size, encoded_data, 480); | ||
600 | |||
601 | if (encoded_size <= 0) { | ||
602 | printf("Could not encode audio packet\n"); | ||
603 | } else { | ||
604 | pthread_mutex_lock(&cs->rtp_msg_mutex_lock); | ||
605 | |||
606 | rtp_send_msg ( cs->_rtp_audio, cs->_messenger, encoded_data, encoded_size ); | ||
607 | |||
608 | pthread_mutex_unlock(&cs->rtp_msg_mutex_lock); | ||
609 | |||
610 | } | ||
611 | } else { | ||
612 | usleep(1000); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | /* clean up codecs */ | ||
617 | pthread_mutex_lock(&cs->avcodec_mutex_lock); | ||
618 | alcCaptureStop(cs->audio_capture_device); | ||
619 | alcCaptureCloseDevice(cs->audio_capture_device); | ||
620 | |||
621 | pthread_mutex_unlock(&cs->avcodec_mutex_lock); | ||
622 | pthread_exit ( NULL ); | ||
623 | } | ||
624 | |||
625 | |||
626 | int video_decoder_refresh(codec_state *cs, int width, int height) | ||
627 | { | ||
628 | printf("need to refresh\n"); | ||
629 | screen = SDL_SetVideoMode(width, height, 0, 0); | ||
630 | |||
631 | if (cs->video_picture.bmp) | ||
632 | SDL_FreeYUVOverlay(cs->video_picture.bmp); | ||
633 | |||
634 | cs->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen); | ||
635 | cs->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P, | ||
636 | SWS_BILINEAR, NULL, NULL, NULL); | ||
637 | return 1; | ||
638 | } | ||
639 | |||
640 | void *decode_video_thread(void *arg) | ||
641 | { | ||
642 | codec_state *cs = (codec_state *)arg; | ||
643 | cs->video_stream = 0; | ||
644 | RTPMessage *r_msg; | ||
645 | int dec_frame_finished; | ||
646 | AVFrame *r_video_frame; | ||
647 | r_video_frame = avcodec_alloc_frame(); | ||
648 | AVPacket dec_video_packet; | ||
649 | av_new_packet (&dec_video_packet, 65536); | ||
650 | int width = 0; | ||
651 | int height = 0; | ||
652 | |||
653 | while (!cs->quit && cs->receive_video) { | ||
654 | r_msg = rtp_recv_msg ( cs->_rtp_video ); | ||
655 | |||
656 | if (r_msg) { | ||
657 | memcpy(dec_video_packet.data, r_msg->data, r_msg->length); | ||
658 | dec_video_packet.size = r_msg->length; | ||
659 | avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet); | ||
660 | |||
661 | if (dec_frame_finished) { | ||
662 | if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) { | ||
663 | width = cs->video_decoder_ctx->width; | ||
664 | height = cs->video_decoder_ctx->height; | ||
665 | printf("w: %d h%d \n", width, height); | ||
666 | video_decoder_refresh(cs, width, height); | ||
667 | } | ||
668 | |||
669 | display_received_frame(cs, r_video_frame); | ||
670 | } else { | ||
671 | /* TODO: request the sender to create a new i-frame immediatly */ | ||
672 | printf("bad video packet\n"); | ||
673 | } | ||
674 | |||
675 | rtp_free_msg(cs->_rtp_video, r_msg); | ||
676 | } | ||
677 | |||
678 | usleep(1000); | ||
679 | } | ||
680 | |||
681 | printf("vend\n"); | ||
682 | /* clean up codecs */ | ||
683 | pthread_mutex_lock(&cs->avcodec_mutex_lock); | ||
684 | av_free(r_video_frame); | ||
685 | avcodec_close(cs->video_decoder_ctx); | ||
686 | pthread_mutex_unlock(&cs->avcodec_mutex_lock); | ||
687 | pthread_exit ( NULL ); | ||
688 | } | ||
689 | |||
690 | void *decode_audio_thread(void *arg) | ||
691 | { | ||
692 | codec_state *cs = (codec_state *)arg; | ||
693 | RTPMessage *r_msg; | ||
694 | |||
695 | int frame_size = AUDIO_FRAME_SIZE; | ||
696 | int data_size; | ||
697 | |||
698 | ALCdevice *dev; | ||
699 | ALCcontext *ctx; | ||
700 | ALuint source, *buffers; | ||
701 | dev = alcOpenDevice(NULL); | ||
702 | ctx = alcCreateContext(dev, NULL); | ||
703 | alcMakeContextCurrent(ctx); | ||
704 | int openal_buffers = 5; | ||
705 | |||
706 | buffers = calloc(sizeof(ALuint) * openal_buffers,1); | ||
707 | alGenBuffers(openal_buffers, buffers); | ||
708 | alGenSources((ALuint)1, &source); | ||
709 | alSourcei(source, AL_LOOPING, AL_FALSE); | ||
710 | |||
711 | ALuint buffer; | ||
712 | ALint val; | ||
713 | |||
714 | ALenum error; | ||
715 | uint16_t zeros[frame_size]; | ||
716 | int i; | ||
717 | |||
718 | for (i = 0; i < frame_size; i++) { | ||
719 | zeros[i] = 0; | ||
720 | } | ||
721 | |||
722 | for (i = 0; i < openal_buffers; ++i) { | ||
723 | alBufferData(buffers[i], AL_FORMAT_MONO16, zeros, frame_size, 48000); | ||
724 | } | ||
725 | |||
726 | alSourceQueueBuffers(source, openal_buffers, buffers); | ||
727 | alSourcePlay(source); | ||
728 | |||
729 | if (alGetError() != AL_NO_ERROR) { | ||
730 | fprintf(stderr, "Error starting audio\n"); | ||
731 | cs->quit = 1; | ||
732 | } | ||
733 | |||
734 | struct jitter_buffer *j_buf = NULL; | ||
735 | |||
736 | j_buf = create_queue(20); | ||
737 | |||
738 | int success = 0; | ||
739 | |||
740 | int dec_frame_len; | ||
741 | |||
742 | opus_int16 PCM[frame_size]; | ||
743 | |||
744 | while (!cs->quit && cs->receive_audio) { | ||
745 | |||
746 | r_msg = rtp_recv_msg ( cs->_rtp_audio ); | ||
747 | |||
748 | if (r_msg) { | ||
749 | /* push the packet into the queue */ | ||
750 | queue(j_buf, r_msg); | ||
751 | } | ||
752 | |||
753 | /* grab a packet from the queue */ | ||
754 | success = 0; | ||
755 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); | ||
756 | |||
757 | if (val > 0) | ||
758 | r_msg = dequeue(j_buf, &success); | ||
759 | |||
760 | if (success > 0) { | ||
761 | /* good packet */ | ||
762 | if (success == 1) { | ||
763 | dec_frame_len = opus_decode(cs->audio_decoder, r_msg->data, r_msg->length, PCM, frame_size, 0); | ||
764 | rtp_free_msg(cs->_rtp_audio, r_msg); | ||
765 | } | ||
766 | |||
767 | /* lost packet */ | ||
768 | if (success == 2) { | ||
769 | printf("lost packet\n"); | ||
770 | dec_frame_len = opus_decode(cs->audio_decoder, NULL, 0, PCM, frame_size, 1); | ||
771 | } | ||
772 | |||
773 | if (dec_frame_len > 0) { | ||
774 | alGetSourcei(source, AL_BUFFERS_PROCESSED, &val); | ||
775 | |||
776 | if (val <= 0) | ||
777 | continue; | ||
778 | |||
779 | alSourceUnqueueBuffers(source, 1, &buffer); | ||
780 | data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1); | ||
781 | alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000); | ||
782 | int error = alGetError(); | ||
783 | |||
784 | if (error != AL_NO_ERROR) { | ||
785 | fprintf(stderr, "Error setting buffer %d\n", error); | ||
786 | break; | ||
787 | } | ||
788 | |||
789 | alSourceQueueBuffers(source, 1, &buffer); | ||
790 | |||
791 | if (alGetError() != AL_NO_ERROR) { | ||
792 | fprintf(stderr, "error: could not buffer audio\n"); | ||
793 | break; | ||
794 | } | ||
795 | |||
796 | alGetSourcei(source, AL_SOURCE_STATE, &val); | ||
797 | |||
798 | if (val != AL_PLAYING) | ||
799 | alSourcePlay(source); | ||
800 | |||
801 | |||
802 | } | ||
803 | } | ||
804 | |||
805 | usleep(1000); | ||
806 | } | ||
807 | |||
808 | /* clean up codecs */ | ||
809 | pthread_mutex_lock(&cs->avcodec_mutex_lock); | ||
810 | |||
811 | /* clean up openal */ | ||
812 | alDeleteSources(1, &source); | ||
813 | alDeleteBuffers(openal_buffers, buffers); | ||
814 | alcMakeContextCurrent(NULL); | ||
815 | alcDestroyContext(ctx); | ||
816 | alcCloseDevice(dev); | ||
817 | pthread_mutex_unlock(&cs->avcodec_mutex_lock); | ||
818 | pthread_exit ( NULL ); | ||
819 | } | ||