/*
* Copyright (C) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// [Start all_audioCapturer]
// [Start create_AudioCapturer]
import { audio } from '@kit.AudioKit';
// [StartExclude create_AudioCapturer]
// [Start listen_AudioCapturer]
// [Start start_AudioCapturer]
// [Start stop_AudioCapturer]
// [Start release_AudioCapturer]
import { BusinessError } from '@kit.BasicServicesKit';
// [StartExclude start_AudioCapturer]
// [StartExclude stop_AudioCapturer]
// [StartExclude release_AudioCapturer]
import { fileIo as fs } from '@kit.CoreFileKit';
import { common, abilityAccessCtrl, PermissionRequestResult } from '@kit.AbilityKit';

// [StartExclude listen_AudioCapturer]
const TAG = 'AudioCapturerDemo';

// [EndExclude listen_AudioCapturer]
class Options {
  public offset?: number;
  public length?: number;
}

// [StartExclude listen_AudioCapturer]
let audioRenderer: audio.AudioRenderer | undefined = undefined;
let audioCapturer: audio.AudioCapturer | undefined = undefined;
// [EndExclude create_AudioCapturer]
let audioStreamInfo: audio.AudioStreamInfo = {
  samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_48000, // 采样率。
  channels: audio.AudioChannel.CHANNEL_2, // 通道。
  sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式。
  encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式。
};
let audioCapturerInfo: audio.AudioCapturerInfo = {
  source: audio.SourceType.SOURCE_TYPE_MIC, // 音源类型:Mic音频源。根据业务场景配置,参考SourceType。
  capturerFlags: 0 // 音频采集器标志。
};
let audioCapturerOptions: audio.AudioCapturerOptions = {
  streamInfo: audioStreamInfo,
  capturerInfo: audioCapturerInfo
};
// [StartExclude create_AudioCapturer]
let audioRendererInfo: audio.AudioRendererInfo = {
  usage: audio.StreamUsage.STREAM_USAGE_MUSIC, // 音频流使用类型:音乐。根据业务场景配置,参考StreamUsage。
  rendererFlags: 0 // 音频渲染器标志。
};
let audioRendererOptions: audio.AudioRendererOptions = {
  streamInfo: audioStreamInfo,
  rendererInfo: audioRendererInfo
};

let file: fs.File;
let readDataCallback: Callback<ArrayBuffer>;
let writeDataCallback: audio.AudioRendererWriteDataCallback;

// [StartExclude all_audioCapturer]
async function requestMicrophonePermission(context: common.UIAbilityContext): Promise<boolean> {
  let atManager = abilityAccessCtrl.createAtManager();
  let result: PermissionRequestResult = await atManager
    .requestPermissionsFromUser(context, ['ohos.permission.MICROPHONE']);
  return result.authResults[0] === 0;
}

// [EndExclude all_audioCapturer]

async function initArguments(context: common.UIAbilityContext): Promise<void> {
  // [EndExclude listen_AudioCapturer]
  let bufferSize: number = 0;
  let path = context.cacheDir;
  let filePath = path + '/S16LE_2_48000.pcm';
  file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  readDataCallback = (buffer: ArrayBuffer) => {
    let options: Options = {
      offset: bufferSize,
      length: buffer.byteLength
    }
    fs.writeSync(file.fd, buffer, options);
    bufferSize += buffer.byteLength;
  };
  // [StartExclude listen_AudioCapturer]
}

async function initRender(context: common.UIAbilityContext) {
  let bufferSize: number = 0;
  let path = context.cacheDir;
  // 此处仅作示例,实际使用时需要将文件替换为应用要播放的PCM文件。
  let filePath = path + '/S16LE_2_48000.pcm';
  file = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
  writeDataCallback = (buffer: ArrayBuffer) => {
    let options: Options = {
      offset: bufferSize,
      length: buffer.byteLength
    };

    try {
      let bufferLength = fs.readSync(file.fd, buffer, options);
      bufferSize += buffer.byteLength;
      // 如果当前回调传入的数据不足一帧,空白区域需要使用静音数据填充,否则会导致播放出现杂音。
      if (bufferLength < buffer.byteLength) {
        let view = new DataView(buffer);
        for (let i = bufferLength; i < buffer.byteLength; i++) {
          // 空白区域填充静音数据。当使用音频采样格式为SAMPLE_FORMAT_U8时0x7F为静音数据,使用其他采样格式时0为静音数据。
          view.setUint8(i, 0);
        }
      }
      // API version 11不支持返回回调结果,从API version 12开始支持返回回调结果。
      // 如果开发者不希望播放某段buffer,返回audio.AudioDataCallbackResult.INVALID即可。
      return audio.AudioDataCallbackResult.VALID;
    } catch (error) {
      console.error('Error reading file:', error);
      // API version 11不支持返回回调结果,从API version 12开始支持返回回调结果。
      return audio.AudioDataCallbackResult.INVALID;
    }
  };
  audio.createAudioRenderer(audioRendererOptions, (err, renderer) => { // 创建AudioRenderer实例。
    if (!err) {
      console.info(`${TAG}: creating AudioRenderer success`);
      audioRenderer = renderer;
      if (audioRenderer !== undefined) {
        audioRenderer.on('writeData', writeDataCallback);
      }
    } else {
      console.info(`${TAG}: creating AudioRenderer failed, error: ${err.message}`);
    }
  });
}

// 开始一次音频渲染。
async function startRender(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioRenderer !== undefined) {
    let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];
    if (stateGroup.indexOf(audioRenderer.state.valueOf()) === -1) { // 当且仅当状态为prepared、paused和stopped之一时才能启动渲染。
      console.error(TAG + 'start failed');
      return;
    }
    // 启动渲染。
    audioRenderer.start((err: BusinessError) => {
      if (err) {
        console.error('Renderer start failed.');
      } else {
        console.info('Renderer start success.');
      }
    });
  }
}

// 停止渲染。
async function stopRender(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioRenderer !== undefined) {
    // 只有渲染器状态为running或paused的时候才可以停止。
    if (audioRenderer.state.valueOf() !== audio.AudioState.STATE_RUNNING &&
      audioRenderer.state.valueOf() !== audio.AudioState.STATE_PAUSED) {
      console.info('Renderer is not running or paused.');
      return;
    }
    // 停止渲染。
    audioRenderer.stop((err: BusinessError) => {
      if (err) {
        console.error('Renderer stop failed.');
      } else {
        console.info('Renderer stop success.');
      }
    });
  }
}

// 销毁实例,释放资源。
async function releaseRender(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioRenderer !== undefined) {
    // 渲染器状态不是released状态,才能release。
    if (audioRenderer.state.valueOf() === audio.AudioState.STATE_RELEASED) {
      console.info('Renderer already released');
      return;
    }
    // 释放资源。
    audioRenderer.release((err: BusinessError) => {
      if (err) {
        console.error('Renderer release failed.');
      } else {
        fs.closeSync(file);
        console.info('Renderer release success.');
      }
    });
  }
}

// 初始化,创建实例,设置监听事件。
async function init(updateCallback?: (msg: string, isError: boolean) => void, stateCallback?:
  (msg: string) => void): Promise<void> {
  // [EndExclude create_AudioCapturer]
  audio.createAudioCapturer(audioCapturerOptions, (err, capturer) => { // 创建AudioCapturer实例。
    if (err) {
      console.error(`Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`);
      // [StartExclude all_audioCapturer]
      // [StartExclude create_AudioCapturer]
      const errorMsg = `Invoke createAudioCapturer failed, code is ${err.code}, message is ${err.message}`;
      if (updateCallback) {
        updateCallback(errorMsg, true);
      }
      // [EndExclude create_AudioCapturer]
      // [EndExclude all_audioCapturer]
      return;
    }
    console.info(`${TAG}: create AudioCapturer success`);
    // [StartExclude all_audioCapturer]
    // [StartExclude create_AudioCapturer]
    const successMsg = `${TAG}: create AudioCapturer success`;
    if (updateCallback) {
      updateCallback(successMsg, false);
    }
    // [EndExclude create_AudioCapturer]
    // [EndExclude all_audioCapturer]
    audioCapturer = capturer;
    if (audioCapturer !== undefined) {
      // [EndExclude listen_AudioCapturer]
      audioCapturer.on('readData', readDataCallback);
      // [End listen_AudioCapturer]
      // [StartExclude all_audioCapturer]
      // [StartExclude create_AudioCapturer]
      // 自动启动状态监听
      listenAudioCapturerState(stateCallback);
      // [EndExclude create_AudioCapturer]
      // [EndExclude all_audioCapturer]
    }
  });
  // [End create_AudioCapturer]
}

// 开始一次音频采集。
async function start(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioCapturer !== undefined) {
    let stateGroup = [audio.AudioState.STATE_PREPARED
      , audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED];
    // 当且仅当状态为STATE_PREPARED、STATE_PAUSED和STATE_STOPPED之一时才能启动采集。
    if (stateGroup.indexOf(audioCapturer.state.valueOf()) === -1) {
      console.error(`${TAG}: start failed`);
      // [StartExclude all_audioCapturer]
      const errorMsg = `${TAG}: start failed`;
      if (updateCallback) {
        updateCallback(errorMsg, true);
      }
      // [EndExclude all_audioCapturer]
      return;
    }

    // 启动采集。
    // [EndExclude start_AudioCapturer]
    audioCapturer.start((err: BusinessError) => {
      if (err) {
        // [StartExclude all_audioCapturer]
        // [StartExclude start_AudioCapturer]
        const errorMsg = 'Capturer start failed.';
        if (updateCallback) {
          updateCallback(errorMsg, true);
        }
        // [EndExclude start_AudioCapturer]
        // [EndExclude all_audioCapturer]
        console.error('Capturer start failed.');
      } else {
        // [StartExclude all_audioCapturer]
        // [StartExclude start_AudioCapturer]
        const successMsg = 'Capturer start success.';
        if (updateCallback) {
          updateCallback(successMsg, false);
        }
        // [EndExclude start_AudioCapturer]
        // [EndExclude all_audioCapturer]
        console.info('Capturer start success.');
      }
    });
    // [End start_AudioCapturer]
  }
}

// 停止采集。
async function stop(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioCapturer !== undefined) {
    // 只有采集器状态为STATE_RUNNING或STATE_PAUSED的时候才可以停止。
    if (audioCapturer.state.valueOf() !== audio.AudioState.STATE_RUNNING &&
      audioCapturer.state.valueOf() !== audio.AudioState.STATE_PAUSED) {
      console.info('Capturer is not running or paused');
      // [StartExclude all_audioCapturer]
      const infoMsg = 'Capturer is not running or paused';
      if (updateCallback) {
        updateCallback(infoMsg, false);
      }
      // [EndExclude all_audioCapturer]
      return;
    }

    // 停止采集。
    // [EndExclude stop_AudioCapturer]
    audioCapturer.stop((err: BusinessError) => {
      if (err) {
        // [StartExclude all_audioCapturer]
        // [StartExclude stop_AudioCapturer]
        const errorMsg = 'Capturer stop failed.';
        if (updateCallback) {
          updateCallback(errorMsg, true);
        }
        // [EndExclude stop_AudioCapturer]
        // [EndExclude all_audioCapturer]
        console.error('Capturer stop failed.');
      } else {
        // [StartExclude all_audioCapturer]
        // [StartExclude stop_AudioCapturer]
        const successMsg = 'Capturer stop success.';
        if (updateCallback) {
          updateCallback(successMsg, false);
        }
        // [EndExclude stop_AudioCapturer]
        // [EndExclude all_audioCapturer]
        console.info('Capturer stop success.');
      }
    });
    // [End stop_AudioCapturer]
  }
}

// 销毁实例,释放资源。
async function release(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioCapturer !== undefined) {
    // 采集器状态不是STATE_RELEASED或STATE_NEW状态,才能release。
    if (audioCapturer.state.valueOf() === audio.AudioState.STATE_RELEASED ||
      audioCapturer.state.valueOf() === audio.AudioState.STATE_NEW) {
      console.info('Capturer already released');
      // [StartExclude all_audioCapturer]
      const infoMsg = 'Capturer already released';
      if (updateCallback) {
        updateCallback(infoMsg, false);
      }
      // [EndExclude all_audioCapturer]
      return;
    }

    // 释放资源。
    // [EndExclude release_AudioCapturer]
    audioCapturer.release((err: BusinessError) => {
      if (err) {
        // [StartExclude all_audioCapturer]
        // [StartExclude release_AudioCapturer]
        const errorMsg = 'Capturer release failed.';
        if (updateCallback) {
          updateCallback(errorMsg, true);
        }
        // [EndExclude release_AudioCapturer]
        // [EndExclude all_audioCapturer]
        console.error('Capturer release failed.');
      } else {
        fs.closeSync(file);
        console.info('Capturer release success.');
        // [StartExclude all_audioCapturer]
        // [StartExclude release_AudioCapturer]
        const successMsg = 'Capturer release success.';
        if (updateCallback) {
          updateCallback(successMsg, false);
        }
        // [EndExclude release_AudioCapturer]
        // [EndExclude all_audioCapturer]
      }
    });
    // [End release_AudioCapturer]
  }
}

// [StartExclude all_audioCapturer]
async function viewAudioCapturerState(updateCallback?: (msg: string, isError: boolean) => void): Promise<void> {
  if (audioCapturer !== undefined) {
    // [Start view_AudioCapturerState]
    let audioCapturerState: audio.AudioState = audioCapturer.state;
    console.info(`Current state is: ${audioCapturerState}`)
    // [End view_AudioCapturerState]
    const stateMsg = `Current state is: ${audioCapturerState}`;
    if (updateCallback) {
      updateCallback(stateMsg, false);
    }
  }
}

// [EndExclude all_audioCapturer]

// [StartExclude all_audioCapturer]
async function listenAudioCapturerState(callbackUpdate?: (msg: string) => void): Promise<void> {
  if (audioCapturer !== undefined) {
    // [Start listen_AudioCapturerState]
    audioCapturer.on('stateChange', (capturerState: audio.AudioState) => {
      console.info(`State change to: ${capturerState}`)
      // [StartExclude listen_AudioCapturerState]
      const stateMsg = `State change to: ${capturerState}`;
      if (callbackUpdate) {
        callbackUpdate(stateMsg);
      }
      // [EndExclude listen_AudioCapturerState]
    });
    // [End listen_AudioCapturerState]
  }
}

// [EndExclude all_audioCapturer]
// [End all_audioCapturer]

@Entry
@Component
struct Index {
  @State currentState: string = '未初始化';
  @State logMessages: string = '暂无日志信息';
  @State callbackMessages: string = '暂无回调信息';

  // 更新日志信息
  updateLogInfo(msg: string, isError: boolean): void {
    const timestamp = new Date().toLocaleTimeString();
    const prefix = isError ? '[ERROR]' : '[INFO]';
    this.logMessages = `[${timestamp}] ${prefix} ${msg}`;
  }

  // 更新回调信息
  updateCallbackInfo(msg: string): void {
    const timestamp = new Date().toLocaleTimeString();
    this.callbackMessages = `[${timestamp}] ${msg}`;
  }

  build(): void {
    Scroll() {
      Column() {
        // 信息显示区域
        Column() {
          Text('实时状态信息')
            .fontSize(18)
            .fontWeight(600)
            .margin({ bottom: 12 })

          // 当前状态
          Column() {
            Text('当前状态')
              .fontSize(14)
              .fontWeight(600)
              .margin({ bottom: 8 })
            Text(this.currentState)
              .fontSize(14)
              .fontColor('#007DFF')
              .width('100%')
              .padding(10)
              .backgroundColor('#F0F0F0')
              .borderRadius(8)
          }
          .width('100%')
          .alignItems(HorizontalAlign.Start)
          .margin({ bottom: 12 })

          // 日志信息
          Column() {
            Text('日志信息')
              .fontSize(14)
              .fontWeight(600)
              .margin({ bottom: 8 })
            Text(this.logMessages)
              .fontSize(13)
              .fontColor('#52C41A')
              .width('100%')
              .padding(10)
              .backgroundColor('#F0F0F0')
              .borderRadius(8)
              .maxLines(5)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
          }
          .width('100%')
          .alignItems(HorizontalAlign.Start)
          .margin({ bottom: 12 })

          // 回调信息
          Column() {
            Text('回调信息')
              .fontSize(14)
              .fontWeight(600)
              .margin({ bottom: 8 })
            Text(this.callbackMessages)
              .fontSize(13)
              .fontColor('#FA8C16')
              .width('100%')
              .padding(10)
              .backgroundColor('#F0F0F0')
              .borderRadius(8)
              .maxLines(3)
              .textOverflow({ overflow: TextOverflow.Ellipsis })
          }
          .width('100%')
          .alignItems(HorizontalAlign.Start)
          .margin({ bottom: 20 })
        }
        .width('100%')
        .padding(16)
        .backgroundColor(Color.White)
        .borderRadius(12)
        .margin({ bottom: 16 })

        // 功能按钮
        Row() {
          Column() {
            Text('初始化').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ right: 12, bottom: 12 })
          .onClick(async (): Promise<void> => {
            let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
            let hasPermission = await requestMicrophonePermission(context);
            if (!hasPermission) {
              console.error('麦克风权限未授权,无法录音');
              this.updateLogInfo('麦克风权限未授权,无法录音', true);
              this.currentState = '权限未授权';
              return;
            }
            initArguments(context);
            init((msg, isError) => this.updateLogInfo(msg, isError), (msg) => this.updateCallbackInfo(msg));
            this.currentState = '已初始化';
          });

          Column() {
            Text('开始录制').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ bottom: 12 })
          .onClick(async (): Promise<void> => {
            start((msg, isError) => this.updateLogInfo(msg, isError));
            this.currentState = '录制中';
          });
        }

        Row() {
          Column() {
            Text('停止录制').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ right: 12, bottom: 12 })
          .onClick(async (): Promise<void> => {
            stop((msg, isError) => this.updateLogInfo(msg, isError));
            this.currentState = '已停止';
          });

          Column() {
            Text('释放资源').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ bottom: 12 })
          .onClick(async (): Promise<void> => {
            release((msg, isError) => this.updateLogInfo(msg, isError));
            this.currentState = '已释放';
          });
        }

        Row() {
          Column() {
            Text('查看状态').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ right: 12, bottom: 12 })
          .onClick(async (): Promise<void> => {
            viewAudioCapturerState((msg, isError) => this.updateLogInfo(msg, isError));
            if (audioCapturer !== undefined) {
              let state = audioCapturer.state;
              let stateText = '';
              switch (state) {
                case audio.AudioState.STATE_NEW:
                  stateText = '新建';
                  break;
                case audio.AudioState.STATE_PREPARED:
                  stateText = '准备就绪';
                  break;
                case audio.AudioState.STATE_RUNNING:
                  stateText = '运行中';
                  break;
                case audio.AudioState.STATE_STOPPED:
                  stateText = '已停止';
                  break;
                case audio.AudioState.STATE_RELEASED:
                  stateText = '已释放';
                  break;
                case audio.AudioState.STATE_PAUSED:
                  stateText = '已暂停';
                  break;
                default:
                  stateText = '未知';
              }
              this.currentState = stateText;
            }
          });

          Column() {
            Text('初始化录制内容').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ bottom: 12 })
          .onClick(async (): Promise<void> => {
            let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
            initRender(context);
            this.currentState = '已初始化';
          });
        }

        Row() {
          Column() {
            Text('开始播放').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ right: 12, bottom: 12 })
          .onClick(async (): Promise<void> => {
            startRender((msg, isError) => this.updateLogInfo(msg, isError));
            this.currentState = '播放开始';
          });

          Column() {
            Text('停止播放').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ bottom: 12 })
          .onClick(async (): Promise<void> => {
            stopRender((msg, isError) => this.updateLogInfo(msg, isError));
            this.currentState = '播放停止';
          });
        }

        Row() {
          Column() {
            Text('释放播放资源').fontColor(Color.Black).fontSize(14);
          }
          .backgroundColor(Color.White)
          .borderRadius(20)
          .width('45%')
          .height(60)
          .justifyContent(FlexAlign.Center)
          .margin({ right: 12, bottom: 12 })
          .onClick(async (): Promise<void> => {
            releaseRender((msg, isError) => this.updateLogInfo(msg, isError));
            this.currentState = '释放成功';
          });
        }
      }
      .height('100%')
      .width('100%')
      .backgroundColor('#F1F3F5')
      .padding(16);
    }
  }
}