@@ -633,21 +633,35 @@ class MyOboeEngine : oboe::AudioStreamDataCallback,
633
633
public:
634
634
MyOboeEngine (struct oboe_aud_stream *stream_, pjmedia_dir dir_)
635
635
: stream(stream_), dir(dir_), oboe_stream(NULL ), dir_st(NULL ),
636
- thread (NULL ), thread_quit(PJ_FALSE ), queue(NULL ),
637
- err_thread_registered(false )
636
+ thread (NULL ), thread_quit(PJ_TRUE ), queue(NULL ),
637
+ err_thread_registered(false ), mutex( NULL )
638
638
{
639
639
pj_assert (dir == PJMEDIA_DIR_CAPTURE || dir == PJMEDIA_DIR_PLAYBACK);
640
640
dir_st = (dir == PJMEDIA_DIR_CAPTURE? " capture" :" playback" );
641
641
pj_set_timestamp32 (&ts, 0 , 0 );
642
642
}
643
643
644
644
pj_status_t Start () {
645
- if (oboe_stream)
646
- return PJ_SUCCESS;
645
+ pj_status_t status;
646
+
647
+ if (!mutex) {
648
+ status = pj_mutex_create_recursive (stream->pool , " oboe" , &mutex);
649
+ if (status != PJ_SUCCESS) {
650
+ PJ_PERROR (3 ,(THIS_FILE, status,
651
+ " Oboe stream %s failed creating mutex" , dir_st));
652
+ return status;
653
+ }
654
+ }
647
655
648
656
int dev_id = 0 ;
649
657
oboe::AudioStreamBuilder sb;
650
- pj_status_t status;
658
+
659
+ pj_mutex_lock (mutex);
660
+
661
+ if (oboe_stream) {
662
+ pj_mutex_unlock (mutex);
663
+ return PJ_SUCCESS;
664
+ }
651
665
652
666
if (dir == PJMEDIA_DIR_CAPTURE) {
653
667
sb.setDirection (oboe::Direction::Input);
@@ -710,22 +724,26 @@ class MyOboeEngine : oboe::AudioStreamDataCallback,
710
724
711
725
/* Create semaphore */
712
726
if (sem_init (&sem, 0 , 0 ) != 0 ) {
727
+ pj_mutex_unlock (mutex);
713
728
return PJ_RETURN_OS_ERROR (pj_get_native_os_error ());
714
729
}
715
730
716
731
/* Create thread */
717
732
thread_quit = PJ_FALSE;
718
733
status = pj_thread_create (stream->pool , " android_oboe" ,
719
- AudioThread, this , 0 , 0 , &thread);
720
- if (status != PJ_SUCCESS)
734
+ &AudioThread, this , 0 , 0 , &thread);
735
+ if (status != PJ_SUCCESS) {
736
+ pj_mutex_unlock (mutex);
721
737
return status;
738
+ }
722
739
723
740
/* Open & start oboe stream */
724
741
oboe::Result result = sb.openStream (&oboe_stream);
725
742
if (result != oboe::Result::OK) {
726
743
PJ_LOG (3 ,(THIS_FILE,
727
744
" Oboe stream %s open failed (err=%d/%s)" ,
728
745
dir_st, result, oboe::convertToText (result)));
746
+ pj_mutex_unlock (mutex);
729
747
return PJMEDIA_EAUD_SYSERR;
730
748
}
731
749
@@ -734,6 +752,7 @@ class MyOboeEngine : oboe::AudioStreamDataCallback,
734
752
PJ_LOG (3 ,(THIS_FILE,
735
753
" Oboe stream %s start failed (err=%d/%s)" ,
736
754
dir_st, result, oboe::convertToText (result)));
755
+ pj_mutex_unlock (mutex);
737
756
return PJMEDIA_EAUD_SYSERR;
738
757
}
739
758
@@ -762,30 +781,48 @@ class MyOboeEngine : oboe::AudioStreamDataCallback,
762
781
oboe_stream->getFramesPerBurst ()
763
782
));
764
783
784
+ pj_mutex_unlock (mutex);
765
785
return PJ_SUCCESS;
766
786
}
767
787
768
788
void Stop () {
769
- if (oboe_stream) {
770
- oboe_stream->close ();
771
- delete oboe_stream;
772
- oboe_stream = NULL ;
789
+ /* Just return if it has not been started */
790
+ if (!mutex || thread_quit) {
791
+ PJ_LOG (5 , (THIS_FILE, " Oboe stream %s stop request when "
792
+ " already stopped." , dir_st));
793
+ return ;
773
794
}
774
795
796
+ PJ_LOG (5 , (THIS_FILE, " Oboe stream %s stop requested." , dir_st));
797
+
798
+ pj_mutex_lock (mutex);
799
+
775
800
if (thread) {
801
+ PJ_LOG (5 ,(THIS_FILE, " Oboe %s stopping thread" , dir_st));
776
802
thread_quit = PJ_TRUE;
777
803
sem_post (&sem);
778
804
pj_thread_join (thread);
779
805
pj_thread_destroy (thread);
780
806
thread = NULL ;
781
- sem_destroy (&sem);
807
+ }
808
+
809
+ if (oboe_stream) {
810
+ PJ_LOG (5 ,(THIS_FILE, " Oboe %s closing stream" , dir_st));
811
+ oboe_stream->close ();
812
+ delete oboe_stream;
813
+ oboe_stream = NULL ;
782
814
}
783
815
784
816
if (queue) {
817
+ PJ_LOG (5 ,(THIS_FILE, " Oboe %s deleting queue" , dir_st));
785
818
delete queue;
786
819
queue = NULL ;
787
820
}
788
821
822
+ sem_destroy (&sem);
823
+
824
+ pj_mutex_unlock (mutex);
825
+
789
826
PJ_LOG (4 , (THIS_FILE, " Oboe stream %s stopped." , dir_st));
790
827
}
791
828
@@ -810,11 +847,16 @@ class MyOboeEngine : oboe::AudioStreamDataCallback,
810
847
811
848
sem_post (&sem);
812
849
813
- return oboe::DataCallbackResult::Continue;
850
+ return (thread_quit? oboe::DataCallbackResult::Stop :
851
+ oboe::DataCallbackResult::Continue);
814
852
}
815
853
816
854
void onErrorAfterClose (oboe::AudioStream *oboeStream, oboe::Result result)
817
855
{
856
+ __android_log_print (ANDROID_LOG_INFO, THIS_FILE,
857
+ " Oboe %s got onErrorAfterClose(%d)" ,
858
+ dir_st, result);
859
+
818
860
/* Register callback thread */
819
861
if (!err_thread_registered || !pj_thread_is_registered ())
820
862
{
@@ -825,17 +867,40 @@ class MyOboeEngine : oboe::AudioStreamDataCallback,
825
867
err_thread_registered = true ;
826
868
}
827
869
828
- PJ_LOG (3 ,(THIS_FILE,
829
- " Oboe stream %s error (%d/%s), trying to restart stream.." ,
830
- dir_st, result, oboe::convertToText (result)));
831
-
832
870
/* Just try to restart */
833
- Stop ();
834
- Start ();
871
+ pj_mutex_lock (mutex);
872
+
873
+ /* Make sure stop request has not been made */
874
+ if (!thread_quit) {
875
+ PJ_LOG (3 ,(THIS_FILE,
876
+ " Oboe stream %s error (%d/%s), "
877
+ " trying to restart stream.." ,
878
+ dir_st, result, oboe::convertToText (result)));
879
+
880
+ Stop ();
881
+ Start ();
882
+ }
883
+
884
+ pj_mutex_unlock (mutex);
835
885
}
836
886
837
887
~MyOboeEngine () {
888
+ /* Oboe should have been stopped before destroying the engine.
889
+ * As stopping it here (below) may cause undefined behaviour when
890
+ * there is race condition against restart in onErrorAfterClose().
891
+ */
892
+ pj_assert (thread_quit == PJ_TRUE);
893
+
894
+ /* Forcefully stopping Oboe anyway */
838
895
Stop ();
896
+
897
+ /* Try to trigger context switch in case onErrorAfterClose() is
898
+ * waiting for mutex.
899
+ */
900
+ pj_thread_sleep (1 );
901
+
902
+ if (mutex)
903
+ pj_mutex_destroy (mutex);
839
904
}
840
905
841
906
private:
@@ -932,6 +997,8 @@ class MyOboeEngine : oboe::AudioStreamDataCallback,
932
997
}
933
998
934
999
delete [] tmp_buf;
1000
+
1001
+ PJ_LOG (5 ,(THIS_FILE, " Oboe %s thread stopped" , this_->dir_st ));
935
1002
return 0 ;
936
1003
}
937
1004
@@ -941,12 +1008,13 @@ class MyOboeEngine : oboe::AudioStreamDataCallback,
941
1008
oboe::AudioStream *oboe_stream;
942
1009
const char *dir_st;
943
1010
pj_thread_t *thread;
944
- pj_bool_t thread_quit;
1011
+ volatile pj_bool_t thread_quit;
945
1012
sem_t sem;
946
1013
AtomicQueue *queue;
947
1014
pj_timestamp ts;
948
1015
bool err_thread_registered;
949
1016
pj_thread_desc err_thread_desc;
1017
+ pj_mutex_t *mutex;
950
1018
951
1019
};
952
1020
@@ -1119,6 +1187,15 @@ static pj_status_t strm_destroy(pjmedia_aud_stream *s)
1119
1187
/* Stop the stream */
1120
1188
strm_stop (s);
1121
1189
1190
+ if (stream->rec_engine ) {
1191
+ delete stream->rec_engine ;
1192
+ stream->rec_engine = NULL ;
1193
+ }
1194
+ if (stream->play_engine ) {
1195
+ delete stream->play_engine ;
1196
+ stream->play_engine = NULL ;
1197
+ }
1198
+
1122
1199
pj_pool_release (stream->pool );
1123
1200
PJ_LOG (4 , (THIS_FILE, " Oboe stream destroyed" ));
1124
1201
0 commit comments