• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (C) 2023-2024 Huawei Device Co., Ltd.
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16import Logger from '../../../ohosTest/ets/utils/Logger';
17import common from '@ohos.app.ability.common';
18import fs from '@ohos.file.fs';
19import router from '@ohos.router';
20import audio from '@ohos.multimedia.audio';
21import { BusinessError } from '@ohos.base';
22
23const CLOSE_MODE = 0;
24const OPEN_MODE = 1;
25const TRACKING_MODE = 2;
26
27@Entry
28@Component
29struct SpatialAudio {
30  private audioRenderers: audio.AudioRenderer[] = [];
31  private audioRendererOptions: audio.AudioRendererOptions[] = [
32    {
33      streamInfo: {
34        samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000,
35        channels: audio.AudioChannel.CHANNEL_2,
36        sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
37        encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW,
38        channelLayout: audio.AudioChannelLayout.CH_LAYOUT_STEREO
39      },
40
41      rendererInfo: {
42        usage: audio.StreamUsage.STREAM_USAGE_MUSIC,
43        rendererFlags: 0
44      }
45    },
46    {
47      streamInfo: {
48        samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000,
49        channels: audio.AudioChannel.CHANNEL_6,
50        sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
51        encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW,
52        channelLayout: audio.AudioChannelLayout.CH_LAYOUT_5POINT1
53      },
54      rendererInfo: {
55        usage: audio.StreamUsage.STREAM_USAGE_MOVIE,
56        rendererFlags: 0
57      }
58    }
59  ];
60
61  private appContext?: common.Context;
62  private audioSources = ['/2p0.pcm', '/5p1.pcm'];
63  private audioSpatializationManager?: audio.AudioSpatializationManager;
64  private audioRoutingManager?: audio.AudioRoutingManager;
65  private curPos: number[] = [0, 0]
66  @State supportState: number = 1;
67  @State spatializationEnabled: boolean = false;
68  @State trackingEnabled: boolean = false;
69  @State musicState1: boolean = false;
70  @State musicState2: boolean = false;
71  @State spatialSceneMode: audio.AudioSpatializationSceneType = audio.AudioSpatializationSceneType.DEFAULT;
72
73  @Builder Press2PlayDemo1() {
74    Image($r("app.media.ic_pause_spa"))
75      .height(36)
76      .width(36)
77      .margin({ right: 16 })
78      .id("2P0_play_btn")
79      .onClick(async () => {
80        this.musicState1 = !this.musicState1;
81        await this.playAudio(0);
82      })
83  }
84
85  @Builder Press2PauseDemo1() {
86    Image($r("app.media.ic_play_spa"))
87      .height(36)
88      .width(36)
89      .margin({ right: 16 })
90      .id("2P0_pause_btn")
91      .onClick(async () => {
92        this.musicState1 = !this.musicState1;
93        await this.pauseAudio(0);
94      })
95  }
96
97  @Builder Press2PlayDemo2() {
98    Image($r("app.media.ic_pause_spa"))
99      .height(36)
100      .width(36)
101      .margin({ right: 16 })
102      .id("5P1_play_btn")
103      .onClick(async () => {
104        this.musicState2 = !this.musicState2;
105        await this.playAudio(1);
106      })
107  }
108
109  @Builder Press2PauseDemo2() {
110    Image($r("app.media.ic_play_spa"))
111      .height(36)
112      .width(36)
113      .margin({ right: 16 })
114      .id("5P1_pause_btn")
115      .onClick(async () => {
116        this.musicState2 = !this.musicState2;
117        await this.pauseAudio(1);
118      })
119
120  }
121
122  @Builder CloseModeOn() {
123    Image($r("app.media.ic_audio_close_on"))
124      .height(48)
125      .width(48)
126      .margin({ left: 8 })
127      .id("close_mode_on")
128  }
129
130  @Builder CloseModeOff() {
131    Image($r("app.media.ic_audio_close_normal"))
132      .height(48)
133      .width(48)
134      .margin({ left: 8 })
135      .id("close_mode_off")
136      .onClick(async () => {
137        if (this.supportState !== CLOSE_MODE && this.audioSpatializationManager) {
138          try {
139            this.audioSpatializationManager.setSpatializationEnabled(false, () => {
140            })
141            this.audioSpatializationManager.setHeadTrackingEnabled(false, () => {
142            })
143          } catch (err) {
144            Logger.error(`Set Spatialization or Head Tracking disabled failed, ${JSON.stringify(err)}`);
145            return;
146          }
147        }
148      })
149  }
150
151  @Builder OpenModeDisabled() {
152    Image($r("app.media.ic_audio_open_disable"))
153      .height(48)
154      .width(48)
155  }
156
157  @Builder OpenModeOn() {
158    Image($r("app.media.ic_audio_open_on"))
159      .height(48)
160      .width(48)
161      .id("open_mode_on")
162  }
163
164  @Builder OpenModeOff() {
165    Image($r("app.media.ic_audio_open_normal"))
166      .height(48)
167      .width(48)
168      .id("open_mode_off")
169      .onClick(async () => {
170        if (this.audioSpatializationManager) {
171          try {
172            this.audioSpatializationManager.setSpatializationEnabled(true, () => {
173            })
174            this.audioSpatializationManager.setHeadTrackingEnabled(false, () => {
175            })
176          } catch (err) {
177            Logger.error(`Set open mode failed, ${JSON.stringify(err)}`);
178            return;
179          }
180        }
181
182      })
183  }
184
185  @Builder TrackingModeOn() {
186    Image($r("app.media.ic_audio_track_on"))
187      .height(48)
188      .width(48)
189      .margin({ right: 8 })
190      .id("tracking_mode_on")
191  }
192
193  @Builder TrackingModeOff() {
194    Image($r("app.media.ic_audio_track_normal"))
195      .height(48)
196      .width(48)
197      .margin({ right: 8 })
198      .id("tracking_mode_off")
199      .onClick(async () => {
200        if (this.audioSpatializationManager) {
201          try {
202            this.audioSpatializationManager.setSpatializationEnabled(true, () => {
203            })
204            this.audioSpatializationManager.setHeadTrackingEnabled(true, () => {
205            })
206          } catch (err) {
207            Logger.error(`Set HeadTracking enabled failed, ${JSON.stringify(err)}`);
208            return;
209          }
210        }
211      })
212  }
213
214  @Builder TrackingModeDisabled() {
215    Image($r("app.media.ic_audio_track_disable"))
216      .height(48)
217      .width(48)
218      .margin({ right: 8 })
219      .fillColor("#182431")
220  }
221
222  @Builder UIForClose() {
223    this.CloseModeOn();
224    this.OpenModeDisabled();
225    this.TrackingModeDisabled();
226  }
227
228  @Builder UIForOpen() {
229    if (this.spatializationEnabled === true) {
230      this.CloseModeOff();
231      this.OpenModeOn();
232    } else {
233      this.CloseModeOn();
234      this.OpenModeOff();
235    }
236    this.TrackingModeDisabled();
237  }
238
239  @Builder UIForTracking() {
240    if (this.spatializationEnabled === true && this.trackingEnabled === true) {
241      this.CloseModeOff();
242      this.OpenModeOff();
243      this.TrackingModeOn();
244    } else if (this.spatializationEnabled === true && this.trackingEnabled === false) {
245      this.CloseModeOff();
246      this.OpenModeOn();
247      this.TrackingModeOff();
248    } else {
249      this.CloseModeOn();
250      this.OpenModeOff();
251      this.TrackingModeOff();
252    }
253  }
254
255  @Builder OpenTextEnable() {
256    Text($r("app.string.OPEN_TEXT"))
257      .height("100%")
258      .width(64)
259      .fontSize(12)
260      .fontWeight(500)
261      .margin({ right: 68 })
262      .fontColor("#182431")
263      .textAlign(TextAlign.Center)
264  }
265
266  @Builder OpenTextDisable() {
267    Text($r("app.string.OPEN_TEXT"))
268      .height("100%")
269      .width(64)
270      .fontSize(12)
271      .fontWeight(500)
272      .margin({ right: 68 })
273      .fontColor(Color.Grey)
274      .textAlign(TextAlign.Center)
275      .id("open_mode_disabled")
276  }
277
278  @Builder TrackingTextEnable() {
279    Text($r("app.string.TRACKING_TEXT"))
280      .height(16)
281      .width(48)
282      .fontSize(12)
283      .fontWeight(500)
284      .fontColor("#182431")
285      .textAlign(TextAlign.Center)
286  }
287
288  @Builder TrackingTextDisable() {
289    Text($r("app.string.TRACKING_TEXT"))
290      .height(16)
291      .width(48)
292      .fontSize(12)
293      .fontWeight(500)
294      .fontColor(Color.Grey)
295      .textAlign(TextAlign.Center)
296      .id("tracking_mode_disabled")
297  }
298
299  @Builder DIYTitle() {
300    Row() {
301      Text($r('app.string.SPATIAL_AUDIO'))
302        .fontWeight(700)
303        .fontSize(20)
304    }
305    .height("100%")
306    .justifyContent(FlexAlign.Center)
307  }
308
309  @Builder ChooseSpatialSceneMode() {
310    Row() {
311      Row() {
312        Text($r('app.string.SPATIAL_SCENE_MODE'))
313          .fontSize(14)
314          .fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
315          .fontColor('#000000')
316          .opacity(0.6)
317          .fontWeight(500)
318      }
319      .height(20)
320      .width(176)
321      .margin({ top: 28, left: 28 })
322      .justifyContent(FlexAlign.Start)
323    }
324    .width(360)
325    .height(56)
326    .justifyContent(FlexAlign.Start)
327
328    Column() {
329      Row() {
330        Image($r('app.media.ic_space_normal'))
331          .height(24)
332          .width(24)
333        Row() {
334          Text($r('app.string.SCENE_MODE_DEFAULT'))
335            .fontSize(16)
336            .fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
337            .fontColor('#000000')
338            .opacity(0.9)
339            .fontWeight(500)
340          Checkbox()
341            .shape((CheckBoxShape.CIRCLE))
342            .select(this.spatialSceneMode === audio.AudioSpatializationSceneType.DEFAULT)
343            .margin({ right: 2 })
344            .height(20)
345            .width(20)
346            .onChange((value: boolean) => {
347              if (value === true) {
348                this.spatialSceneMode = audio.AudioSpatializationSceneType.DEFAULT;
349                if (this.audioSpatializationManager) {
350                  try {
351                    this.audioSpatializationManager.setSpatializationSceneType(this.spatialSceneMode);
352                  } catch (err) {
353                    Logger.error(`setSpatializationSceneType failed ,Error: ${JSON.stringify(err)}`);
354                    return;
355                  }
356                }
357
358              }
359            })
360        }
361        .width(264)
362        .height(22)
363        .margin({ left: 16 })
364        .justifyContent(FlexAlign.SpaceBetween)
365      }
366      .justifyContent(FlexAlign.SpaceBetween)
367      .width(304)
368      .height(55.5)
369
370      Row() {
371        Column() {
372        }
373        .width(264)
374        .height(0.5)
375        .opacity(0.05)
376        .backgroundColor('#000000')
377      }
378      .justifyContent(FlexAlign.End)
379      .width(304)
380      .height(0.5)
381
382      Row() {
383        Image($r('app.media.ic_space_theatre'))
384          .height(24)
385          .width(24)
386        Row() {
387          Text($r('app.string.SCENE_MODE_AUDIOBOOK'))
388            .fontSize(16)
389            .fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
390            .fontColor('#000000')
391            .opacity(0.9)
392            .fontWeight(500)
393          Checkbox()
394            .shape((CheckBoxShape.CIRCLE))
395            .margin({ right: 2 })
396            .height(20)
397            .width(20)
398            .select(this.spatialSceneMode === audio.AudioSpatializationSceneType.AUDIOBOOK)
399            .onChange((value: boolean) => {
400              if (value === true) {
401                this.spatialSceneMode = audio.AudioSpatializationSceneType.AUDIOBOOK;
402                if (this.audioSpatializationManager) {
403                  try {
404                    this.audioSpatializationManager.setSpatializationSceneType(this.spatialSceneMode);
405                  } catch (err) {
406                    Logger.error(`setSpatializationSceneType failed ,Error: ${JSON.stringify(err)}`);
407                    return;
408                  }
409                }
410              }
411            })
412        }
413        .width(264)
414        .height(22)
415        .margin({ left: 16 })
416        .justifyContent(FlexAlign.SpaceBetween)
417      }
418      .justifyContent(FlexAlign.SpaceBetween)
419      .width(304)
420      .height(55.5)
421
422      Row() {
423        Column() {
424        }
425        .width(264)
426        .height(0.5)
427        .opacity(0.05)
428        .backgroundColor('#000000')
429      }
430      .justifyContent(FlexAlign.End)
431      .width(304)
432      .height(0.5)
433
434      Row() {
435        Image($r('app.media.ic_space_movie'))
436          .height(24)
437          .width(24)
438        Row() {
439          Text($r('app.string.SCENE_MODE_MOVIE'))
440            .fontSize(16)
441            .fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
442            .fontColor('#000000')
443            .opacity(0.9)
444            .fontWeight(500)
445          Checkbox()
446            .shape((CheckBoxShape.CIRCLE))
447            .margin({ right: 2 })
448            .height(20)
449            .width(20)
450            .select(this.spatialSceneMode === audio.AudioSpatializationSceneType.MOVIE)
451            .onChange((value: boolean) => {
452              if (value === true) {
453                this.spatialSceneMode = audio.AudioSpatializationSceneType.MOVIE;
454                if (this.audioSpatializationManager) {
455                  try {
456                    this.audioSpatializationManager.setSpatializationSceneType(this.spatialSceneMode);
457                  } catch (err) {
458                    Logger.error(`setSpatializationSceneType failed ,Error: ${JSON.stringify(err)}`);
459                    return;
460                  }
461                }
462              }
463            })
464        }
465        .width(264)
466        .height(22)
467        .margin({ left: 16 })
468        .justifyContent(FlexAlign.SpaceBetween)
469      }
470      .justifyContent(FlexAlign.SpaceBetween)
471      .width(304)
472      .height(55.5)
473
474      Row() {
475        Column() {
476        }
477        .width(264)
478        .height(0.5)
479        .opacity(0.05)
480        .backgroundColor('#000000')
481      }
482      .justifyContent(FlexAlign.End)
483      .width(304)
484      .height(0.5)
485
486      Row() {
487        Image($r('app.media.ic_space_music'))
488          .height(24)
489          .width(24)
490        Row() {
491          Text($r('app.string.SCENE_MODE_MUSIC'))
492            .fontSize(16)
493            .fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
494            .fontColor('#000000')
495            .opacity(0.9)
496            .fontWeight(500)
497          Checkbox()
498            .shape((CheckBoxShape.CIRCLE))
499            .margin({ right: 2 })
500            .height(20)
501            .width(20)
502            .select(this.spatialSceneMode === audio.AudioSpatializationSceneType.MUSIC)
503            .onChange((value: boolean) => {
504              if (value === true) {
505                this.spatialSceneMode = audio.AudioSpatializationSceneType.MUSIC;
506                if (this.audioSpatializationManager) {
507                  try {
508                    this.audioSpatializationManager.setSpatializationSceneType(this.spatialSceneMode);
509                  } catch (err) {
510                    Logger.error(`setSpatializationSceneType failed ,Error: ${JSON.stringify(err)}`);
511                    return;
512                  }
513                }
514              }
515            })
516        }
517        .width(264)
518        .height(22)
519        .margin({ left: 16 })
520        .justifyContent(FlexAlign.SpaceBetween)
521      }
522      .justifyContent(FlexAlign.SpaceBetween)
523      .width(304)
524      .height(56)
525    }
526    .backgroundColor('#FFFFFF')
527    .borderRadius(24)
528    .height(232)
529    .width(328)
530    .justifyContent(FlexAlign.Center)
531  }
532
533  updateSupportStateUI(): void {
534    this.supportState = this.supportStateQuery();
535    if (this.audioSpatializationManager) {
536      try {
537        this.spatializationEnabled = this.audioSpatializationManager.isSpatializationEnabled();
538        this.trackingEnabled = this.audioSpatializationManager.isHeadTrackingEnabled();
539        this.spatialSceneMode = this.audioSpatializationManager.getSpatializationSceneType();
540      } catch (err) {
541        Logger.error(`update Support State UI failed ,Error: ${JSON.stringify(err)}`);
542        return;
543      }
544    }
545  }
546
547  supportStateQuery(): number {
548    if (this.audioRoutingManager) {
549      let audioDeviceDescriptors: audio.AudioDeviceDescriptors =
550      this.audioRoutingManager.getPreferredOutputDeviceForRendererInfoSync(this.audioRendererOptions[0].rendererInfo);
551      audioDeviceDescriptors.forEach(audioDeviceDescriptor => {
552        Logger.info("Device Role:" + audioDeviceDescriptor.deviceRole + ", device Type:" +
553        audioDeviceDescriptor.deviceType + ", Macaddress:" + audioDeviceDescriptor.address);
554      })
555
556      let isSpaSupported: boolean = false;
557      let isSpaSupportedForDevice: boolean = false;
558      let isTraSupported: boolean = false;
559      let isTraSupportedForDevice: boolean = false;
560      if (this.audioSpatializationManager) {
561        try {
562          isSpaSupported = this.audioSpatializationManager.isSpatializationSupported();
563          isSpaSupportedForDevice =
564          this.audioSpatializationManager.isSpatializationSupportedForDevice(audioDeviceDescriptors[0]);
565          isTraSupported = this.audioSpatializationManager.isHeadTrackingSupported();
566          isTraSupportedForDevice =
567          this.audioSpatializationManager.isHeadTrackingSupportedForDevice(audioDeviceDescriptors[0]);
568        } catch (err) {
569          Logger.error(`supportStateQuery ,Error: ${JSON.stringify(err)}`);
570        }
571      } else {
572        Logger.info("Get manager failed.");
573      }
574      let isSpatializationSupportedBoth: boolean = isSpaSupported && isSpaSupportedForDevice;
575      let isHeadTrackingSupportedBoth: boolean = isTraSupported && isTraSupportedForDevice;
576      if (isSpatializationSupportedBoth && isHeadTrackingSupportedBoth) {
577        return TRACKING_MODE;
578      } else if (isSpatializationSupportedBoth) {
579        return OPEN_MODE;
580      } else {
581        return CLOSE_MODE;
582      }
583    }
584    return CLOSE_MODE;
585  }
586
587  async init(): Promise<void> {
588    if (this.appContext) {
589      return;
590    }
591    this.appContext = getContext(this);
592
593    for (let index = 0; index < 2; index++) {
594      try {
595        let renderer = await audio.createAudioRenderer(this.audioRendererOptions[index]);
596        Logger.info("Create renderer success");
597        this.audioRenderers.push(renderer);
598      } catch (err) {
599        Logger.error(`audioRenderer_${index} create ,Error: ${JSON.stringify(err)}`);
600        return;
601      }
602    }
603
604    let audioManager = audio.getAudioManager();
605    try {
606      this.audioSpatializationManager = audioManager.getSpatializationManager();
607    } catch (err) {
608      Logger.error(`Get Spatialization Manager failed, Error: ${JSON.stringify(err)}`);
609      return;
610    }
611
612    this.audioRoutingManager = audioManager.getRoutingManager();
613    this.updateSupportStateUI();
614    let t_audioRendererInfo: audio.AudioRendererInfo = {
615      usage: audio.StreamUsage.STREAM_USAGE_MUSIC,
616      rendererFlags: 0
617    }
618    if (this.audioRoutingManager) {
619      this.audioRoutingManager.on("preferOutputDeviceChangeForRendererInfo", t_audioRendererInfo, () => {
620        Logger.info("Output device changed");
621        this.updateSupportStateUI();
622      })
623    }
624    if (this.audioSpatializationManager) {
625      this.audioSpatializationManager.on("spatializationEnabledChange", (res) => {
626        this.spatializationEnabled = res;
627      })
628    }
629
630    if (this.audioSpatializationManager) {
631      this.audioSpatializationManager.on("headTrackingEnabledChange", (res) => {
632        this.trackingEnabled = res;
633      })
634    }
635  }
636
637  async over(): Promise<void> {
638    this.appContext = undefined;
639    try {
640      this.audioRenderers[0].stop();
641      this.audioRenderers[0].release();
642      this.audioRenderers[1].stop();
643      this.audioRenderers[1].release();
644    } catch (err) {
645      let error = err as BusinessError;
646      Logger.error(`AudioRenderer stop or release : Error: ${JSON.stringify(error)}`);
647      return;
648    }
649    this.audioRenderers = [];
650
651    if (this.audioRoutingManager) {
652      this.audioRoutingManager.off("deviceChange");
653    }
654
655    if (this.audioSpatializationManager) {
656      this.audioSpatializationManager.off("spatializationEnabledChange");
657    }
658
659    if (this.audioSpatializationManager) {
660      this.audioSpatializationManager.off("headTrackingEnabledChange");
661    }
662  }
663
664  async playAudio(index: number): Promise<void> {
665    if (this.audioRenderers[index] === null) {
666      return;
667    }
668
669
670    let bufferSize: number = 0;
671    try {
672      bufferSize = await this.audioRenderers[index].getBufferSize();
673      await this.audioRenderers[index].start();
674    } catch (err) {
675      let error = err as BusinessError;
676      Logger.error(`AudioRenderer start : Error: ${JSON.stringify(error)}`);
677      return;
678    }
679
680    let buf = new ArrayBuffer(bufferSize);
681    let filePath: string = "";
682    if (this.appContext) {
683      filePath = this.appContext.filesDir + this.audioSources[index];
684    }
685    let stat = await fs.stat(filePath);
686    let len = stat.size % bufferSize == 0 ? Math.floor(stat.size / bufferSize) : Math.floor(stat.size / bufferSize + 1);
687    let file = await fs.open(filePath, 0o0);
688    let i: number = this.curPos[index]
689
690    while (true) {
691      if (!this.audioRenderers[index]) {
692        break;
693      }
694      Logger.info("start write");
695      while (i < len) {
696        if (this.audioRenderers[index].state === audio.AudioState.STATE_RELEASED) {
697          return;
698        }
699        if (this.audioRenderers[index].state === audio.AudioState.STATE_PAUSED) {
700          this.curPos[index] = i;
701          return;
702        }
703
704        class options {
705          offset: number = 0
706          length: number = 0
707        }
708
709        let readOptions: options = {
710          offset: i * bufferSize,
711          length: bufferSize
712        }
713        await fs.read(file.fd, buf, readOptions);
714        await this.audioRenderers[index].write(buf);
715        i += 1;
716      }
717      i = 0;
718    }
719
720  }
721
722  async pauseAudio(index: number): Promise<void> {
723    try {
724      if (this.audioRenderers[index]) {
725        await this.audioRenderers[index].pause();
726      }
727    } catch (err) {
728      Logger.error(`Pause Error: ${JSON.stringify(err)}`);
729      return;
730    }
731  }
732
733  async aboutToAppear(): Promise<void> {
734    await this.init();
735  }
736
737  aboutToDisappear(): void {
738    this.over();
739  }
740
741  onPageShow(): void {
742    if (this.audioSpatializationManager === undefined) {
743      return;
744    }
745    this.updateSupportStateUI()
746    Logger.info("Page show");
747  }
748
749  onPageHide(): void {
750    Logger.info("Page Hide");
751    if (this.audioRenderers[0] && this.audioRenderers[0].state === audio.AudioState.STATE_RUNNING) {
752      this.audioRenderers[0].pause();
753      this.musicState1 = false;
754    }
755    if (this.audioRenderers[1] && this.audioRenderers[1].state === audio.AudioState.STATE_RUNNING) {
756      this.audioRenderers[1].pause();
757      this.musicState2 = false;
758    }
759  }
760
761  build() {
762    Column() {
763      Column() {
764        Row() {
765          Navigation() {
766          }
767          .hideBackButton(false)
768          .titleMode(NavigationTitleMode.Mini)
769          .title(this.DIYTitle())
770          .mode(NavigationMode.Stack)
771        }
772        .height(56)
773        .width(360)
774        .id('spatial_audio_back_btn')
775        .onClick(async () => {
776          await router.replaceUrl({ url: 'pages/Index' });
777        })
778
779        Row() {
780          Row() {
781            Text($r("app.string.2P0_MUSIC"))
782              .fontSize(20)
783              .fontWeight(500)
784              .fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
785              .margin({ top: 21, bottom: 21, left: 16.5 })
786            if (!this.musicState1) {
787              this.Press2PlayDemo1();
788            } else {
789              this.Press2PauseDemo1();
790            }
791          }
792          .height("100%")
793          .width(336)
794          .backgroundColor('#FFFFFF')
795          .justifyContent(FlexAlign.SpaceBetween)
796          .borderRadius(24)
797        }
798        .justifyContent(FlexAlign.SpaceAround)
799        .height(68)
800        .width('100%')
801        .margin({ top: 8 })
802
803        Row() {
804          Row() {
805            Text($r("app.string.5P1_MUSIC"))
806              .fontSize(20)
807              .fontWeight(500)
808              .fontFamily($r('sys.string.ohos_id_text_font_family_medium'))
809              .margin({ top: 21, bottom: 21, left: 16.5 })
810
811            if (!this.musicState2) {
812              this.Press2PlayDemo2();
813            } else {
814              this.Press2PauseDemo2();
815            }
816          }
817          .height("100%")
818          .width(336)
819          .backgroundColor('#FFFFFF')
820          .justifyContent(FlexAlign.SpaceBetween)
821          .borderRadius(24)
822        }
823        .justifyContent(FlexAlign.SpaceAround)
824        .height(68)
825        .width('100%')
826        .margin({ top: 12 })
827
828        if (this.supportState > CLOSE_MODE && this.spatializationEnabled === true) {
829          this.ChooseSpatialSceneMode()
830        }
831      }
832      .width('100%')
833      .justifyContent(FlexAlign.Start)
834
835
836      Column() {
837        Row() {
838          if (this.supportState === 2) {
839            this.UIForTracking();
840          } else if (this.supportState === 1) {
841            this.UIForOpen();
842          } else {
843            this.UIForClose();
844          }
845        }
846        .height(64)
847        .width(312)
848        .borderRadius(100)
849        .backgroundColor('#FFFFFF')
850        .justifyContent(FlexAlign.SpaceBetween)
851
852        Row() {
853          Text($r("app.string.CLOSE_TEXT"))
854            .height("100%")
855            .width(64)
856            .fontSize(12)
857            .fontWeight(500)
858            .margin({ right: 60 })
859            .fontColor(Color.Black)
860            .textAlign(TextAlign.Center)
861
862          if (this.supportState === 0) {
863            this.OpenTextDisable();
864            this.TrackingTextDisable();
865          } else if (this.supportState === 1) {
866            this.OpenTextEnable();
867            this.TrackingTextDisable();
868          } else {
869            this.OpenTextEnable();
870            this.TrackingTextEnable();
871          }
872        }
873        .height(16)
874        .width(312)
875        .margin({ left: 24, right: 24, top: 8 })
876      }
877      .height(112)
878      .width('100%')
879    }
880    .height('100%')
881    .width('100%')
882    .backgroundColor('#f1f3f5')
883    .justifyContent(FlexAlign.SpaceBetween)
884  }
885}