9

アプリで音声を iPhone の上部スピーカー (通話中に耳に押し付けるスピーカー) から再生しようとしています。電話をシミュレートし、まさにそれを行うApp Storeのゲーム(「タップタップタップ」による「ザハイスト」)をプレイしたので、それが可能であることを知っています。

私はオンラインで多くの調査を行ってきましたが、その可能性について話し合ったことのある人を見つけるのに驚くほど苦労しています. 投稿の圧倒的多数は、上部の「電話」スピーカーとハンズフリー スピーカーではなく、ハンズフリー スピーカーとプラグイン イヤホン (これこれこれのように) に関するものであるようです。(その問題の一部は、適切な名前を持っていない可能性があります。「電話スピーカー」は、多くの場合、デバイスの下部にあるハンズフリー スピーカーなどを意味するため、ターゲットを絞った検索を行うのは困難です)。Apple のAudio Session Category Route Overrides.

これに関すると思われる 1 つの投稿を見つけました: link。たくさんのコードも提供されているので、家にいるのは自由だと思っていましたが、今ではコードを機能させることができないようです。簡単にするために、DisableSpeakerPhoneメソッド(正しく理解すれば、オーディオを上部スピーカーに再ルーティングするメソッドである必要があります)をコピーしてviewDidLoad、それが機能するかどうかを確認しましたが、最初の「アサート」行が失敗し、オーディオが続行します底を再生します。(コメントで提案されているように、AudioToolbox Frameworkもインポートしたので、それは問題ではありません。)

以下は、私が作業しているコードのメイン ブロックです (これは、viewDidLoadテストのためにコピーしたものです)。リンク先の記事には、さらにいくつかのメソッドがあります。

void DisableSpeakerPhone () {
    UInt32 dataSize = sizeof(CFStringRef);
    CFStringRef currentRoute = NULL;
    OSStatus result = noErr;

    AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &dataSize, &currentRoute);

    // Set the category to use the speakers and microphone.
    UInt32 sessionCategory = kAudioSessionCategory_PlayAndRecord;
    result = AudioSessionSetProperty (
                                      kAudioSessionProperty_AudioCategory,
                                      sizeof (sessionCategory),
                                      &sessionCategory
                                      );
    assert(result == kAudioSessionNoError);

    Float64 sampleRate = 44100.0;
    dataSize = sizeof(sampleRate);
    result = AudioSessionSetProperty (
                                      kAudioSessionProperty_PreferredHardwareSampleRate,
                                      dataSize,
                                      &sampleRate
                                      );
    assert(result == kAudioSessionNoError);

    // Default to speakerphone if a headset isn't plugged in.
    // Overriding the output audio route

    UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None; 
    dataSize = sizeof(audioRouteOverride);
    AudioSessionSetProperty(
                            kAudioSessionProperty_OverrideAudioRoute,
                            dataSize,
                            &audioRouteOverride);

    assert(result == kAudioSessionNoError);

    AudioSessionSetActive(YES);
} 

私の質問は次のとおりです。A) そのコードが機能しない理由を理解するのを手伝ってくれる人、または B) ボタンを押してオーディオを上部スピーカーにルーティングできるようにするためのより良い提案を提供してくれる人はいますか?

PS iOS プログラミングにどんどん慣れてきましたが、AudioSessions などの世界に足を踏み入れるのはこれが初めてなので、詳細とコード サンプルは大歓迎です! ご協力ありがとうございました!

アップデート:

「彼は」(以下)の提案から、上記のコードを削除して、次のように置き換えました。

[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive: YES error:nil];

の冒頭でviewDidLoad。ただし、まだ機能していません (つまり、電話の上部にあるレシーバーではなく、電話の下部にあるスピーカーからまだ音声が出ているということです)。どうやらデフォルトの動作はAVAudioSessionCategoryPlayAndRecord、受信機からオーディオを独自に送信するためのものであるべきなので、まだ何かが間違っています。

より具体的には、このコードで行っていることは、iPod Music Player を介してオーディオを再生することです (上記の AVAudioSession 行の直後に初期化されますviewDidLoad)。

_musicPlayer = [MPMusicPlayerController iPodMusicPlayer];

その iPod Music Player のメディアは、次の方法で選択されますMPMediaPickerController

- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection {
    if (mediaItemCollection) {
        [_musicPlayer setQueueWithItemCollection: mediaItemCollection];
        [_musicPlayer play];
    }

    [self dismissViewControllerAnimated:YES completion:nil];
}

これはすべて私にはかなり簡単に思えます。エラーや警告はありません。メディア ピッカーとミュージック プレーヤーが正しく機能していることもわかっています。正しい曲の再生が開始されるためです。間違ったスピーカーから出ているだけです。「このAudioSessionを使用してメディアを再生する」メソッドなどはありますか? または、現在アクティブなオーディオ セッション カテゴリを確認して、元に戻すものがないことを確認する方法はありますか? デフォルトに依存するのではなく、レシーバーを使用するようにコードに強調する方法はありますか? 1 ヤード ラインにいるような気がします。最後のビットを越える必要があります...

編集:私は、受信機から再生したくない iPod Music Player に関する何かであるという理論を考えました。私の推論: 公式の iPod アプリを介して再生を開始するように曲を設定し、開発中のアプリを介してシームレスに調整 (一時停止、スキップなど) することが可能です。あるアプリから次のアプリへの連続再生は、iPod Music Player が独自のオーディオ ルート設定を持っているか、新しいアプリで設定を確認するために停止しないのではないかと考えさせられました。彼らが話していることを知っている人は、それがそのようなものである可能性があると思いますか?

4

4 に答える 4

28

これも一時期苦労しました。多分これは後で誰かを助けるでしょう.ポートをオーバーライドする新しい方法を使用することもできます. サンプル コードのメソッドの多くは、実際には推奨されていません。

したがって、取得して AudioSession sharedInstance を取得した場合、

NSError *error = nil;
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
[session setActive: YES error:nil];

セッション カテゴリは AVAudioSessionCategoryPlayAndRecord である必要があります。この値を確認することで、現在の出力を取得できます。

AVAudioSessionPortDescription *routePort = session.currentRoute.outputs.firstObject;
NSString *portType = routePort.portType;

そして、送信先のポートに応じて、次を使用して出力を切り替えるだけです

if ([portType isEqualToString:@"Receiver"]) {
       [session  overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
} else {
       [session  overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:&error];
}

これにより、スピーカーフォンとレシーバーへの出力をすばやく切り替えることができます。

于 2014-06-25T20:45:26.577 に答える