플러터:마이크 입력

학교의 모든 지식. SMwiki
둘러보기로 이동 검색으로 이동

틀:플러터 Dart:개요 플러터에 대한 지식 분류

  1. 플러터:개요
    1. 플러터:VSCode
  2. 플러터:실행
  3. 개념 잡기
    1. 플러터:화면 하나 만들기
    2. 플러터:변하는 화면(StatefulWidget)
    3. 플러터:화면 전환(화면 쌓기, 하단 네비게이션 바)
    4. 플러터:화면 전환(Drawer)
    5. 플러터:키보드 입력
    6. 플러터:슬라이더
    7. 플러터:그래프 그리기(fl chart)
    8. 플러터:데이터 저장(간단한 데이터)
    9. 플러터:인증(Firebase 인증)
    10. 플러터:인증(OAuth2)
  4. 권한 사용
    1. 플러터:마이크 입력
  5. 위젯
    1. 플러터:아이콘
    2. 플러터:레이아웃 계열 위젯
    3. 플러터:네비게이션 계열 위젯
    4. 플러터:버튼
    5. 플러터:상태관리
  6. 플러터:DB연결
    1. 플러터:Firebase
    2. 플러터:MySQL
  7. 디자인
    1. 플러터:테마
    2. 플러터:앱바
    3. 플러터:버튼
  8. 플러터:배포
  9. 플러터:참고자료
  10. 플러터:위젯
    1. 플러터:공간배치용 위젯
  11. 플러터:라이브러리
    1. 플러터:logger

개요[편집 | 원본 편집]

기기에서 마이크를 사용하는 법.

플랫폼 지원 현황[편집 | 원본 편집]

noise_meter를 이용할건데, 모바일에서만 사용 가능하다.

플랫폼 지원 여부 이유
Android 완전 지원
iOS 완전 지원
Windows noise_meter 미지원
Web 마이크 API 제한
macOS
Linux

사전준비 권한 설정[편집 | 원본 편집]

권한 부여[편집 | 원본 편집]

항목 설명 비고
안드로이드 android/app/src/main/AndroidManifest.xml 에 넣는다.
  • 권한은 <application> 태그 밖, <manifest> 태그 안에 위치해야 함.
  • <uses-permission android:name="android.permission.RECORD_AUDIO"/>
아이폰 ios/Runner/Info.plist에 넣는다. <key>NSMicrophoneUsageDescription</key>

<string>앱에서 음성 입력을 사용합니다.</string>

iOS에선 메시지도 직접 입력할 수 있음.(여기에 사용 목적 명시해야 함.)

Windows,

Web

별도 설정 불필요. 자동으로 팝업이 뜸.

필요한 패키지 점검[편집 | 원본 편집]

항목 설명 비고
패키지 설치 # pubspec.yaml

dependencies:

  flutter:

    sdk: flutter

permission_handler: ^11.3.1

noise_meter: ^5.0.1

noise_meter는 db를 읽는다.

아마 시간이 지나면 오래된 버전이라 문제가 발생할 수 있음.

flutter pub get

동작 흐름[편집 | 원본 편집]

  1. 앱 시작
  2. 마이크 권한 요청
  3. 권한 허용 시 NoiseMeter 시작
  4. 실시간 데시벨 스트림 수신
  5. UI 업데이트 (setState)
  6. 정지 버튼으로 스트림 취소

데시벨 측정 예시 코드[편집 | 원본 편집]

마찬가지로 패키지 버전에 따라 함수명이 달라지기도 함. 오래되면 문제가 발생할 수 있음.

// filepath: c:\Temp\for device\decibel_app\lib\main.dart
import 'package:flutter/material.dart';
import 'package:noise_meter/noise_meter.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:async';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '데시벨 측정기',
      home: DecibelMeter(),
    );
  }
}

class DecibelMeter extends StatefulWidget {
  @override
  _DecibelMeterState createState() => _DecibelMeterState();
}

class _DecibelMeterState extends State<DecibelMeter> {
  double _currentDB = 0.0;
  bool _isListening = false;
  StreamSubscription<NoiseReading>? _noiseSubscription;

  Future<void> _startListening() async {
    // 마이크 권한 요청
    var status = await Permission.microphone.request();
    if (status.isGranted) {
      _noiseSubscription = NoiseMeter().noise.listen(
        (NoiseReading noiseReading) {
          setState(() {
            _currentDB = noiseReading.meanDecibel;
          });
        },
        onError: (error) {
          print('오류: $error');
        },
      );
      setState(() {
        _isListening = true;
      });
    }
  }

  void _stopListening() {
    _noiseSubscription?.cancel();
    setState(() {
      _isListening = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('데시벨 측정기'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              '${_currentDB.toInt()} dB',
              style: TextStyle(fontSize: 48),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: _isListening ? _stopListening : _startListening,
              child: Text(_isListening ? '정지' : '시작'),
            ),
          ],
        ),
      ),
    );
  }
}

코드 구조 분석[편집 | 원본 편집]

핵심 클래스들[편집 | 원본 편집]

// 📊 데시벨 읽기
NoiseMeter().noise.listen((NoiseReading reading) {
  double db = reading.meanDecibel; // 평균 데시벨
});

// 🔒 권한 요청
Permission.microphone.request();

// 🎛️ 스트림 제어
StreamSubscription<NoiseReading>? subscription;

상태 관리[편집 | 원본 편집]

class _DecibelMeterState extends State<DecibelMeter> {
  double _currentDB = 0.0;                      // 현재 데시벨 값
  bool _isListening = false;                    // 측정 중인지 상태
  StreamSubscription<NoiseReading>? _noiseSubscription;  // 스트림 구독 객체
}

주요 학습 포인트[편집 | 원본 편집]

1. 스트림(Stream) 패턴[편집 | 원본 편집]

// 스트림 구독
_subscription = NoiseMeter().noise.listen(
  (data) => setState(() => _currentDB = data.meanDecibel),
  onError: (error) => print('에러: $error'),
);

// 메모리 누수 방지
_subscription?.cancel();

2. 권한 관리[편집 | 원본 편집]

Future<void> _requestPermission() async {
  var status = await Permission.microphone.request();
  if (status.isGranted) {
    // 권한 허용됨
  } else if (status.isDenied) {
    // 권한 거부됨
  } else if (status.isPermanentlyDenied) {
    // 영구 거부됨 - 설정으로 유도
    openAppSettings();
  }
}

3. 생명주기 관리[편집 | 원본 편집]

@override
void dispose() {
  _noiseSubscription?.cancel(); // 위젯 해제 시 스트림 정리
  super.dispose();
}

데시벨 참고값[편집 | 원본 편집]

데시벨(dB) 소음 수준 예시
0-20 매우 조용 도서관, 속삭임
20-40 조용 조용한 사무실
40-60 보통 일반 대화
60-80 시끄러움 TV, 음악
80-100 매우 시끄러움 지하철, 공사장
100+ 위험 콘서트, 제트기

UI 개선 아이디어[편집 | 원본 편집]

데시벨 수준별 색상[편집 | 원본 편집]

Color _getDecibelColor(double db) {
  if (db < 40) return Colors.green;      // 조용
  if (db < 70) return Colors.yellow;     // 보통
  return Colors.red;                     // 시끄러움
}

프로그레스 바[편집 | 원본 편집]

LinearProgressIndicator(
  value: _currentDB / 120.0, // 120dB 기준
  backgroundColor: Colors.grey[300],
  valueColor: AlwaysStoppedAnimation(_getDecibelColor(_currentDB)),
)

다음 단계 학습[편집 | 원본 편집]

중급 기능[편집 | 원본 편집]

  • 📈 실시간 그래프 (charts_flutter)
  • 💾 측정값 저장 (shared_preferences)
  • 🔔 임계값 알림 (flutter_local_notifications)

고급 기능[편집 | 원본 편집]

  • 🎵 주파수 분석 (FFT)
  • 📊 통계 분석 (평균, 최대, 최소)
  • 🌐 데이터 공유 (Firebase)

완성된 기능[편집 | 원본 편집]

  • ✅ 실시간 데시벨 측정
  • ✅ 마이크 권한 관리
  • ✅ 간단한 시작/정지 제어
  • ✅ 크로스 플랫폼 (Android/iOS)
  • ✅ 메모리 안전 (스트림 정리)

이 프로젝트로 Flutter의 스트림, 권한, 네이티브 패키지 사용법을 모두 학습할 수 있습니다! 🎉