1bf7ab50dSStephan Aßmus /* 2*b543dbc2SStephan Aßmus * Copyright 2003-2010 Haiku Inc. All rights reserved. 3bf7ab50dSStephan Aßmus * Distributed under the terms of the MIT License. 4bf7ab50dSStephan Aßmus * 5bf7ab50dSStephan Aßmus * Authors: 6bf7ab50dSStephan Aßmus * Marcus Overhagen 7bf7ab50dSStephan Aßmus */ 8a9cf57cfSAxel Dörfler 9a9cf57cfSAxel Dörfler 10bf7ab50dSStephan Aßmus #include "MixerCore.h" 11a9cf57cfSAxel Dörfler 12a9cf57cfSAxel Dörfler #include <Buffer.h> 13a9cf57cfSAxel Dörfler #include <string.h> 14a9cf57cfSAxel Dörfler #include <TimeSource.h> // TODO: debug only 15a9cf57cfSAxel Dörfler 16a9cf57cfSAxel Dörfler #include "ByteSwap.h" 17bf7ab50dSStephan Aßmus #include "MixerInput.h" 18bf7ab50dSStephan Aßmus #include "MixerUtils.h" 19bf7ab50dSStephan Aßmus #include "Resampler.h" 20bf7ab50dSStephan Aßmus 21678c2017Sbeveloper 22a9cf57cfSAxel Dörfler MixerInput::MixerInput(MixerCore *core, const media_input &input, 23a9cf57cfSAxel Dörfler float mixFrameRate, int32 mixFrameCount) 24a9cf57cfSAxel Dörfler : 25a9cf57cfSAxel Dörfler fCore(core), 262e9d6607Sbeveloper fInput(input), 2788777023Sbeveloper fInputByteSwap(0), 281c237c18Sbeveloper fEnabled(true), 292e9d6607Sbeveloper fInputChannelInfo(0), 302e9d6607Sbeveloper fInputChannelCount(0), 312e9d6607Sbeveloper fInputChannelMask(0), 322e9d6607Sbeveloper fMixerChannelInfo(0), 332e9d6607Sbeveloper fMixerChannelCount(0), 342e9d6607Sbeveloper fMixBuffer(0), 357b0daf5cSbeveloper fMixBufferFrameRate(0), 367b0daf5cSbeveloper fMixBufferFrameCount(0), 37e92593f4Sbeveloper fLastDataFrameWritten(-1), 38af8d0a4dSbeveloper fLastDataAvailableTime(-1), 39e92593f4Sbeveloper fFractionalFrames(0.0), 407b0daf5cSbeveloper fResampler(0), 41356855c3Sbeveloper fRtmPool(0), 429c3be6a5Sbeveloper fUserOverridesChannelDestinations(false) 43678c2017Sbeveloper { 44e6c7c99fSbeveloper fix_multiaudio_format(&fInput.format.u.raw_audio); 45e6c7c99fSbeveloper PRINT_INPUT("MixerInput::MixerInput", fInput); 46e6c7c99fSbeveloper PRINT_CHANNEL_MASK(fInput.format); 472e9d6607Sbeveloper 482e9d6607Sbeveloper ASSERT(fInput.format.u.raw_audio.channel_count > 0); 492e9d6607Sbeveloper 509c3be6a5Sbeveloper for (int i = 0; i < MAX_CHANNEL_TYPES; i++) 519c3be6a5Sbeveloper fChannelTypeGain[i] = 1.0f; 529c3be6a5Sbeveloper 532e9d6607Sbeveloper fInputChannelCount = fInput.format.u.raw_audio.channel_count; 542e9d6607Sbeveloper fInputChannelMask = fInput.format.u.raw_audio.channel_mask; 552e9d6607Sbeveloper fInputChannelInfo = new input_chan_info[fInputChannelCount]; 562e9d6607Sbeveloper 5788777023Sbeveloper // perhaps we need byte swapping 5888777023Sbeveloper if (fInput.format.u.raw_audio.byte_order != B_MEDIA_HOST_ENDIAN) { 59a9cf57cfSAxel Dörfler if (fInput.format.u.raw_audio.format 60a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_FLOAT 61a9cf57cfSAxel Dörfler || fInput.format.u.raw_audio.format 62a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_INT 63a9cf57cfSAxel Dörfler || fInput.format.u.raw_audio.format 64a9cf57cfSAxel Dörfler == media_raw_audio_format::B_AUDIO_SHORT) { 6588777023Sbeveloper fInputByteSwap = new ByteSwap(fInput.format.u.raw_audio.format); 6688777023Sbeveloper } 6788777023Sbeveloper } 6888777023Sbeveloper 692e9d6607Sbeveloper // initialize fInputChannelInfo 702e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) { 71*b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base = 0; 72*b543dbc2SStephan Aßmus // will be set by SetMixBufferFormat() 73*b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask = 0; 74*b543dbc2SStephan Aßmus // will be set by UpdateInputChannelDestinationMask() 752e9d6607Sbeveloper fInputChannelInfo[i].gain = 1.0; 762e9d6607Sbeveloper } 772e9d6607Sbeveloper 787b0daf5cSbeveloper // create resamplers 797b0daf5cSbeveloper fResampler = new Resampler * [fInputChannelCount]; 804cc71346SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 81ff617a11SAdrien Destugues // TODO create Interpolate instead of Resampler if the settings says so 82*b543dbc2SStephan Aßmus fResampler[i] = new Resampler(fInput.format.u.raw_audio.format, 83*b543dbc2SStephan Aßmus media_raw_audio_format::B_AUDIO_FLOAT); 844cc71346SStephan Aßmus } 857b0daf5cSbeveloper 86*b543dbc2SStephan Aßmus // fMixerChannelInfo and fMixerChannelCount will be initialized by 87*b543dbc2SStephan Aßmus // UpdateInputChannelDestinations() 88bf7ab50dSStephan Aßmus SetMixBufferFormat((int32)mixFrameRate, mixFrameCount); 89678c2017Sbeveloper } 90678c2017Sbeveloper 91a9cf57cfSAxel Dörfler 92678c2017Sbeveloper MixerInput::~MixerInput() 93678c2017Sbeveloper { 942e9d6607Sbeveloper if (fMixBuffer) 952e9d6607Sbeveloper rtm_free(fMixBuffer); 96356855c3Sbeveloper if (fRtmPool) 97356855c3Sbeveloper rtm_delete_pool(fRtmPool); 982e9d6607Sbeveloper delete [] fInputChannelInfo; 992e9d6607Sbeveloper delete [] fMixerChannelInfo; 1007b0daf5cSbeveloper 1017b0daf5cSbeveloper // delete resamplers 1027b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) 1037b0daf5cSbeveloper delete fResampler[i]; 1047b0daf5cSbeveloper delete [] fResampler; 105db6f1135SJérôme Duval delete fInputByteSwap; 106678c2017Sbeveloper } 107678c2017Sbeveloper 108a9cf57cfSAxel Dörfler 109678c2017Sbeveloper void 110678c2017Sbeveloper MixerInput::BufferReceived(BBuffer *buffer) 111678c2017Sbeveloper { 11288777023Sbeveloper void *data; 11388777023Sbeveloper size_t size; 11488777023Sbeveloper bigtime_t start; 115e92593f4Sbeveloper bigtime_t buffer_duration; 11688777023Sbeveloper 117d5848e21Sbeveloper if (!fMixBuffer) { 118*b543dbc2SStephan Aßmus ERROR("MixerInput::BufferReceived: dropped incoming buffer as we " 119*b543dbc2SStephan Aßmus "don't have a mix buffer\n"); 120d5848e21Sbeveloper return; 121d5848e21Sbeveloper } 1222e9d6607Sbeveloper 12388777023Sbeveloper data = buffer->Data(); 12488777023Sbeveloper size = buffer->SizeUsed(); 12588777023Sbeveloper start = buffer->Header()->start_time; 126*b543dbc2SStephan Aßmus buffer_duration = duration_for_frames(fInput.format.u.raw_audio.frame_rate, 127*b543dbc2SStephan Aßmus size / bytes_per_frame(fInput.format.u.raw_audio)); 1288d28117fSbeveloper if (start < 0) { 129*b543dbc2SStephan Aßmus ERROR("MixerInput::BufferReceived: buffer with negative start time of " 130*b543dbc2SStephan Aßmus "%Ld dropped\n", start); 1318d28117fSbeveloper return; 1328d28117fSbeveloper } 13388777023Sbeveloper 13488777023Sbeveloper // swap the byte order of this buffer, if necessary 13588777023Sbeveloper if (fInputByteSwap) 13688777023Sbeveloper fInputByteSwap->Swap(data, size); 13788777023Sbeveloper 138*b543dbc2SStephan Aßmus int offset = frames_for_duration(fMixBufferFrameRate, start) 139*b543dbc2SStephan Aßmus % fMixBufferFrameCount; 1408d28117fSbeveloper 141*b543dbc2SStephan Aßmus PRINT(4, "MixerInput::BufferReceived: buffer start %10Ld, offset %6d\n", 142*b543dbc2SStephan Aßmus start, offset); 1437b0daf5cSbeveloper 144191033efSbeveloper int in_frames = size / bytes_per_frame(fInput.format.u.raw_audio); 145*b543dbc2SStephan Aßmus double frames = double(in_frames * fMixBufferFrameRate) 146*b543dbc2SStephan Aßmus / fInput.format.u.raw_audio.frame_rate; 147e92593f4Sbeveloper int out_frames = int(frames); 148e92593f4Sbeveloper fFractionalFrames += frames - double(out_frames); 149e92593f4Sbeveloper if (fFractionalFrames >= 1.0) { 150e92593f4Sbeveloper fFractionalFrames -= 1.0; 1517619f562Sbeveloper out_frames++; 152e92593f4Sbeveloper } 153e92593f4Sbeveloper 154e92593f4Sbeveloper // if fLastDataFrameWritten != -1, then we have a valid last position 155e92593f4Sbeveloper // and can do glitch compensation 156e92593f4Sbeveloper if (fLastDataFrameWritten >= 0) { 157*b543dbc2SStephan Aßmus int expected_frame = (fLastDataFrameWritten + 1) 158*b543dbc2SStephan Aßmus % fMixBufferFrameCount; 159e92593f4Sbeveloper if (offset != expected_frame) { 160e92593f4Sbeveloper // due to rounding and other errors, offset might be off by +/- 1 161e92593f4Sbeveloper // this is not really a bad glitch, we just adjust the position 162e92593f4Sbeveloper if (offset == fLastDataFrameWritten) { 163*b543dbc2SStephan Aßmus // printf("MixerInput::BufferReceived: -1 frame GLITCH! last " 164*b543dbc2SStephan Aßmus // "frame was %ld, expected frame was %d, new frame is %d\n", 165*b543dbc2SStephan Aßmus // fLastDataFrameWritten, expected_frame, offset); 166e92593f4Sbeveloper offset = expected_frame; 167*b543dbc2SStephan Aßmus } else if (offset == ((fLastDataFrameWritten + 2) 168*b543dbc2SStephan Aßmus % fMixBufferFrameCount)) { 169*b543dbc2SStephan Aßmus // printf("MixerInput::BufferReceived: +1 frame GLITCH! last " 170*b543dbc2SStephan Aßmus // "frame was %ld, expected frame was %d, new frame is %d\n", 171*b543dbc2SStephan Aßmus // fLastDataFrameWritten, expected_frame, offset); 172e92593f4Sbeveloper offset = expected_frame; 173e92593f4Sbeveloper } else { 174*b543dbc2SStephan Aßmus printf("MixerInput::BufferReceived: GLITCH! last frame was " 175*b543dbc2SStephan Aßmus "%4ld, expected frame was %4d, new frame is %4d\n", 176*b543dbc2SStephan Aßmus fLastDataFrameWritten, expected_frame, offset); 177e92593f4Sbeveloper 178e92593f4Sbeveloper if (start > fLastDataAvailableTime) { 179*b543dbc2SStephan Aßmus if ((start - fLastDataAvailableTime) 180*b543dbc2SStephan Aßmus < (buffer_duration / 10)) { 181e92593f4Sbeveloper // buffer is less than 10% of buffer duration too late 182*b543dbc2SStephan Aßmus printf("short glitch, buffer too late, time delta " 183*b543dbc2SStephan Aßmus "%Ld\n", start - fLastDataAvailableTime); 184e92593f4Sbeveloper offset = expected_frame; 185e92593f4Sbeveloper out_frames++; 186e92593f4Sbeveloper } else { 187e92593f4Sbeveloper // buffer more than 10% of buffer duration too late 188*b543dbc2SStephan Aßmus // TODO: zerofill buffer 189*b543dbc2SStephan Aßmus printf("MAJOR glitch, buffer too late, time delta " 190*b543dbc2SStephan Aßmus "%Ld\n", start - fLastDataAvailableTime); 191e92593f4Sbeveloper } 192e92593f4Sbeveloper } else { // start <= fLastDataAvailableTime 193e92593f4Sbeveloper // the new buffer is too early 194*b543dbc2SStephan Aßmus if ((fLastDataAvailableTime - start) 195*b543dbc2SStephan Aßmus < (buffer_duration / 10)) { 196e92593f4Sbeveloper // buffer is less than 10% of buffer duration too early 197*b543dbc2SStephan Aßmus printf("short glitch, buffer too early, time delta " 198*b543dbc2SStephan Aßmus "%Ld\n", fLastDataAvailableTime - start); 199e92593f4Sbeveloper offset = expected_frame; 200e92593f4Sbeveloper out_frames--; 201e92593f4Sbeveloper if (out_frames < 1) 202e92593f4Sbeveloper out_frames = 1; 203e92593f4Sbeveloper } else { 204e92593f4Sbeveloper // buffer more than 10% of buffer duration too early 205*b543dbc2SStephan Aßmus // TODO: zerofill buffer 206*b543dbc2SStephan Aßmus printf("MAJOR glitch, buffer too early, time delta " 207*b543dbc2SStephan Aßmus "%Ld\n", fLastDataAvailableTime - start); 208e92593f4Sbeveloper } 209e92593f4Sbeveloper } 210e92593f4Sbeveloper } 211e92593f4Sbeveloper } 212e92593f4Sbeveloper } 2137b0daf5cSbeveloper 214*b543dbc2SStephan Aßmus // printf("data arrived for %10Ld to %10Ld, storing at frames %ld to %ld\n", 215*b543dbc2SStephan Aßmus // start, 216*b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 217*b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 218*b543dbc2SStephan Aßmus // offset + out_frames); 2197b0daf5cSbeveloper if (offset + out_frames > fMixBufferFrameCount) { 2207b0daf5cSbeveloper int out_frames1 = fMixBufferFrameCount - offset; 2217b0daf5cSbeveloper int out_frames2 = out_frames - out_frames1; 2227b0daf5cSbeveloper int in_frames1 = (out_frames1 * in_frames) / out_frames; 2237b0daf5cSbeveloper int in_frames2 = in_frames - in_frames1; 2247b0daf5cSbeveloper 225*b543dbc2SStephan Aßmus // printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at " 226*b543dbc2SStephan Aßmus // "frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), 227*b543dbc2SStephan Aßmus // start, 228*b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 229*b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 230*b543dbc2SStephan Aßmus // offset + out_frames1 - 1, 0, out_frames2 - 1); 231*b543dbc2SStephan Aßmus PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at " 232*b543dbc2SStephan Aßmus "frames %ld to %ld and %ld to %ld\n", fCore->fTimeSource->Now(), 233*b543dbc2SStephan Aßmus start, 234*b543dbc2SStephan Aßmus start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 235*b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)), offset, 236*b543dbc2SStephan Aßmus offset + out_frames1 - 1, 0, out_frames2 - 1); 237*b543dbc2SStephan Aßmus PRINT(5, " in_frames %5d, out_frames %5d, in_frames1 %5d, " 238*b543dbc2SStephan Aßmus "out_frames1 %5d, in_frames2 %5d, out_frames2 %5d\n", 239*b543dbc2SStephan Aßmus in_frames, out_frames, in_frames1, out_frames1, in_frames2, 240*b543dbc2SStephan Aßmus out_frames2); 2417b0daf5cSbeveloper 242e92593f4Sbeveloper fLastDataFrameWritten = out_frames2 - 1; 243e92593f4Sbeveloper 244*b543dbc2SStephan Aßmus // convert offset from frames into bytes 245*b543dbc2SStephan Aßmus offset *= sizeof(float) * fInputChannelCount; 2468d28117fSbeveloper 2477b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 248*b543dbc2SStephan Aßmus fResampler[i]->Resample( 249*b543dbc2SStephan Aßmus reinterpret_cast<char *>(data) 250*b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio), 251*b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames1, 252*b543dbc2SStephan Aßmus reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) 253*b543dbc2SStephan Aßmus + offset, fInputChannelCount * sizeof(float), out_frames1, 2547b0daf5cSbeveloper fInputChannelInfo[i].gain); 2557b0daf5cSbeveloper 256*b543dbc2SStephan Aßmus fResampler[i]->Resample( 257*b543dbc2SStephan Aßmus reinterpret_cast<char *>(data) 258*b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio) 259*b543dbc2SStephan Aßmus + in_frames1 * bytes_per_frame(fInput.format.u.raw_audio), 260*b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames2, 2617b0daf5cSbeveloper reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base), 262*b543dbc2SStephan Aßmus fInputChannelCount * sizeof(float), out_frames2, 2637b0daf5cSbeveloper fInputChannelInfo[i].gain); 264e92593f4Sbeveloper 2657b0daf5cSbeveloper } 2667b0daf5cSbeveloper } else { 267*b543dbc2SStephan Aßmus // printf("at %10Ld, data arrived for %10Ld to %10Ld, storing at " 268*b543dbc2SStephan Aßmus // "frames %ld to %ld\n", fCore->fTimeSource->Now(), start, 269*b543dbc2SStephan Aßmus // start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 270*b543dbc2SStephan Aßmus // frames_per_buffer(fInput.format.u.raw_audio)), offset, 271*b543dbc2SStephan Aßmus // offset + out_frames - 1); 272*b543dbc2SStephan Aßmus PRINT(3, "at %10Ld, data arrived for %10Ld to %10Ld, storing at " 273*b543dbc2SStephan Aßmus "frames %ld to %ld\n", fCore->fTimeSource->Now(), start, 274*b543dbc2SStephan Aßmus start + duration_for_frames(fInput.format.u.raw_audio.frame_rate, 275*b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)), offset, 276*b543dbc2SStephan Aßmus offset + out_frames - 1); 277191033efSbeveloper PRINT(5, " in_frames %5d, out_frames %5d\n", in_frames, out_frames); 2788d28117fSbeveloper 279e92593f4Sbeveloper fLastDataFrameWritten = offset + out_frames - 1; 280*b543dbc2SStephan Aßmus // convert offset from frames into bytes 281*b543dbc2SStephan Aßmus offset *= sizeof(float) * fInputChannelCount; 2827b0daf5cSbeveloper for (int i = 0; i < fInputChannelCount; i++) { 283*b543dbc2SStephan Aßmus fResampler[i]->Resample( 284*b543dbc2SStephan Aßmus reinterpret_cast<char *>(data) 285*b543dbc2SStephan Aßmus + i * bytes_per_sample(fInput.format.u.raw_audio), 286*b543dbc2SStephan Aßmus bytes_per_frame(fInput.format.u.raw_audio), in_frames, 287*b543dbc2SStephan Aßmus reinterpret_cast<char *>(fInputChannelInfo[i].buffer_base) 288*b543dbc2SStephan Aßmus + offset, fInputChannelCount * sizeof(float), 289*b543dbc2SStephan Aßmus out_frames, fInputChannelInfo[i].gain); 2907b0daf5cSbeveloper } 2917b0daf5cSbeveloper } 292e92593f4Sbeveloper fLastDataAvailableTime = start + buffer_duration; 293678c2017Sbeveloper } 2947ee2c804Sbeveloper 295bf7ab50dSStephan Aßmus 2967ee2c804Sbeveloper media_input & 2977ee2c804Sbeveloper MixerInput::MediaInput() 2987ee2c804Sbeveloper { 2997ee2c804Sbeveloper return fInput; 3007ee2c804Sbeveloper } 301e6c7c99fSbeveloper 302bf7ab50dSStephan Aßmus 303e6c7c99fSbeveloper int32 304e6c7c99fSbeveloper MixerInput::ID() 305e6c7c99fSbeveloper { 306e6c7c99fSbeveloper return fInput.destination.id; 307e6c7c99fSbeveloper } 308e6c7c99fSbeveloper 309bf7ab50dSStephan Aßmus 310d91580cdSbeveloper int 311fae6ce82Sbeveloper MixerInput::GetInputChannelCount() 312fae6ce82Sbeveloper { 313fae6ce82Sbeveloper return fInputChannelCount; 314fae6ce82Sbeveloper } 315fae6ce82Sbeveloper 316bf7ab50dSStephan Aßmus 3172e9d6607Sbeveloper void 3189c3be6a5Sbeveloper MixerInput::AddInputChannelDestination(int channel, int destination_type) 3192e9d6607Sbeveloper { 3209c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 321e6c7c99fSbeveloper 3222e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3232e9d6607Sbeveloper return; 3242e9d6607Sbeveloper 3252e9d6607Sbeveloper // test if it is already set 3269c3be6a5Sbeveloper if (fInputChannelInfo[channel].destination_mask & mask) 3272e9d6607Sbeveloper return; 3282e9d6607Sbeveloper 3299c3be6a5Sbeveloper // verify that no other channel has id 3309c3be6a5Sbeveloper if (-1 != GetInputChannelForDestination(destination_type)) { 331*b543dbc2SStephan Aßmus ERROR("MixerInput::AddInputChannelDestination: destination_type %d " 332*b543dbc2SStephan Aßmus "already assigned to channel %d\n", destination_type, 333*b543dbc2SStephan Aßmus GetInputChannelForDestination(destination_type)); 3349c3be6a5Sbeveloper return; 3359c3be6a5Sbeveloper } 3362e9d6607Sbeveloper 3372e9d6607Sbeveloper // add it to specified channel 3389c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask |= mask; 3392e9d6607Sbeveloper 3409c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 3419c3be6a5Sbeveloper UpdateInputChannelDestinations(); 3422e9d6607Sbeveloper } 3432e9d6607Sbeveloper 344a9cf57cfSAxel Dörfler 3452e9d6607Sbeveloper void 3469c3be6a5Sbeveloper MixerInput::RemoveInputChannelDestination(int channel, int destination_type) 3472e9d6607Sbeveloper { 3489c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 3492e9d6607Sbeveloper 3502e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3512e9d6607Sbeveloper return; 3522e9d6607Sbeveloper 3532e9d6607Sbeveloper // test if it is really set 3549c3be6a5Sbeveloper if ((fInputChannelInfo[channel].destination_mask & mask) == 0) 3552e9d6607Sbeveloper return; 3562e9d6607Sbeveloper 3572e9d6607Sbeveloper // remove it from specified channel 3589c3be6a5Sbeveloper fInputChannelInfo[channel].destination_mask &= ~mask; 3592e9d6607Sbeveloper 3609c3be6a5Sbeveloper fUserOverridesChannelDestinations = true; 3619c3be6a5Sbeveloper UpdateInputChannelDestinations(); 3622e9d6607Sbeveloper } 3632e9d6607Sbeveloper 364a9cf57cfSAxel Dörfler 3659c3be6a5Sbeveloper bool 3669c3be6a5Sbeveloper MixerInput::HasInputChannelDestination(int channel, int destination_type) 3672e9d6607Sbeveloper { 3682e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3699c3be6a5Sbeveloper return false; 3709c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 3719c3be6a5Sbeveloper return false; 372*b543dbc2SStephan Aßmus return fInputChannelInfo[channel].destination_mask 373*b543dbc2SStephan Aßmus & ChannelTypeToChannelMask(destination_type); 3742e9d6607Sbeveloper } 3752e9d6607Sbeveloper 376a9cf57cfSAxel Dörfler 3779c3be6a5Sbeveloper int 3789c3be6a5Sbeveloper MixerInput::GetInputChannelForDestination(int destination_type) 3799c3be6a5Sbeveloper { 3809c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 3819c3be6a5Sbeveloper return -1; 3829c3be6a5Sbeveloper uint32 mask = ChannelTypeToChannelMask(destination_type); 3839c3be6a5Sbeveloper for (int chan = 0; chan < fInputChannelCount; chan++) { 3849c3be6a5Sbeveloper if (fInputChannelInfo[chan].destination_mask & mask) 3859c3be6a5Sbeveloper return chan; 3869c3be6a5Sbeveloper } 3879c3be6a5Sbeveloper return -1; 3889c3be6a5Sbeveloper } 3899c3be6a5Sbeveloper 390a9cf57cfSAxel Dörfler 3919c3be6a5Sbeveloper int 3922e9d6607Sbeveloper MixerInput::GetInputChannelType(int channel) 3932e9d6607Sbeveloper { 3942e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 3952e9d6607Sbeveloper return 0; 3969c3be6a5Sbeveloper return GetChannelType(channel, fInputChannelMask); 3972e9d6607Sbeveloper } 3982e9d6607Sbeveloper 399a9cf57cfSAxel Dörfler 4002e9d6607Sbeveloper void 4012e9d6607Sbeveloper MixerInput::SetInputChannelGain(int channel, float gain) 4022e9d6607Sbeveloper { 4032e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4042e9d6607Sbeveloper return; 4052e9d6607Sbeveloper if (gain < 0.0f) 4062e9d6607Sbeveloper gain = 0.0f; 4072e9d6607Sbeveloper 4082e9d6607Sbeveloper fInputChannelInfo[channel].gain = gain; 4092e9d6607Sbeveloper } 4102e9d6607Sbeveloper 411a9cf57cfSAxel Dörfler 4122e9d6607Sbeveloper float 4132e9d6607Sbeveloper MixerInput::GetInputChannelGain(int channel) 4142e9d6607Sbeveloper { 4152e9d6607Sbeveloper if (channel < 0 || channel >= fInputChannelCount) 4162e9d6607Sbeveloper return 0.0f; 4172e9d6607Sbeveloper return fInputChannelInfo[channel].gain; 4182e9d6607Sbeveloper } 4192e9d6607Sbeveloper 420a9cf57cfSAxel Dörfler 4212e9d6607Sbeveloper void 4229c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinationMask() 4232e9d6607Sbeveloper { 4242e9d6607Sbeveloper // is the user already messed with the assignmens, don't do anything. 4259c3be6a5Sbeveloper if (fUserOverridesChannelDestinations) 4262e9d6607Sbeveloper return; 4272e9d6607Sbeveloper 4289c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinationMask: enter\n"); 4292e9d6607Sbeveloper 430806cf560Sbeveloper // first apply a 1:1 mapping 431*b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 432*b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask = GetChannelMask(i, 433*b543dbc2SStephan Aßmus fInputChannelMask); 434*b543dbc2SStephan Aßmus } 435806cf560Sbeveloper 436806cf560Sbeveloper // specialize this, depending on the available physical output channels 437643e1b2eSbeveloper if (fCore->OutputChannelCount() <= 2) { 438643e1b2eSbeveloper // less or equal two channels 439*b543dbc2SStephan Aßmus if (fInputChannelCount == 1 440*b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) 441*b543dbc2SStephan Aßmus & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 442ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 443806cf560Sbeveloper } 444643e1b2eSbeveloper } else { 445643e1b2eSbeveloper // more than two channel output card 446*b543dbc2SStephan Aßmus if (fInputChannelCount == 1 447*b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) 448*b543dbc2SStephan Aßmus & (B_CHANNEL_LEFT | B_CHANNEL_RIGHT))) { 449ab276ac8Sbeveloper fInputChannelInfo[0].destination_mask = B_CHANNEL_MONO; 450806cf560Sbeveloper } 451*b543dbc2SStephan Aßmus if (fInputChannelCount == 2 452*b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_LEFT)) { 453*b543dbc2SStephan Aßmus fInputChannelInfo[0].destination_mask 454*b543dbc2SStephan Aßmus = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 455806cf560Sbeveloper } 456*b543dbc2SStephan Aßmus if (fInputChannelCount == 2 457*b543dbc2SStephan Aßmus && (GetChannelMask(0, fInputChannelMask) & B_CHANNEL_RIGHT)) { 458*b543dbc2SStephan Aßmus fInputChannelInfo[0].destination_mask 459*b543dbc2SStephan Aßmus = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 460806cf560Sbeveloper } 461*b543dbc2SStephan Aßmus if (fInputChannelCount == 2 462*b543dbc2SStephan Aßmus && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_LEFT)) { 463*b543dbc2SStephan Aßmus fInputChannelInfo[1].destination_mask 464*b543dbc2SStephan Aßmus = B_CHANNEL_LEFT | B_CHANNEL_REARLEFT; 465806cf560Sbeveloper } 466*b543dbc2SStephan Aßmus if (fInputChannelCount == 2 467*b543dbc2SStephan Aßmus && (GetChannelMask(1, fInputChannelMask) & B_CHANNEL_RIGHT)) { 468*b543dbc2SStephan Aßmus fInputChannelInfo[1].destination_mask 469*b543dbc2SStephan Aßmus = B_CHANNEL_RIGHT | B_CHANNEL_REARRIGHT; 470806cf560Sbeveloper } 4712e9d6607Sbeveloper } 4722e9d6607Sbeveloper 473*b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 474*b543dbc2SStephan Aßmus TRACE("UpdateInputChannelDestinationMask: input channel %d, " 475*b543dbc2SStephan Aßmus "destination_mask 0x%08lX, base %p, gain %.3f\n", i, 476*b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask, 477*b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 478*b543dbc2SStephan Aßmus } 4799c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinationMask: leave\n"); 4802e9d6607Sbeveloper } 4812e9d6607Sbeveloper 482a9cf57cfSAxel Dörfler 4832e9d6607Sbeveloper void 4849c3be6a5Sbeveloper MixerInput::UpdateInputChannelDestinations() 4852e9d6607Sbeveloper { 486d91580cdSbeveloper int channel_count; 4872e9d6607Sbeveloper uint32 all_bits; 4882e9d6607Sbeveloper uint32 mask; 4892e9d6607Sbeveloper 4909c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinations: enter\n"); 491*b543dbc2SStephan Aßmus for (int i = 0; i < fInputChannelCount; i++) { 492*b543dbc2SStephan Aßmus TRACE("UpdateInputChannelDestinations: input channel %d, " 493*b543dbc2SStephan Aßmus "destination_mask 0x%08lX, base %p, gain %.3f\n", i, 494*b543dbc2SStephan Aßmus fInputChannelInfo[i].destination_mask, 495*b543dbc2SStephan Aßmus fInputChannelInfo[i].buffer_base, fInputChannelInfo[i].gain); 496*b543dbc2SStephan Aßmus } 4972e9d6607Sbeveloper 4982e9d6607Sbeveloper all_bits = 0; 4992e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 5009c3be6a5Sbeveloper all_bits |= fInputChannelInfo[i].destination_mask; 5012e9d6607Sbeveloper 502d91580cdSbeveloper TRACE("UpdateInputChannelDestinations: all_bits = %08lx\n", all_bits); 5032e9d6607Sbeveloper 5042e9d6607Sbeveloper channel_count = count_nonzero_bits(all_bits); 505*b543dbc2SStephan Aßmus TRACE("UpdateInputChannelDestinations: %d input channels, %d mixer " 506*b543dbc2SStephan Aßmus "channels (%d old)\n", fInputChannelCount, channel_count, 507*b543dbc2SStephan Aßmus fMixerChannelCount); 5082e9d6607Sbeveloper if (channel_count != fMixerChannelCount) { 5099c3be6a5Sbeveloper delete [] fMixerChannelInfo; 5102e9d6607Sbeveloper fMixerChannelInfo = new mixer_chan_info[channel_count]; 5112e9d6607Sbeveloper fMixerChannelCount = channel_count; 5122e9d6607Sbeveloper } 5132e9d6607Sbeveloper 5142e9d6607Sbeveloper // assign each mixer channel one type 5159c3be6a5Sbeveloper // and the gain from the fChannelTypeGain[] 516d91580cdSbeveloper mask = 1; 517d91580cdSbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5182e9d6607Sbeveloper while (mask != 0 && (all_bits & mask) == 0) 5192e9d6607Sbeveloper mask <<= 1; 5209c3be6a5Sbeveloper fMixerChannelInfo[i].destination_type = ChannelMaskToChannelType(mask); 521*b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_gain 522*b543dbc2SStephan Aßmus = fChannelTypeGain[fMixerChannelInfo[i].destination_type]; 5232e9d6607Sbeveloper mask <<= 1; 5242e9d6607Sbeveloper } 5252e9d6607Sbeveloper 5262e9d6607Sbeveloper // assign buffer_base pointer for each mixer channel 5272e9d6607Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5282e9d6607Sbeveloper int j; 5292e9d6607Sbeveloper for (j = 0; j < fInputChannelCount; j++) { 530*b543dbc2SStephan Aßmus if (fInputChannelInfo[j].destination_mask 531*b543dbc2SStephan Aßmus & ChannelTypeToChannelMask( 532*b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_type)) { 533*b543dbc2SStephan Aßmus fMixerChannelInfo[i].buffer_base = fMixBuffer ? &fMixBuffer[j] 534*b543dbc2SStephan Aßmus : 0; 5352e9d6607Sbeveloper break; 5362e9d6607Sbeveloper } 5372e9d6607Sbeveloper } 5382e9d6607Sbeveloper if (j == fInputChannelCount) { 539a2ca4723Sbeveloper ERROR("buffer assignment failed for mixer chan %d\n", i); 5402e9d6607Sbeveloper fMixerChannelInfo[i].buffer_base = fMixBuffer; 5412e9d6607Sbeveloper } 5422e9d6607Sbeveloper } 5432e9d6607Sbeveloper 544*b543dbc2SStephan Aßmus for (int i = 0; i < fMixerChannelCount; i++) { 545*b543dbc2SStephan Aßmus TRACE("UpdateInputChannelDestinations: mixer channel %d, type %2d, " 546*b543dbc2SStephan Aßmus "base %p, gain %.3f\n", i, fMixerChannelInfo[i].destination_type, 547*b543dbc2SStephan Aßmus fMixerChannelInfo[i].buffer_base, 548*b543dbc2SStephan Aßmus fMixerChannelInfo[i].destination_gain); 549*b543dbc2SStephan Aßmus } 5502e9d6607Sbeveloper 5519c3be6a5Sbeveloper TRACE("UpdateInputChannelDestinations: leave\n"); 5522e9d6607Sbeveloper } 553bf7ab50dSStephan Aßmus 554a9cf57cfSAxel Dörfler 555bf7ab50dSStephan Aßmus // Note: The following code is outcommented on purpose 556bf7ab50dSStephan Aßmus // and is about to be modified at a later point 55769517c15Sbeveloper /* 5582e9d6607Sbeveloper void 559*b543dbc2SStephan Aßmus MixerInput::SetInputChannelDestinationGain(int channel, int destination_type, 560*b543dbc2SStephan Aßmus float gain) 5612e9d6607Sbeveloper { 562*b543dbc2SStephan Aßmus TRACE("SetInputChannelDestinationGain: channel %d, destination_type %d, 563*b543dbc2SStephan Aßmus gain %.4f\n", channel, destination_type, gain); 5649c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 5659c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 5669c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 5672e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 5682e9d6607Sbeveloper return; 5699c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 5709c3be6a5Sbeveloper return; 5712e9d6607Sbeveloper if (gain < 0.0f) 5722e9d6607Sbeveloper gain = 0.0f; 5739c3be6a5Sbeveloper fChannelTypeGain[destination_type] = gain; 5749c3be6a5Sbeveloper for (int i = 0; i < fMixerChannelCount; i++) { 5759c3be6a5Sbeveloper if (fMixerChannelInfo[i].destination_type == destination_type) { 5769c3be6a5Sbeveloper fMixerChannelInfo[i].destination_gain = gain; 5779c3be6a5Sbeveloper return; 5789c3be6a5Sbeveloper } 5799c3be6a5Sbeveloper } 5802e9d6607Sbeveloper } 5812e9d6607Sbeveloper 582a9cf57cfSAxel Dörfler 5832e9d6607Sbeveloper float 5849c3be6a5Sbeveloper MixerInput::GetInputChannelDestinationGain(int channel, int destination_type) 5852e9d6607Sbeveloper { 5869c3be6a5Sbeveloper // we don't need the channel, as each destination_type can only exist 5879c3be6a5Sbeveloper // once for each MixerInput, but we use it for parameter validation 5889c3be6a5Sbeveloper // and to have a interface similar to MixerOutput 5892e9d6607Sbeveloper if (channel < 0 || channel >= fMixerChannelCount) 5909c3be6a5Sbeveloper return 0.0f; 5919c3be6a5Sbeveloper if (destination_type < 0 || destination_type >= MAX_CHANNEL_TYPES) 5929c3be6a5Sbeveloper return 0.0f; 5939c3be6a5Sbeveloper return fChannelTypeGain[destination_type]; 5942e9d6607Sbeveloper } 59569517c15Sbeveloper */ 59669517c15Sbeveloper 597a9cf57cfSAxel Dörfler 59869517c15Sbeveloper void 59969517c15Sbeveloper MixerInput::SetMixerChannelGain(int mixer_channel, float gain) 60069517c15Sbeveloper { 60169517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 60269517c15Sbeveloper return; 60369517c15Sbeveloper if (gain < 0.0f) 60469517c15Sbeveloper gain = 0.0f; 60569517c15Sbeveloper 60669517c15Sbeveloper fMixerChannelInfo[mixer_channel].destination_gain = gain; 60769517c15Sbeveloper fChannelTypeGain[fMixerChannelInfo[mixer_channel].destination_type] = gain; 60869517c15Sbeveloper } 60969517c15Sbeveloper 610a9cf57cfSAxel Dörfler 61169517c15Sbeveloper float 61269517c15Sbeveloper MixerInput::GetMixerChannelGain(int mixer_channel) 61369517c15Sbeveloper { 61469517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 61569517c15Sbeveloper return 0.0; 61669517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_gain; 61769517c15Sbeveloper } 61869517c15Sbeveloper 619a9cf57cfSAxel Dörfler 62069517c15Sbeveloper int 62169517c15Sbeveloper MixerInput::GetMixerChannelType(int mixer_channel) 62269517c15Sbeveloper { 62369517c15Sbeveloper if (mixer_channel < 0 || mixer_channel >= fMixerChannelCount) 62469517c15Sbeveloper return -1; 62569517c15Sbeveloper return fMixerChannelInfo[mixer_channel].destination_type; 62669517c15Sbeveloper } 6272e9d6607Sbeveloper 628a9cf57cfSAxel Dörfler 6292e9d6607Sbeveloper void 6301c237c18Sbeveloper MixerInput::SetEnabled(bool yesno) 6311c237c18Sbeveloper { 6321c237c18Sbeveloper fEnabled = yesno; 6331c237c18Sbeveloper } 6341c237c18Sbeveloper 635a9cf57cfSAxel Dörfler 6361c237c18Sbeveloper bool 6371c237c18Sbeveloper MixerInput::IsEnabled() 6381c237c18Sbeveloper { 6391c237c18Sbeveloper return fEnabled; 6401c237c18Sbeveloper } 6411c237c18Sbeveloper 642a9cf57cfSAxel Dörfler 6431c237c18Sbeveloper void 6448d28117fSbeveloper MixerInput::SetMixBufferFormat(int32 framerate, int32 frames) 6452e9d6607Sbeveloper { 646a9cf57cfSAxel Dörfler TRACE("MixerInput::SetMixBufferFormat: framerate %ld, frames %ld\n", 647a9cf57cfSAxel Dörfler framerate, frames); 648d5848e21Sbeveloper 6497b0daf5cSbeveloper fMixBufferFrameRate = framerate; 650a9cf57cfSAxel Dörfler fDebugMixBufferFrames = frames; 6512e9d6607Sbeveloper 652d5848e21Sbeveloper // frames and/or framerate can be 0 (if no output is connected) 653d5848e21Sbeveloper if (framerate == 0 || frames == 0) { 654a9cf57cfSAxel Dörfler if (fMixBuffer != NULL) { 655d5848e21Sbeveloper rtm_free(fMixBuffer); 656a9cf57cfSAxel Dörfler fMixBuffer = NULL; 657d5848e21Sbeveloper } 658d5848e21Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 659d5848e21Sbeveloper fInputChannelInfo[i].buffer_base = 0; 660d5848e21Sbeveloper fMixBufferFrameCount = 0; 661d5848e21Sbeveloper 6629c3be6a5Sbeveloper UpdateInputChannelDestinationMask(); 6639c3be6a5Sbeveloper UpdateInputChannelDestinations(); 664d5848e21Sbeveloper return; 665d5848e21Sbeveloper } 6667b0daf5cSbeveloper 6677b0daf5cSbeveloper // make fMixBufferFrameCount an integral multiple of frames, 6687b0daf5cSbeveloper // but at least 3 times duration of our input buffer 6697b0daf5cSbeveloper // and at least 2 times duration of the output buffer 670*b543dbc2SStephan Aßmus bigtime_t inputBufferLength = duration_for_frames( 671*b543dbc2SStephan Aßmus fInput.format.u.raw_audio.frame_rate, 672*b543dbc2SStephan Aßmus frames_per_buffer(fInput.format.u.raw_audio)); 6737b0daf5cSbeveloper bigtime_t outputBufferLength = duration_for_frames(framerate, frames); 674*b543dbc2SStephan Aßmus bigtime_t mixerBufferLength 675*b543dbc2SStephan Aßmus = max_c(3 * inputBufferLength, 2 * outputBufferLength); 6767b0daf5cSbeveloper int temp = frames_for_duration(framerate, mixerBufferLength); 6777b0daf5cSbeveloper fMixBufferFrameCount = ((temp / frames) + 1) * frames; 6787b0daf5cSbeveloper 679a2ca4723Sbeveloper TRACE(" inputBufferLength %10Ld\n", inputBufferLength); 680a2ca4723Sbeveloper TRACE(" outputBufferLength %10Ld\n", outputBufferLength); 681a2ca4723Sbeveloper TRACE(" mixerBufferLength %10Ld\n", mixerBufferLength); 682d91580cdSbeveloper TRACE(" fMixBufferFrameCount %10d\n", fMixBufferFrameCount); 6837b0daf5cSbeveloper 6848d28117fSbeveloper ASSERT((fMixBufferFrameCount % frames) == 0); 6858d28117fSbeveloper 686e92593f4Sbeveloper fLastDataFrameWritten = -1; 687e92593f4Sbeveloper fFractionalFrames = 0.0; 688e92593f4Sbeveloper 6892e9d6607Sbeveloper rtm_free(fMixBuffer); 690356855c3Sbeveloper rtm_delete_pool(fRtmPool); 691a9cf57cfSAxel Dörfler 6927b0daf5cSbeveloper int size = sizeof(float) * fInputChannelCount * fMixBufferFrameCount; 693a9cf57cfSAxel Dörfler if (rtm_create_pool(&fRtmPool, size) != B_OK) 694a9cf57cfSAxel Dörfler fRtmPool = NULL; 695a9cf57cfSAxel Dörfler 696356855c3Sbeveloper fMixBuffer = (float*)rtm_alloc(fRtmPool, size); 697a9cf57cfSAxel Dörfler if (fMixBuffer == NULL) 698a9cf57cfSAxel Dörfler return; 6997b0daf5cSbeveloper 7007b0daf5cSbeveloper memset(fMixBuffer, 0, size); 7012e9d6607Sbeveloper 7022e9d6607Sbeveloper for (int i = 0; i < fInputChannelCount; i++) 7037b0daf5cSbeveloper fInputChannelInfo[i].buffer_base = &fMixBuffer[i]; 704d5848e21Sbeveloper 7059c3be6a5Sbeveloper UpdateInputChannelDestinationMask(); 7069c3be6a5Sbeveloper UpdateInputChannelDestinations(); 7072e9d6607Sbeveloper } 708