@@ -14,7 +14,9 @@ See the License for the specific language governing permissions and
14
14
limitations under the License.
15
15
*/
16
16
17
+ import { isEqual } from "lodash" ;
17
18
import { Optional } from "matrix-events-sdk" ;
19
+ import { logger } from "matrix-js-sdk/src/logger" ;
18
20
import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter" ;
19
21
20
22
import { getChunkLength } from ".." ;
@@ -38,6 +40,12 @@ export interface ChunkRecordedPayload {
38
40
length : number ;
39
41
}
40
42
43
+ // char sequence of "OpusHead"
44
+ const OpusHead = [ 79 , 112 , 117 , 115 , 72 , 101 , 97 , 100 ] ;
45
+
46
+ // char sequence of "OpusTags"
47
+ const OpusTags = [ 79 , 112 , 117 , 115 , 84 , 97 , 103 , 115 ] ;
48
+
41
49
/**
42
50
* This class provides the function to seamlessly record fixed length chunks.
43
51
* Subscribe with on(VoiceBroadcastRecordingEvents.ChunkRecorded, (payload: ChunkRecordedPayload) => {})
@@ -47,11 +55,11 @@ export class VoiceBroadcastRecorder
47
55
extends TypedEventEmitter < VoiceBroadcastRecorderEvent , EventMap >
48
56
implements IDestroyable
49
57
{
50
- private headers = new Uint8Array ( 0 ) ;
58
+ private opusHead ?: Uint8Array ;
59
+ private opusTags ?: Uint8Array ;
51
60
private chunkBuffer = new Uint8Array ( 0 ) ;
52
61
// position of the previous chunk in seconds
53
62
private previousChunkEndTimePosition = 0 ;
54
- private pagesFromRecorderCount = 0 ;
55
63
// current chunk length in seconds
56
64
private currentChunkLength = 0 ;
57
65
@@ -73,7 +81,7 @@ export class VoiceBroadcastRecorder
73
81
public async stop ( ) : Promise < Optional < ChunkRecordedPayload > > {
74
82
try {
75
83
await this . voiceRecording . stop ( ) ;
76
- } catch {
84
+ } catch ( e ) {
77
85
// Ignore if the recording raises any error.
78
86
}
79
87
@@ -82,7 +90,6 @@ export class VoiceBroadcastRecorder
82
90
const chunk = this . extractChunk ( ) ;
83
91
this . currentChunkLength = 0 ;
84
92
this . previousChunkEndTimePosition = 0 ;
85
- this . headers = new Uint8Array ( 0 ) ;
86
93
return chunk ;
87
94
}
88
95
@@ -103,11 +110,19 @@ export class VoiceBroadcastRecorder
103
110
104
111
private onDataAvailable = ( data : ArrayBuffer ) : void => {
105
112
const dataArray = new Uint8Array ( data ) ;
106
- this . pagesFromRecorderCount ++ ;
107
113
108
- if ( this . pagesFromRecorderCount <= 2 ) {
109
- // first two pages contain the headers
110
- this . headers = concat ( this . headers , dataArray ) ;
114
+ // extract the part, that contains the header type info
115
+ const headerType = Array . from ( dataArray . slice ( 28 , 36 ) ) ;
116
+
117
+ if ( isEqual ( OpusHead , headerType ) ) {
118
+ // data seems to be an "OpusHead" header
119
+ this . opusHead = dataArray ;
120
+ return ;
121
+ }
122
+
123
+ if ( isEqual ( OpusTags , headerType ) ) {
124
+ // data seems to be an "OpusTags" header
125
+ this . opusTags = dataArray ;
111
126
return ;
112
127
}
113
128
@@ -134,9 +149,14 @@ export class VoiceBroadcastRecorder
134
149
return null ;
135
150
}
136
151
152
+ if ( ! this . opusHead || ! this . opusTags ) {
153
+ logger . warn ( "Broadcast chunk cannot be extracted. OpusHead or OpusTags is missing." ) ;
154
+ return null ;
155
+ }
156
+
137
157
const currentRecorderTime = this . voiceRecording . recorderSeconds ;
138
158
const payload : ChunkRecordedPayload = {
139
- buffer : concat ( this . headers , this . chunkBuffer ) ,
159
+ buffer : concat ( this . opusHead ! , this . opusTags ! , this . chunkBuffer ) ,
140
160
length : this . getCurrentChunkLength ( ) ,
141
161
} ;
142
162
this . chunkBuffer = new Uint8Array ( 0 ) ;
0 commit comments