Skip to content

Commit

Permalink
コードの構成を整理してインターフェイスで集約する
Browse files Browse the repository at this point in the history
  • Loading branch information
tnoho committed Feb 27, 2024
1 parent 4992738 commit 111092a
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import android.content.Context;

class MainThreadWrapper extends SoraAudioManager {
class MainThreadWrapper implements SoraAudioManager {
private SoraAudioManager soraAudioManager;

private static class OnChangeRouteObserver implements SoraAudioManager.OnChangeRouteObserver {
SoraAudioManager.OnChangeRouteObserver observer;
private static class OnChangeRouteObserverWrapper implements OnChangeRouteObserver {
OnChangeRouteObserver observer;

public OnChangeRouteObserver(SoraAudioManager.OnChangeRouteObserver observer) {
public OnChangeRouteObserverWrapper(OnChangeRouteObserver observer) {
this.observer = observer;
}

Expand Down Expand Up @@ -36,12 +36,12 @@ public void OnChangeRoute() {
}

@Override
public void start(SoraAudioManager.OnChangeRouteObserver observer) {
public void start(OnChangeRouteObserver observer) {
//メインスレッドでない場合はメインスレッドで再実行
if (!SoraThreadUtils.runOnMainThread(() -> start(observer))) {
return;
}
soraAudioManager.start(new OnChangeRouteObserver(observer));
soraAudioManager.start(new OnChangeRouteObserverWrapper(observer));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,180 +1,23 @@
/*
* Copyright 2014 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*
* Modifications made by tnoho in 2024.
*/

package jp.shiguredo.sora.audiomanager;

import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioAttributes;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Build;
import android.util.Log;

public class SoraAudioManager {
private static final String TAG = "SoraAudioManager";
protected Context context;
protected AudioManager audioManager;
protected BroadcastReceiver wiredHeadsetReceiver;
protected boolean running;
private int savedAudioMode = AudioManager.MODE_INVALID;
private boolean savedIsMicrophoneMute;
protected boolean hasWiredHeadset;
protected boolean isSetHandsfree;
protected Object audioFocus;
protected OnChangeRouteObserver onChangeRouteObserver;

public interface OnChangeRouteObserver {
public interface SoraAudioManager {
interface OnChangeRouteObserver {
// オーディオデバイスの変更を通知するコールバック
void OnChangeRoute();
}

// 有線ヘッドセットの接続を通知するレシーバー
private class WiredHeadsetReceiver extends BroadcastReceiver {
private static final int STATE_UNPLUGGED = 0;
private static final int STATE_PLUGGED = 1;
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra("state", STATE_UNPLUGGED);
hasWiredHeadset = (state == STATE_PLUGGED);
updateAudioDeviceState();
}
}

protected SoraAudioManager() {
}

protected SoraAudioManager(Context context) {
SoraThreadUtils.checkIsOnMainThread();
this.context = context;
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
wiredHeadsetReceiver = new WiredHeadsetReceiver();
running = false;
}

/*
* オーディオの制御を開始する
* Java は destructor がないので start - stop にする
* TODO(tnoho) 以下のパラメーターは start の段階で調整できてもいい気がする
* - オーディオフォーカス
* - モード
* - マイクミュート
*/
public void start(SoraAudioManagerLegacy.OnChangeRouteObserver observer) {
savedAudioMode = audioManager.getMode();
savedIsMicrophoneMute = audioManager.isMicrophoneMute();

// オーディオフォーカスを取得する
// 前のオーディオフォーカス保持者に再生の一時停止を期待する
int result;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
audioFocus = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
.setAudioAttributes(
new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build()
).build();
result = audioManager.requestAudioFocus((AudioFocusRequest) audioFocus);
} else {
audioFocus = (AudioManager.OnAudioFocusChangeListener) focusChange -> {
// 取ったからといってその後何かするわけではないのでログだけ出す
Log.d(TAG, "onAudioFocusChange: " + focusChange);
};
result = audioManager.requestAudioFocus((AudioManager.OnAudioFocusChangeListener) audioFocus,
AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
}
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.d(TAG, "Audio focus request granted for VOICE_CALL streams");
} else {
Log.e(TAG, "Audio focus request failed");
}

// VoIP 向けのモードに切り替え
// MODE_IN_CALL か MODE_IN_COMMUNICATION でなければ setSpeakerphoneOn が使えない
audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);

// マイクのミュートは解除する
setMicrophoneMute(false);

// 初期化を行う
isSetHandsfree = false;
}

// 有線ヘッドセットの接続を通知するレシーバーを登録する
protected void registerWiredHeadsetReceiver() {
context.registerReceiver(
wiredHeadsetReceiver,
new IntentFilter(Intent.ACTION_HEADSET_PLUG));
}
void start(OnChangeRouteObserver observer);

// オーディオの制御を終了する
@SuppressLint("WrongConstant")
public void stop() {
// 開始時に保存していた設定に戻す
setMicrophoneMute(savedIsMicrophoneMute);
audioManager.setMode(savedAudioMode);

// オーディオフォーカスを放棄する
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
audioManager.abandonAudioFocusRequest((AudioFocusRequest) audioFocus);
} else {
audioManager.abandonAudioFocus((AudioManager.OnAudioFocusChangeListener) audioFocus);
}
audioFocus = null;

// コールバックを破棄する
onChangeRouteObserver = null;
}

// 有線ヘッドセットの接続を通知するレシーバーを解除
protected void unregisterWiredHeadsetReceiver() {
context.unregisterReceiver(wiredHeadsetReceiver);
}


// ハンズフリーかを確認する
public boolean isHandsfree() {
return false;
}
void stop();

// ハンズフリーに設定する
public void setHandsfree(boolean on) {
SoraThreadUtils.checkIsOnMainThread();
if (isSetHandsfree == on) {
return;
}
isSetHandsfree = on;
updateAudioDeviceState();
}

// マイクミュートの設定を変更する
private void setMicrophoneMute(boolean on) {
boolean wasMuted = audioManager.isMicrophoneMute();
if (wasMuted == on) {
return;
}
audioManager.setMicrophoneMute(on);
}
void setHandsfree(boolean on);

// 電話用スピーカーがデバイスにあるかを確認する
protected boolean hasEarpiece() {
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
}

// 状態に基づいてデバイスを選択する
void updateAudioDeviceState() {}
// ハンズフリーかを確認する
boolean isHandsfree();
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import java.util.List;

@TargetApi(Build.VERSION_CODES.S)
public class SoraAudioManager2 extends SoraAudioManager {
public class SoraAudioManager2 extends SoraAudioManagerBase {
private static final String TAG = "SoraAudioManager2";
private final BroadcastReceiver bluetoothHeadsetReceiver;
private final List<AudioDeviceInfo> audioDevices = new ArrayList<>();
Expand Down Expand Up @@ -72,10 +72,6 @@ private SoraAudioManager2(Context context) {
this.bluetoothHeadsetReceiver = new BluetoothHeadsetBroadcastReceiver();
}

/*
* オーディオの制御を開始する
* Java は destructor がないので start - stop にする
*/
@Override
public void start(OnChangeRouteObserver observer) {
Log.d(TAG, "start");
Expand Down Expand Up @@ -107,7 +103,6 @@ public void start(OnChangeRouteObserver observer) {
registerWiredHeadsetReceiver();
}

// オーディオの制御を終了する
@SuppressLint("WrongConstant")
public void stop() {
Log.d(TAG, "stop");
Expand All @@ -128,7 +123,7 @@ public void stop() {
super.stop();
}

// ハンズフリーかを確認する
@Override
public boolean isHandsfree() {
AudioDeviceInfo currentDeviceInfo = audioManager.getCommunicationDevice();
if (currentDeviceInfo == null) {
Expand Down
Loading

0 comments on commit 111092a

Please sign in to comment.