- Timestamp:
- Feb 5, 2013 5:15:01 AM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia-audiodev/bb10_dev.c
r4316 r4340 123 123 124 124 /* Playback */ 125 unsigned int pb_ctrl_audio_manager_handle; 125 126 snd_pcm_t *pb_pcm; 126 127 unsigned int pb_audio_manager_handle; … … 169 170 pjmedia_aud_dev_info *adi; 170 171 int pb_result, ca_result; 171 int card = -1;172 int dev = 0;173 172 unsigned int handle; 174 173 snd_pcm_t *pcm_handle; … … 184 183 &pcm_handle, 185 184 &handle, 186 "/dev/snd/voicep",185 (char*)"voice", 187 186 SND_PCM_OPEN_PLAYBACK)) 188 187 >= 0) 189 188 { 190 if ((pb_result = snd_pcm_plugin_set_disable (pcm_handle, PLUGIN_DISABLE_MMAP)) < 0) { 191 TRACE_((THIS_FILE, "snd_pcm_plugin_set_disable ret = %d", pb_result)); 192 }else{ 193 TRACE_((THIS_FILE, "Try to open the device for playback - success")); 194 } 195 snd_pcm_close (pcm_handle); 196 audio_manager_free_handle(handle); 189 snd_pcm_close (pcm_handle); 190 audio_manager_free_handle(handle); 197 191 } else { 198 192 TRACE_((THIS_FILE, "Try to open the device for playback - failure")); … … 202 196 &pcm_handle, 203 197 &handle, 204 "/dev/snd/voicec",198 (char*)"voice", 205 199 SND_PCM_OPEN_CAPTURE)) 206 200 >= 0) 207 201 { 208 if ((ca_result = snd_pcm_plugin_set_disable (pcm_handle, PLUGIN_DISABLE_MMAP)) < 0) { 209 TRACE_((THIS_FILE, "snd_pcm_plugin_set_disable ret = %d", ca_result)); 210 }else{ 211 TRACE_((THIS_FILE, "Try to open the device for capture - success")); 212 } 213 snd_pcm_close (pcm_handle); 214 audio_manager_free_handle(handle); 202 snd_pcm_close (pcm_handle); 203 audio_manager_free_handle(handle); 215 204 216 205 } else { … … 397 386 snd_pcm_close(stream->pb_pcm); 398 387 stream->pb_pcm = NULL; 399 if(stream->pb_audio_manager_handle != 0){ 388 389 if (stream->pb_audio_manager_handle != 0) { 400 390 audio_manager_free_handle(stream->pb_audio_manager_handle); 401 391 stream->pb_audio_manager_handle = 0; 402 392 } 393 394 if (stream->pb_ctrl_audio_manager_handle != 0) { 395 audio_manager_free_handle(stream->pb_ctrl_audio_manager_handle); 396 stream->pb_ctrl_audio_manager_handle = 0; 397 } 403 398 } 404 399 } … … 416 411 snd_pcm_close(stream->ca_pcm); 417 412 stream->ca_pcm = NULL; 418 if(stream->ca_audio_manager_handle != 0){ 413 414 if (stream->ca_audio_manager_handle != 0) { 419 415 audio_manager_free_handle(stream->ca_audio_manager_handle); 420 416 stream->ca_audio_manager_handle = 0; … … 458 454 close_play_pcm(stream); 459 455 TRACE_((THIS_FILE, "pb_thread_func failed prepare = %d", result)); 460 456 return PJ_SUCCESS; 461 457 } 462 458 … … 471 467 frame.bit_info = 0; 472 468 469 /* Read the audio from pjmedia */ 473 470 result = stream->pb_cb (user_data, &frame); 474 471 if (result != PJ_SUCCESS || stream->quit) … … 481 478 result = snd_pcm_plugin_write(stream->pb_pcm,buf,size); 482 479 if (result != size || result < 0) { 483 snd_pcm_channel_status_t status; 480 /* either the write to output device has failed or not the 481 * full amount of bytes have been written. This usually happens 482 * when audio routing is being changed by another thread 483 * Use a status variable for reading the error 484 */ 485 snd_pcm_channel_status_t status; 486 status.channel = SND_PCM_CHANNEL_PLAYBACK; 484 487 if (snd_pcm_plugin_status (stream->pb_pcm, &status) < 0) { 485 PJ_LOG(4,(THIS_FILE, 488 /* Call has failed nothing we can do except log and 489 * continue */ 490 PJ_LOG(4,(THIS_FILE, 486 491 "underrun: playback channel status error")); 487 continue; 488 } 489 490 if (status.status == SND_PCM_STATUS_READY || 491 status.status == SND_PCM_STATUS_UNDERRUN) 492 { 493 if (snd_pcm_plugin_prepare (stream->pb_pcm, 494 SND_PCM_CHANNEL_PLAYBACK) < 0) 495 { 496 PJ_LOG(4,(THIS_FILE, 497 "underrun: playback channel prepare error")); 498 continue; 499 } 500 } 501 502 TRACE_((THIS_FILE, "pb_thread_func failed write = %d", result)); 492 } else { 493 /* The status of the error has been read 494 * RIM say these are expected so we can "re-prepare" the stream 495 */ 496 PJ_LOG(4,(THIS_FILE,"PLAY thread ERROR status = %d", 497 status.status)); 498 if (status.status == SND_PCM_STATUS_READY || 499 status.status == SND_PCM_STATUS_UNDERRUN || 500 status.status == SND_PCM_STATUS_ERROR ) 501 { 502 if (snd_pcm_plugin_prepare (stream->pb_pcm, 503 SND_PCM_CHANNEL_PLAYBACK) < 0) 504 { 505 PJ_LOG(4,(THIS_FILE, 506 "underrun: playback channel prepare error")); 507 } 508 } 509 } 503 510 } 504 505 511 tstamp.u64 += nframes; 506 512 } … … 553 559 close_capture_pcm(stream); 554 560 TRACE_((THIS_FILE, "ca_thread_func failed prepare = %d", result)); 555 561 return PJ_SUCCESS; 556 562 } 557 563 … … 561 567 pj_bzero (buf, size); 562 568 569 /* read the input device */ 563 570 result = snd_pcm_plugin_read(stream->ca_pcm, buf,size); 564 571 if(result <0 || result != size) { 572 /* We expect result to be size (640) 573 * It's not so we have to read the status error and "prepare" 574 * the channel. This usually happens when output audio routing 575 * has been changed by another thread. 576 * We won't "continue", instead just do what we can and leave 577 * the end of the loop to write what's in the buffer. Not entirely 578 * correct but saves a potential underrun in PJMEDIA 579 */ 580 PJ_LOG (4,(THIS_FILE, 581 "snd_pcm_plugin_read ERROR read = %d required = %d", 582 result,size)); 565 583 snd_pcm_channel_status_t status; 566 if (snd_pcm_plugin_status (stream->ca_pcm, &status) < 0) { 567 PJ_LOG (4,(THIS_FILE, "overrun: capture channel status " 568 "error")); 569 continue; 570 } 571 572 if (status.status == SND_PCM_STATUS_READY || 573 status.status == SND_PCM_STATUS_OVERRUN) { 574 if (snd_pcm_plugin_prepare (stream->ca_pcm, 575 SND_PCM_CHANNEL_CAPTURE) < 0) 576 { 577 PJ_LOG (4,(THIS_FILE, "overrun: capture channel prepare " 578 "error")); 579 continue; 580 } 584 status.channel = SND_PCM_CHANNEL_CAPTURE; 585 if ((result = snd_pcm_plugin_status (stream->ca_pcm, &status)) < 0) 586 { 587 /* Should not fail but all we can do is continue */ 588 PJ_LOG(4,(THIS_FILE, "capture: snd_pcm_plugin_status ret = %d", 589 result)); 590 } else { 591 /* RIM say these are the errors that we should "prepare" 592 * after */ 593 if (status.status == SND_PCM_STATUS_READY || 594 status.status == SND_PCM_STATUS_OVERRUN || 595 status.status == SND_PCM_STATUS_ERROR) 596 { 597 if (snd_pcm_plugin_prepare (stream->ca_pcm, 598 SND_PCM_CHANNEL_CAPTURE) < 0) 599 { 600 PJ_LOG (4,(THIS_FILE, 601 "overrun: capture channel prepare error")); 602 } 603 } 581 604 } 582 605 } … … 585 608 break; 586 609 610 /* Write the capture audio data to PJMEDIA */ 587 611 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 588 612 frame.buf = (void *) buf; … … 605 629 } 606 630 631 /* Audio routing, speaker/headset */ 632 static pj_status_t bb10_initialize_playback_ctrl(struct bb10_stream *stream, 633 bool speaker) 634 { 635 /* Although the play and capture have audio manager handles, audio routing 636 * requires a separate handle 637 */ 638 int ret = PJ_SUCCESS; 639 640 if (stream->pb_ctrl_audio_manager_handle == 0) { 641 /* lazy init an audio manager handle */ 642 ret = audio_manager_get_handle(AUDIO_TYPE_VIDEO_CHAT, 0, false, 643 &stream->pb_ctrl_audio_manager_handle); 644 if (ret != 0) { 645 TRACE_((THIS_FILE, "audio_manager_get_handle ret = %d",ret)); 646 return PJMEDIA_EAUD_SYSERR; 647 } 648 } 649 650 /* Set for either speaker or earpiece */ 651 if (speaker) { 652 ret = audio_manager_set_handle_type( 653 stream->pb_ctrl_audio_manager_handle, 654 AUDIO_TYPE_VIDEO_CHAT, 655 AUDIO_DEVICE_SPEAKER, 656 AUDIO_DEVICE_DEFAULT); 657 } else { 658 ret = audio_manager_set_handle_type( 659 stream->pb_ctrl_audio_manager_handle, 660 AUDIO_TYPE_VIDEO_CHAT, 661 AUDIO_DEVICE_HANDSET, 662 AUDIO_DEVICE_DEFAULT); 663 } 664 665 if (ret == 0) { 666 /* RIM recommend this call */ 667 ret = audio_manager_set_handle_routing_conditions( 668 stream->pb_ctrl_audio_manager_handle, 669 SETTINGS_RESET_ON_DEVICE_CONNECTION); 670 if (ret != 0) { 671 TRACE_((THIS_FILE, 672 "audio_manager_set_handle_routing_conditions ret = %d", 673 ret)); 674 return PJMEDIA_EAUD_SYSERR; 675 } 676 } else { 677 TRACE_((THIS_FILE, "audio_manager_set_handle_type ret = %d", ret)); 678 return PJMEDIA_EAUD_SYSERR; 679 } 680 681 return PJ_SUCCESS; 682 } 607 683 608 684 static pj_status_t bb10_open_playback (struct bb10_stream *stream, 609 685 const pjmedia_aud_param *param) 610 686 { 611 int card = -1;612 int dev = 0;613 687 int ret = 0; 614 688 snd_pcm_channel_info_t pi; … … 623 697 } 624 698 625 if ((ret = audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, 626 &stream->pb_pcm, &stream->pb_audio_manager_handle, 627 "/dev/snd/voicep", 628 SND_PCM_OPEN_PLAYBACK)) < 0) 699 /* Use the bb10 audio manager API to open as opposed to QNX core audio 700 * Echo cancellation built in 701 */ 702 if ((ret = audio_manager_snd_pcm_open_name( 703 AUDIO_TYPE_VIDEO_CHAT, 704 &stream->pb_pcm, &stream->pb_audio_manager_handle, 705 (char*)"voice", 706 SND_PCM_OPEN_PLAYBACK)) < 0) 629 707 { 630 708 TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret)); 631 709 return PJMEDIA_EAUD_SYSERR; 632 710 } 633 ret = audio_manager_set_handle_type(stream->pb_audio_manager_handle, AUDIO_TYPE_VIDEO_CHAT, AUDIO_DEVICE_HANDSET , AUDIO_DEVICE_HANDSET); 634 if (ret==0) { 635 ret = audio_manager_set_handle_routing_conditions(stream->pb_audio_manager_handle, SETTINGS_RESET_ON_DEVICE_CONNECTION); 636 if(ret != 0){ 637 TRACE_((THIS_FILE, "audio_manager_set_handle_routing_conditions ret = %d", ret)); 638 return PJMEDIA_EAUD_SYSERR; 639 } 640 }else{ 641 TRACE_((THIS_FILE, "audio_manager_set_handle_type ret = %d", ret)); 642 return PJMEDIA_EAUD_SYSERR; 643 } 644 645 if ((ret = snd_pcm_plugin_set_disable (stream->pb_pcm, PLUGIN_DISABLE_MMAP)) < 0) { 646 TRACE_((THIS_FILE, "snd_pcm_plugin_set_disable ret = %d", ret)); 647 return PJMEDIA_EAUD_SYSERR; 648 } 711 712 /* Required call from January 2013 gold OS release */ 713 if ((ret = snd_pcm_plugin_set_disable(stream->pb_pcm, 714 PLUGIN_DISABLE_MMAP)) < 0) 715 { 716 TRACE_((THIS_FILE, "snd_pcm_plugin_set_disable ret = %d", ret)); 717 return PJMEDIA_EAUD_SYSERR; 718 } 719 720 /* Required call from January 2013 gold OS release */ 721 if ((ret = snd_pcm_plugin_set_enable(stream->pb_pcm, 722 PLUGIN_ROUTING)) < 0) 723 { 724 TRACE_((THIS_FILE, "snd_pcm_plugin_set_enable ret = %d", ret)); 725 return PJMEDIA_EAUD_SYSERR; 726 } 727 649 728 /* TODO PJ_ZERO */ 650 729 memset (&pi, 0, sizeof (pi)); 651 730 pi.channel = SND_PCM_CHANNEL_PLAYBACK; 652 731 if ((ret = snd_pcm_plugin_info (stream->pb_pcm, &pi)) < 0) { 653 654 732 TRACE_((THIS_FILE, "snd_pcm_plugin_info ret = %d", ret)); 733 return PJMEDIA_EAUD_SYSERR; 655 734 } 656 735 657 736 memset (&pp, 0, sizeof (pp)); 658 737 659 /* Request VoIP compatible capabilities 660 * On simulator frag_size is always negotiated to 170 661 */ 738 /* Request VoIP compatible capabilities */ 662 739 pp.mode = SND_PCM_MODE_BLOCK; 663 740 pp.channel = SND_PCM_CHANNEL_PLAYBACK; … … 666 743 /* HARD CODE for the time being PJMEDIA expects 640 for 16khz */ 667 744 pp.buf.block.frag_size = PREFERRED_FRAME_SIZE*2; 668 /* Increasing this internal buffer count delays write failure in the loop*/669 pp.buf.block.frags_max = 4;745 /* RIM recommends maximum of 3 */ 746 pp.buf.block.frags_max = 3; 670 747 pp.buf.block.frags_min = 1; 671 748 pp.format.interleave = 1; … … 715 792 TRACE_((THIS_FILE, "bb10_open_playback: pb_frames = %d clock = %d", 716 793 stream->pb_frames, param->clock_rate)); 717 794 718 795 return PJ_SUCCESS; 719 796 } … … 725 802 unsigned int rate; 726 803 unsigned long tmp_buf_size; 727 int card = -1;728 int dev = 0;729 804 int frame_size; 730 805 snd_pcm_channel_info_t pi; … … 736 811 return PJMEDIA_EAUD_INVDEV; 737 812 738 if ((ret =audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT,739 740 741 "/dev/snd/voicec",742 813 if ((ret=audio_manager_snd_pcm_open_name(AUDIO_TYPE_VIDEO_CHAT, 814 &stream->ca_pcm, 815 &stream->ca_audio_manager_handle, 816 (char*)"voice", 817 SND_PCM_OPEN_CAPTURE)) < 0) 743 818 { 744 819 TRACE_((THIS_FILE, "audio_manager_snd_pcm_open_name ret = %d", ret)); 745 820 return PJMEDIA_EAUD_SYSERR; 746 821 } 747 if ((ret = snd_pcm_plugin_set_disable (stream->ca_pcm, PLUGIN_DISABLE_MMAP)) < 0) { 822 /* Required call from January 2013 gold OS release */ 823 if ((ret = snd_pcm_plugin_set_disable (stream->ca_pcm, 824 PLUGIN_DISABLE_MMAP)) < 0) 825 { 748 826 TRACE_(("snd_pcm_plugin_set_disable failed: %d",ret)); 827 return PJMEDIA_EAUD_SYSERR; 828 } 829 /* Required call from January 2013 gold OS release */ 830 if ((ret = snd_pcm_plugin_set_enable(stream->ca_pcm, 831 PLUGIN_ROUTING)) < 0) 832 { 833 TRACE_(("snd_pcm_plugin_set_enable failed: %d",ret)); 749 834 return PJMEDIA_EAUD_SYSERR; 750 835 } … … 770 855 /* HARD CODE for the time being PJMEDIA expects 640 for 16khz */ 771 856 pp.buf.block.frag_size = PREFERRED_FRAME_SIZE*2; 772 /* Not applicable for capture hence -1*/773 pp.buf.block.frags_max = -1;857 /* From January 2013 gold OS release. RIM recommend these for capture */ 858 pp.buf.block.frags_max = 1; 774 859 pp.buf.block.frags_min = 1; 775 860 pp.format.interleave = 1; … … 803 888 } 804 889 805 /* frag_size should be 160 */806 890 frame_size = setup.buf.block.frag_size; 807 808 /* END BB10 init */809 891 810 892 /* Set clock rate */ … … 883 965 } 884 966 967 /* Part of the play functionality but the RIM/Truphone loopback sample 968 * initialializes after the play and capture 969 * "false" is default/earpiece for output 970 */ 971 status = bb10_initialize_playback_ctrl(stream,false); 972 if (status != PJ_SUCCESS) { 973 return PJMEDIA_EAUD_SYSERR; 974 } 975 885 976 *p_strm = &stream->base; 886 977 return PJ_SUCCESS; … … 888 979 889 980 890 /* API: get running parameter */ 981 /* 982 * API: get running parameter 983 * based on ALSA template 984 */ 891 985 static pj_status_t bb10_stream_get_param(pjmedia_aud_stream *s, 892 986 pjmedia_aud_param *pi) … … 902 996 903 997 904 /* API: get capability */ 998 /* 999 * API: get capability 1000 * based on ALSA template 1001 */ 905 1002 static pj_status_t bb10_stream_get_cap(pjmedia_aud_stream *s, 906 1003 pjmedia_aud_dev_cap cap, … … 917 1014 *(unsigned*)pval = stream->param.input_latency_ms; 918 1015 return PJ_SUCCESS; 1016 919 1017 } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY && 920 1018 (stream->param.dir & PJMEDIA_DIR_PLAYBACK)) … … 923 1021 *(unsigned*)pval = stream->param.output_latency_ms; 924 1022 return PJ_SUCCESS; 1023 925 1024 } else { 926 1025 return PJMEDIA_EAUD_INVCAP; … … 929 1028 930 1029 931 /* API: set capability */ 1030 /* 1031 * API: set capability 1032 * Currently just supporting toggle between speaker and earpiece 1033 */ 932 1034 static pj_status_t bb10_stream_set_cap(pjmedia_aud_stream *strm, 933 1035 pjmedia_aud_dev_cap cap, 934 1036 const void *value) 935 1037 { 936 PJ_UNUSED_ARG(strm); 937 PJ_UNUSED_ARG(cap); 938 PJ_UNUSED_ARG(value); 939 940 return PJMEDIA_EAUD_INVCAP; 1038 pj_status_t ret = PJ_SUCCESS; 1039 struct bb10_stream *stream = (struct bb10_stream*)strm; 1040 1041 if (cap != PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE || value == NULL) { 1042 TRACE_((THIS_FILE,"bb10_stream_set_cap() = PJMEDIA_EAUD_INVCAP")); 1043 return PJMEDIA_EAUD_INVCAP; 1044 1045 } else { 1046 pjmedia_aud_dev_route route = *((pjmedia_aud_dev_route*)value); 1047 /* Use the initialization function which lazy-inits the 1048 * handle for routing 1049 */ 1050 if (route == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER) { 1051 ret = bb10_initialize_playback_ctrl(stream,true); 1052 } else { 1053 ret = bb10_initialize_playback_ctrl(stream,false); 1054 } 1055 } 1056 1057 if (ret != PJ_SUCCESS) { 1058 TRACE_((THIS_FILE,"bb10_stream_set_cap() = %d",ret)); 1059 } 1060 return ret; 941 1061 } 942 1062
Note: See TracChangeset
for help on using the changeset viewer.